【问题标题】:Python pygame character idle animationPython pygame 角色空闲动画
【发布时间】:2020-07-08 06:28:45
【问题描述】:

我有一个播放器类的更新方法,它检查我已存储空闲动画的两个图像文件的列表。在我的更新方法中,我正在检查是否已经过了足够的时间,是否应该更新图像。最初运行脚本时它会动画但停止,我如何使其连续?

import pygame
import os
from os import path

os.environ['SDL_VIDEO_CENTERED'] = '1'
img_dir = path.join(path.dirname(__file__), 'img')

WIDTH = 720
HEIGHT = 360
FPS = 30

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

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

class Player(pygame.sprite.Sprite):
    def __init__(self, size):
        pygame.sprite.Sprite.__init__(self)
        self.size = size
        self.image = playerIdle_anim[self.size][0]
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 10
        self.speedx = 0
        self.speedy = 0
        self.frame = 0
        self.last_update = pygame.time.get_ticks()
        self.frame_rate = 500

    def update(self):
        now = pygame.time.get_ticks()
        if now - self.last_update > self.frame_rate:
            self.last_update = now
            self.frame += 1
            if self.frame == 1:
                center = self.rect.center 
                self.image = playerIdle_anim[self.size][self.frame]
                self.rect = self.image.get_rect()
                self.rect.center = center
                self.frame = 0
            if self.frame == 0:
                center = self.rect.center 
                self.image = playerIdle_anim[self.size][self.frame]
                self.rect = self.image.get_rect()
                self.rect.center = center
                
                
                


        self.speedx = 0
        self.speedy = 0
        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_LEFT]:
            self.speedx = -8
        if keystate[pygame.K_RIGHT]:
            self.speedx = 8
        if keystate[pygame.K_UP]:
            self.speedy = -8
        if keystate[pygame.K_DOWN]:
            self.speedy = 8
        self.rect.x += self.speedx
        self.rect.y += self.speedy

playerIdle_anim = {}
playerIdle_anim['lg'] = []

for i in range(2):
    filename = 'player_idle0{}.png'.format(i)
    img = pygame.image.load(path.join(img_dir, filename)).convert()
    img.set_colorkey(BLACK)
    img_lg = pygame.transform.scale(img, (128, 75))
    playerIdle_anim['lg'].append(img_lg)
    
        
all_sprites = pygame.sprite.Group()
player = Player('lg')
all_sprites.add(player)

running = True
while running:

    clock.tick(FPS)
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            running = False

    #draw / render
    all_sprites.update()
    screen.fill(WHITE)
    all_sprites.draw(screen)
    pygame.display.update()

pygame.quit()
quit()

【问题讨论】:

    标签: python oop pygame


    【解决方案1】:
    1. 您不需要在每个帧索引情况下都在编辑器中键入相同的操作。 我认为您只需要计算帧索引并在一个算法中将其绘制在 Update() 中

    更改案例:

       def update(self):
            now = pygame.time.get_ticks()
            if now - self.last_update > self.frame_rate:
                self.last_update = now
                self.frame += 1
                if self.frame == 1:
                    center = self.rect.center 
                    self.image = playerIdle_anim[self.size][self.frame]
                    self.rect = self.image.get_rect()
                    self.rect.center = center
                    self.frame = 0
                if self.frame == 0:
                    center = self.rect.center 
                    self.image = playerIdle_anim[self.size][self.frame]
                    self.rect = self.image.get_rect()
                    self.rect.center = center
        ................
    

    计算:

        def update(self):
            now = pygame.time.get_ticks()
            if now - self.last_update > self.frame_rate:
                self.last_update = now            
                self.frame = (self.frame + 1) % len(playerIdle_anim['lg'])
                center = self.rect.center 
                self.image = playerIdle_anim[self.size][self.frame]
                self.rect = self.image.get_rect()
                self.rect.center = center
        ................
    
    1. 另外,您可能应该在类中设置帧列表 (playerIdle_anim['lg'])。

    代替:

     class Player(pygame.sprite.Sprite):
         def __init__(self, size):
             pygame.sprite.Sprite.__init__(self)
             self.size = size
    

    写:

    class Player(pygame.sprite.Sprite):
        def __init__(self, FramesList):
            pygame.sprite.Sprite.__init__(self)
            self.frames = FramesList        
            self.image = self.frames[0]
            ................
        def update(self):
            now = pygame.time.get_ticks()
            if now - self.last_update > self.frame_rate:
                self.last_update = now            
                self.frame = (self.frame + 1) % len(self.frames)
                center = self.rect.center
                self.image = self.frames[self.frame]
            ................
    
    ................
    player = Player(playerIdle_anim['lg'])
    ................
    

    希望你能听懂我的英语

    【讨论】:

      【解决方案2】:

      @PSV 为您的动画代码布局提供了很好的建议,这些更改将修复并且只是代码,但它没有解释什么是错误的。

      您的动画停止的原因是因为 next-frame-index 的计算不太正确。它总是停留在帧0 对吗?

      让我们来看看你的 `update() 函数:

      def update(self):
          now = pygame.time.get_ticks()
          if now - self.last_update > self.frame_rate:
              self.last_update = now
              self.frame += 1                          # <<- UPDATE HERE
              if self.frame == 1:
                  ...            
                  self.frame = 0
              if self.frame == 0:                      # <<-- NOT an "else"
                  ...
      

      动画开始时,self.frame0(在__init__ 中设置)。一段时间过去了,self.frame += 1 发生了。现在我们检查self.frame == 1是否是,所以我们将图像设置为frame['lg'][1],并将self.frame再次设置为0。一段时间过去了,self.frame += 1 发生了……

      代码在测试之前总是有self.frame += 1,所以它总是沿着设置帧#1 的路径前进。但是,因为一旦将self.frame 设置回零(作为索引的一部分为1),就有两个if 语句(而不是ifelse),下一个子句if self.frame == 0也立即被允许,所以你得到两个更新!但人类永远不会看到第一次更新,只会看到最终结果。

      删除self.frame += 1;添加self.frame = 1 并将第二个if 更改为else 将简单地修复代码:

      def update(self):
          now = pygame.time.get_ticks()
          if now - self.last_update > self.frame_rate:
              self.last_update = now
              if self.frame == 1:
                  center = self.rect.center 
                  self.image = playerIdle_anim[self.size][self.frame]
                  self.rect = self.image.get_rect()
                  self.rect.center = center
                  self.frame = 0
              elif self.frame == 0:                      # <-- HERE
                  center = self.rect.center 
                  self.image = playerIdle_anim[self.size][self.frame]
                  self.rect = self.image.get_rect()
                  self.rect.center = center
                  self.frame = 1                         # <-- HERE
      

      然而,这是相当狗血的。当你的动画是 12 帧时,你不想有 12 个几乎相同的子句。必须有更好的方法来处理索引更新。

      @PSV 回答的代码通过使用与当前帧相比的帧计数的modulus(除法余数)解决了这个“下一个图像索引”更新问题。因此,如果您在列表中有 7 帧,则在模数中使用它会返回 0 -> 6,从而停止索引溢出。它相当于:

      self.frame += 1
      frame_count = len( playerIdle_anim[self.size] )
      if ( self.frame >=  frame_count ):
          self.frame = 0
      

      这允许您将帧选择代码减少到两个部分:更新索引和设置图像:

      now = pygame.time.get_ticks()
      if now - self.last_update > self.frame_rate:
          # Update image index
          self.last_update = now
          self.frame += 1
          # ensure the frame-index loops around the list
          if ( self.frame >= len( playerIdle_anim[self.size] ) ):
              self.frame = 0
          # Change the frame to the next (or 0th) image
          center = self.rect.center 
          self.image = playerIdle_anim[self.size][self.frame]
          self.rect = self.image.get_rect()
          self.rect.center = center
      
      
       
      

      【讨论】:

      • 当我上下按键时它不会动画,但是当我左右移动时它会出于某种原因继续动画。
      • @BrandOcOder - 玩家输入的事件处理需要下移到你的主循环中。这将允许更新动画独立于运动运行。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-09
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      相关资源
      最近更新 更多