0

我在搞乱 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

它提高了内存使用率(对于 10000 个具有 200kB 图像的单元,从 430MB 到 160MB。但是,这对于两个图像来说还是相当多的。:)

我的问题:在 Kivy 中是否有更有效的方法来创建包含大量重复图像的 2D 网格?也许我解决这个问题的方法有缺陷——我在创造游戏方面真的没有过期......

4

1 回答 1

1

您看到的内存问题来自您的小部件而不是纹理管理不善,kivy 中的图像纹理使用 kivy 的内部缓存机制进行缓存,因此如果您尝试在一分钟内加载图像 100 次,kivy 只会重新使用缓存中的现有纹理.

但是,此缓存在设定的时间后会超时,并且会在此超时后从磁盘重新加载。由于这个原因,图像小部件有一个reload方法和一个可以设置的nocache属性。您可以手动设置缓存::

from kivy.cache import Cache
Cache._categories['kv.image']['limit'] = 0
Cache._categories['kv.texture']['limit'] = 0 

对于游戏来说,虽然应该总是尝试使用Atlas,但它的缓存不会超时,整个机制旨在让您获得更好的性能和纹理管理。其他优点包括将单个纹理上传到 gpu = 上传时间的巨大改进,从磁盘读取时间大大减少。

无论多么微不足道,每个小部件都有开销,并且在处理同一个小部件的 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 视为物理引擎。

于 2013-10-08T16:25:15.083 回答