Pygame和Numpy动画

时间:2019-01-29 06:38:16

标签: python python-3.x numpy animation pygame

假设我有一个数据类型为myAnimation的Numpy数组np.uint8,代表一个形状为(y,x,4,k)的动画(多帧仍为8位RGBA图像的帧),其中y是高度,x是宽度,4是通道数(红色,绿色,蓝色,alpha),k是动画中的帧数。

假设我想以指定的帧频(例如每秒15帧)在PyGame中播放此NumPy数组的帧,并进行动画循环。

这可能与Pygame有关吗?

如果是,您将如何实现?你能举个例子吗?

我在网上找到的所有内容都涉及从磁盘读取文件,但是重要的是我能够使用内存中已经存在的值,因为它们会在程序运行时频繁更改。

1 个答案:

答案 0 :(得分:0)

  

[...]形状(y,x,4,k),其中y是高度,x是宽度,4是通道数(红色,绿色,蓝色,alpha),以及k是帧数[...]

遗憾的是,这不可能直接实现。

通过pygame.surfarray.make_surface,可以将(numpy)数据数组转换为pygame.Surface
但是该数组必须是形状为(x, y, 3)的3维数组。

这意味着必须首先将数组从形状(y, x, 4, k)转换为(k, x, y, 4)。这可以通过numpy.moveaxis来实现:

myAnimation = np.moveaxis(myAnimation, 1, 0)
myAnimation = np.moveaxis(myAnimation, 3, 0)

最后,每帧的Alpha通道必须由numpy.delete删除:

np.delete(myAnimation[i], 3, 2) )

具有{em>(y,x,4,k)形状的np.uint8数组可以转换为 k pygame.Surface es的列表者:

myAnimation = np.moveaxis(myAnimation, 1, 0)
myAnimation = np.moveaxis(myAnimation, 3, 0)
surfL = [pygame.surfarray.make_surface( np.delete(myAnimation[i], 3, 2) ).convert_alpha() \
    for i in range(myAnimation.shape[0])]

可以通过pygame.time.Clock.tick()设置帧频。参见示例:

import pygame
import pygame.font
import numpy as np

size = (400,400)
pygame.init()
screen = pygame.display.set_mode(size)

myAnimation = np.zeros(shape = (80, 80, 4, 20), dtype = "uint8")

imageCpt = pygame.Vector2(myAnimation.shape[0]/2, myAnimation.shape[1]/2)
radius = myAnimation.shape[0]/2
maxI = 20
for x in range(myAnimation.shape[0]): 
    for y in range(myAnimation.shape[1]):
        pos = pygame.math.Vector2(x, y) - imageCpt
        for i in range(myAnimation.shape[3]):
            pos2 = pygame.math.Vector2(pos)
            pos2.x = pos2.x * maxI / max(1,abs(i-maxI/2))
            if pos.length() < radius:
                    myAnimation[x][y][3][i] = 255
                    if pos2.length() < radius:
                        myAnimation[x][y][0][i] = 255
                        if pos.length()*2 > radius:
                            myAnimation[x][y][1][i] = 255
                            myAnimation[x][y][2][i] = 255
                    else:
                        myAnimation[x][y][2][i] = 255 

myAnimation = np.moveaxis(myAnimation, 1, 0)
myAnimation = np.moveaxis(myAnimation, 3, 0)
surfL = [pygame.surfarray.make_surface( np.delete(myAnimation[i], 3, 2) ).convert_alpha() for i in range(myAnimation.shape[0])]

pos = [160, 160]
clock = pygame.time.Clock()
count = 0
done = False
while not done:
    clock.tick(20)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    screen.fill(0)
    screen.blit(surfL[count % len(surfL)], pos)
    pygame.display.flip()
    count += 1