我已经在基于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)内,则将其绘制到屏幕上
&#34; ghostCopy&#34;获取当前gamestate
元素(例如法术)的快照,以便线程接收服务器数据在迭代过程中不会更新。
在一些优化测试中,我在开始时减少了y,x范围,以最小化总循环迭代量。 我读到使用纹理图集/ spritesheet可以提高渲染速度,但我无法使用它进行改进。
我尝试手动绘制通常在for循环中的常规场景中渲染的图像数量,并获得大约30+ fps。所以我的渲染函数比它可能慢25 fps。
我假设常量检查每个循环迭代以确定是否在屏幕内是否可以优化,但我不确定如何在不使用这样的循环的情况下这样做。
如果有人有任何建议我会非常感激..我已经坚持这个问题好几个星期了,并且我的游戏根本没有取得任何真正的进展:(
** [编辑] ** 大多数建议似乎都是为了限制数学表达式的数量。我还没有机会对此进行测试,但可能只是限制数学量会大大优化帧率吗?
答案 0 :(得分:0)
您可以在外部(y
)循环内部计算所有涉及常量和for y
的表达式;例如,player.mapY + y - 21
,y * halfGraphicSizeX
,y * halfGraphicSizeY
等:计算机每次只需一次,插入变量,并在整个代码中使用。同样适用于x
,但不太有效。
答案 1 :(得分:0)
以下是应该改善性能的前19行代码的更新。在这个例子中,我所做的就是减少你执行数学运算的总次数。
for y in range(0, 42):
for x in range(0, 42):
player_y = player.mapY + y - 21
player_x = player.mapX + x -21
if player_y > 0 and player_y < 128 and player_x > 0 and player_x < 128:
start_drawing_x_half_graphic_size = startDrawingPosX + x * halfGraphicSizeX - y * halfGraphicSizeX
start_drawing_y_half_graphic_size = startDrawingPosY + x * halfGraphicSizeY + y * halfGraphicSizeY
if start_drawing_x_half_graphic_size > -64 and start_drawing_x_half_graphic_size + halfGraphicSizeX < 1024+32 and\
start_drawing_y_half_graphic_size > -32 and start_drawing_y_half_graphic_size + halfGraphicSizeY < 600+32:
if self.getGroundAtYX(player.mapY + (y - 21), player.mapX + (x - 21)) is not 0:
canvas.create_image(start_drawing_x_half_graphic_size,
start_drawing_y_half_graphic_size,
image=groundGraphics[
self.getGroundAtYX(player.mapY + (y - 21), player.mapX + (x - 21))],
anchor=NW)