假设我有一个数据类型为myAnimation
的Numpy数组np.uint8
,代表一个形状为(y,x,4,k)
的动画(多帧仍为8位RGBA图像的帧),其中y
是高度,x
是宽度,4是通道数(红色,绿色,蓝色,alpha),k
是动画中的帧数。
假设我想以指定的帧频(例如每秒15帧)在PyGame中播放此NumPy数组的帧,并进行动画循环。
这可能与Pygame有关吗?
如果是,您将如何实现?你能举个例子吗?
我在网上找到的所有内容都涉及从磁盘读取文件,但是重要的是我能够使用内存中已经存在的值,因为它们会在程序运行时频繁更改。
答案 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