Welcome to tutorial number 5 in the Pygame RPG Series
Our Player character can now move, thanks to our efforts in the last tutorial. However, the game lacks gravity as well as interactivity with the ground itself. Currently, our Player is just floating in the air, which of course is not acceptable.
You could make a temporary hacky solution where you render the Player using the Y coordinates of the top of the ground object. This however will quickly prove to be insufficient, and isn’t a good game concept anyway.
The first step is a quick edit to the move method in the Player class. Add the following line of code to the very top of the move method.
def move(self): # Keep a constant acceleration of 0.5 in the downwards direction (gravity) self.acc = vec(0,0.5)
As the comment explains, it adds a constant vertical acceleration of the value
0.5. If you think about it, that’s what gravity is too. It’s a force that constantly pulling downwards on you.
Now, this is all we had to. Gravity has now been added. However! there is a problem now. If you were to run the program now with this addition your player will immediately drop off the screen, accelerating in the downwards direction.
Why is this happening? It’s because there was nothing to stop him from falling. It’s same as falling through the air, constantly accelerating. In the next section we’ll be adding a gravity check, which is basically collision detection between the player and the ground.
Furthermore, before we proceed we need to add new variable to the Player class
self.jumping = False
This is going to be used to track the state of the Player, whether he is jumping or not. More on this later though.
Colliding with the Ground
This is going to be your first taste on how collision detection in pygame. Expect to see alot more of it from now on.
Sprite groups and Collision Detection in Pygame go hand in hand, so we’ll be explaining Sprite groups here too. The following code is used to create a Sprite group and add the ground object to it.
(We’ll be creating all sprite groups in the global space, so that all classes can access them. In short, just place this code right above the game loop, and below the classes)
ground = Ground() ground_group = pygame.sprite.Group() ground_group.add(ground)
Why did we do this? It’s because the collision detection functions that detect collisions requires a Sprite group as a parameter. There are other ways of doing this, but this is easy to implement.
Below is our main code, comprising of a new function to be added to the Player class, called
gravity_check(). This function first using the
spritecollide() takes three parameters, the sprite to be tested, and secondly the sprite group against which the sprite will be tested.
The third parameter takes a
False value which determines whether to kill the sprite if a collision occurs. Obviously, we set this to false. The reason why a sprite group is used so that we can check collisions against hundreds of other sprites in a single function. We’ll use this same function later to check collisions against the enemy sprite group.
def gravity_check(self): hits = pygame.sprite.spritecollide(player ,ground_group, False) if self.vel.y > 0: if hits: lowest = hits if self.pos.y < lowest.rect.bottom: self.pos.y = lowest.rect.top + 1 self.vel.y = 0 self.jumping = False
The next thing to do is check whether the player has any velocity in the downwards direction (Don’t confuse velocity with acceleration). If he doesn’t, then all is good (because he isn’t falling and thus is on the ground). If however he is falling we will proceed.
The if statement will run if the
hits variable recorded a collision between the player and ground. The next three lines aren’t really nessacery (at this point) as they are meant for when they are multiple ground surfaces. Right now we have just one “ground object”.
The main point here is that the vertical velocity of the Player is set to 0 and the
self.jumping variable is set to False (because if the player is touching the ground, he obviously can’t be in a state of jump).
This code is in charge of the jump mechanic. It’s pretty short, because we have already implemented gravity and acceleration so most of the work is already done.
Once again, you can see the collide function being used to check for the collision between the Player and the ground. The idea is that the Player should only be allowed to jump if he is currently standing on the ground. This prevents him from jumping again mid-air which would be really weird.
self.rect.x lines are lower the Player down a pixel to ensure a collision (just in case he is standing a pixel above the ground). This is immediately reversed after the collision detection function.
def jump(self): self.rect.x += 1 # Check to see if payer is in contact with the ground hits = pygame.sprite.spritecollide(self, ground_group, False) self.rect.x -= 1 # If touching the ground, and not currently jumping, cause the player to jump. if hits and not self.jumping: self.jumping = True self.vel.y = -12
The second half of the code is even simpler. “If” the player is touching the ground and is “not” jumping, then set
self.jumping to True and set velocity of
-12. You can of course, change value to suit your needs.
Velocity for jumping must be in negative direction, since the downwards direction is considered positive and upwards is negative.
Now it’s time to add our code to the game loop. The only change we’ve made that has taken effect is the gravity force downwards. The gravity check and jump commands need to be added.
For the gravity check, just call the method right at the start of the game loop. This ensures that it’s the first thing that’s checked, before any jump commands are executed or any player movements are made.
while True: player.gravity_check() ... ... ... # Event handling for a range of different key presses if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: player.jump()
The above code also includes the jump code. In the event handling for keys, we add an if statement to check for the
SPACE key, which is what we have assigned the jump command. If it’s detected, the
jump() method of the Player is called.
If you’ve successfully added all the above code, your output should look like this:
Now that we’re able to properly control our Player, it’s time to make the movement more realistic. Currently, the player is always facing the “right” direction, even while moving left. Secondly the player remains stiff (no animation) while moving. We will be fixing both problems in the next section.
This marks the end of Pygame RPG Tutorial – Gravity and Jumping. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.