2013-08-30 57 views
3

在我的遊戲好了,所以基本上,這個世界是做出來的瓷磚和地磚被分割成塊(50 * 50瓷磚和瓷磚是16×16),所以整個世界ISN」 t加載到內存中。這些塊被保存到文件,並只需要加載的人(在屏幕上的人與1關閉,屏幕畫面的每一側(上,左,下,右)),以及其他被卸載等。這一切工作精細然而,當加載實際上包含瓷磚塊遊戲邏輯凍結了相當多的(要知道加載文件?),基本上我的問題是我怎麼會讓我目前的方法更快,所以這是幾乎沒有明顯的滯後?如何加載/卸載瓦塊快(C#)

基本上每個塊只包含字節的2D陣列,含有該瓦片型而不是實際的瓷磚類,而字節數組被保存到稍後被加載的文件。 我的塊加載/保存功能:

節能:

public void SaveChunk(int cx, int cy) 
    { 

     String chunkname = ""; 
     chunkname = WorldChunks[cx, cy].X + "_" + WorldChunks[cx, cy].Y; 

     FileStream fileStream = File.Create(Main.ChunkPath + "\\Chunks\\" + chunkname + ".chnk"); 
     StreamWriter writer = new StreamWriter(fileStream); 
     String json = JsonConvert.SerializeObject(WorldChunks[cx, cy].myTiles, Formatting.None); 
     writer.Write(json); 
     writer.Close(); 
    } 

加載:

public void LoadChunk(int xx, int yy) 
    { 

     string chunkname = xx + "_" + yy; 
     if (File.Exists(Main.ChunkPath + "\\Chunks\\" + chunkname + ".chnk")) 
     { 
      //If the chunk is not loaded, Create a new chunk and begin loading it's tiles. 
      if (WorldChunks[xx, yy] == null) 
      { 
       WorldChunks[xx, yy] = new Chunk(xx, yy); 
      } 

      System.Diagnostics.Debug.WriteLine("Loading chunk [" + xx + "," + yy + "]"); 
      Stream stream = File.Open(Main.ChunkPath + "\\Chunks\\" + chunkname + ".chnk", FileMode.Open); 
      StreamReader reader = new StreamReader(stream); 
      JsonSerializerSettings settings = new JsonSerializerSettings(); 
      settings.TypeNameHandling = TypeNameHandling.Objects; 
      WorldChunks[xx, yy].myTiles = JsonConvert.DeserializeObject<byte[,]>(reader.ReadToEnd(), settings); 
      stream.Close(); 
      System.Diagnostics.Debug.WriteLine("Chunk loaded.. [" + xx + "," + yy + "]"); 
      int x, y; 
      for (x = 0; x < Main.ChunkSizeX; x++) 
      { 
       for (y = 0; y < Main.ChunkSizeY; y++) 
       { 
        byte _Type = WorldChunks[xx, yy].myTiles[x, y]; 
        int tx = (xx * ChunkSizeX) + x; 
        int ty = (yy * ChunkSizeY) + y; 
        if (_Type > 0) 
        { 
         if (Tiles[tx, ty] == null && tx < MaxTilesX && ty < MaxTilesY) 
         { 
          Tiles[x + (xx * ChunkSizeX), (yy * ChunkSizeY) + y] = new Tile(); 
          Tiles[(xx * ChunkSizeX) + x, (yy * ChunkSizeY) + y].Type = _Type; 
          if (ty > GROUND_LEVEL[tx] + 1) 
          { 
           //System.Diagnostics.Debug.Write("Below level:" + x + "|" + tx); 
           Tiles[tx, ty].HasBG = true; 
          } 

         } 
         else continue; 
        } 

       } 
      } 

     } 

    } 

我試圖改變周圍的CHUNKSIZE,我試過25×16×35x35等等等等..但仍然無濟於事。 那麼我怎樣才能使這些功能更快?任何其他提示/建議將非常感謝!謝謝!

編輯:從我的代碼去秒錶和其他測試的瓶頸是從文件實際加載我甚至取消了瓷磚的擺放,它仍然鎖定了遊戲邏輯,但是我意識到最大的明顯延遲是當我之間的塊和它必須加載更多的塊比平常像這樣: Picturing showing when my game logic takes the biggest hit http://img854.imageshack.us/img854/8031/wcs2.png

現在我可能是塊實際上比那大,但同樣的事情是可能的。

我的保存功能簡單地保存每個瓷磚1個字節,我的文件大小每塊只有2.5kb左右,因爲每個瓷塊有2,500個瓷磚,每個瓷磚1個字節(只保存瓷磚類型)。

所以我沒想到的保存和加載它們將是多大的影響,我有一個異步FILESTREAM以及更早的設置,但表現得幾乎相同。

這裏是我的加載/卸載大塊代碼:

public void CheckChunks() 
    { 
     int StartX = (int)Math.Floor(ScreenPosition.X/(ChunkSizeX * 16)) - 2; 
     int StartY = (int)Math.Floor(ScreenPosition.Y/(ChunkSizeY * 16)) - 2; 

     if (StartX < 0) StartX = 0; 
     if (StartY < 0) StartY = 0; 

     int EndX = (int)Math.Floor((ScreenPosition.X + GraphicsDevice.Viewport.Width)/(ChunkSizeX * 16)) + 2; 
     int EndY = (int)Math.Floor((ScreenPosition.Y + GraphicsDevice.Viewport.Height)/(ChunkSizeY * 16)) + 2; 
     if (EndX > MaxChunksX) EndX = MaxChunksX; 
     if (EndY > MaxChunksY) EndY = MaxChunksY; 

     for (int x = StartX; x < EndX; x++) 
     { 
      for (int y = StartY; y < EndY; y++) 
      { 
       if (WorldChunks[x, y] == null) 
       { 

        LoadChunk(x, y, true); 

        if (WorldChunks[x, y] != null) 
        { 

         LoadedChunks.Add(WorldChunks[x, y]); 
        } 
        break; 
       } 

      } 
     } 

      foreach (Chunk cc in LoadedChunks) 
      { 

       if (cc.X < StartX || cc.Y < StartY || cc.X >EndX || cc.Y > EndY) 
       { 
        System.Diagnostics.Debug.WriteLine("Chunk to be unloaded.."); 
        ChunkBuffer.Add(cc); 
        UnloadChunk(cc); 

       } 
      } 

      foreach (Chunk c in ChunkBuffer) 
      { 
       LoadedChunks.Remove(c); 
      } 
     ChunkBuffer.Clear(); 

    } 

如何遊戲一樣的Minecraft負荷等方面迅速卸下自己的塊?

+0

爲了加快速度,您需要知道代碼中的速度緩慢。配置文件(或至少用'秒錶'測量時間)並從那裏開始。 –

+0

謝謝你,但我忘了提及我已經使用秒錶,甚至刪除了部件,以查看瓶頸在哪裏。它是從文件實際加載的,但我不確定它是否與反序列化或從文件中讀取(很可能是閱讀)。我會做進一步的測試,看看它究竟在哪裏。 – Brassx

+0

我也在製作類似的遊戲。我可以問一下你的「世界塊」是什麼,我正在猜測一堂課?另外,你如何跟蹤哪些塊被加載/卸載?我爲此使用了一個List,但我正在尋找其他人從事類似工作的看法,以瞭解他們是如何做到的。謝謝! – user9993

回答

2

磁盤操作通常會過於沉重而不明顯影響幀率一個遊戲框架內執行。您的磁盤操作可以在單獨的線程中運行。在加載過程中,您需要確保內存已被適當鎖定。如果玩家碰巧在下一個塊完成加載之前到達塊的邊緣,則這仍然可能導致可見的延遲。如果玩家在大塊的底部角落,然後同時向下和向下移動到卸載的對角塊中,該怎麼辦?這可以通過加載4個相鄰的塊以及4個對角塊來解決,並且確保塊大到足以使得玩家不會很快到達邊緣。如果您不熟悉多線程,則需要進行一些研究。

http://www.yoda.arachsys.com/csharp/threads/

另一種可能的方法是你的遊戲世界分割成多個地圖和加載一個整體映射到內存中,而不是更小的塊。這需要花費更長時間才能加載,但只需要在玩家在地圖之間移動時執行,因此通常對玩家體驗影響較小。如有必要,可以在這裏使用加載屏幕。

+0

感謝您的回覆!我一定會考慮多線程!我之前已經爲這些塊設置了異步加載,但是在使用它時沒有提及性能提升,也許我做錯了?但是,任何想法像Minecraft這樣的遊戲如何在沒有遊戲邏輯的重大中斷的情況下如此順利地加載它們的塊(我假設它使用Async在不同的線程上運行加載函數?) – Brassx

+0

很難說,但我的猜測是資源被主線程鎖定了。當前塊的內存是否與相鄰塊分開? – rdans

+0

文件總數有多大?如果它只是一個二維數組ID,可以加載整個文件嗎? – rdans

1

LoadChunk只做兩件事情,磁盤IO和反序列化。你可以嘗試獨立加速。根據您加載的數據量,只需添加BufferedStream即可。完全不同的選擇是使用異步I/O。處理起來有點難,但它不會阻塞你的UI線程,你會得到一些簡單的並行性。

我不希望JSON反序列化是最快的,您應該將它的性能與您自己的反序列化例程進行比較。

16 x 16的瓷磚看起來很小,有沒有理由不讓它們變大? Tile越大,調用LoadChunk的次數越少。一旦你儘可能地加快了加載速度,你將會有一個好主意,何時加載下一個離屏平鋪。例如。如果需要3個「蜱蟲」來加載瓦片,當玩家在邊緣的3個方格內時,應該加載它。

SaveChunk可以移動到ThreadPool線程或重寫爲使用異步IO。