Exploring pygame 5 - Movement and Collision
Published on
Movement is part of a large portion of games. When jumping between platforms, shooting against a horde of enemies, piloting a space ship and running through the streets, we are causing movement and interacting with the game environment, applying action and causing reactions.
This chapter is to describe the basics of moving objects across the screen and their interaction with other elements through collision detection.
Movement
If you are following this series of posts, you already saw an example of movement at the post about the game loop, where we implemented a ball that moves through the screen bouncing around.
This time we’ll go through a similar code sample, adding more details to it and also, adding some new concepts:
|
|
The code is pretty straight forward. We create a variable position_x
to hold the square position on x.
Inside the loop, we increment its position by one pixel per cycle and then it’s drawn again at its new position.
The drawing loop creates a cinematic effect of movement on the screen, but this implementation has a problem.
You can’t control the object movement velocity, and powerful the computer, more loops are processed, causing results like that:
To fix this issue, we need to go back to physics class, when we learned about linear motion. To ensure constant velocity, we’ll use the following formula:
$$d = d_{i} + v \Delta t$$
Applying it to the code, we’ll have this:
|
|
We start defining the velocity at the x-axis to 100 pixels per second.
Then we get the initial time to be used at the delta time calculation.
Inside the loop, we capture the final time and at the next line, the dt
(delta time) subtracting the final time by the initial time.
At line 28, the initial time receives the final time to be used at the next loop cycle.
In the end, we calculate the displacement at line 36.
As we can see, it is possible to control the object movement velocity, but that solves only the visible part of the issue, the loop executes much more than the necessary generating noting more than overhead.
FPS
These drawing cycles are also known as frames, and the frame rate control is a common practice among the audio-visual professionals. The measuring unit used on this kind of control is the FPS (Frames Per Second).
Implementing this frame control gives you some benefits:
- Reduces de unnecessary machine overload
- Makes the multiplayer game sync easier to implement
- Reduces the error propagation of the floating-point operation (there are techniques to mitigate this kind of issue, but if you are starting, don’t spend time on that yet)
- Increases the predictability and facilitates the process of planning your game. Now you can calculate how many processing you can have during a frame interval once you know the minimum requirements of your game.
The traditional refresh rate for movies is 24fps, and in games, it can change from 30 to 60fps. In our case, we’ll use the 30fps refresh rate.
|
|
Thanks to pygame’s Clock
implementation we could simplify things a little.
Different than Python’s time
library that works on a scale of seconds, pygame’s Clock
works on milliseconds, so we changed the velocity from 100
to 0.1
to ensure the same velocity of a hundred pixels per second.
Next, we instantiate Clock
before entering the loop, and then, inside the loop, we call the tick
function passing as argument the amount of FPS to limit the loop.
The tick
function must be called on each cycle, so if a cycle runs faster than the expected rate, it sleeps for a brief moment to ensure the defined rate. As a result, the function returns the delta time between this loop and the previous one.
We have the square sliding through the screen on a constant speed, so let’s proceed to the collision detection.
Collision
The collision is the product of the interaction between the objects of your game. Their interaction can produce it, or the interaction with the environment.
The collision detection tends to grow on complexity as long as you add more elements with different formats to the scene.
At the example below, we’ll see its basic concept by making the square interact with two pads, changing direction after colliding with them.
|
|
The most straightforward collision detection consists of treating all elements as rectangular areas. Pygame has it implemented on the Rect
class. It was used at the code to create a rectangular area to the square and for the pads.
With the creation of Rect
we start to use the function move_ip
to move it. This function changes the caller position in place, different from the move
function that produces a new object with the position changed.
At line 37 the collidelist
function checks if any collision happened to return the collided object index from the list passed. In case there is no collision, it returns -1
.
In the end, the square and the pads are drawn to the screen using their Rect
instances to produce the following result:
Conclusion
With these concepts of movement and collision, you can create some exciting games like Pong. I’ll end this post with a challenge to you. Use these concepts to implement the Pong game.
The code used to make this post is available at exploring-pygame.
This work is licensed under a Creative Commons Attribuition-ShareAlike 4.0 International License .