2016-12-30 38 views
0

我已經在基於2D等距tile的MORPG上工作了幾個月,並意識到我的遊戲屏幕渲染速度非常低。 我一直在研究和測試幾個星期,現在只能使邊際收益,我的幀速率。我已經使用cProfile並測試了幀速率,通常我可以在程序上實現100 + FPS,但是一旦我的「render()」函數被調用,它就會降低到5 FPS。 下面是函數的(有點)濃縮版本:需要關於優化python 2d tileset渲染的建議

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範圍,以儘量減少總循環迭代次數。 我讀過使用紋理圖集/ spritesheet可以提高渲染速度,但我無法使用一個改進。

我試着手動繪製一般情況下在for循環中渲染的圖像數量,並獲得大約30+ fps。所以我的渲染功能比它的速度慢25 fps。

我假設常量檢查每個循環迭代是否在屏幕內可以優化,但我真的不知道如何做到這一點,而不使用像這樣的循環。

如果任何人有我將不勝感激的任何建議..我一直停留在這個問題上星期,還未與我的比賽在所有:(

** [編輯]任何實際進展** 大多數建議似乎是要限制數學表達式的數量,我還沒有機會測試這個,但它可能只是限制了數學的數量會大大優化幀率嗎?

+0

這是在Python2還是Python3? –

+0

我正在使用python3 –

+0

對象(玩家,鬼魂)是否完全在特定的瓷磚中?這樣你可以確定每個對象的瓦片是什麼? –

回答

0

你可以拉所有涉及常數和y的表達式僅在外部(for y)循環內計算;例如,player.mapY + y - 21,y * halfGraphicSizeX,y * halfGraphicSizeY等:計算機每個只是一次,塞進一個變量,並在整個代碼中使用。同樣爲x,但效果不甚理想。

+0

在此代碼中獲得如此多的數學成果。 –

+0

使用Emett的優化建議,並刪除所有涉及'y'的數學到'y'循環的上限已經產生了一些幀速率增益(0。5 fps,用於將'y'表達式移動到上部用於循環) –

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) 
+0

我測試了這一點,並在對象密集的場景中將幀速率從5 fps提高到6 fps,並且在場景很少的情況下,幀速率從15 fps提高到17 20 FPS。 感謝您的推薦優化,我不認爲數學會導致這樣的放緩! –

+0

爲了提高代碼速度,還有很多可以做的事情。這只是第一個合理的開始。 –