Pygame:从精灵表中显示这些船及其运动的最佳方式是什么? [英] Pygame: What is the best way to display these ships and their movement from sprite sheet?
问题描述
下面附上我正在使用的精灵表之一.现在,我想知道移动时显示带有动画的船只的最佳方式.这些船有 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:从精灵表中显示这些船及其运动的最佳方式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!