Я работаю над 2D-изометрической MORPG на основе плитки на протяжении нескольких месяцев и понял, что мой игровой экран имеет очень низкую частоту кадров. Я занимаюсь исследованиями и тестированием в течение нескольких недель и могу только сделать маргинальную прибыль для своей частоты кадров. Я использовал cProfile и тестировал свою частоту кадров, и я могу добиться 100+ FPS в программе в обычном режиме, но как только моя функция «render()» называется, она падает до 5 FPS. Вот (несколько) сжатая версия этой функции:Нужна консультация по оптимизации рендеринга python 2d для рендеринга
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
относится к карте в этом сегменте кода). Он эффективно проходит через плитки -21 .. 21 по оси x, y и если плитка находится в пределах границ плитки карт (0 .. 128), а плитка находится в пределах размера экрана (1024x600), она рисует ее на экране ,
«ghostCopy» принимает моментальный снимок текущего элемента gamestate
(например, заклинания), чтобы он не обновлялся промежуточной итерацией данных принимающего потоков.
В некоторых тестах оптимизации я уменьшил диапазон y, x в начале, чтобы свести к минимуму количество итераций полного цикла. Я читал, что использование текстурного атласа/спрайта может улучшить скорость рендеринга, но я не смог бы улучшить его.
Я попробовал только вручную рисовать количество изображений, которые обычно отображались бы в общей сцене в цикле for и получались около 30 + fps. Таким образом, моя функция рендеринга на 25 кадров в секунду медленнее, чем могла бы быть.
Я предполагаю, что константа проверяет каждую итерацию цикла на то, можно ли оптимизировать плиту внутри экрана, но я не уверен, как это сделать, не используя такой цикл.
Если у кого есть какие-либо рекомендации, я бы очень признателен .. я торчу на эту проблему в течение нескольких недель и не сделали никакого реального прогресса в моей игре на всех :(
** [EDIT] ** Большинство рекомендаций, по-видимому, направлены на ограничение количества математических выражений. У меня не было возможности проверить это, но возможно ли, что только ограничение количества математики будет значительно оптимизировать частоту кадров?
Это в Python2 или Python3? –
Я использую python3 –
Являются ли объекты (игроки, призраки) каждый целиком в пределах определенной плитки? Чтобы вы могли определить, какая плитка для каждого объекта? –