python - 来自几张图片的动画 Sprite

标签 python animation pygame sprite pygame-surface

我一直在寻找一些关于使用 Pygame 在 Python 中从几张图像制作简单的 Sprite 动画的好教程。我仍然没有找到我要找的东西。

我的问题很简单:如何用几张图片制作一个动画 Sprite (例如:制作几张尺寸为 20x20 像素的爆炸图片作为一个动画)

有什么好主意吗?

最佳答案

有两种类型的动画:帧相关时间相关。两者都以相似的方式工作。


主循环之前

  1. 将所有图像加载到列表中。
  2. 创建三个变量:
    1. index,跟踪图像列表的当前索引。
    2. current_timecurrent_frame 跟踪自上次索引切换以来的当前时间或当前帧。
    3. animation_timeanimation_frames 定义在切换图像之前应该经过多少秒或帧。

在主循环中

  1. current_time 增加自上次增加以来经过的秒数,或者将 current_frame 增加 1。
  2. 检查 current_time >= animation_timecurrent_frame >= animation_frame。如果为真,则继续 3-5。
  3. 重置 current_time = 0current_frame = 0
  4. 增加索引,除非它等于或大于图像的数量。在这种情况下,重置 index = 0
  5. 相应地更改 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. 第 1 帧; 0.00 秒;图片 1
  2. 第 2 帧; 0.05秒;图片 1
  3. 第 3 帧; 0.10秒;图 2
  4. 第 4 帧; 0.15秒;图片 1
  5. 第 5 帧; 0.20秒;图片 1
  6. 第 6 帧; 0.25秒;图 2

等等……

Frame-dependent 如果您的计算机能够始终如一地处理帧速率,则看起来会更流畅。如果发生滞后,它将暂停在当前状态并在滞后停止时重新启动,这使得滞后更加明显。这种替代方法更容易实现,因为您只需要在每次调用时将 current_frame 递增 1,而不是处理增量时间 (dt) 并将其传递给每个对象.

Sprite

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here

结果

enter image description here

关于python - 来自几张图片的动画 Sprite ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14044147/

相关文章:

python - 如何在 Processing 中编码固定数量的半随机间隔且仍然适合固定大小图像的行?

css - 我想在翻译后旋转但旋转效果不起作用(CSS 3 aniamtion)

python - 计算机之间的套接字

java - 在 java maven 测试之前运行 python 脚本

python - 如何在 axis=1 内连接张量?

ios - 调整 UICollectionViewCells 的大小以始终填充 UICollectionView

java - Android - TranslateAnimation 动态更新布局的大小

python - 如何在 Debian jessie 上安装适用于 Python 3 的 pygame?

python - Pygame 中鼠标的对象移动不准确

python - 从 QWebEngineProfile 获取 cookie 作为字典