gpt4 book ai didi

python - Pyglet图像渲染

转载 作者:行者123 更新时间:2023-12-04 19:02:21 26 4
gpt4 key购买 nike

我正在为我的第一个深度Pyglet项目开发2D Minecraft克隆,但遇到了一个问题。每当我在屏幕上有相当数量的块时,帧速率都会急剧下降。

这是我的渲染方法:
我使用字典,键是元组(代表块的坐标),项是纹理。

我遍历整个字典并渲染每个块:

for key in self.blocks:
self.blocks[key].blit(key[0] * 40 + sx,key[1] * 40+ sy)


附言sx和sy是屏幕滚动的坐标偏移

我想知道是否有一种方法可以更有效地渲染每个块。

最佳答案

我将尽力解释为什么以及如何在不真正了解代码外观的情况下优化代码。

我将假设您具有以下特点:

self.blocks['monster001'] = pyglet.image.load('./roar.png')


如果您想加载静态图像,而又不想做太多事情,那么这一切都很好。但是,您正在制作游戏,并且将要使用比一个简单的图像文件更多的精灵和对象。

现在,在这里共享对象,批处理和精灵就派上用场了。
首先,将您的图像输入精灵,这是一个很好的开始。

sprite = pyglet.sprite.Sprite(pyglet.image.load('./roar.png'))
sprite.draw() # This is instead of blit. Position is done via sprite.x = ...


现在,由于许多原因,draw比 .blit()快得多,但是我们暂时跳过为什么,只坚持极速的升级。

再次,这只是迈向成功帧率的一小步(除了硬件有限。)。

无论如何,回到pew升级您的代码。
现在,您还想将精灵添加到批处理中,这样就可以一次性一次性渲染很多东西(读取:批处理),而不是手动将东西推到图形卡上。图形卡的主要目的是能够一次疯狂地处理计算中的千兆吞吐量,而不是处理多个小型I / O。

为此,您需要创建一个批处理容器。并添加“图层”。
确实很简单,您需要做的只是:

main_batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
# stuff_above_background = pyglet.graphics.OrderedGroup(1)
# ...


现在,我们将批量处理一个,您可能不需要更多的资源来实现此学习目的。
好,那么您就批了,现在呢?好吧,现在我们尽最大努力从您的图形卡中解脱掉那个生活的地狱,看看我们是否甚至可以在压力下将其弯折(在此过程中,没有图形车受到伤害,请不要使事物窒息。)

哦,还有一件事,还记得有关共享库的注释吗?好吧,我们将在此处创建一个共享图像对象,然后将其推入精灵,而不是每次都加载一个新图像。

monster_image = pyglet.image.load('./roar.png')
for i in range(100): # We'll create 100 test monsters
self.blocks['monster'+str(i)] = pyglet.sprite.Sprite(imgage=monster_image, x=0, y=0, batch=main_batch, group=background)


现在,您已经创建了 monster_image个怪物,并将它们添加到了批次 100的子组 main_batch中。简单如馅饼。

这是踢球者,我们现在可以调用 background而不是调用 self.blocks[key].blit().draw(),它将把每个怪兽发射到图形卡上并产生奇迹。

好的,所以现在您已经优化了代码的速度,但是,从长远来看,如果您要制作游戏,那实际上对您没有帮助。或者在这种情况下,为您的游戏提供图形引擎。您要做的就是加入大联盟并使用课程。如果您对之前的使用感到惊讶,那么在完成之后,您可能会松懈一下自己的代码。

好的,首先,您要为屏幕上的对象创建一个基类,在 main_batch.draw()中进行调用。
现在,您需要使用Pyglet解决一些问题,例如,当继承 baseSprite对象尝试设置 Sprite时,使用这些东西时会引起各种各样的故障和错误,因此我们将设置 直接,这基本上是相同的,但是我们将其挂接到pyglet库变量中; D pew pew hehe。

class baseSprite(pyglet.sprite.Sprite):
def __init__(self, texture, x, y, batch, subgroup):
self.texture = texture

super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
self.x = x
self.y = y

def move(self, x, y):
""" This function is just to show you
how you could improve your base class
even further """
self.x += x
self.y += y

def _draw(self):
"""
Normally we call _draw() instead of .draw() on sprites
because _draw() will contains so much more than simply
drawing the object, it might check for interactions or
update inline data (and most likely positioning objects).
"""
self.draw()


现在这是您的基础,您现在可以通过执行以下操作来创建怪物:

main_batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
monster_image = pyglet.image.load('./roar.png')
self.blocks['monster001'] = baseSprite(monster_image, 10, 50, main_batch, background)
self.blocks['monster002'] = baseSprite(monster_image, 70, 20, main_batch, background)

...
main_batch.draw()


如何,您可能会使用其他所有人都在使用的默认 image示例,这很好,但是从长远来看,我发现它很慢,很丑,而且不切实际。您想进行面向对象的编程吗?
这就是所谓的,我将其称为您喜欢整天观看的可读代码。 RCTYLTWADL的简称。

为此,我们需要创建一个模仿pyglet行为的 self.texture,并依次调用它的后续函数并轮询事件处理程序,否则sh **会卡住,请相信我。和瓶颈很容易创建。
但是我有很多错误,这里可以使用一个基本的 @on_window_draw()类,该类使用基于轮询的事件处理,从而将刷新率限制在您的编程中,而不是在Pyglet中内置行为。

class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(800, 800, fullscreen = False)
self.x, self.y = 0, 0
self.sprites = {}
self.batches = {}
self.subgroups = {}

self.alive = 1

def on_draw(self):
self.render()

def on_close(self):
self.alive = 0

def render(self):
self.clear()

for batch_name, batch in self.batches.items():
batch.draw()

for sprite_name, sprite in self.sprites.items():
sprite._draw()

self.flip() # This updates the screen, very much important.

def run(self):
while self.alive == 1:
self.render()

# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze.
# Basically it flushes the event pool that otherwise
# fill up and block the buffers and hangs stuff.
event = self.dispatch_events()

x = main()
x.run()


现在,这再次只是一个基本的 class类,除了渲染黑色背景以及放置在 mainmain中的所有内容外,什么也不做。

注意!我们在Sprite上调用 self.sprites是因为我们之前创建了自己的Sprite类?是的,这是很棒的基本Sprite类,您可以在每个单独的Sprite上完成 self.batches之前,将自己挂接到自己的东西中。

任何人,这都归结为两件事。


制作游戏时使用精灵,您的生活会更轻松
使用批处理,您的GPU将爱您,刷新率将惊人
使用类和东西,您的眼睛和代码mojo最终将爱您。


这是所有困惑在一起的完整示例:


import pyglet
from pyglet.gl import *

glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_LINE_SMOOTH)
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE)

pyglet.clock.set_fps_limit(60)

class baseSprite(pyglet.sprite.Sprite):
def __init__(self, texture, x, y, batch, subgroup):
self.texture = texture

super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
self.x = x
self.y = y

def move(self, x, y):
""" This function is just to show you
how you could improve your base class
even further """
self.x += x
self.y += y

def _draw(self):
"""
Normally we call _draw() instead of .draw() on sprites
because _draw() will contains so much more than simply
drawing the object, it might check for interactions or
update inline data (and most likely positioning objects).
"""
self.draw()

class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(800, 800, fullscreen = False)
self.x, self.y = 0, 0
self.sprites = {}
self.batches = {}
self.subgroups = {}

self._handles = {}

self.batches['main'] = pyglet.graphics.Batch()
self.subgroups['base'] = pyglet.graphics.OrderedGroup(0)

monster_image = pyglet.image.load('./roar.png')
for i in range(100):
self._handles['monster'+str(i)] = baseSprite(monster_image, randint(0, 50), randint(0, 50), self.batches['main'], self.subgroups['base'])

# Note: We put the sprites in `_handles` because they will be rendered via
# the `self.batches['main']` batch, and placing them in `self.sprites` will render
# them twice. But we need to keep the handle so we can use `.move` and stuff
# on the items later on in the game making process ;)

self.alive = 1

def on_draw(self):
self.render()

def on_close(self):
self.alive = 0

def render(self):
self.clear()

for batch_name, batch in self.batches.items():
batch.draw()

for sprite_name, sprite in self.sprites.items():
sprite._draw()

self.flip() # This updates the screen, very much important.

def run(self):
while self.alive == 1:
self.render()

# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze.
# Basically it flushes the event pool that otherwise
# fill up and block the buffers and hangs stuff.
event = self.dispatch_events()

# Fun fact:
# If you want to limit your FPS, this is where you do it
# For a good example check out this SO link:
# http://stackoverflow.com/questions/16548833/pyglet-not-running-properly-on-amd-hd4250/16548990#16548990

x = main()
x.run()




一些奖励内容,我添加了GL选项,这些选项通常为您提供一些有益的内容。
我还添加了一个FPS限制器,您可以修改并使用它。

编辑:

批量更新

由于可以通过将精灵对象全部发送到图形卡来一次完成大量渲染,因此类似地,您希望进行批量更新。
例如,如果您想更新每个对象的位置,颜色或任何可能的颜色。

这是聪明的编程发挥作用的地方,而不是漂亮的小工具。
看,我在编程中所涉及的一切。如果你想要的话。

假设您(在代码的顶部)有一个名为:

global_settings = {'player position' : (50, 50)}
# The player is at X cord 50 and Y cord 50.


在基本精灵中,您可以简单地执行以下操作:

class baseSprite(pyglet.sprite.Sprite):
def __init__(self, texture, x, y, batch, subgroup):
self.texture = texture

super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
self.x = x + global_settings['player position'][0]#X
self.y = y + global_settings['player position'][1]#Y


请注意,您必须微调 ._draw()(注意,不是 draw(),因为批处理渲染将调用 draw()而不是 _draw())功能来遵循和更新每个渲染序列的位置更新。那或者您可以创建一个继承 draw的新类,并且只更新那些类型的sprite:

class monster(baseSprite):
def __init__(self, monster_image, main_batch, background):
super(monster, self).__init__(imgage=monster_image, x=0, y=0, batch=main_batch, group=background)
def update(self):
self.x = x + global_settings['player position'][0]#X
self.y = y + global_settings['player position'][1]#Y


因此,仅在 _draw类型的类/子画面上调用 baseSprite
要使其达到最佳状态有些棘手,并且有一些方法可以解决它并仍然使用批处理渲染,但是遵循这些思路的某个地方可能是一个好的开始。



重要说明:我只是从脑子里写了很多(不是我第一次用Pyglet编写GUI类),无论出于何种原因,我的* Nix实例都找不到我的X服务器。因此无法测试代码。

下班后的一个小时内,我会对其进行测试,但这可以使您大致了解在Pyglet中制作游戏时该做什么和该怎么想。记住,在玩的时候玩得开心,或者在开始之前就退出了,因为游戏需要时间才能制作^^

皮尤拉子剃须刀和东西,祝你好运!

关于python - Pyglet图像渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34846635/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com