Building an A Level Platform Game Project — Part 3: Adding Gravity and Jumping
In Part 1, we planned the platform game and set realistic success criteria.
In Part 2, we created the first working prototype: a game window, a visible player, left and right movement, frame rate control and screen boundary checks.
At that point, the game was visible and interactive, but it was not really a platform game yet.
A player sliding left and right across the screen is a start. But a platform game needs vertical movement. It needs the player to fall, jump, land and respond to gravity.
This is where the project starts to become much more interesting technically.
Adding gravity and jumping introduces some important programming ideas:
- velocity
- acceleration
- game physics
- state checking
- keyboard input
- conditions
- testing awkward cases
- preventing repeated jumping in mid-air
It also gives students a proper programming problem to solve, not just a drawing exercise.
Why Gravity Makes the Game Feel Real
In a simple game, the player’s position is controlled by x and y coordinates.
In Part 2, we changed the x-coordinate to move the player left and right.
Now we need to change the y-coordinate as well.
This is where students often meet one of the first confusing ideas in game programming: screen coordinates do not behave like a normal maths graph.
On most screens:
- x increases as you move right
- y increases as you move down
- y decreases as you move up
So when the player falls, the y-coordinate increases.
When the player jumps, the y-coordinate decreases.
This feels backwards at first, but students soon get used to it.
The Aim for Part 3
The target for this stage is:
Add gravity so the player falls downwards, add jumping so the player can move upwards, and prevent the player from jumping again while already in the air.
By the end of this stage, the player should be able to:
- move left and right
- stand on the ground
- jump when the space bar is pressed
- rise into the air
- slow down
- fall back down
- land on the ground
- avoid repeated jumping while in the air
This is a major step forward.
The game will still not have platforms yet. That comes in Part 4.
For now, we will use the bottom of the screen as the ground.
Thinking About Vertical Velocity
In Part 2, movement was simple.
If the right arrow was pressed:
player_x += player_speedIf the left arrow was pressed:
player_x -= player_speedJumping is more complicated because it changes over time.
When the player first jumps, they move upwards quickly. Then gravity slows them down. Eventually they stop rising and begin to fall.
This means we need a vertical velocity.
A velocity is a speed in a particular direction.
For the player, we can create a variable:
player_y_velocity = 0This will control how much the player’s y-position changes each frame.
If the vertical velocity is positive, the player moves down.
If the vertical velocity is negative, the player moves up.
That is because screen y-coordinates increase as you move down.
Adding Gravity
Gravity can be represented by increasing the vertical velocity each frame.
For example:
gravity = 0.5
player_y_velocity += gravity
player_y += player_y_velocityThis means the player falls faster and faster.
At first, the vertical velocity may be 0.
After one frame, it becomes 0.5.
Then 1.0.
Then 1.5.
Then 2.0.
This creates acceleration.
The player does not simply fall at one fixed speed. The fall becomes faster over time, which feels more natural.
This is a very useful teaching point because it connects programming with physics.
Creating a Ground Level
Before we add platforms, we need somewhere for the player to land.
A simple approach is to define the ground as a y-coordinate near the bottom of the screen.
For example:
GROUND_LEVEL = 540If the player is 60 pixels tall, and the screen height is 600 pixels, then placing the player’s top-left y-coordinate at 540 means the bottom of the player is at 600.
So the player stands exactly on the bottom of the screen.
We can check if the player has fallen below the ground:
if player_y > GROUND_LEVEL:
player_y = GROUND_LEVEL
player_y_velocity = 0This prevents the player falling forever.
It also resets the vertical velocity when the player lands.
Adding the Jump
To make the player jump, we give the vertical velocity a negative value.
For example:
player_y_velocity = -12This moves the player upwards because it reduces the y-coordinate.
The number controls the strength of the jump.
A larger negative number makes the player jump higher.
A smaller negative number makes the player jump lower.
For example:
jump_strength = -12Then, when the player presses space:
if keys[pygame.K_SPACE]:
player_y_velocity = jump_strengthThis seems simple, but it creates a problem.
The Infinite Jump Problem
If we use the code above, the player may be able to jump again and again while already in the air.
This is sometimes called infinite jumping.
The player can keep pressing space and fly upwards forever.
That might be useful in a different type of game, but it is not what we want in a normal platform game.
We need the program to know whether the player is on the ground.
We can use a Boolean variable:
on_ground = TrueA Boolean can only be True or False.
The player should only be allowed to jump if on_ground is True.
For example:
if keys[pygame.K_SPACE] and on_ground:
player_y_velocity = jump_strength
on_ground = FalseThen, when the player lands:
if player_y > GROUND_LEVEL:
player_y = GROUND_LEVEL
player_y_velocity = 0
on_ground = TrueThis is an important moment in the project.
The student is no longer just moving a shape. They are managing the state of the player.
The Updated Prototype Code
At the end of Part 3, the prototype might look like this:
import pygame
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GROUND_LEVEL = 540
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Escape the Platforms")
clock = pygame.time.Clock()
player_x = 100
player_y = GROUND_LEVEL
player_width = 40
player_height = 60
player_speed = 5
player_y_velocity = 0
gravity = 0.5
jump_strength = -12
on_ground = True
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
# Horizontal movement
if keys[pygame.K_LEFT]:
player_x -= player_speed
if keys[pygame.K_RIGHT]:
player_x += player_speed
# Jumping
if keys[pygame.K_SPACE] and on_ground:
player_y_velocity = jump_strength
on_ground = False
# Apply gravity
player_y_velocity += gravity
player_y += player_y_velocity
# Ground collision
if player_y > GROUND_LEVEL:
player_y = GROUND_LEVEL
player_y_velocity = 0
on_ground = True
# Screen boundary checks
if player_x < 0:
player_x = 0
if player_x + player_width > SCREEN_WIDTH:
player_x = SCREEN_WIDTH - player_width
# Draw everything
screen.fill((255, 255, 255))
pygame.draw.rect(
screen,
(0, 0, 255),
(player_x, player_y, player_width, player_height)
)
pygame.draw.line(
screen,
(0, 0, 0),
(0, GROUND_LEVEL + player_height),
(SCREEN_WIDTH, GROUND_LEVEL + player_height),
3
)
pygame.display.update()
pygame.quit()This is still a simple prototype, but it now behaves much more like a game.
The player can move.
The player can jump.
The player falls because of gravity.
The player lands on the ground.
The player cannot repeatedly jump in mid-air.
That is a very important development stage.
Why We Draw a Ground Line
In the example code, a black line is drawn at the bottom of the screen:
pygame.draw.line(
screen,
(0, 0, 0),
(0, GROUND_LEVEL + player_height),
(SCREEN_WIDTH, GROUND_LEVEL + player_height),
3
)This is mainly for visual clarity.
It helps the student see where the ground is.
At this stage, the ground is not a proper platform. It is simply a boundary that stops the player falling off the screen.
In Part 4, we will replace this simple ground idea with proper platforms.
Testing Gravity and Jumping
This stage needs proper testing.
Students should not simply say “jumping works”.
They should test specific behaviours.
| Test Number | Test | Expected Result | Actual Result | Pass/Fail |
|---|---|---|---|---|
| 1 | Run the program | Player appears standing on the ground | Player appears on the ground | Pass |
| 2 | Press left arrow | Player moves left | Player moves left | Pass |
| 3 | Press right arrow | Player moves right | Player moves right | Pass |
| 4 | Press space while on ground | Player jumps upwards | Player jumps upwards | Pass |
| 5 | Release space after jumping | Player continues moving according to velocity and gravity | Player rises then falls | Pass |
| 6 | Press space repeatedly in the air | Player does not keep jumping upwards | Player cannot double jump | Pass |
| 7 | Player falls back to ground | Player lands and stops falling | Player lands correctly | Pass |
| 8 | Hold left arrow while jumping | Player moves left in the air | Player moves left while airborne | Pass |
| 9 | Hold right arrow while jumping | Player moves right in the air | Player moves right while airborne | Pass |
| 10 | Move to screen edge while jumping | Player stays within the screen | Player remains inside screen | Pass |
This table creates useful evidence for the project.
It also shows that the student has thought about normal tests and more awkward cases.
Linking Back to Success Criteria
In Part 1, we created success criteria for the project.
This stage helps meet several of them:
- The player falls when not standing on a platform.
- The player can jump from the ground.
- The player cannot repeatedly jump while already in the air.
- The player lands without falling through the ground.
- The player can move left and right while jumping.
- The player cannot move beyond the edge of the game screen.
This is why success criteria are so valuable.
They allow the student to show measurable progress.
A development log could say:
This stage successfully added gravity and jumping. Testing showed that the player could jump from the ground, fall back down and land correctly. A Boolean variable was added to prevent the player from repeatedly jumping while in the air.
That is much stronger than simply writing:
I added jumping.
Common Bugs Students May Meet
This stage often produces interesting bugs.
That is good.
A Level projects need evidence of problems being found and solved.
Bug 1: The Player Falls Through the Ground
This may happen if the ground check is missing or incorrect.
For example, if the program checks:
if player_y == GROUND_LEVEL:this may fail because the player might move from just above the ground to just below the ground in one frame.
It is safer to check:
if player_y > GROUND_LEVEL:or sometimes:
if player_y >= GROUND_LEVEL:This is a useful programming lesson.
Exact equality is not always the best test when movement is changing every frame.
Bug 2: The Player Can Jump Forever
This usually happens if the program does not check whether the player is on the ground.
The solution is to use a variable such as:
on_groundand only allow jumping when this is True.
Bug 3: The Jump Is Too High or Too Low
This is controlled by the jump strength and gravity.
For example:
gravity = 0.5
jump_strength = -12Students can experiment with these values.
A smaller gravity value makes the player float for longer.
A larger gravity value pulls the player down faster.
A more negative jump strength creates a higher jump.
A less negative jump strength creates a smaller jump.
This gives a good opportunity for testing and user feedback.
The student could ask a user:
Does the jump feel too high, too low or about right?
Then they can adjust the values and record the improvement.
Bug 4: The Player Appears to Sink Into the Ground
This may happen if the ground level has been calculated incorrectly.
The important question is:
Does player_y represent the top of the player or the bottom of the player?
In our example, player_y represents the top-left corner of the player rectangle.
That means the bottom of the player is:
player_y + player_heightThis distinction becomes very important when we add platforms.
Why This Is Good Evidence for A Level
Gravity and jumping create a strong section for the project write-up because the student can explain the algorithm.
They can describe:
- why a vertical velocity variable was needed
- how gravity changes the velocity each frame
- why a negative velocity moves the player upwards
- how the program detects landing
- why a Boolean variable prevents repeated jumping
- how the values for gravity and jump strength were tested
This is exactly the kind of thinking that should appear in a strong programming project.
The final program matters, but the explanation of the development process matters too.
Improving the Code Structure
At this stage, the code is still manageable.
However, we can already see that it is becoming more complex.
The player now has:
- x-position
- y-position
- width
- height
- horizontal speed
- vertical velocity
- jump strength
- ground state
Later, the player may also have:
- lives
- score
- direction
- animation state
- collision rectangle
- health
- current level
This is a good point to discuss whether a class may eventually be useful.
A Player class could store the player’s data and methods in one place.
For example, it might eventually include:
class Player:
def __init__(self, x, y):
self.x = x
self.y = y
self.width = 40
self.height = 60
self.speed = 5
self.y_velocity = 0
self.on_ground = True
def move(self, keys):
pass
def jump(self):
pass
def apply_gravity(self):
pass
def draw(self, screen):
passStudents do not need to do this immediately, but they should be aware of why it might help.
A strong project can show how the code was improved as complexity increased.
Should the Player Be Able to Move in the Air?
In the current version, the player can move left and right while jumping.
That is common in many platform games.
However, it is a design decision.
Some games give the player a lot of control in the air. Others make jumping more rigid and realistic.
Students can think about this as part of their evaluation.
Questions to consider:
- Should the player be able to change direction while in the air?
- Should air movement be slower than ground movement?
- Should the game feel realistic or arcade-like?
- What does the target user prefer?
This is a nice example of how programming choices connect to user experience.
Adding Debug Information
During development, it can be useful to display values on the screen or print them to the console.
For example, students might print:
print(player_y, player_y_velocity, on_ground)This helps them see what is happening when the player jumps and lands.
However, debug output should usually be removed or hidden in the final version.
Students can mention this in their documentation:
I used printed debug values to check the player’s y-coordinate, vertical velocity and ground state while testing the jump algorithm. This helped identify when the player was landing and when the
on_groundvariable changed.
That is useful evidence of debugging.
Practical Task for Students
Before moving on to platforms, students should complete this task.
Part 3 Student Task
Add gravity and jumping to your platform game prototype.
Your program should include:
- A vertical velocity variable.
- A gravity value.
- A jump strength value.
- A ground level.
- A Boolean variable to record whether the player is on the ground.
- A jump controlled by the space bar or another chosen key.
- A check to stop the player falling through the ground.
- A check to stop repeated jumping in mid-air.
- A test table for gravity and jumping.
- Screenshots or short video evidence of the player jumping and landing.
Extension Task
Improve the jumping system by adding one of the following:
- a different jump height
- a maximum falling speed
- a double jump as an intentional feature
- a smoother jump animation
- reduced air control
- a sound effect when jumping
- a debug display showing vertical velocity
Students should only attempt the extension once the basic jump works correctly.
Development Log Example
A good development log entry for this stage might look like this:
Development Stage
Adding gravity and jumping.
Aim
To make the player fall under gravity, jump when the space bar is pressed and land correctly on the ground.
What Was Added
- vertical velocity variable
- gravity variable
- jump strength variable
- ground level
on_groundBoolean variable- jump input using the space bar
- landing check
- testing for repeated jumping
Problems Found
- The player initially kept jumping while already in the air.
- The player sometimes moved slightly below the ground before being reset.
- The jump height needed adjusting to feel natural.
Changes Made
- Added an
on_groundvariable to prevent repeated jumping. - Reset the player’s y-position to the ground level after landing.
- Adjusted gravity and jump strength values after testing.
Evidence Collected
- screenshot of the player standing on the ground
- screenshot of the player in the air
- test table showing jump behaviour
- code section showing gravity and jump logic
- notes explaining how the infinite jump bug was fixed
This kind of evidence is valuable because it shows a real development process.
Final Thoughts: The Game Is Starting to Behave
At the end of Part 3, the game still looks simple.
The player may still be just a rectangle.
There may be no platforms yet.
There may be no enemies, collectables or levels.
But something important has changed.
The game now has behaviour.
The player can move, jump, fall and land. The program now includes a simple physics system. It uses velocity, gravity and state checking. It has already produced bugs that need proper solutions.
That is exactly what makes it a useful A Level project.
A platform game becomes interesting not because of the graphics, but because of the rules underneath.
In the next article, we will add one of the most important and challenging parts of the project: platforms and collision detection.
That is where the player stops jumping on an imaginary ground and starts interacting with the world of the game.



