Here is the fifth and final tutorial, dedicated to discovering Pygame in Python! 😃 There may be others later, but for many, it will already be great to have made it (alive) this far! 😅
Now we're going to handle the jumps! 😮
Let's start with the constants first, this will allow us to do a bit of theory before moving on! 😉
File: Constants.py
# Created by Jay81, on 06/16/2024 in Python 3.7 """Game constants""" # Window settings WIDTH = 640 HEIGHT = 360 # Window customization TITLE = "Rabidja" ICON = "" # List of game images (graphics) BACKGROUND = "graphics/background.png" SPRITE_JOUEUR = "graphics/rabidja.png" # Player sprite size PLAYER_HEIGTH = 50 PLAYER_WIDTH = 40 # State machine NONE = 0 RIGHT = 1 LEFT = 2 IDLE = 0 WALK = 1 JUMP = 2 DOUBLEJUMP = 3 DEAD = 4 # Timer for animation TIMER = 8 # Player speed PLAYER_SPEED = 4 # Constants defining gravity and maximum fall speed GRAVITY_SPEED = 0.6 MAX_FALL_SPEED = 15 JUMP_HEIGHT = 10 HEIGHT_FLOOR = HEIGHT - PLAYER_HEIGTH - 40 |
We will first change the value of our TIMER constant so that the animation is slower but you can do as you wish. 😆
# Timer for animation
TIMER = 8
|
We will then create several constants to manage our jump:
- GROUND_HEIGHT will correspond to the height from the ground at which Rabidja was displayed until now. The goal will be to test if we are above (so we jump) or at that level (or below), in which case, we must place Rabidja on the ground and manage him as if he were walking or standing still. ☺️
- GRAVITY_SPEED corresponds to the gravity in real life. That is to say that every frame, Rabidja is made to fall 0.6 pixels. If he is already on the ground, the ground holds him and he is forbidden from going below (otherwise, he would go through the ground and fall forever! 😱)
- MAX_FALL_JUMP corresponds to the maximum speed of the character's fall (here 15 pixels but you can modify it). Same, it's like in real life, there is a maximum speed at which we can fall and still happy, otherwise we would end up reaching the speed of light!!! 🥵
- JUMP_HEIGHT corresponds to the force vector which allows jumping (like in physics 🤪).
Thanks to this, if we press the jump key, in the 1st frame our hero will jump 10 pixels, but caught by gravity, he will lose 0.6 pixels in the second frame, which will make him only rise 9.4 pixels, then 8.8 in frame 3 and so on... When his jump force reaches 0, he will have reached the maximum point of the jump and its value will then become negative, making him fall faster and faster, until reaching the maximum fall speed. 🧐
You don't have to understand everything to implement it in code and test it. You can have fun changing these values later to better understand how physics works. 😅
Finally, note that we are not respecting the true values of terrestrial physics here, because we are not capable of making fabulous jumps in real life and a platform game without spectacular jumps would no longer be a platform game. 😌
# Constants defining gravity and maximum fall speed
GRAVITY_SPEED = 0.6
MAX_FALL_SPEED = 15
JUMP_HEIGHT = 10
HEIGHT_FLOOR = HEIGHT - PLAYER_HEIGTH - 40
|
Now let's update the main() !
File: Main.py
# Created by Jay81, on 06/16/2024 in Python 3.7 # Import from pygame import pygame from pygame.locals import * #Import game constants and classes from Constants import * from Player import * #Initializing pygame pygame.init() clock = pygame.time.Clock() # Open the game window in 640 x 360 pixel resolution window = pygame.display.set_mode((WIDTH, HEIGHT)) #, pygame.FULLSCREEN|SCALED) |
And there you have it! 😃 Now, we will explain these modifications step by step.
We start by creating a boolean to manage the switch to full screen, as well as a timer ⏰ to delay the press between two keys (otherwise, if you leave your finger pressed on a key, the boolean changes value 60 times per second! 😮 It's a bit fast for humans like us! 👽). We must therefore create a countdown / timer ⏰ which delays the support between two presses on a key. Here, we set it to 60 frames, or one second . 🤖
#Boolean to know if the game is in full screen (Fullscreen)
isFullScreen = False
|
To avoid bugs 🐞, if you press multiple keys, you first reset the input variable (to erase any previous key presses when you're not pressing anything anymore 😁). And then, you prohibit the simultaneous pressing of the LEFT and RIGHT keys, canceling them in order to avoid, again, bugs 🕷.
# We test the presses on the Left / Right keys
player. input = NONE
dicKeys = pygame.key.get_pressed()
if dicKeys[K_LEFT]:
player. input = LEFT
if dicKeys[K_RIGHT]:
player. input = RIGHT
if dicKeys[K_LEFT] & dicKeys[K_RIGHT]:
player.input = NONE
|
We then manage the transition from full screen to window mode and vice versa by pressing the F key . We use our timer to delay and prevent the screen from flashing completely between full screen and window... 😕
Note however that there is a bug 🐜 in the version of pygame provided with Edupython and it does not work very well . You have to update pygame using another IDE for it to work. Unfortunately Edupython seems to be at the end of development at the moment and it is no longer updated. 😓
if dicKeys[K_f]:
if timer <= 0 :
if isFullScreen:
isFullScreen = False
window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
#pygame.display.toggle_fullscreen()
else :
isFullScreen = True
window = pygame.display.set_mode((WIDTH, HEIGHT), pygame.FULLSCREEN|SCALED)
timer = 60
#We decrement our timer (countdown) if it is greater than 0
if timer > 0 :
timer -= 1
|
And don't forget to use the JUMP key to jump (here C but you can change it if you want 😉).
# Jump management
if dicKeys[K_c]:
player.jump = True
|
And there you have it, now let's move on to the Player.py file , which contains most of the changes! ☺️
File: Player.py
# Created by Jay81, on 06/16/2024 in Python 3.7 # Import from pygame import pygame from pygame.locals import * #Import game constants and classes from Constants import * """Class for creating a character""" class Player : def __init__ ( self ): # Load the sprite file self.sprite = pygame.image.load(SPRITE_PLAYER).convert_alpha() # Sprite coordinates self.x = 0 self.y = GROUND_HEIGHT # Sprite Direction self.direction = RIGHT # Animation self.frame = 0 self.timer = TIMER self.state = IDLE self.maxframes = 7 # Keyboard input management self.input = NONE # Jump handling self.jump = False self.dirY = 0 self.onGround = True # Sprite update def update ( self ): # We manage the timer (countdown to scroll the animation) |
We start by replacing the height from the ground with our constant then we create 3 new variables to manage our jumps:
- jump which is a boolean to know if we are jumping or not.
- dirY which is our force vector which will allow us to jump.
- and onGround which is another boolean to know if we are touching the ground or not.
# Jump handling
self.jump = False
self.dirY = 0
self.onGround = True
|
Then we need to update the timer ⏱ depending on whether it is jumping or not, because the jump animation is only two frames long. So, in this case, we need to alternate between 0 and 1. 😆
# We manage the timer (countdown to scroll the animation)
|
Here, we manage gravity by decreasing the force vector (dirY) by the gravity value (GRAVITY_SPEED) at each frame (as explained above). We then test our dirY vector and limit it to the maximum fall speed: MAX_FALL_SPEED if it exceeds it. 😉
# Gravity always makes the character fall:
|
Here, we manage the jump itself. If we press the JUMP key and we are on the ground (otherwise, we would end up with infinite jumps... 😨), we give our force vector the value - JUMP_HEIGHT, we set onGround to False and we reset the animation frame to 0 to avoid bugs 🐛 (because I remind you that the jump animation is less frames long 😉).
If we had pressed the JUMP key while we were already in the air, then we set self.jump to False to cancel the key press. 😋
But wait! 😐 Why is the value of JUMP_HEIGHT negative? 😱
This is because our orthonormal reference point is reversed in a video game. The point (0,0) is at the very top left. So you have to add to go down and subtract to go up ! The complete opposite of logic, yes I know... 🙄
There you go, once we have our force vector dirY , we add it to our Rabidja y coordinate to make it go up or down depending on its value. We just have to check that it does not exceed the height of the ground , and if necessary stick it there otherwise it would fall to infinity, the poor thing!!! ☹👻
We then update our state machine to:
- put him in JUMP state if he goes airborne, ✈️
- and put it in IDLE (immobile) if it is neither in the air nor running. ⛺
# Jump handling
if self.jump:
if self.onGround == True :
self.dirY = -JUMP_HEIGHT
self.onGround = False
self.frame = 0
self.jump = False
self.y += self.dirY
if self.y > GROUND_HEIGHT :
self.y = GROUND_HEIGHT
self.onGround = True
#Manage the character's animation if he is jumping/falling
if not self.onGround:
self.state = JUMP
elif not (self.state == WALK):
self.state = IDLE
|
Now that the hardest part is done, all we have to do is manage its display! 🤓
For walking, the code remains the same. 💻
For the jump, it's almost the same code, except that since there are only two frames, we have to transform frames 0 and 1 on the right into 8 and 9 for the left . Otherwise, it's the same thing! 😄
# Jump management: if we touch the ground
if self.onGround:
# Depending on the direction, we orient the player by doing a flip to the left
if self.direction == LEFT:
spritecopy = pygame.transform.flip(self.sprite, True , False )
surface.blit(spritecopy, (self.x, self.y),
|
And that concludes this last chapter of the course! 😅 For the next one, it will be about training to teach you how to manipulate the code with some challenges ranging from the simplest to the most complicated and you will be able to evaluate your skills according to your successes! 🤩
See you soon for new challenges! 😄

English
Français