改变精灵动画速度(pygame)

Posted

技术标签:

【中文标题】改变精灵动画速度(pygame)【英文标题】:Changing Sprite animation Speed (pygame) 【发布时间】:2018-08-20 14:22:39 【问题描述】:

我设法使用我创建的“动画”功能为我的播放器设置动画 - 在角色移动时循环遍历每帧的角色图像列表。但是,我也发现这与游戏运行的速度相同;并希望有一种简单的方法来改变它,使精灵的动画速度比游戏 FPS 慢。

这是我的精灵类代码:

class Civilian(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites, game.player1group, game.bothplayers
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self._layer = PLAYER1_LAYER
        self.image = pg.Surface((61, 67))
        self.rect = self.image.get_rect()
        self.hit_rect = PLAYER_HIT_RECT
        self.hit_rect.center = self.rect.center
        self.playerspeed = 90
        self.vel = vec(0, 0)
        self.pos = vec(x , y)
        self.move = 0
        self.speedboost = False
        self.last_dir = 'down'#
        self.anim_speed = 0

    def animate(self, direction):
        if direction == 'right':
            self.spritesheet = pg.image.load('walk right civ.png') # Loading the right directional movement spritesheet into the variable
        if direction == 'left':
            self.spritesheet = pg.image.load('walk left civ.png')
        if direction == 'up':
            self.spritesheet = pg.image.load('walk up civ.png')
        if direction == 'down':
            self.spritesheet = pg.image.load('walk down civ.png')
        self.frames = [] # List which will contain each cell of the spritesheet
        # Adding the cells to the list #
        self.frames.append(self.spritesheet.subsurface(pg.Rect(0, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(61, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(122, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(183, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(244, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(305, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(366, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(427, 0, 61, 67)).convert_alpha())
        self.frames.append(self.spritesheet.subsurface(pg.Rect(488, 0, 61, 67)).convert_alpha())
        # Number of frames/cells
        self.frames_number = len(self.frames)
        # Current animation frame
        self.current_frame = 0
        # Frame rectangle
        self.frame_rect = self.frames[0].get_rect()
        self.last_dir = direction

    def get_keys(self):
        self.vel= vec(0, 0)
        keys = pg.key.get_pressed()

        if keys[pg.K_a]:    # Const. subtracts player speed from velocity (E.g. Moves sprite to the left)
            self.vel.x= -self.playerspeed
            self.move += 1
            self.moving = 'left' # Uses different spritesheet depending on direction
        elif keys[pg.K_d]:    # Const. adds player speed value to velocity (E.g. Moves sprite to the right)
            self.vel.x= self.playerspeed
            self.move += 1
            self.moving = 'right'
        elif keys[pg.K_w]:    # Const. subtracts player speed value from y velocity (Moves player upwards; opposite)
            self.vel.y= -self.playerspeed
            self.move += 1
            self.moving = 'up'
        elif keys[pg.K_s]: # Const. adds player speed value to y velocity (Moves player downwards; opposite)
            self.vel.y= self.playerspeed
            self.move += 1
            self.moving = 'down'

    def add_speed(self):
        pass

    def collide_with_player2(self, dir, ifColliding):
        if dir == 'x':
            collides = pg.sprite.spritecollide(self, self.game.player2group, False, collide_player_hit_rect)
            if collides:
                if self.vel.x > 0:
                    self.pos.x = collides[0].hit_rect.left - self.hit_rect.width / 2
                if self.vel.x < 0:
                    self.pos.x = collides[0].hit_rect.right + self.hit_rect.width / 2
                self.vel.x = 0
                self.hit_rect.centerx = self.pos.x
                print("collide x")
                if random.randint(0, 100) <= 4:
                    random.choice(self.game.thief_hit_sounds).play()
                self.ifColliding = True

        if dir == 'y':
            collides = pg.sprite.spritecollide(self, self.game.player2group, False, collide_player_hit_rect)
            if collides:
                if self.vel.y > 0:
                    self.pos.y = collides[0].hit_rect.top - self.hit_rect.height / 2
                if self.vel.y < 0:
                    self.pos.y = collides[0].hit_rect.bottom + self.hit_rect.height / 2
                self.vel.y = 0
                self.hit_rect.centery = self.pos.y
                print("collide y")
                if random.randint(0, 100) <= 4:
                    random.choice(self.game.thief_hit_sounds).play()
                self.ifColliding = True

    def collide_with_walls(self, dir):
        if dir == 'x':
            collides = pg.sprite.spritecollide(self, self.game.walls, False, collide_hit_rect)
            if collides:
                if self.vel.x > 0:
                    self.pos.x = collides[0].rect.left - self.hit_rect.width / 2
                if self.vel.x < 0:
                    self.pos.x = collides[0].rect.right + self.hit_rect.width / 2
                self.vel.x = 0
                self.hit_rect.centerx = self.pos.x
        if dir == 'y':
            collides = pg.sprite.spritecollide(self, self.game.walls, False, collide_hit_rect)
            if collides:
                if self.vel.y > 0:
                    self.pos.y = collides[0].rect.top - self.hit_rect.height / 2
                if self.vel.y < 0:
                    self.pos.y = collides[0].rect.bottom + self.hit_rect.height / 2
                self.vel.y = 0
                self.hit_rect.centery = self.pos.y

    def update(self):
        # frame updates
        self.anim_speed += 1
        self.moving = 'idle'
        self.animate(self.last_dir) # Sets the down spritesheet as default
        self.get_keys()
        if self.moving == 'up':
            self.animate(self.moving) # Uses the up-movement spritesheet if char moving upwards
        if self.moving == 'down':
            self.animate(self.moving) # Same as above, different direction
        if self.moving == 'left':
            self.animate(self.moving)
        if self.moving == 'right':
            self.animate(self.moving)
        self.ifColliding = False




        self.rect.center = self.pos
        self.pos += self.vel * self.game.dt
        self.hit_rect.centerx = self.pos.x
        self.collide_with_walls('x'), self.collide_with_player2('x', self.ifColliding)
        self.hit_rect.centery = self.pos.y
        self.collide_with_walls('y'), self.collide_with_player2('y', self.ifColliding)
        self.rect.center = self.hit_rect.midtop




        if self.ifColliding == True:
            Thief.health -= COL_DAMAGE
            print(Thief.health)
        self.current_frame = (self.current_frame + self.move) % self.frames_number
        if self.moving == 'idle':
            self.current_frame = 0
        self.image = self.frames[self.current_frame] # Image of sprite changes as program cycles through the sheet

【问题讨论】:

【参考方案1】:

您可以通过某种方式将动画速率与帧速率联系起来,从而将动画速率与帧速率解耦。

一种方法是使用pygame.time.get_ticks() 返回自调用pygame.init() 以来的毫秒数。如果您存储此值,您可以测量已经过去了多少时间并适当地制作动画。

def update(self):
    self.elapsed = pygame.time.get_ticks() - self.elapsed
    if self.elapsed > 500: # animate every half second
        self.animate()

注意:您还需要在构造函数中初始化self.elapsed

【讨论】:

你提到在搞乱动画等之前初始化'self.elapsed';其中的值可以是任何数字/自定义值吗? - 只是为了澄清:) 上面的逻辑非常简单,如果你想确保在第一次update 调用时产生动画,你可以将值初始化为零。如果您有多个精灵并且不希望它们同步,则应在创建时将这些值初始化为 0 到 500 之间的随机值。【参考方案2】:

这是我为帧速率为 60 的精灵制作动画并且精灵动画比帧速率慢的代码

import pygame
import glob


def fps():
    fr = "V.3 Fps: " + str(int(clock.get_fps()))
    frt = font.render(fr, 1, pygame.Color("coral"))
    return frt


class MySprite(pygame.sprite.Sprite):
    def __init__(self, action):
        super(MySprite, self).__init__()
        self.action = action
        # This is to slow down animation # takes the frame now and...
        self.elapsed = 0
        self.images = []
        self.temp_imgs = []
        self.load_images()
        self.count = 0

    def load_images(self):
        l_imgs = glob.glob(f"png\\self.action*.png")
        for img in l_imgs:
            if len(img) == len(l_imgs[0]):
                self.images.append(pygame.image.load(img))
            else:
                self.temp_imgs.append(pygame.image.load(img))
        self.images.extend(self.temp_imgs)
        self.index = 0
        self.rect = pygame.Rect(5, 5, 150, 198)

    def update(self):
        self.count += 1
        if self.index == len(self.images):
                self.index = 0
        self.image = self.images[self.index]
        if self.count > 2:
                #self.image = self.images[self.index]
                self.index += 1
                self.count = 0

    def group_sprites(self):
        return pygame.sprite.Group(self)


def group():
    "Dictionary of group of sprites"
    dici = 
    actions = "idle walk run jump dead"
    actions = actions.split()
    for action in actions:
        dici[action] = MySprite(action).group_sprites()
    return dici


def main():
    global clock
    global font

    SIZE = 600, 600
    FPS = 60
    pygame.init()
    action = group()
    my_group = action["idle"]
    screen = pygame.display.set_mode(SIZE)
    pygame.display.set_caption("Game v.3")
    font = pygame.font.SysFont("Arial", 60)
    clock = pygame.time.Clock()

    loop = 1
    while loop:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = 0
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    my_group = action["walk"]
                if event.key == pygame.K_UP:
                    my_group = action["jump"]
                if event.key == pygame.K_SPACE:
                    my_group = action["idle"]
                if event.key == pygame.K_RIGHT:
                    my_group = action["run"]
                if event.key == pygame.K_DOWN:
                    my_group = action["dead"]

        my_group.update()
        screen.fill((0, 0, 0))
        my_group.draw(screen)
        screen.blit(fps(), (10, 0))
        pygame.display.update()
        clock.tick(FPS)
    pygame.quit()


if __name__ == '__main__':
    main()

阅读这篇文章...slow down animation without affecting the frame rate

Dowload images and put the in a directory called png

【讨论】:

以上是关于改变精灵动画速度(pygame)的主要内容,如果未能解决你的问题,请参考以下文章

计算精灵根据需要行进的距离和行进速度改变大小的速度

Cocos2d-x怎样控制动作速度

Python —— 给女儿写个雷霆战机

如何在Pygame中降低Sprite FPS?

pygame - 子弹精灵错误偏离船角(Vectors2)

如何在 Pygame 中使用 Sprite Sheets 创建动画精灵?