我正在搞乱Kivy,试图通过某种2D网格来获得一些类似应用的游戏。在我的设计中,每个单元格网格都应该有自己的图形表示,具体取决于内部的内容。 下面是我目前的简单代码,它只创建网格并在每个单元格中插入一些图像。
class MyWidget(Widget):
def __init__(self,images,*args, **kwargs):
super(MyWidget, self).__init__(*args, **kwargs)
self.images = []
for img in images:
self.add_image(img)
self.bind(pos=self.callback,size=self.callback)
def add_image(self,image):
self.images.append(Image(source=image,allow_stretch = True,keep_ratio = False))
self.add_widget(self.images[-1])
def callback(self,instance,value):
for image in instance.images:
image.pos = instance.pos
image.size = instance.size
class StartScreen(Screen):
def __init__(self,**kwargs):
super(StartScreen, self).__init__(**kwargs)
i = 10
self.layout = GridLayout(cols=i)
self.add_widget(self.layout)
for i in range(i*i):
self.layout.add_widget(MyWidget(['./images/grass.png','./images/bug1.png']))
class TestApp(App):
def build(self):
return StartScreen()
问题在于,虽然所有图像都是相同的,但是根据我所看到的,每个单元格都会再次加载到内存中。效率不高,特别是当有10000个左右的细胞时。 我试图将相同的图像添加到每个单元格,但事实证明每个窗口小部件只能有一个父窗口。 我也尝试初始化一个已经初始化的纹理的新图像,但是没有改进。 我试图获得加载图像的纹理,然后用它作为纹理创建矩形。像这样:
def add_image(self,texture):
with self.canvas:
rect = Rectangle(texture=texture,pos=self.pos, size=self.size)
self.rects.append(rect)
纹理是:
Image(source='./images/grass.png',allow_stretch = True,keep_ratio = False).texture
它提高了内存使用率(对于具有200kB图像的10000个单元格,从430MB到160MB。但是,对于两个图像来说,这仍然很多。)
我的问题:在Kivy中,是否有更有效的方法来创建具有大量重复图像的2D网格? 也许我对这个问题的处理方式存在缺陷 - 我在制作游戏方面确实没有过期......
答案 0 :(得分:1)
你看到的内存问题来自你的小部件而不是纹理管理不当,kivy中的图像纹理使用kivy的内部cache机制进行缓存,所以如果你尝试在一分钟内加载图像100次,那么kivy就会重新 - 使用缓存中的现有纹理。
此缓存在设置的时间后会超时,并且会在此超时后从磁盘重新加载。出于这个原因,Image小部件有一个reload方法和一个可以设置的nocache属性。您可以手动设置缓存::
from kivy.cache import Cache
Cache._categories['kv.image']['limit'] = 0
Cache._categories['kv.texture']['limit'] = 0
对于游戏,虽然应该总是尝试使用Atlas,但它的缓存不会超时,整个机制的目的是让您获得更好的性能和纹理管理。其他优点包括上传到gpu的单个纹理=上传时间的巨大改进,从磁盘时间读取的数量大大减少。
每个小部件,无论多么微不足道的开销,以及处理相同Widget的10,000多次迭代。您一定会遇到内存使用问题。小部件不适合这种用法。你应该看看使用重复纹理, 操纵纹理坐标,直接绘制到画布上而不使用小部件。像(未经测试的)::
texture = Image('grid.jpg').texture
texture.wrap = 'repeat'
texture.uvsize = (20, 20)
with self.canvas:
Color(1, 1, 1)
Rectangle(pos=(0, 0), size=(2000, 2000), texture=texture)
如果您对编写游戏感兴趣,可能需要将KivEnt和cymunk视为物理引擎。