I would like to create a top down RPG in pygame using sprite sheets.
I want to be able to press space, for example, to attack which would trigger the attacking animation and then go back to normal
import pygame
from pygame.locals import *
pygame.init()
image = pygame.image.load("sprite_sheet.png")
clock = pygame.time.Clock()
screen = pygame.display.set_mode((400, 250))
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.current_animation = 0
self.max_animation = 5
self.animation_cooldown = 150
self.last_animation = pygame.time.get_ticks()
self.status = {"prev": "standing",
"now": "standing"}
def animate_attack(self):
time_now = pygame.time.get_ticks()
if time_now - self.last_animation >= self.animation_cooldown:
self.last_animation = pygame.time.get_ticks()
if self.current_animation == self.max_animation:
self.current_animation = 0
joshua.status["now"] = joshua.status["prev"]
else:
self.current_animation += 1
joshua = Player()
while True:
screen.fill(0)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
joshua.status["prev"] = joshua.status["now"]
joshua.status["now"] = "attacking"
if joshua.status["now"] == "attacking":
joshua.animate_attack()
screen.blit(image, (0, 0), (joshua.current_animation * 64, 0, 64, 64))
pygame.display.flip()
clock.tick(60)
The above piece of code is what i have. If i press space once it will go through the animation and stop but if i double press space it will loop it because of how it is programmed.
Would like some help in animation, thank you
The problem is caused by the following call when space is pressed the second time:
joshua.status["prev"] = joshua.status["now"]
This sets both the "prev" and "now" states to be "attacking".
As a result, when the state is reset in animate_attack()
method,
it will remain "attacking":
joshua.status["now"] = joshua.status["prev"]
As a quick fix, make sure to only change the state if it isn't already set:
if event.key == pygame.K_SPACE:
if not joshua.status["now"] == "attacking":
joshua.status["prev"] = joshua.status["now"]
joshua.status["now"] = "attacking"
As a better fix, you should encapsulate the state, so that only the Player class ever deals with its own state, for example:
class Player():
def __init__(self):
self.current_animation = 0
self.max_animation = 5
self.animation_cooldown = 150
self.last_animation = pygame.time.get_ticks()
self.status = "standing" # Simplified state
def attack(self):
self.status = "attacking"
def animate_attack(self):
if self.status == "attacking":
time_now = pygame.time.get_ticks()
if time_now - self.last_animation >= self.animation_cooldown:
self.last_animation = pygame.time.get_ticks()
if self.current_animation == self.max_animation:
self.current_animation = 0
self.status = "standing" # Reset state
else:
self.current_animation += 1
This way, there is no need to know anything about the state outside of the class:
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
joshua.attack()
joshua.animate_attack()
screen.fill(0)
screen.blit(image, (0, 0), (joshua.current_animation * 64, 0, 64, 64))
pygame.display.flip()
clock.tick(60)