Delta Time and Movement
Before you can move the paddle or ball, you first need to compute the delta time. Remember that delta time is the difference between the current frame’s time and the previous frame’s time. You compute this delta time in UpdateGame
, before updating game objects.
The skeleton of UpdateGame
is:
- Frame limit
- Calculate delta time (as a float in seconds)
- Cap to maximum delta time
- Update all game objects by delta time
Calculating Delta Time
The SDL_GetTicks
function returns the number of milliseconds (ms) elapsed since the game initialized SDL: https://wiki.libsdl.org/SDL_GetTicks. Every frame, use SDL_GetTicks
to get the current time, and the difference between this and the previous frame’s time is the delta time. You’ll have to store this “previous” time in a member variable, which you should initialize to 0.
After computing the difference in time, convert the milliseconds to seconds (as a float
). Remember that there’s 1,000 milliseconds in every second.
We convert the milliseconds to seconds simply because it’s easier to percieve and think about time in seconds. Eg. “I want the enemy to take 5 seconds to move there” is just easier to say than “in 5000 milliseconds”.
Frame Limiting
Although our delta time calculation works, it allows us to have an uncapped (and potentially absurdly high) frame rate. To fix this, we want to implement frame limiting, which means capping the frame rate to a set value. In our case, we will frame limit to ~60 FPS.
One way to implement frame limiting is a with a while()
that loops until SDL_GetTicks
returns 16 ms greater than the “previous” time. As noted above, this should happen before you calculate the delta time.
Capping to Maximum Delta Time
For debugging and slower computers, we also want to set a maximum delta time. To fix this problem, after you calculate the delta time you need to cap the delta time to be no higher than 0.033. All we are doing with this is lying to the system about delta time. This is saying, “If it took more than 0.033 seconds (33 ms) last frame, just pretend like it only took 33 ms.”
An easy way to test your delta time calculation is to add a SDL_Log
(https://wiki.libsdl.org/SDL_Log) call that outputs your delta time every frame. You should see a lot of spam confirming that your delta time is around 0.016. Once you confirm this works, comment out the SDL_Log
.
SDL_Log
uses a printf-style syntax for formatting. You may not be familiar with this as it’s more a C thing than C++. The first parameter to the function is a string literal which can contain variable placeholders that begin with %
and are followed by a letter for the type. The number of additional parameters to the function should equal the number of variable placeholders. For example, this would print a float, an integer, and a C-style string:SDL_Log("My float is %f, int is %d, and %s", 5.0f, 10, "Hello!");
Moving the Paddle
The player should be able to use the W
key to move the paddle up and the S
key to move the paddle down. A rough approach to this is:
- In
ProcessInput
, check the state of the keys, and save the direction you should move in (if any) in a member variable - In
UpdateGame
, use your delta time and move the paddle as a function of delta time, based on the member variable from (1) - Make sure it’s not possible for the player to move the paddle off the screen (one way to do this is to always run the code in (2) and then fix the position afterwards if needed)
Do not attempt to move the paddle in ProcessInput
. In order to move the paddle at the correct speed regardless of the frame rate, you need delta time, and delta time is not provided to the ProcessInput
function.
You should now be able to move the paddle up and down (and not off screen):
Ball Movement/Bouncing
First, add an SDL_Point
member variable for the ball’s velocity (and initialize it to something so the ball moves at the start).
Every frame, the ball’s new position is the old position plus the velocity times delta time (you’ll have to do this calculation separately for the x
and y
components).
The ball should now move based on your velocity.
Now add code that detects if the ball hits the top/bottom/right walls (you can just check the x/y position of the ball relative to these walls). To bounce the ball, you negate one of the velocity components. Bouncing off the top/bottom walls should negate the y-component of the velocity, and likewise the right wall should negate the x-component.
One issue with this approach is that the ball may get stuck on a wall or just appear within the wall for a single frame. To fix this problem, you can move the position of the ball to the edge of the wall when the bounce occurs. (If the ball is overlapping with the right wall, move the ball to the left so that it is exactly touching and no longer overlapping.)
It is important that you first move the ball and then handle the collisions. If you do it in the opposite order, the ball may end up moving into a wall and getting drawn there for that frame.
The ball should now bounce off the three walls, and not get stuck on walls.
Bouncing off the paddle is like bouncing off the walls. First, imagine that the paddle is just a wall. So, implement code bouncing against the paddle like the other walls.
Now, restrict it so that the ball only bounces off the “left wall” if the y-position of the paddle is such that it would touch the ball. Hint: If you are having trouble with this calculation, it may help to draw a diagram of the paddle and the ball.
You should now be able to bounce the ball off the paddle, and only if the paddle touches the ball.
Losing the Game
Finally, add code that checks if the ball has gone off the screen to the left (meaning the player missed the ball). If this happens, exit the game loop (you can set your bool to false
).
This concludes Lab 1. Make sure you push your completed code to GitHub, and verify that you successfully pushed by viewing your code on the GitHub website. You should also confirm that your GitHub actions successfully finished and there are no warnings.
Once you’ve pushed your code, you should review the grading specifications to confirm you’ve satisfied them.