【发布时间】:2016-12-30 23:19:14
【问题描述】:
几个月来,我一直在研究基于 2D 等距图块的 MORPG,并意识到我的游戏屏幕渲染的帧速率非常低。 我已经研究和测试了几个星期,并且只能对我的帧速率进行边际提升。我使用了 cProfile 并测试了我的帧速率,我可以在程序上正常达到 100+ FPS,但是一旦我的“render()”函数被调用,它就会下降到 5 FPS。 这是该函数的(有点)精简版:
for y in range(0, 42):
for x in range(0, 42):
if (player.mapY + y - 21 > 0) and (player.mapY + y - 21 < 128) and (player.mapX + x - 21 > 0) and (
player.mapX + x - 21 < 128):
if (startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX) > -64 and (startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX)+halfGraphicSizeX < 1024+32 and\
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY) > -32 and (startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY)+halfGraphicSizeY < 600+32:
if self.getGroundAtYX(player.mapY + (y - 21), player.mapX + (x - 21)) is not 0:
canvas.create_image((startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY),
image=groundGraphics[
self.getGroundAtYX(player.mapY + (y - 21), player.mapX + (x - 21))],
anchor=NW)
if (self.getObjectAtYX(player.mapY + (y - 21), player.mapX + (x - 21)) is not 0):
canvas.create_image((startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 34),
# -34 for img height diff between ground & objects
image=objectGraphics[
self.getObjectAtYX(player.mapY + (y - 21), player.mapX + (x - 21))],
anchor=NW)
ghostCopy = list(gameState.itemsOnGround)
for i in range(0, len(ghostCopy)):
if ghostCopy[i].idNum > 0:
if (player.mapX - 21 + x == ghostCopy[i].mapX and player.mapY - 21 + y ==
ghostCopy[i].mapY):
canvas.create_image((startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY),
image=itemGraphics[ghostCopy[i].idNum],
anchor=NW)
ghostCopy = ""
ghostCopy = list(gameState.monster)
for i in range(0, len(ghostCopy)):
if ghostCopy[i].active == True and ghostCopy[i].hp > 0:
if (player.mapX - 21 + x == ghostCopy[i].mapX and player.mapY - 21 + y ==
ghostCopy[i].mapY):
canvas.create_image((startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 34),
# -34 for img height diff between ground & objects
image=monsterGraphics[ghostCopy[i].type],
anchor=NW)
canvas.create_rectangle(
(startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX) + 15,
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 35),
(startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX) + 16 + 33,
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 29), fill="black",
width=0)
canvas.create_rectangle(
(startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX) + 16,
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 30),
(startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX) + 16 + (
32 * (ghostCopy[i].hp / ghostCopy[i].maxHp)),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 34), fill="green",
width=0)
ghostCopy = ""
ghostCopy = list(gameState.sprite)
for i in range(0, len(ghostCopy)):
if ghostCopy[i].graphic[0:1] == "0":
if ghostCopy[i].active == True and ghostCopy[i].username != "ME":
if (player.mapX - 21 + x == ghostCopy[i].mapX and player.mapY - 21 + y ==
ghostCopy[i].mapY):
#"graphicToDraw" variable is derived from an animation state but has
#been removed from here to make it easier to read
canvas.create_image((startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 34),
# -34 for img height diff between ground & objects
image=graphicToDraw,
anchor=NW)
if (y == 21):
if (x == 21):
#"graphicToDraw" variable is derived from an animation state but has
#been removed from here to make it easier to read
canvas.create_image(
(startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 34),
# -34 for img height diff between ground & sprites
image=graphicToDraw,
anchor=NW)
ghostCopy = ""
ghostCopy = list(gameState.spells)
for i in range(0, len(ghostCopy)):
if ghostCopy[i].active:
if (player.mapX - 21 + x == ghostCopy[i].mapX and player.mapY - 21 + y ==
ghostCopy[i].mapY):
canvas.create_image((startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX),
(startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY - 34),
image=spellGraphics[ghostCopy[i].id],
anchor=NW)
render() 函数属于map 对象(self 指的是此代码段中的映射)。它有效地通过 x,y 轴上的图块 -21 .. 21,如果图块在地图图块边界 (0 .. 128) 内并且图块在屏幕尺寸 (1024x600) 之内,它会将其绘制到屏幕上.
“ghostCopy”对当前的gamestate 元素(例如拼写)进行快照,这样它就不会被接收服务器数据的线程在迭代过程中更新。
在我做的一些优化测试中,我在开始时减小了 y、x 范围,以最大限度地减少总循环迭代的数量。 我读到使用纹理图集/精灵表可以提高渲染速度,但我无法使用它来改进。
我尝试在 for 循环中手动绘制通常会在一般场景中渲染的图像数量,并获得大约 30+ fps 的速度。所以我的渲染功能比它可能慢了 25 fps。
我假设常量会检查每个循环迭代,以确定图块是否在屏幕内可以优化,但我不确定如何在不使用这样的循环的情况下做到这一点。
如果有人有任何建议,我将不胜感激。我已经被这个问题困扰了好几个星期,而且我的游戏根本没有取得任何真正的进展:(
** [编辑] ** 大多数建议似乎都是为了限制数学表达式的数量。我没有机会对此进行测试,但它是否可能只是限制数学量会显着优化帧速率?
【问题讨论】:
-
这是在 Python2 还是 Python3 中?
-
我正在使用 python3
-
对象(玩家、幽灵)是否都完全在一个特定的图块中?这样您就可以确定每个对象的图块是什么?
-
是的,但是服务器会在每次游戏状态更新时确定玩家可见的内容,以尽量减少发送的数量
标签: python loops optimization render tile