Goose _
Goose _

Reputation: 267

Walking animation loop

I've created a dragon that moves towards the player, and while doing so it has an animation where it flies. However, if the player stands at certain angles to the dragon, the flying animation stops until it is either directly above/to the side of the player, or immediately diagonal.

For example, standing below the dragon will trigger the animation, but standing below and over to the right will cause the dragons animation to pause until it is immediately diagonal. Here is a fully runnable example;

Main game

from Rooms import *
from Player import *
import pygame


BLACK = (0, 0, 0)
WHITE = (255, 255, 255)


pygame.init()

screen_width = 1080
screen_height = 607
screen = pygame.display.set_mode([screen_width, screen_height])

pygame.display.set_caption('Labyrinth')

block_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()

rooms = []

room = Room0()
rooms.append(room)

current_room_no = 0
current_room = rooms[current_room_no]

player = Player("Isaac.png", 420, 150, current_room)
all_sprites_list.add(player)


clock = pygame.time.Clock()


done = False


# -- MAIN PROGRAM LOOP -- #

# -- Event processing --

while not done:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True


# Player controls

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player.changespeed(-7, 0)
            elif event.key == pygame.K_RIGHT:
                player.changespeed(7, 0)
            elif event.key == pygame.K_UP:
                player.changespeed(0, -7)
            elif event.key == pygame.K_DOWN:
                player.changespeed(0, 7)

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                player.changespeed(7, 0)
            elif event.key == pygame.K_RIGHT:
                player.changespeed(-7, 0)
            elif event.key == pygame.K_UP:
                player.changespeed(0, 7)
            elif event.key == pygame.K_DOWN:
                player.changespeed(0, -7)

# -- Game Logic --

    all_sprites_list.update()
    current_room.enemy_sprites.update(player)

# Hit detection 

    screen.blit(current_room.background_image, current_room.background_position)

    all_sprites_list.draw(screen)
    current_room.enemy_sprites.draw(screen)


    pygame.display.flip()

    clock.tick(60)

pygame.quit()

Dragon class

import pygame
import math
from Player import Player
import time

BLACK = (0, 0, 0)

class SpriteSheet(object):

    def __init__(self, file_name):

        self.sprite_sheet = pygame.image.load(file_name).convert()


    def get_image(self, x, y, width, height):

        image = pygame.Surface([width, height]).convert()
        image.blit(self.sprite_sheet, (0, 0), (x, y, width, height))
        image.set_colorkey(BLACK)

        return image


class Dragon(pygame.sprite.Sprite):

    def __init__(self, x, y):

        super().__init__()

        self.flying_frames_l = []
        self.flying_frames_r = []

        sprite_sheet = SpriteSheet("Dragon.png")

# Flying left
        image = sprite_sheet.get_image(12, 22, 95, 85)
        self.flying_frames_l.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        self.flying_frames_l.append(image)
        image = sprite_sheet.get_image(18, 138, 96, 55)
        self.flying_frames_l.append(image)
        image = sprite_sheet.get_image(128, 131, 96, 63)
        self.flying_frames_l.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        self.flying_frames_l.append(image)
        image = sprite_sheet.get_image(12, 22, 95, 85)
        self.flying_frames_l.append(image)

# Flying right
        image = sprite_sheet.get_image(12, 22, 95, 85)
        image = pygame.transform.flip(image, True, False)
        self.flying_frames_r.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        image = pygame.transform.flip(image, True, False)
        self.flying_frames_r.append(image)
        image = sprite_sheet.get_image(18, 138, 96, 55)
        image = pygame.transform.flip(image, True, False)
        self.flying_frames_r.append(image)
        image = sprite_sheet.get_image(128, 131, 96, 63)
        image = pygame.transform.flip(image, True, False)
        self.flying_frames_r.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        image = pygame.transform.flip(image, True, False)
        self.flying_frames_r.append(image)
        image = sprite_sheet.get_image(12, 22, 95, 85)
        image = pygame.transform.flip(image, True, False)
        self.flying_frames_r.append(image)


        self.image = self.flying_frames_r[0]
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x

        self.speedx = 0
        self.speedy = 0

        self.health = 100


    def update(self, player):

        posx = self.rect.x
        posy = self.rect.y

        dx = self.rect.x - player.rect.x
        dy = self.rect.y - player.rect.y

        dist = math.hypot(dx, dy)

        dx = dx / dist
        dy = dy / dist

        if dx > 0:
            self.speedx = -1.5

        if dx <= 0:
            self.speedx = -1.5          

        if dy >= 0:
            self.speedy = -1.5

        if dy <= 0:
            self.speedy = -1.5


        self.rect.x += dx * self.speedx
        self.rect.y += dy * self.speedy


        if self.rect.x < player.rect.x:
            frame = (posx // 10) % len(self.flying_frames_l)
            self.image = self.flying_frames_l[frame]
        else:
            frame = (posx // 10) % len(self.flying_frames_r)
            self.image = self.flying_frames_r[frame]

        if self.rect.y < player.rect.y:
            frame = (posy // 10) % len(self.flying_frames_l)
            self.image = self.flying_frames_l[frame]
        else:
            frame = (posy // 10) % len(self.flying_frames_r)
            self.image = self.flying_frames_r[frame]

Player class

import pygame


BLACK = (0, 0, 0)
WHITE = (255, 255, 255)


class Player(pygame.sprite.Sprite):


    def __init__(self, filename, x, y, current_room):

        super().__init__()

        self.image = pygame.image.load(filename).convert()
        self.image.set_colorkey(BLACK)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

        self.change_x = 0
        self.change_y = 0

    def changespeed(self, x, y):
        self.change_x += x
        self.change_y += y

    def update(self):
        self.rect.x += self.change_x
        self.rect.y += self.change_y

Room class

import Player
import pygame
from Enemies import Dragon


class Room(object):
    enemy_sprites = None

    def __init__(self):
        self.enemy_sprites = pygame.sprite.Group()


class Room0(Room):
    def __init__(self):
        super().__init__()

        enemy = Dragon(380, 280)
        self.enemy_sprites.add(enemy)

        self.background_position = [0, 0]
        self.background_image = pygame.image.load("Floor.png").convert()

enter image description here

This is the spritesheet im using to make it easier to run the code

Upvotes: 3

Views: 1107

Answers (1)

sloth
sloth

Reputation: 101052

Besides the ZeroDivisionError Azhy already pointed out, your problem is that you calculate the current image of the animation by diving posx/posy by a constant.

So if posy does not change, the image will not change.

You can print out frame at the end of update to see it yourself.


You could extract handling the animation into its own class or something, here's a simple example:

class Animation(object):
    def __init__(self, sprite, speed, images):
        self.sprite = sprite
        self.images = images
        self.speed = speed
        self.step = 0
        self.frame = 0

    def update(self):
        self.step += 1
        if self.step >= self.speed:
            self.frame = (self.frame + 1) % len(self.images)
            self.sprite.image = self.images[self.frame]
            self.step = 0

and then the Dragon class could look like this:

class Dragon(pygame.sprite.Sprite):

    def __init__(self, x, y):

        super().__init__()

        flying_frames_l = []
        flying_frames_r = []

        sprite_sheet = SpriteSheet("Dragon.png")

# Flying left
        image = sprite_sheet.get_image(12, 22, 95, 85)
        flying_frames_l.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        flying_frames_l.append(image)
        image = sprite_sheet.get_image(18, 138, 96, 55)
        flying_frames_l.append(image)
        image = sprite_sheet.get_image(128, 131, 96, 63)
        flying_frames_l.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        flying_frames_l.append(image)
        image = sprite_sheet.get_image(12, 22, 95, 85)
        flying_frames_l.append(image)
        self.flying_left = Animation(self, 6, flying_frames_l)

# Flying right
        image = sprite_sheet.get_image(12, 22, 95, 85)
        image = pygame.transform.flip(image, True, False)
        flying_frames_r.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        image = pygame.transform.flip(image, True, False)
        flying_frames_r.append(image)
        image = sprite_sheet.get_image(18, 138, 96, 55)
        image = pygame.transform.flip(image, True, False)
        flying_frames_r.append(image)
        image = sprite_sheet.get_image(128, 131, 96, 63)
        image = pygame.transform.flip(image, True, False)
        flying_frames_r.append(image)
        image = sprite_sheet.get_image(140, 35, 95, 67)
        image = pygame.transform.flip(image, True, False)
        flying_frames_r.append(image)
        image = sprite_sheet.get_image(12, 22, 95, 85)
        image = pygame.transform.flip(image, True, False)
        flying_frames_r.append(image)
        self.flying_right = Animation(self, 6, flying_frames_r)

        self.image = flying_frames_r[0]
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x

        self.speedx = 0
        self.speedy = 0

        self.health = 100
        self.animation = self.flying_right

    def update(self, player):

        posx = self.rect.x
        posy = self.rect.y

        dx = self.rect.x - player.rect.x
        dy = self.rect.y - player.rect.y

        dist = math.hypot(dx, dy)

        if dist > 0:
            dx = dx / dist
            dy = dy / dist

        if dx > 0:
            self.speedx = -1.5
            self.animation = self.flying_left

        if dx <= 0:
            self.speedx = -1.5          
            self.animation = self.flying_right

        if dy >= 0:
            self.speedy = -1.5

        if dy <= 0:
            self.speedy = -1.5


        self.rect.x += dx * self.speedx
        self.rect.y += dy * self.speedy


        self.animation.update()

Note how we simply increase a counter to see if we should change the image instead on relying on the current position.

Upvotes: 2

Related Questions