At the moment I am creating a program in Python, and Pygame, similar to Fire emblem, so a game that has a tile based system in which the sprites use to move to and determine location. I have been able to code the movement of the sprites to a tile, however, as the sprite is being animated whilst moving, using pauses in the code to give the illusion that it is one sprite changing stance, it means that the whole program waits around half a second before continuing on meaning that the movement is very slow (This is shown through the Trans_1 = 0.5 and Trans_2 = 0.15 variables). I was wondering if anyone could help me in finding a way to run the animation, with the pauses in, whilst moving the sprite from one position to another.

Here is the code I have for it, sorry if it's a little long:

import pygame as pg, sys
from pygame.locals import *
import shelve
import time

GREY = ( 50, 50, 50)
WHITE = (255,255,255)
DARK_GREEN = ( 0 ,100, 0 )

#Defining the Display surface
x = 750 #The x value represents the x value of the resolution.
y = 609 #The y value represents the y value of the resolution.
HW,HH = x/2,y/2#Finding the Middle of the screen
clock = pg.time.Clock()

Screen = pg.display.set_mode((x, y))

def Tile_Round(x, y,x50 = 0,y47 = 0):
    x50 = 0
    y47 = 0
    while x >= 50 or y >= 47:
        if x >= 50:
            x -= 50
            x50 += 1
        elif y >= 47:
            y -= 47
            y47 += 1
    N_xPos = 50*x50
    N_yPos = 47*y47
    return N_xPos, N_yPos

class Soldier_Ally(pg.sprite.Sprite):

    def __init__(self, S1_xPos,S1_yPos):
        ld = pg.image.load
        self.S1_xPos = S1_xPos
        self.S1_yPos = S1_yPos        
        self.SS1_Img = ld("Soldier_Standing_1.PNG").convert_alpha()
        self.SS2_Img = ld("Soldier_Standing_2.PNG").convert_alpha()
        self.SS3_Img = ld("Soldier_Standing_3.PNG").convert_alpha()
        self.SU1_Img = ld("Soldier_Up_1.PNG").convert_alpha()
        self.SU2_Img = ld("Soldier_Up_2.PNG").convert_alpha()
        self.SU3_Img = ld("Soldier_Up_3.PNG").convert_alpha()
        self.SU4_Img = ld("Soldier_Up_4.PNG").convert_alpha()
        self.SD1_Img = ld("Soldier_Down_1.PNG").convert_alpha()
        self.SD2_Img = ld("Soldier_Down_2.PNG").convert_alpha()
        self.SD3_Img = ld("Soldier_Down_3.PNG").convert_alpha()
        self.SD4_Img = ld("Soldier_Down_4.PNG").convert_alpha()
        self.SL1_Img = ld("Soldier_Left_1.PNG").convert_alpha()
        self.SL2_Img = ld("Soldier_Left_2.PNG").convert_alpha()
        self.SL3_Img = ld("Soldier_Left_3.PNG").convert_alpha()
        self.SR1_Img = ld("Soldier_Right_1.PNG").convert_alpha()
        self.SR2_Img = ld("Soldier_Right_2.PNG").convert_alpha()
        self.SR3_Img = ld("Soldier_Right_3.PNG").convert_alpha()
        self.SR4_Img = ld("Soldier_Right_4.PNG").convert_alpha()

        self.Img_Size = self.SS2_Img.get_size()
        self.Img_Rect_Size = self.SS3_Img.get_rect()
        self.Size = (50,47)

    def Draw_SR(self,N_xPos):
        Trans_1 = 0.5
        Trans_2 = 0.15
        N_xPos = N_xPos
        Stage_Img = pg.image.load("Stage.PNG").convert()
        for x in range (0,10):
            self.S1 = Screen.blit(self.SR1_Img,((self.S1_xPos,self.S1_yPos)))
            self.S1_xPos = (self.S1_xPos + (N_xPos/29))
            Screen.blit(Stage_Img,((self.S1_xPos,self.S1_yPos)), pg.Rect((self.S1_xPos,self.S1_yPos),(self.Size)))
            self.S1 = Screen.blit(self.SR2_Img,((self.S1_xPos,self.S1_yPos)))
            Screen.blit(Stage_Img,((self.S1_xPos,self.S1_yPos)), pg.Rect((self.S1_xPos,self.S1_yPos),(self.Size)))
            self.S1 = Screen.blit(self.SR3_Img,((self.S1_xPos,self.S1_yPos)))
            self.S1_xPos = (self.S1_xPos + (N_xPos/29)) #1
            Screen.blit(Stage_Img,((self.S1_xPos,self.S1_yPos)), pg.Rect((self.S1_xPos,self.S1_yPos),(self.Size)))
            self.S1 = Screen.blit(self.SR4_Img,((self.S1_xPos,self.S1_yPos)))
            Screen.blit(Stage_Img,((self.S1_xPos,self.S1_yPos)), pg.Rect((self.S1_xPos,self.S1_yPos),(self.Size)))
            self.S1 = Screen.blit(self.SR3_Img,((self.S1_xPos,self.S1_yPos)))
            self.S1_xPos = (self.S1_xPos + (N_xPos/29))
            Screen.blit(self.SR2_Img,((self.S1_xPos,self.S1_yPos)), pg.Rect((self.S1_xPos,self.S1_yPos),(self.Size)))
            self.S1 = Screen.blit(self.SR2_Img,((self.S1_xPos,self.S1_yPos)))
            Screen.blit(self.SR2_Img,((self.S1_xPos,self.S1_yPos)), pg.Rect((self.S1_xPos,self.S1_yPos),(self.Size))) #2

    def Game_Start():
        S1_xPos = 0 #Soldier1_x_Position
        S1_yPos = 0 #Soldier1_y_Position
        Stage_Img = pg.image.load("Stage.PNG").convert()
        Stage = Screen.blit(Stage_Img,(0,0))

        x = 0
        y = 0
        Table_Loop = True
        pg.draw.line(Screen, WHITE, (0, y), (750, y), (1))
        pg.draw.line(Screen, WHITE, (x, 0), (x, 609), (1))
        while Table_Loop == True and x <= 750:
            pg.draw.line(Screen, WHITE, (0, y), (750, y), (1))
            pg.draw.line(Screen, WHITE, (x, 0), (x, 609), (1))

        def Sprites_Standing(S1_xPos,S1_yPos):
            Selected = 0
            Sprite_Loop = True
            while Sprite_Loop == True:
                S = Soldier_Ally(S1_xPos,S1_yPos)
                for event in pg.event.get():
                    if event.type == pg.MOUSEBUTTONDOWN and event.button == 1:
                        Mouse_x,Mouse_y = pg.mouse.get_pos()
                        if S.S1.collidepoint(Mouse_x,Mouse_y):
                            Selected = 1
                        elif Selected == 1:
                            First = 1
                            Sprite_Loop = False

            if N_xPos > S.S1_xPos:


    if __name__ == "__main__":
        Initial_Time = (time.time()) 
  • \$\begingroup\$ Is the code here correctly indented? I'm a bit familiar with Python, but the way the code is currently displayed, this seems like it's not completely correct. It makes it a bit harder to follow through. \$\endgroup\$ – Vaillancourt Mar 16 '18 at 0:52
  • \$\begingroup\$ Sorry about that, changed the indenting now. \$\endgroup\$ – Benedict Cartwright Mar 16 '18 at 9:50

So I think you're looking for an animation system. You'll want to keep ticking the game forwards (never sleep in the game loop) while changing the sprite frame every now an then. Here's an example of a very basic animation system: (pseudo-Python)

class Animation:
    def __init__(self, frames, frame_interval):
        self.frames = frames
        self.frame_interval = frame_interval
        self.frame = 0
        self.currentFrame = 0

    def tick(self):
        self.frame += 1
        if (self.frame >= self.frame_interval):
            self.current_frame = (self.currentFrame + 1) % len(self.frames)

    def redrawSurface():
        current_frame = self.frames[self.current_frame]
        self.surface = pygame.Surface((current_frame.w, current_frame.h))
        # Draw a part of a surface to another.
        self.surface.blit(PLAYER_SPRITE, current_frame)  

So you'd supply the animation frames to the animation, and you'd call tick from your game loop, which would periodically change the surface every now and then. Then you just need to use the animation's surface to draw your player. So something like this:

while True:
    player.position += player.speed
    screen.blit(player.animation.surface, player.position)

All in all, the use of sleep is a beginner "mistake" in game dev. It's crucial to keep the game loop running without interuptions for smooth movement as you've noticed. It might be a good idea to lookup a tutorial on basic game loops & animations, I'm sure you can find some.

Note that there might be some pygame specific animation stuff that you could use instead of rolling your own, but I'm not really that familiar with the pygame functionality these days anymore.

| improve this answer | |

Here's how to make a very simple animation system in Pygame.

  • Add all your frames in a list, called, for example, frames.

  • Let frame_duration be however many milliseconds you want each frame to last.

  • Let current_frame track which frame you're on.

  • Let last_anim_update track the last time the current frame was incremented.

  • In your update() method, continuously check to see if the current_time - last_anim_update > frame_duration. When it is, increment the current frame.

Then you can set things up like this:

idle_frames = [frame1, frame2, frame3]
frame_duration = 0.2
last_anim_update = 0
current_frame = 0

def update():
    if Globals.current_time - last_anim_update > frame_duration:
        current_frame += 1
        current_frame = current_frame % len(idle_frames)
        sprite = frames[current_frame]
        last_anim_update = Globals.current_time

def draw():
    # code which draws your sprite at the appropriate location
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.