Python 来自少数图像的动画精灵

Python 来自少数图像的动画精灵,python,animation,pygame,sprite,pygame-surface,Python,Animation,Pygame,Sprite,Pygame Surface,我一直在寻找一些关于使用Pygame从Python中的一些图像制作简单精灵动画的好教程。我还没找到我要找的东西 我的问题很简单:如何从几个图像中制作一个动画精灵(例如:制作几个尺寸为20x20px的爆炸图像,使其成为一个动画) 有什么好主意吗?你可以尝试修改你的精灵,让它在更新中换成另一个。这样,当精灵被渲染时,它将看起来是动画 编辑: 下面是我起草的一个快速示例: import pygame import sys def load_image(name): image = pygam

我一直在寻找一些关于使用Pygame从Python中的一些图像制作简单精灵动画的好教程。我还没找到我要找的东西

我的问题很简单:如何从几个图像中制作一个动画精灵(例如:制作几个尺寸为20x20px的爆炸图像,使其成为一个动画)


有什么好主意吗?

你可以尝试修改你的精灵,让它在
更新
中换成另一个。这样,当精灵被渲染时,它将看起来是动画

编辑

下面是我起草的一个快速示例:

import pygame
import sys

def load_image(name):
    image = pygame.image.load(name)
    return image

class TestSprite(pygame.sprite.Sprite):
    def __init__(self):
        super(TestSprite, self).__init__()
        self.images = []
        self.images.append(load_image('image1.png'))
        self.images.append(load_image('image2.png'))
        # assuming both images are 64x64 pixels

        self.index = 0
        self.image = self.images[self.index]
        self.rect = pygame.Rect(5, 5, 64, 64)

    def update(self):
        '''This method iterates through the elements inside self.images and 
        displays the next one each tick. For a slower animation, you may want to 
        consider using a timer of some sort so it updates slower.'''
        self.index += 1
        if self.index >= len(self.images):
            self.index = 0
        self.image = self.images[self.index]

def main():
    pygame.init()
    screen = pygame.display.set_mode((250, 250))

    my_sprite = TestSprite()
    my_group = pygame.sprite.Group(my_sprite)

    while True:
        event = pygame.event.poll()
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit(0)

        # Calling the 'my_group.update' function calls the 'update' function of all 
        # its member sprites. Calling the 'my_group.draw' function uses the 'image'
        # and 'rect' attributes of its member sprites to draw the sprite.
        my_group.update()
        my_group.draw(screen)
        pygame.display.flip()

if __name__ == '__main__':
    main()

它假设您在代码所在的同一文件夹中有两个名为
image1.png
image2.png
的图像。

您应该将所有精灵动画放在一个大“画布”上,因此对于3个20x20爆炸精灵帧,您将拥有60x20图像。现在,您可以通过加载图像的一个区域来获得正确的帧

在您的sprite类中,最有可能的是在update方法中,您应该有这样的内容(为了简单起见,硬编码,我更喜欢使用单独的类来负责选择正确的动画帧)<在
\uuuu init\uuuu
上,code>self.f=0

def update(self):
    images = [[0, 0], [20, 0], [40, 0]]
    self.f += 1 if self.f < len(images) else 0
    self.image = your_function_to_get_image_by_coordinates(images[i])
def更新(自):
图像=[[0,0],[20,0],[40,0]]
如果self.f
有两种类型的动画:帧相关的时间相关的。两者的工作方式相似


在主回路之前
  • 将所有图像加载到列表中
  • 创建三个变量:
  • 索引
    ,用于跟踪图像列表的当前索引
  • current_time
    current_frame
    跟踪自上次索引切换以来的当前时间或当前帧
  • animation\u time
    animation\u frames
    定义切换图像前应经过的秒数或帧数

  • 在主循环期间
  • current_time
    增加自上次增加后经过的秒数,或将
    current_frame
    增加1
  • 检查
    当前时间>=动画时间
    当前帧>=动画帧
    。如果为true,则继续3-5
  • 重置
    当前\u时间=0
    当前\u帧=0
  • 增加索引,除非它等于或大于图像数量。在这种情况下,重置
    index=0
  • 相应地更改精灵的图像

  • 一个完整的工作示例
    导入操作系统
    导入pygame
    pygame.init()
    尺寸=宽度,高度=720480
    背景颜色=pygame.COLOR('黑色')
    FPS=60
    screen=pygame.display.set_模式(大小)
    clock=pygame.time.clock()
    def加载_图像(路径):
    """
    加载目录中的所有图像。目录必须仅包含图像。
    Args:
    路径:要从中加载图像的目录的相对或绝对路径。
    返回:
    图像列表。
    """
    图像=[]
    对于os.listdir(路径)中的文件名:
    image=pygame.image.load(path+os.sep+文件名).convert()
    images.append(图像)
    返回图像
    类AnimatedSprite(pygame.sprite.sprite):
    定义初始化(自身、位置、图像):
    """
    动画精灵对象。
    Args:
    位置:屏幕上的x,y坐标以放置动画精灵。
    图像:要在动画中使用的图像。
    """
    超级(动画精灵,自我)。\uuuu init\uuuu()
    大小=(32,32)#这应该与图像的大小相匹配。
    self.rect=pygame.rect(位置、大小)
    self.images=图像
    self.images\u right=图像
    self.images_left=[pygame.transform.flip(图像中的图像,真,假)]#翻转每个图像。
    self.index=0
    self.image=images[self.index]#“image”是动画的当前图像。
    self.velocity=pygame.math.Vector2(0,0)
    self.animation\u time=0.1
    self.current\u time=0
    self.animation_frames=6
    self.current\u frame=0
    def更新取决于时间(自身,dt):
    """
    大约每0.1秒更新一次精灵图像。
    Args:
    dt:每帧之间经过的时间。
    """
    如果self.velocity.x>0:#如果sprite向右移动,则使用正确的图像。
    self.images=self.images\u右
    elif自速度x<0:
    self.images=self.images\u左
    自身电流_时间+=dt
    如果self.current\u time>=self.animation\u time:
    self.current\u time=0
    self.index=(self.index+1)%len(self.images)
    self.image=self.images[self.index]
    自校正移动ip(*自校正速度)
    def更新取决于帧(自身):
    """
    每6帧更新一次精灵图像(如果帧速率为60,则大约每0.1秒更新一次)。
    """
    如果self.velocity.x>0:#如果sprite向右移动,则使用正确的图像。
    self.images=self.images\u右
    elif自速度x<0:
    self.images=self.images\u左
    自当前帧+=1
    如果self.current\u frame>=self.animation\u frames:
    self.current\u frame=0
    self.index=(self.index+1)%len(self.images)
    self.image=self.images[self.index]
    自校正移动ip(*自校正速度)
    def更新(自我,dt):
    “”“这是在调用'all_sprites.update(dt)'时调用的方法。”“”
    #通过注释/取消注释在两种更新方法之间切换。
    自我更新依赖于时间(dt)
    #self.update_frame_dependent()
    def main():
    images=load_images(path='temp')#确保提供到images目录的相对或完整路径。
    player=AnimatedSprite(位置=(100100),images=imag
    
    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()