Terraria Like 類型的 TileMap 存取思路

問題總結一句話:在遊戲中修改了 TileMap 之後該如何儲存?

思路上是把 Gid 陣列 parseJson 後存進 localStorage,下次載入之後一個個比對預設 TileMap,不一樣就 setTileGIDAt,但想想這方法有些笨,有更高效的解法嗎?

實行的前提是在極大的地圖(例如 2048*2048)下兼顧效能,盡可能不要在進遊戲之後重繪整張地圖,我之前的嘗試實驗過程是這樣的:

在 2.4.8 中讀取 Json 用 Sprite 一塊塊拚地圖,效能有夠差……

在 3.4.1 中讀取 Json 嘗試用多邊形遮罩來合併連接的每個 Tile,結果被 3.x 的各種 BUG 氣到去載 Unity

讀了 Unity 的文檔之後發現 Unity 和 2.4 一樣不支援多邊形遮罩。

回到 2.4.8(真香)覺得還是 tileMap 直接拉進遊戲裡效率最高,讀取也快,但如果像 Terraria 或 Oxygen not included 玩家在遊戲中大範圍修改了地圖,該如何儲存呢?我上面的思路正確嗎?

其实这个问题可以考虑mc的地图构成,mc地图分区块,16x16x高度为一个区块。但是tr是2d的,就是宽高。这个你可以自己定义。用 cc.sys.localStorage完全没问题。c++底层是对sqlite3操作。

你要做的就是把地图切分成很多小块,根据玩家坐标去获取周围的地图数据,不要一次性获取2048x2048的数据,获取玩家坐标附近的。然后再根据数据去动态生成地图。不然你一次性把整个地图生成出来肯定不行的,注意精灵合批渲染。

1赞

先感謝幫忙驗證思路,這邊就想提一個實驗結果:

Chunk 我其實一開始就有做,但在繪圖方面,我發現拖整個 tmx 進編輯器效率更高,開遊戲加載完畢(2048*2048)之後完全不卡頓,比較起來自己寫分段渲染比較卡……大概是 tmx 在底層是被當作一張紋理載入的?

不過 tmx 雖然渲高效,碰撞箱就得自己加了,所以 Chunk 的概念還是有用在動態增刪碰撞箱上。

也因為如此才有了最初的問題,拖入高效就該拖入,但玩家修改了地圖後還是得在 tmx 加載完畢之後做修改,慢慢去比對哪邊被修改過感覺有些蠢,才上來問這個問題的,但看來是得去比對沒跑了 Orz

我有一个需要保存建筑进度到后端的开源项目,有兴趣的话可以看看,做的方法不会只有一种的

1赞

感謝,檔案已經先下載了,等到實際進行到存檔這塊的時候一定會參考看看的!

TiledMap 渲染高效是因为所有的贴图都是一张很大的贴图,并且只会产生少量的节点,大概3-5个,跟你图层有关,但是后面每次更改不同坐标的方块就会多加一个节点。
如果自己动态生成,那么1个方块就得占用1个节点,所以初次生成地图会产生大量的节点,渲染倒不用担心,如果你把所有的方块贴图放在一个图集里面,渲染完全没有问题。问题会出在第一次生成节点的时候。

其实这个时候,方案还是我上面说的那种。以区块的形式动态生成。但是是以一个区块,一张大贴图的方式。具体实现方式可以参考

虽然这个问题探讨的字体,其实大同小异,自己生成一张大的贴图,覆盖一个区块,然后动态更改大贴图。TiledMap每次更改地形会生成一个节点,如果对初次的地形多次改变,会产生很多小节点。

关于碰撞盒,这个其实也不是什么大问题,本质上你仅仅只需要找到地图当中能产生碰撞的方块,如果这些方块连在一起,就将他们当成一个整体添加包围盒,这样效率会比单个方块添加一个包围盒效率高。类似的算法github上应该很多。

1赞

原來如此,那其實我的思路還是有問題的……讀取存檔後逐一修可能改造成節點過多而爆掉。

不好意思這裡我不太懂,大貼圖是指圖集嗎?還是指想辦法生成一張跟一個 Chunk 一樣大的圖呢?前者(圖集)我已經做了,後者我不知道該如何在玩家遊玩過程中動態做到……假設一個 Chunk 一個 Node,我該如何在一個 Sprite 裡面顯示一整個 Chunk 的圖片紋理呢?

關於碰撞箱的部分沒有問題,碰撞箱連結和處理有洞圖形都寫好了。