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 :)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With