Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jumping verification code not working using the y-axis (pygame)

When verifying the states of the player (running, jumping, idling), the jumping overrides them because y-axis velocity (the code has vectors included) does not stop although not moving(I think).

Jumping verification code:

if self.vel.y != 0:
   self.jumping = True
else:
   self.jumping = False

Idling verification code:

if self.vel.x == 0 and self.vel.y == 0:
   self.jumping = False
   self.running = False

Running verification code:

keys = pg.key.get_pressed()

if keys[pg.K_a] or keys[pg.K_d] and not self.jumping:
    self.running = True
 else:
    self.running = False

Is there any other way to verify if the the player is jumping?

When removing this code there are no more jumping animations but the idling is working, before removing the code the idling did not work at all but the running worked with or without the code. I already tried break pointing the important bits and they all get passed.

I am using this code to animate the player, the animation code works perfectly fine.

Here is all the code for the Player class and Wall class:

sprites.py

import pygame as pg
from settings import *
import os
vec = pg.math.Vector2


game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, 'img')
animation_folder = os.path.join(img_folder, 'animations')

class Sprite_sheet:
    def __init__(self, filename):
        self.sprite_sheet = pg.image.load(os.path.join(animation_folder, filename)).convert()

    def get_image(self, x, y, width, height):
        image = pg.Surface((width, height))
        image.blit(self.sprite_sheet, (0,0), (x, y, width, height))
        return image


def collide_hit_rect(one, two):
    return one.hit_rect.colliderect(two.rect)


def collide_with_walls(sprite, group, dir):
    if dir == 'x':
        hits = pg.sprite.spritecollide(sprite, group, False, collide_hit_rect)
        if hits:
            if hits[0].rect.centerx > sprite.hit_rect.centerx:
                sprite.pos.x = hits[0].rect.left - sprite.hit_rect.width / 2
            if hits[0].rect.centerx < sprite.hit_rect.centerx:
                sprite.pos.x = hits[0].rect.right + sprite.hit_rect.width / 2
            sprite.vel.x = 0
            sprite.hit_rect.centerx = sprite.pos.x
    if dir == 'y':
        hits = pg.sprite.spritecollide(sprite, group, False, collide_hit_rect)
        if hits:
            if hits[0].rect.centery > sprite.hit_rect.centery:
                sprite.pos.y = hits[0].rect.top - sprite.hit_rect.height / 2
            if hits[0].rect.centery < sprite.hit_rect.centery:
                sprite.pos.y = hits[0].rect.bottom + sprite.hit_rect.height / 2
            sprite.vel.y = 0
            sprite.hit_rect.centery = sprite.pos.y


class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.load_images()
        self.image = self.standing_frames_r[0]
        self.rect = self.image.get_rect()
        self.x = x * TILESIZE
        self.y = y * TILESIZE
        self.rect.center = (x, y)
        self.hit_rect = PLAYER_HIT_RECT
        self.hit_rect.center = self.rect.center
        self.vel = vec(0, 0)
        self.pos = vec(x, y)
        self.jumping = False
        self.running = False
        self.current_frame = 0
        self.last_update = 0
        self.idle_right = True
        self.idle_left = False
        self.falling_right = True
        self.falling_left = False

    def load_images(self):
        #idle right
        self.spritesheet_idle = Sprite_sheet('idle.png')
        self.standing_frames_r = [self.spritesheet_idle.get_image(0, 0, 19, 34),
                                  self.spritesheet_idle.get_image(19, 0, 19, 34),
                                  self.spritesheet_idle.get_image(38, 0, 19, 34),
                                  self.spritesheet_idle.get_image(57, 0, 19, 34),
                                  self.spritesheet_idle.get_image(76, 0, 19, 34),
                                  self.spritesheet_idle.get_image(95, 0, 19, 34),
                                  self.spritesheet_idle.get_image(114, 0, 19, 34),
                                  self.spritesheet_idle.get_image(133, 0, 19, 34),
                                  self.spritesheet_idle.get_image(152, 0, 19, 34),
                                  self.spritesheet_idle.get_image(171, 0, 19, 34),
                                  self.spritesheet_idle.get_image(190, 0, 19, 34),
                                  self.spritesheet_idle.get_image(209, 0, 19, 34)]
        for frame in self.standing_frames_r:
            frame.set_colorkey(BLACK)

        # idle left
        self.standing_frames_l = []
        for frame in self.standing_frames_r:
            self.standing_frames_l.append(pg.transform.flip(frame, True, False))
            frame.set_colorkey(BLACK)

        # walk right
        self.spritesheet_walk = Sprite_sheet('walk.png')
        self.walk_frames_r = [self.spritesheet_walk.get_image(0, 0, 21, 33),
                              self.spritesheet_walk.get_image(21, 0, 21, 33),
                              self.spritesheet_walk.get_image(42, 0, 21, 33),
                              self.spritesheet_walk.get_image(63, 0, 21, 33),
                              self.spritesheet_walk.get_image(84, 0, 21, 33),
                              self.spritesheet_walk.get_image(105, 0, 21, 33),
                              self.spritesheet_walk.get_image(126, 0, 21, 33),
                              self.spritesheet_walk.get_image(147, 0, 21, 33)]
        for frame in self.walk_frames_r:
            frame.set_colorkey(BLACK)

        # walk left
        self.walk_frames_l = []
        for frame in self.walk_frames_r:
            self.walk_frames_l.append(pg.transform.flip(frame, True, False))
            frame.set_colorkey(BLACK)

        # falling right
        self.spritesheet_falling = Sprite_sheet('falling.png')
        self.falling_frames_r = [self.spritesheet_falling.get_image(0, 0, 20, 35),
                                 self.spritesheet_falling.get_image(20, 0, 20, 35)]
        for frame in self.falling_frames_r:
            frame.set_colorkey(BLACK)

        # falling left
            self.falling_frames_l = []
        for frame in self.falling_frames_r:
            self.falling_frames_l.append(pg.transform.flip(frame, True, False))

    def jump(self):
        self.hit_rect.y += 1
        hits = pg.sprite.spritecollide(self, self.game.walls, False, collide_hit_rect)
        self.hit_rect.y -= 1
        if hits:
            self.vel.y = -6

    def animate(self):
        # determining the direction
        if self.vel.x > 0:
            self.idle_right = True
            self.idle_left = False
            self.falling_right = True
            self.falling_left = False
        if self.vel.x < 0:
            self.idle_right = False
            self.idle_left = True
            self.falling_right = False
            self.falling_left = True

        now = pg.time.get_ticks()
        keys = pg.key.get_pressed()
        # Testing for the states

        if self.vel.y != 0:
            self.jumping = True
            self.running = False
        elif keys[pg.K_a] or keys[pg.K_d]:
            self.running = True
            self.jumping = False
        elif self.vel.y == 0:
            self.jumping = False
        else:
            self.jumping = False
            self.running = False

        # Animating (changing the image)
        if self.jumping:
            if now - self.last_update > 150:
                self.last_update = now
                self.current_frame = (self.current_frame + 1) % len(self.falling_frames_r)
                bottom = self.rect.bottom
                if self.falling_right:
                    self.image = self.falling_frames_r[self.current_frame]
                elif self.falling_left:
                    self.image = self.falling_frames_l[self.current_frame]
                self.rect.bottom = bottom

        if not self.jumping and not self.running:
            if now - self.last_update > 200:
                bottom = self.rect.bottom
                self.last_update = now
                self.current_frame = (self.current_frame + 1) % len(self.standing_frames_r)
                if self.idle_left:
                    self.image = self.standing_frames_l[self.current_frame]
                elif self.idle_right:
                    self.image = self.standing_frames_r[self.current_frame]
                self.rect.bottom = bottom

        if self.running:
            if now - self.last_update > 100:
                self.last_update = now
                self.current_frame = (self.current_frame + 1) % len(self.walk_frames_r)
                bottom = self.rect.bottom
                if self.vel.x > 0:
                    self.image = self.walk_frames_r[self.current_frame]
                else:
                    self.image = self.walk_frames_l[self.current_frame]
                self.rect.bottom = bottom

    def update(self):
        self.animate()
        self.acc = vec(0, PLAYER_GRAV)
        keys = pg.key.get_pressed()
        if keys[pg.K_a]:
            self.acc.x = -PLAYER_ACC
        if keys[pg.K_d]:
            self.acc.x = PLAYER_ACC
        if keys[pg.K_SPACE]:
            self.jump()
        self.acc.x += self.vel.x * PLAYER_FRICTION
        self.vel += self.acc
        self.pos += self.vel + 0.5 * self.acc

        self.hit_rect.centerx = self.pos.x
        collide_with_walls(self, self.game.walls, 'x')
        self.hit_rect.centery = self.pos.y
        collide_with_walls(self, self.game.walls, 'y')
        self.rect.center = self.hit_rect.center


class Wall(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.walls
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = pg.Surface((TILESIZE, TILESIZE))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.rect.x = x * TILESIZE
        self.rect.y = y * TILESIZE

Thanks for the help :)

like image 236
Tudor Popescu Avatar asked Feb 23 '26 18:02

Tudor Popescu


2 Answers

I fixed your code to the point where it answers your question and fixes your problem. The jumping verification now works, which is what your problem is. But I think that there are other parts of the code which need fixing, but I will leave that to you.

Changes I made to the code:

  • Got rid of all uses of self.hit_rect. I have no idea why you needed this and why it was being used. In all cases I just changed it to self.rect. As far as I know, you really only need one rect here.

  • I commented out some of the code in the collide_with_walls function. I also removed the lines of code to do with the hit_rect. I also made the function return True or return False whenever based on whether there are any sprites in hits. This was done to allow for the code later on in the update method to work.

    • The self.vel.y variable is now set based on whether the player is colliding with the walls. I commented out most of the code with acceleration to simplify things a little. I added some of it back but you I'll leave the rest to you.

    • In the update method the hit_rect is not being used anymore either.

Here is the fixed code:

sprites.py

import pygame as pg
from settings import *
import os
vec = pg.math.Vector2


game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, 'img')
animation_folder = os.path.join(img_folder, 'animations')

class Sprite_sheet:
    def __init__(self, filename):
        self.sprite_sheet = pg.image.load(os.path.join(animation_folder, filename)).convert()

    def get_image(self, x, y, width, height):
        image = pg.Surface((width, height))
        image.blit(self.sprite_sheet, (0,0), (x, y, width, height))
        return image


def collide_hit_rect(one, two):
    return one.rect.colliderect(two.rect)


def collide_with_walls(sprite, group, dir):
    if dir == 'x':
        hits = pg.sprite.spritecollide(sprite, group, False, collide_hit_rect )
        if hits:
            # if hits[0].rect.centerx > sprite.rect.centerx:
                # sprite.pos.x = hits[0].rect.left - sprite.rect.width / 2
            # if hits[0].rect.centerx < sprite.rect.centerx:
                # sprite.pos.x = hits[0].rect.right + sprite.rect.width / 2
            sprite.vel.x = 0
            return True

    if dir == 'y':
        hits = pg.sprite.spritecollide(sprite, group, False, collide_hit_rect)
        if hits:
            # if hits[0].rect.centery > sprite.rect.centery:
                # sprite.pos.y = hits[0].rect.top - sprite.rect.height / 2
            # if hits[0].rect.centery < sprite.rect.centery:
                # sprite.pos.y = hits[0].rect.bottom + sprite.rect.height / 2
            sprite.vel.y = 0    
            return True

    if hits == []:
        return False
    elif hits != []:
        return True 


class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.load_images()
        self.image = self.standing_frames_r[0]
        self.rect = self.image.get_rect()
        self.x = x * TILESIZE
        self.y = y * TILESIZE
        self.rect.center = (x, y)


        self.vel = vec(0, 0)
        self.pos = vec(x, y)
        self.jumping = False
        self.running = False
        self.current_frame = 0
        self.last_update = 0
        self.idle_right = True
        self.idle_left = False
        self.falling_right = True
        self.falling_left = False

        # hit_rect

    def load_images(self):
        #idle right
        self.spritesheet_idle = Sprite_sheet('idle.png')
        self.standing_frames_r = [self.spritesheet_idle.get_image(0, 0, 19, 34),
                                  self.spritesheet_idle.get_image(19, 0, 19, 34),
                                  self.spritesheet_idle.get_image(38, 0, 19, 34),
                                  self.spritesheet_idle.get_image(57, 0, 19, 34),
                                  self.spritesheet_idle.get_image(76, 0, 19, 34),
                                  self.spritesheet_idle.get_image(95, 0, 19, 34),
                                  self.spritesheet_idle.get_image(114, 0, 19, 34),
                                  self.spritesheet_idle.get_image(133, 0, 19, 34),
                                  self.spritesheet_idle.get_image(152, 0, 19, 34),
                                  self.spritesheet_idle.get_image(171, 0, 19, 34),
                                  self.spritesheet_idle.get_image(190, 0, 19, 34),
                                  self.spritesheet_idle.get_image(209, 0, 19, 34)]
        for frame in self.standing_frames_r:
            frame.set_colorkey(BLACK)

        # idle left
        self.standing_frames_l = []
        for frame in self.standing_frames_r:
            self.standing_frames_l.append(pg.transform.flip(frame, True, False))
            frame.set_colorkey(BLACK)

        # walk right
        self.spritesheet_walk = Sprite_sheet('walk.png')
        self.walk_frames_r = [self.spritesheet_walk.get_image(0, 0, 21, 33),
                              self.spritesheet_walk.get_image(21, 0, 21, 33),
                              self.spritesheet_walk.get_image(42, 0, 21, 33),
                              self.spritesheet_walk.get_image(63, 0, 21, 33),
                              self.spritesheet_walk.get_image(84, 0, 21, 33),
                              self.spritesheet_walk.get_image(105, 0, 21, 33),
                              self.spritesheet_walk.get_image(126, 0, 21, 33),
                              self.spritesheet_walk.get_image(147, 0, 21, 33)]
        for frame in self.walk_frames_r:
            frame.set_colorkey(BLACK)

        # walk left
        self.walk_frames_l = []
        for frame in self.walk_frames_r:
            self.walk_frames_l.append(pg.transform.flip(frame, True, False))
            frame.set_colorkey(BLACK)

        # falling right
        self.spritesheet_falling = Sprite_sheet('falling.png')
        self.falling_frames_r = [self.spritesheet_falling.get_image(0, 0, 20, 35),
                                 self.spritesheet_falling.get_image(20, 0, 20, 35)]
        for frame in self.falling_frames_r:
            frame.set_colorkey(BLACK)

        # falling left
            self.falling_frames_l = []
        for frame in self.falling_frames_r:
            self.falling_frames_l.append(pg.transform.flip(frame, True, False))

    def jump(self):
        self.rect.y += 1
        hits = pg.sprite.spritecollide(self, self.game.walls, False, collide_hit_rect)
        self.rect.y -= 1
        if hits:
            print("Jump")
            self.vel.y = -30


    def animate(self):
        # determining the direction
        if self.vel.x > 0:
            self.idle_right = True
            self.idle_left = False
            self.falling_right = True
            self.falling_left = False
        if self.vel.x < 0:
            self.idle_right = False
            self.idle_left = True
            self.falling_right = False
            self.falling_left = True

        now = pg.time.get_ticks()
        keys = pg.key.get_pressed()
        # Testing for the states

        if self.vel.y != 0:
            self.jumping = True
            self.running = False
        elif keys[pg.K_a] or keys[pg.K_d]:
            self.running = True
            self.jumping = False
        elif self.vel.y == 0:
            self.jumping = False
        else:
            self.jumping = False
            self.running = False

        print(self.jumping)

        # Animating (changing the image)
        if self.jumping:
            if now - self.last_update > 150:
                self.last_update = now
                self.current_frame = (self.current_frame + 1) % len(self.falling_frames_r)
                bottom = self.rect.bottom
                if self.falling_right:
                    self.image = self.falling_frames_r[self.current_frame]
                elif self.falling_left:
                    self.image = self.falling_frames_l[self.current_frame]
                self.rect.bottom = bottom

        if not self.jumping and not self.running:
            if now - self.last_update > 200:
                bottom = self.rect.bottom
                self.last_update = now
                self.current_frame = (self.current_frame + 1) % len(self.standing_frames_r)
                if self.idle_left:
                    self.image = self.standing_frames_l[self.current_frame]
                elif self.idle_right:
                    self.image = self.standing_frames_r[self.current_frame]
                self.rect.bottom = bottom

        if self.running:
            if now - self.last_update > 100:
                self.last_update = now
                self.current_frame = (self.current_frame + 1) % len(self.walk_frames_r)
                bottom = self.rect.bottom
                if self.vel.x > 0:
                    self.image = self.walk_frames_r[self.current_frame]
                else:
                    self.image = self.walk_frames_l[self.current_frame]
                self.rect.bottom = bottom

    def update(self):
        self.animate()

        self.acc = vec(0, PLAYER_GRAV)

        keys = pg.key.get_pressed()

        if keys[pg.K_a]:
            self.acc.x = -PLAYER_ACC
        if keys[pg.K_d]:
            self.acc.x = PLAYER_ACC

        self.acc.x += self.vel.x * PLAYER_FRICTION

        if collide_with_walls(self, self.game.walls, 'y'):
            # print("Colliding")
            self.vel.y = 0
            self.acc.y = 0
        else:
            # print("Falling")
            self.vel.y = 2

        if keys[pg.K_SPACE]:
            self.jump()

        if self.vel.y > 0:
            self.vel.y += PLAYER_GRAV

        self.pos += self.vel + 0.5 * self.acc

        self.rect.centerx = self.pos.x
        self.rect.centery = self.pos.y


class Wall(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.walls
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = pg.Surface((TILESIZE, TILESIZE))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
        self.rect.x = x * TILESIZE
        self.rect.y = y * TILESIZE

I hope this answer helped you and if you have any more problems post a comment below!

Can you consolidate your state checking code in one place to prevent race conditions?

if self.vel.y != 0:
    self.jumping = True
    self.running = False
elif keys[pg.K_a] or keys[pg.K_d]:
    # perhaps modify self.vel.x here?
    self.running = True
    self.jumping = False
else:  # must be idle here
    self.running = False
    self.jumping = False
like image 40
import random Avatar answered Feb 26 '26 06:02

import random