Rebagliati Loris
Rebagliati Loris

Reputation: 579

Class player - Animation stop first frame

Quick question. I have my Player Class, working perfectly. Except for a small detail. This is the class:

from dict.entity_dict import player, player_class
from collections import OrderedDict
import pyglet, random

key = pyglet.window.key

class Player(pyglet.sprite.Sprite):

    dir_stand = "south"
    dir_run = "south"
    sprite_stand = 3
    sprite_run = 3
    image = None
    s = 0

    def __init__(self, game):
        self.game = game

        self.keyboard = key.KeyStateHandler()

        self.statistics_base = OrderedDict()

        self.image_stand = pyglet.resource.image(player.get("player_stand", {'x': None}).get("resource"))
        self.image_run = pyglet.resource.image(player.get("player_run", {'x': None}).get("resource"))
        self.image_stand_width = player.get("player_stand", {'x': None}).get("width")
        self.image_stand_height = player.get("player_stand", {'x': None}).get("height")
        self.image_run_width = player.get("player_run", {'x': None}).get("width")
        self.image_run_height = player.get("player_run", {'x': None}).get("height")

        self.vx = self.game.wd / 2
        self.vy = self.game.wh / 2

        self.load_sprite()

    def class_player(self, type):
        self.statistics_base["hp"] = player_class.get(type, {'x': None}).get("hp")
        self.statistics_base["atk"] = player_class.get(type, {'x': None}).get("atk")
        self.statistics_base["dif"] = player_class.get(type, {'x': None}).get("dif")
        self.statistics_base["atk_sp"] = player_class.get(type, {'x': None}).get("atk_sp")
        self.statistics_base["dif_sp"] = player_class.get(type, {'x': None}).get("dif_sp")
        self.statistics_base["vel"] = player_class.get(type, {'x': None}).get("vel")
        for stat in self.statistics_base:
            if self.statistics_base[stat] is None:
                self.statistics_base[stat] = 10


    def animation(self, image, da, width, height):
        frame_list = [image.get_region(x=width * i, y=height * da, width=46, height=58) for i in range(22)]
        image_animation = pyglet.image.Animation.from_image_sequence(frame_list, 0.10, True)

        return image_animation

    def direction_sprite(self):
        if self.dir_stand == "north":
            self.sprite_stand = 7
        elif self.dir_stand == "east":
            self.sprite_stand = 5
        elif self.dir_stand == "south":
            self.sprite_stand = 3
        elif self.dir_stand == "west":
            self.sprite_stand = 1
        if self.dir_run == "north":
            self.sprite_run = 7
        elif self.dir_run == "north-east":
            self.sprite_run = 6
        elif self.dir_run == "east":
            self.sprite_run = 5
        elif self.dir_run == "south-east":
            self.sprite_run = 4
        elif self.dir_run == "south":
            self.sprite_run = 3
        elif self.dir_run == "south-west":
            self.sprite_run = 2
        elif self.dir_run == "west":
            self.sprite_run = 1
        elif self.dir_run == "north-west":
            self.sprite_run = 0

    def load_sprite(self):
        if not self.keyboard[key.W] and not self.keyboard[key.S] and not self.keyboard[key.D] and not self.keyboard[key.A]:
            self.keyboard.clear()
            img = self.image_stand
            img_width = self.image_stand_width
            img_height = self.image_stand_height
            da = self.sprite_stand
        else:
            img = self.image_run
            img_width = self.image_run_width
            img_height = self.image_run_height
            da = self.sprite_run

        self.direction_sprite()
        self.image = self.animation(img, da, img_width, img_height)
        self.image.width, self.image.height = img_width, img_height
        self.image.anchor_x, self.image.anchor_y = img_width // 2, img_height // 2

        self.sprite = pyglet.sprite.Sprite(self.image, batch=self.game.Batch, group=self.game.GroupEntitySprite)


        self.sprite.x = self.vx
        self.sprite.y = self.vy

    def key_player(self):
        if self.keyboard[key.W]:
            self.vy += 1
            self.dir_stand = "north"
            self.dir_run = "north"
        if self.keyboard[key.S]:
            self.vy -= 1
            self.dir_stand = "south"
            self.dir_run = "south"
        if self.keyboard[key.D]:
            self.vx += 1
            self.dir_stand = "east"
            self.dir_run = "east"
        if self.keyboard[key.A]:
            self.vx -= 1
            self.dir_stand = "west"
            self.dir_run = "west"
        if self.keyboard[key.W] and self.keyboard[key.D]:
            random1 = random.randint(1, 2)
            if random1 == 1:
                self.dir_stand = "north"
            else:
                self.dir_stand = "east"
            self.dir_run = "north-east"
        if self.keyboard[key.S] and self.keyboard[key.D]:
            random2 = random.randint(1, 2)
            if random2 == 1:
                self.dir_stand = "south"
            else:
                self.dir_stand = "east"
            self.dir_run = "south-east"
        if self.keyboard[key.W] and self.keyboard[key.A]:
            random3 = random.randint(1, 2)
            if random3 == 1:
                self.dir_stand = "north"
            else:
                self.dir_stand = "west"
            self.dir_run = "north-west"
        if self.keyboard[key.S] and self.keyboard[key.A]:
            random4 = random.randint(1, 2)
            if random4 == 1:
                self.dir_stand = "south"
            else:
                self.dir_stand = "west"
            self.dir_run = "south-west"

    def update(self):
        self.key_player()
        self.load_sprite()

Since to update the Player's sprite, I need to call the "load_sprite" function, which causes the animation to be constantly called. As a result, the same animation does not appear and remains still at the first frame. So how could I solve?

Edit: Modified the script, including the for loop. If you see, I modified the group, using Batch and OrderedGroup instead. In this way we can clearly see the problem I am having.

The problem I have is due to the fact that pyglet.sprite.Sprite is called in order to update which animation is executed. However, doing so at the same time, the animations are not shown exactly because of the constant call of pyglet.sprite.Sprite.

enter image description here

Upvotes: 0

Views: 145

Answers (1)

Ted Klein Bergman
Ted Klein Bergman

Reputation: 9766

First, you can change the sprite's animation by setting its image attribute, instead of creating a new Sprite instance. Second, only change its animation when you actually need to. That is when the direction changes.

I've added a simple example (pseudo) code to roughly show what I mean.

def animation(image, da, width, height):
    frame_list = [image.get_region(x=width * i, y=height * da, width=46, height=58) for i in range(22)]
    image_animation = pyglet.image.Animation.from_image_sequence(frame_list, 0.10, True)
    return image_animation


class Player:

    def __init__(self, standing_animations, running_animations):
        # ... code ...
        self.standing_animations = standing_animations   # List of animations 
        self.running_animations  = running_animations    # List of animations
        self.current_animation = standing_animations[0]  # Just to have a default animation
        self.previous_running_direction  = None
        self.previous_standing_direction = None

    def load_sprite(self):
        self.sprite.x = self.vx
        self.sprite.y = self.vy

        if self.previous_running_direction == self.dir_run and self.previous_standing_direction == self.dir_stand:
            return  # Don't do anything more in here

        if not self.keyboard[key.W] and not self.keyboard[key.S] and not self.keyboard[key.D] and not self.keyboard[key.A]:
            self.keyboard.clear()
            self.current_animation = self.standing_animations[self.sprite_stand]
        else:
            self.current_animation = self.running_animations[self.sprite_run]

        self.sprite.image = self.current_animation

    def update(self):
        self.previous_running_direction  = self.dir_run
        self.previous_standing_direction = self.dir_stand
        self.key_player()
        self.load_sprite()

Upvotes: 1

Related Questions