注意: 我不使用 pygame
,但我专业地编写高清视频的缩放器和转换器,因此我在此基础上进行了绘制。
我在这里查阅了文档:http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert
从文档中可以看出:
如果没有传递参数,则新 Surface 将具有与显示 Surface 相同的像素格式。这始终是最快的 blitting 格式。
换句话说,如果格式匹配,则速度很快。但是,如果不匹配,则必须进行转换[这将运行得更慢]。
在它们被多次 blitting 之前,将所有 Surface 转换为所需格式是一个好主意。
这可能是您想要做的事情(即保留与最终输出格式匹配的已转换表面的缓存副本)
对于您的精灵,它们应该相对较小,因此差异不大。但对于较大的区域,转换可能会[并且似乎是]显著的。
与简单的blit不同,可以使用一系列快速的[C]memcpy
操作完成,转换必须逐像素完成。这可能涉及使用周围像素的卷积核[对于一个好的缩放器,我看到过使用2D 6 tap FIR滤波器]。
由于精灵较小,转换器可以选择更简单的转换算法,因为失真会更不明显。对于较大的区域,转换器可以选择更复杂的算法,因为失真会在更大的区域内累积。
所以,再次强调,预加载是可行的方式。
如果源区域在每帧中发生变化而无法执行上述操作,则可以引入一帧延迟,并将转换分成多个线程/核心,在线程之间将整个区域细分为子区域。
更新:
所以,你会发现一开始速度会降低,因为像素格式必须更改。
在游戏开始时进行预计算不应该是问题,因为你的数字是80毫秒。用户甚至不会注意到游戏开始时这么小的延迟。
专业游戏通过“闪屏”页面来掩盖这一点,其中包含他们的标志,可能会进行[琐碎的]动画(例如只是变形颜色等)
但是,在游戏开始时转换后,剩下的速度不应该更快吗?
是的,根据你已经描述的内容,速度应该更快:后续帧应该是45毫秒而不是80毫秒。这现在给你一个帧率为22,这可能足够了。如果你仍然需要更快(即达到30 fps),那么执行我已经提到的子区域技术可能会有所帮助。此外,仅将从帧N到N + 1更改的内容复制到表面也可能有所帮助。
我仍然困惑于为什么转换后整个游戏的速度都变慢了。
以下是一些简陋的blit和convert代码(仅用于说明,不是真正的代码)。
现在你所做的就像下面的blit_convert一样,对于你的数据中的每一帧,也就是我们将称之为ability_manager_surface。
请注意,它比简单的blit慢(例如下面的blit_fast或blit_slow)。快速的blit只是将每个源像素复制到目标像素。示例转换器必须取当前源像素及其最近邻居的平均值,因此它必须为每个目标像素提取五个源像素值。因此,它更慢。实际用于缩放的算法可能会更慢。
如果在游戏启动时在ability_manager_surface上执行blit_convert并将输出保存到“已经转换”的变量(例如precalc_manager_surface),那么您可以使用precalc_manager_surface在每个帧上使用blit_fast。也就是说,不需要重新计算“静态”数据。
def blit_fast(dstv,dsthgt,dstwid,dstybase,dstxbase,srcv,srchgt,srcwid):
for yoff in range(dstybase,dstybase + srchgt):
dstypos = (yoff * dstwid) + dstxbase
srcypos = (yoff * srcwid);
for xoff in range(0,srcwid):
dstv[dstypos + xoff] = srcv[srcypos + xoff]
def blit_slow(dstv,dsthgt,dstwid,dstybase,dstxbase,srcv,srchgt,srcwid):
for yoff in range(0,srchgt):
for xoff in range(0,srcwid):
dstv[dstybase + yoff][dstxbase + xoff] = srcv[yoff][xoff]
def blit_convert(dstv,dsthgt,dstwid,dstybase,dstxbase,srcv,srchgt,srcwid):
for yoff in range(0,srchgt):
for xoff in range(0,srcwid):
dstv[dstybase + yoff][dstxbase + xoff] = convert(srcv,yoff,xoff)
def convert(srcv,ypos,xpos):
cur = srcv[ypos][xpos]
top = srcv[ypos - 1][xpos]
bot = srcv[ypos + 1][xpos]
left = srcv[ypos][xpos - 1]
right = srcv[ypos][xpos + 1]
out = (cur * 0.6) + (top * 0.1) + (bot * 0.1) + (left * 0.1) + (right * 0.1)
return out
< p >< em >注意:上述示例使用了“玩具”转换函数。要进行高分辨率/高质量图像重新缩放(例如1024x768 --> 1920x1080),您可能需要使用/选择“多相重采样”,其计算量巨大。例如,仅供娱乐,请参见[令人震惊的]:
https://cnx.org/contents/xOVdQmDl@10/Polyphase-Resampling-with-a-Ra
更新 #2:
发现只更新移动的物体的想法很有帮助
这是实时动画和图形的标准建议。只重新计算需要的部分。你只需要确定哪些是需要的。
然而,如果我理解正确,你说我的游戏在每一帧转换后会变慢。
根据你最初的描述,这将应该是情况。
但事实并非如此,因为我在开始时进行转换,所以应该是你所说的快速 blit,但如果我根本不进行转换,则更快。
没有你的实际代码,很难推测。但是...
当你创建一个表面(例如用于保存像 .png
这样的图像文件),默认格式是使用与屏幕格式相近的格式。因此,可以进行 blit 而无需转换。
因此,如果您预先转换了一个离屏表面,为什么在后转换格式与屏幕格式匹配的情况下会更慢[blit]呢?如果它更慢,那么肯定存在某种不匹配。而且,如果您使用默认设置创建表面,为什么它需要转换呢?
标准模型是尽可能直接在屏幕上执行操作。屏幕是“双缓冲区”,实际渲染是在主显示循环底部使用
pygame.display.flip
完成的。
因此,我不确定表面转换在您的程序中的作用是什么。
这是一些示例程序的链接[包括一些精灵]:
http://www.balloonbuilding.com/index.php?chapter=example_code
这只是一个从“pygame sample program”搜索的“all words”的链接之一。因此,上面的链接[以及其他链接]可能会帮助您,如果您能将自己正在做的与它们进行比较。