问题描述
下面附上我正在使用的精灵表之一.现在,我想知道移动时显示带有动画的船只的最佳方式.这些船有 9 个框架.我找到了带有弃用代码的旧示例,或者将图像分解为单个文件的示例.我希望有人向我展示使用这些精灵的最佳方式.感谢您抽出宝贵时间.
Attached below is one of the sprite sheets I am using. Right now, I am wondering the best way to display the ships with their animation when moving. The ships have 9 frames. I have found old examples with deprecated code, or examples that have you break the images into individual files. I would love for someone to show me the best way to use these sprites as they are. Thank you for your time.
推荐答案
什么是最好的方法 无法回答,因为最终那是主观的;取决于你自己的目标.最棒的表演?最简单的代码?最灵活的代码?
What is the best way can't be answered, because in the end that's subjective; and depends on your own goals. Best performance? Easiest code? Most flexible code?
你可以从我在上次无聊的会议中一起破解的类似内容开始:
You could start with something like this I hacked together during my last boring meeting:
import pygame
import random
from pygame import Vector2
SPRITE_SHEET = None
GREEN_SHIP = pygame.Rect(0, 292, 32, 32)
RED_SHIP = pygame.Rect(0, 324, 32, 32)
BLUE_SHIP = pygame.Rect(0, 356, 32, 32)
YELLOW_SHIP = pygame.Rect(0, 388, 32, 32)
class EnemyController:
def __init__(self):
self.direction = Vector2(1, 0)
def update(self, sprite, events, dt):
if not pygame.display.get_surface().get_rect().contains(sprite.rect):
self.direction *= -1
sprite.direction = self.direction
class PlayerController:
movement = {
pygame.K_UP: Vector2( 0, -1),
pygame.K_DOWN: Vector2( 0, 1),
pygame.K_LEFT: Vector2(-1, 0),
pygame.K_RIGHT: Vector2( 1, 0)
}
def update(self, sprite, events, dt):
pressed = pygame.key.get_pressed()
v = Vector2(0, 0)
for key in PlayerController.movement:
if pressed[key]:
v += PlayerController.movement[key]
sprite.direction = v
for e in events:
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_SPACE:
sprite.groups()[0].add(Explosion(sprite.pos))
class Animation:
def __init__(self, frames, speed, sprite):
self.sprite = sprite
self.speed = speed
self.ticks = 0
self.frames = frames
self.running = 0
self.start()
def cycle_func(self, iterable):
saved = []
for element in iterable:
yield element
saved.append(element)
if hasattr(self.sprite, 'on_animation_end'):
self.sprite.on_animation_end()
while saved:
for element in saved:
yield element
if hasattr(self.sprite, 'on_animation_end'):
self.sprite.on_animation_end()
def stop(self):
self.running = 0
if self.idle_image:
self.sprite.image = self.idle_image
def start(self):
if not self.running:
self.running = 1
self.cycle = self.cycle_func(self.frames)
self.sprite.image = next(self.cycle)
def update(self, dt):
self.ticks += dt
if self.ticks >= self.speed:
self.ticks = self.ticks % self.speed
if self.running:
self.sprite.image = next(self.cycle)
class AnimatedSprite(pygame.sprite.Sprite):
def __init__(self, pos, frames, speed):
super().__init__()
self.animation = Animation(frames, speed, self)
self.rect = self.image.get_rect(center=pos)
self.pos = Vector2(pos)
self.animation.start()
def update(self, events, dt):
self.animation.update(dt)
class Explosion(AnimatedSprite):
frames = None
def __init__(self, pos):
if not Explosion.frames:
Explosion.frames = parse_sprite_sheet(SPRITE_SHEET, pygame.Rect(0, 890, 64, 64), 6, 4)
super().__init__(pos, Explosion.frames, 50)
def on_animation_end(self):
self.kill()
class DirectionalImageSprite(pygame.sprite.Sprite):
directions = [(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1),(0,1),(1,1),(0,0)]
def __init__(self, pos, directional_images_rect):
super().__init__()
images = parse_sprite_sheet(SPRITE_SHEET, directional_images_rect, 9, 1)
self.images = { x: img for (x, img) in zip(DirectionalImageSprite.directions, images) }
self.direction = Vector2(0, 0)
self.image = self.images[(self.direction.x, self.direction.y)]
self.rect = self.image.get_rect(center=pos)
self.pos = pos
class SpaceShip(DirectionalImageSprite):
def __init__(self, pos, controller, directional_images_rect):
super().__init__(pos, directional_images_rect)
self.controller = controller
self.speed = 3
def update(self, events, dt):
super().update(events, dt)
if self.controller:
self.controller.update(self, events, dt)
self.image = self.images[(self.direction.x, self.direction.y)]
if self.direction.length():
self.pos = self.pos + self.direction.normalize() * self.speed
self.rect.center = int(self.pos[0]), int(self.pos[1])
def parse_sprite_sheet(sheet, start_rect, frames_in_row, lines):
frames = []
rect = start_rect.copy()
for _ in range(lines):
for _ in range(frames_in_row):
frame = sheet.subsurface(rect)
frames.append(frame)
rect.move_ip(rect.width, 0)
rect.move_ip(0, rect.height)
rect.x = start_rect.x
return frames
def main():
screen = pygame.display.set_mode((800, 600))
global SPRITE_SHEET
SPRITE_SHEET = pygame.image.load("ipLRR.png").convert_alpha()
clock = pygame.time.Clock()
dt = 0
all_sprites = pygame.sprite.Group(
SpaceShip((400, 300), PlayerController(), YELLOW_SHIP),
SpaceShip((400, 100), EnemyController(), GREEN_SHIP)
)
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
all_sprites.update(events, dt)
screen.fill((0, 0, 0))
all_sprites.draw(screen)
pygame.display.flip()
dt = clock.tick(120)
main()
我向函数 parse_sprite_sheet
传递图像,以及动画/相关子图像束第一帧的位置和大小(使用 Rect
).另外,我传递了行中的图像数和行数(因为爆炸动画使用 4 行,每行 4 个图像).然后我使用 subsurface
在嵌套循环中获取我感兴趣的精灵表部分.
I pass the function parse_sprite_sheet
the image, along with the position and size of the first frame of the animation/bunch of related sub-images (using a Rect
). Also, I pass the number of images in the row and the number of rows (since the explosion animation uses 4 rows with 4 images each). Then I use subsurface
the get the part of the sprite sheet I'm interested in in a nested loop.
Animation
类由它所附加的精灵更新,并在足够的时间过去后改变精灵的图像.
The Animation
class is updated by the sprite it's attached to and changes the image of the sprite when enough time has passed.
还有一个名为 on_animation_end
的方法会在动画结束后在精灵上调用.爆炸完成后,我用它来杀死 Explosion
精灵.
Also a method named on_animation_end
is called on the sprite once the animation ends. I use this to kill the Explosion
sprites once the explosion is done.
对于SpaceShip
的定向图像,我在列表中定义了一次方向(按正确的顺序),然后通过创建字典为每个方向附加一个图像.
For the directional images of SpaceShip
, I define the directions in a list once (in the correct order) and then attach each direction an image by creation a dictionary.
这样我就可以轻松查找正确的图像,因为 SpaceShip
的航向方向存储在 direction
属性中.
This way I can easily look up the correct image, since the direction the SpaceShip
is heading is stored in the direction
attribute.
基本上就是这样.您的精灵表中的某些动画有点棘手,因为图块的大小会发生变化,但这是可行的.
That's it basically.Some animations in your sprite sheet are a little more tricky, as the size of the tile changes, but it's doable.
你会明白的.
这篇关于Pygame:从精灵表中显示这些船及其运动的最佳方式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!