快速设置像素
我一直在寻找一个好的答案,快要因为沮丧而哭出来了。我是个业余程序员,做事情不是因为它们有道理或者是正确的做法,而是为了学习怎么做,现在我遇到了瓶颈。
我想在屏幕上设置单独的像素。这听起来很简单,但我的其他条件让事情变得复杂。我需要快速完成,使用CPU,达到每秒20帧或更高(当然还有其他程序元素在运行),在一个400乘300的屏幕上(或者全屏?)。
我用Python写了一些程序,使用Pygame渲染了一些很酷的图像,但填充一个100像素乘100像素的屏幕仅仅用随机像素就需要50毫秒(这就占用了我的20帧,其他程序部分让它变得更慢)。理想情况下,我非常想做一个(糟糕的)3D游戏,只用CPU,设置屏幕上的像素(也许是那种体素八叉树的图形)。
有没有办法(用任何语言,但最好是Python)让我在内存中创建一个像素值的二维数组(更像是一个包含RGB的三维数组)(这叫位图吗?),然后把它显示出来?这样不是会很快吗???怎么才能直接与窗口上的像素交互呢。啊!我真是一头雾水。我是/不是编程新手。给我任何你能想到的建议,我都能消化。我只需要一些正确方向的指引(哈哈)。
5 个回答
如果你想在PyGame中处理图像,最好的方法是使用pygame.surfarray或者pygame.pixelarray。你可以先在数组中设置好所有的值,然后一次性把它们复制过去。如果你查看一下surface.set_at(...)的文档,这个方法是用来单独设置每个像素的,你会发现它只适合处理非常小的任务,不推荐用在大多数情况下。
pygame.surfarray和pygame.pixelarray通常是基于NumPy或Numeric(建议使用NumPy)。你可以在网上搜索一下,找到这个链接 http://pygame.org/docs/tut/surfarray/SurfarrayIntro.html,它会给你一个关于你可以做的一些很酷的事情的基本介绍。
我在使用pygame时,能够在分辨率为(1920,1080)的情况下达到超过20帧每秒的速度。
正如Mallett所提到的,你应该使用pygame.surfarray.blit_array()这个函数来把像素数据复制到pygame中,然后通过调用pygame.display.flip()来更新屏幕。
>>> import timeit
>>> timeit.timeit('pygame.surfarray.blit_array(screen, pixels);pygame.display.flip()', setup='import pygame;import numpy as np;size=(1920,1080);screen=pygame.display.set_mode(size);pixels=np.random.randint(np.iinfo(np.uint32).max,size=size).astype(np.uint32)', number=20)
0.6346819400787354
>>> timeit.timeit("""
... pygame.surfarray.blit_array(screen, pixels)
... pygame.display.flip()
... """,setup="""
... import pygame
... import numpy as np
... size=(1920,1080)
... screen=pygame.display.set_mode(size)
... pixels=np.random.randint(np.iinfo(np.uint32).max,size=size).astype(np.uint32)
... """, number=20)
0.4848361015319824
如果你想自己做一些“逐个像素”的数学运算(而不是仅仅移动圆圈和位图),那么你需要用C(或者C++)来实现,这样才能接近机器的运行速度。
不过,如果你想做一个完整的游戏,全部用像C这样的底层语言来写会很麻烦。你需要把快速的C代码和一些高级脚本语言结合起来。比如,你可以通过numpy把Python和C扩展模块连接起来,或者把像Lua这样的语言嵌入到C代码中,或者(天哪)尝试学习C++中的高级编程。不管怎样,事情都会变得复杂。
如果你只是想玩玩快速的像素渲染,我建议你使用SDL(pygame内部就是用这个),但只限于C或C++。可以跟着像这样的教程来玩玩。
如果你想在Python的舒适环境中待着,我建议你先尝试做一个2D游戏(加载和移动位图),或者试试cairo(渲染几何图形)。