如何在pygame中循环图像精灵

问题描述:

我正在寻找使用pygame和python版本2.7.6在游戏中创建字符。我有一个简单的python脚本,它允许我创建一个窗口并在屏幕上打印图像。这工作成功,但它只是一个静态图像。如何在pygame中循环图像精灵

import pygame 


class Game(object): 
    def main(self, screen): 

     #load first sprite to image for blit" 
     image = pygame.image.load('sprites/sprite1.png') 
     image2 = pygame.image.load('sprites/sprite2.png') 
     image3 = pygame.image.load('sprites/sprite3.png') 
     while 1: 
     for event in pygame.event.get(): 
      if event.type == pygame.QUIT: 
       return 
      if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: 
       return 

     screen.fill((200, 200, 200)) 
     screen.blit(image, (320, 240)) 
     pygame.display.flip() 

if __name__ == '__main__': 
    pygame.init() 
    screen = pygame.display.set_mode((640, 480)) 
    Game().main(screen) 

我期待通过改变与第二等用于至少三个精灵可能更多的第一子画面以创建更动态的图像(如sprite1.pngsprite2.pngsprite3.png)。如何在给定的时间间隔之后我周期的图像已经过期,例如:1秒1/2秒......

+0

一个单独的循环,改变与子画面,例如1秒的睡眠有作为暂停。最容易实现的线程! – 2014-10-18 02:39:42

+0

单独的图像?我混淆了在哪里使用线程 – user2497792 2014-10-18 03:39:34

稍微更详细的@ Puciek的在评论中建议,可以使用一个循环,如

import time 

for img in [image, image1, image2]: 
    screen.fill((200, 200, 200)) 
    screen.blit(img, (320, 240)) 
    time.sleep(1) # sleep 1 second before continuing 
+0

你会明确希望在单独的线程,或至少一个单独的“渲染”线程,远离主循环。 – 2014-10-18 03:02:16

+0

是的,但是这应该是线程内部的基本构造。 – cm2 2014-10-18 03:03:23

+0

那么,我建议一种有效的方法来将您的答案升级为更有用的答案! – 2014-10-18 03:04:06

让我们从顶层开始,在编写游戏时,让渲染循环远离程序的主循环(处理窗口事件的循环)非常重要。这种方式即使在渲染过程中出现问题时,您的窗口也不太可能变得无法响应。除其他好处之外,例如,人们将能够调整大小,并以其他方式操纵它,而不会中断图形线程。 在网络上有一些很好的教程,虽然我没有一个Python,SFML tutorials can teach you the right concepts然后你可以在Python中使用。

随着公共服务的出现,当您已经将应用程序拆分为单独的线程时,我们就留下了动画问题。非常简单的实现,肯定不是最好的,将催生对每个图像的单独的线程将cosist只有类似的东西:

def shake_it(): 
    while True: 
    time.sleep(3) 
    #do rotation here 

虽然这会工作得非常好,这显然不是最好的解决办法因为它非常不灵活。想象一下,现在你还想定期做点别的事情,例如让你的NPC巡逻堡垒。这将需要另一个线程,并且这会很快升级到相当多的线程(这本身并不坏,但不是预期的效果)。

因此,救援将是一个更通用的线程事件处理程序。一个将控制所有需要按特定间隔执行的函数的类。然后,在用于动画图像的额外线程中,您可以在循环中运行event_handler的实例,而这将作为动画的动作的抽象。

+0

感谢一个非常丰富的答案 – user2497792 2014-10-18 20:38:16

要循环显示精灵图像,您只需在循环中对相应的图像进行擦除。一个好的方法是将序列的所有图像放在一个图像中,并在程序启动时加载它。然后使用subsurface()函数获取blitting的图像,这样就可以将整个图像中子表面的“窗口”与循环中变化的某个变量绑定在一起。另一个问题是,如何控制频率,有几种方法,下面是精灵动画的一个简单例子。这是8个状态相同的精灵序列,它以三种不同的FPS循环:初始 - 12 fps(1/12秒暂停),然后是初始fps的1/3 = 4 fps(3/12秒暂停)和1/12的初始fps = 1 fps(12/12 = 1秒暂停)。我发布整个脚本,以便您可以运行并查看它的工作原理,只需将它与图像放在一个地方并运行脚本即可。 使用该图像与所述脚本:

enter image description here

源代码:

import pygame, os 
from pygame.locals import * 

def Cycle(n, N) :   # n - current state, N - max number of states 
    value = n+1 
    case1 = (value >= N) 
    case2 = (value < N) 
    result = case1 * 0 + case2 * value 
    return result 

w = 600   # window size 
h = 400 
cdir = os.path.curdir  # current directory in terminal 
states = 8  # number of sprite states 

pygame.init() 
DISP = pygame.display.set_mode((w, h)) 
BG = (36, 0, 36)  # background color 
DISP.fill(BG) 
band_1 = pygame.image.load(os.path.join(cdir, "band1.png")).convert() 
K = 4   # global scale factor 
band_1 = pygame.transform.scale(band_1, (K * band_1.get_width(), K * band_1.get_height())) 
band_1.set_colorkey((0,0,0)) 
sw = K*8   # sprite width 
sh = K*8   # sprite height 
r0 = (100, 100, sw, sh)  # sprite 0 rectangle 
r1 = (150, 100, sw, sh)  # sprite 1 rectangle 
r2 = (200, 100, sw, sh)  # sprite 2 rectangle 
s0 = 0   # initial state of sprite 0 
s1 = 0   # initial state of sprite 1 
s2 = 0   # initial state of sprite 2 
t0 = 1   # main ticker 
t1 = 1   # ticker 1 
t2 = 1   # ticker 2 
Loop_1 = True 
FPS = 12 
clock = pygame.time.Clock() 
while Loop_1 : 
    clock.tick(FPS) 
    DISP.fill(BG, r0) 
    sprite_0 = band_1.subsurface((s0*sw, 0, sw, sh)) 
    DISP.blit(sprite_0, r0) 
    s0 = Cycle(s0, states) 
    if t1 == 3 : 
     DISP.fill(BG, r1) 
     sprite_1 = band_1.subsurface((s1*sw, 0, sw, sh)) 
     DISP.blit(sprite_1, r1) 
     s1 = Cycle(s1, states) 
     t1 = 0 
    if t2 == 12 : 
     DISP.fill(BG, r2) 
     sprite_2 = band_1.subsurface((s2*sw, 0, sw, sh)) 
     DISP.blit(sprite_2, r2) 
     s2 = Cycle(s2, states) 
     t2 = 0 
    for event in pygame.event.get(): 
     if event.type == QUIT : Loop_1 = False 
     if event.type == KEYDOWN: 
      if event.key == K_ESCAPE : Loop_1 = False 
# t0 = t0 + 1 
    t1 = t1 + 1 
    t2 = t2 + 1 
    pygame.display.update() 

pygame.quit() 
+2

这是很多代码几乎不可读,主要是因为变量名称。具有讽刺意味的是,在简单的变量赋值中有很多不需要它们的注释(它们只需要合适的名称),但在实际的逻辑中为零。 – 2014-10-20 02:15:32

+0

@Puciek如果它对你来说不可读,那并不意味着它对其他人来说是不可读的。 OP总是可以询问它是否不清楚。你认为线程对于初学者来说只是为了制作简单的动画会有什么帮助?此外,我几乎没有看到这个特定问题与线程的任何关系。你是否认真地为每个动画角色创建线程? – 2014-10-20 08:59:41

+2

如果你想对我的回答发表评论,请随时在下面留言,因为这是对它的评论。 – 2014-10-20 13:02:50