我一直在寻找一些关于使用 Pygame 在 Python 中从几张图像制作简单的 Sprite 动画的好教程。我仍然没有找到我要找的东西。
我的问题很简单:如何用几张图片制作一个动画 Sprite (例如:制作几张尺寸为 20x20 像素的爆炸图片作为一个动画)
有什么好主意吗?
最佳答案
有两种类型的动画:帧相关和时间相关。两者都以相似的方式工作。
主循环之前
- 将所有图像加载到列表中。
- 创建三个变量:
index
,跟踪图像列表的当前索引。current_time
或current_frame
跟踪自上次索引切换以来的当前时间或当前帧。animation_time
或animation_frames
定义在切换图像之前应该经过多少秒或帧。
在主循环中
- 将
current_time
增加自上次增加以来经过的秒数,或者将current_frame
增加 1。 - 检查
current_time >= animation_time
或current_frame >= animation_frame
。如果为真,则继续 3-5。 - 重置
current_time = 0
或current_frame = 0
。 - 增加索引,除非它等于或大于图像的数量。在这种情况下,重置
index = 0
。 - 相应地更改 Sprite 的图像。
一个完整的工作示例
import os
import pygame
pygame.init()
SIZE = WIDTH, HEIGHT = 720, 480
BACKGROUND_COLOR = pygame.Color('black')
FPS = 60
screen = pygame.display.set_mode(SIZE)
clock = pygame.time.Clock()
def load_images(path):
"""
Loads all images in directory. The directory must only contain images.
Args:
path: The relative or absolute path to the directory to load images from.
Returns:
List of images.
"""
images = []
for file_name in os.listdir(path):
image = pygame.image.load(path + os.sep + file_name).convert()
images.append(image)
return images
class AnimatedSprite(pygame.sprite.Sprite):
def __init__(self, position, images):
"""
Animated sprite object.
Args:
position: x, y coordinate on the screen to place the AnimatedSprite.
images: Images to use in the animation.
"""
super(AnimatedSprite, self).__init__()
size = (32, 32) # This should match the size of the images.
self.rect = pygame.Rect(position, size)
self.images = images
self.images_right = images
self.images_left = [pygame.transform.flip(image, True, False) for image in images] # Flipping every image.
self.index = 0
self.image = images[self.index] # 'image' is the current image of the animation.
self.velocity = pygame.math.Vector2(0, 0)
self.animation_time = 0.1
self.current_time = 0
self.animation_frames = 6
self.current_frame = 0
def update_time_dependent(self, dt):
"""
Updates the image of Sprite approximately every 0.1 second.
Args:
dt: Time elapsed between each frame.
"""
if self.velocity.x > 0: # Use the right images if sprite is moving right.
self.images = self.images_right
elif self.velocity.x < 0:
self.images = self.images_left
self.current_time += dt
if self.current_time >= self.animation_time:
self.current_time = 0
self.index = (self.index + 1) % len(self.images)
self.image = self.images[self.index]
self.rect.move_ip(*self.velocity)
def update_frame_dependent(self):
"""
Updates the image of Sprite every 6 frame (approximately every 0.1 second if frame rate is 60).
"""
if self.velocity.x > 0: # Use the right images if sprite is moving right.
self.images = self.images_right
elif self.velocity.x < 0:
self.images = self.images_left
self.current_frame += 1
if self.current_frame >= self.animation_frames:
self.current_frame = 0
self.index = (self.index + 1) % len(self.images)
self.image = self.images[self.index]
self.rect.move_ip(*self.velocity)
def update(self, dt):
"""This is the method that's being called when 'all_sprites.update(dt)' is called."""
# Switch between the two update methods by commenting/uncommenting.
self.update_time_dependent(dt)
# self.update_frame_dependent()
def main():
images = load_images(path='temp') # Make sure to provide the relative or full path to the images directory.
player = AnimatedSprite(position=(100, 100), images=images)
all_sprites = pygame.sprite.Group(player) # Creates a sprite group and adds 'player' to it.
running = True
while running:
dt = clock.tick(FPS) / 1000 # Amount of seconds between each loop.
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.velocity.x = 4
elif event.key == pygame.K_LEFT:
player.velocity.x = -4
elif event.key == pygame.K_DOWN:
player.velocity.y = 4
elif event.key == pygame.K_UP:
player.velocity.y = -4
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT:
player.velocity.x = 0
elif event.key == pygame.K_DOWN or event.key == pygame.K_UP:
player.velocity.y = 0
all_sprites.update(dt) # Calls the 'update' method on all sprites in the list (currently just the player).
screen.fill(BACKGROUND_COLOR)
all_sprites.draw(screen)
pygame.display.update()
if __name__ == '__main__':
main()
什么时候选择哪个
Time-dependent 动画允许您以相同的速度播放动画,无论帧速率有多慢/快或您的计算机有多慢/多快。这允许您的程序在不影响动画的情况下自由更改帧率,并且即使计算机无法跟上帧率,它也会保持一致。如果程序滞后,动画将 catch 状态,就好像没有发生滞后一样。
尽管如此,动画周期可能会与帧率不同步,从而使动画周期看起来不规则。例如,假设我们每 0.05 秒更新一次帧,每 0.075 秒更新一次动画切换图像,则周期为:
- 第 1 帧; 0.00 秒;图片 1
- 第 2 帧; 0.05秒;图片 1
- 第 3 帧; 0.10秒;图 2
- 第 4 帧; 0.15秒;图片 1
- 第 5 帧; 0.20秒;图片 1
- 第 6 帧; 0.25秒;图 2
等等……
Frame-dependent 如果您的计算机能够始终如一地处理帧速率,则看起来会更流畅。如果发生滞后,它将暂停在当前状态并在滞后停止时重新启动,这使得滞后更加明显。这种替代方法更容易实现,因为您只需要在每次调用时将 current_frame
递增 1,而不是处理增量时间 (dt
) 并将其传递给每个对象.
Sprite
结果
关于python - 来自几张图片的动画 Sprite ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14044147/