如何製作 tilemap · 完整指南

如何製作 Tilemap — 逐步指南與免費編輯器

動手做你自己的 tilemap

從零學會怎麼做 tilemap — tileset、網格、圖層、碰撞與自動拼接。照著步驟走,然後直接在瀏覽器裡免費做出來並試玩。

✦遊戲
製作 tilemap,場景是 森林地城

學會怎麼做 tilemap,說到底就是按正確順序做四個決定:儲存格大小、tileset 的版面配置、圖層堆疊,還有碰撞要放哪裡。這四個決定做一次,之後畫地圖就變成機械動作。

下面的步驟,就是我們在 Neta Studio 把一段文字描述變成可遊玩世界時用的順序:挑一組或生成一組 tileset、固定網格、先鋪地形再補細節、拆開圖層,最後讓自動拼接處理邊緣。這裡沒有任何一步需要安裝。編輯器直接在瀏覽器裡跑,下面提到的每個數字之後都能改,不必重畫地圖。

什麼是 Tilemap?(明確定義與示意圖)

Tilemap 是一格一格的索引,不是一格一格的圖片。每個儲存格存一個整數,指向 tileset 裡的某一塊 tile,渲染器查出這個索引,把 tile 畫在儲存格的位置上。一張 20×12、儲存格 32 px 的地圖,就是 240 個整數,覆蓋 640×384 像素。

這層間接就是重點。一塊草地 tile 在圖集裡只存一次,卻被上百個儲存格引用,所以地圖檔案很小、載入很快。也因為 tilemap 是資料而不是美術圖,你可以用雜訊函式生成它、把它當文字編輯、用 Git 比對兩個版本,或在鏡頭移動時分塊串流載入。

本頁最上方那張圖,是用我們自己的 tile 鋪在 12×8、儲存格 32 px 的網格上。草地填滿內部,沙地沿著左邊與底邊延伸,水放在右下角沙地結束的地方。當資料來讀:第 3 欄、第 0 列的儲存格存的是草地索引,第 0 欄、第 7 列存的是水角的索引,其餘每一格都是普通的沙地索引。原點在左上,x 往右遞增,y 往下遞增。如果你的引擎原點在左下,地圖會上下顛倒,除非你把列索引換成「總列數 − 1 − y」。

  • 網格欄與列,在地圖建立時就固定。同一種鏡頭縮放下,20×12 和 40×24 的地圖表現完全不同。
  • 儲存格大小單一儲存格的像素尺寸:16、32、48 或 64。它必須和 tileset 的 tile 尺寸完全一致,否則取樣會落在 tile 中間。
  • tile 的集合索引所指的那張圖,加上一份說明它有幾欄幾列的定義。
  • 索引圖層每一層、每一格存一個整數。地面層是密集的,細節層大多是空的,碰撞層存的是旗標,不是圖。

什麼是 Tileset?(以及它和 Tilemap 差在哪)

tileset 是那本圖畫書,tilemap 是指向它的那一頁引用。tileset 擁有像素:一張圖集,加上一條規則說明這張圖集是 8 欄 32 px 的 tile。tilemap 擁有擺放:哪個索引坐在哪一層的哪一格。

這兩個詞經常被混用,因為多數編輯器把它們並排放在同一個面板,也因為有些單檔格式會把這個切分藏起來。在 Tiled 裡切分很明確,tileset 檔和地圖檔是分開的。在 Unity 裡,Tile 資源存 sprite,Tilemap 元件存儲存格。在 Godot 裡,TileSet 和 tilemap 圖層是各自獨立的資源。

實務上的結果是:改 tileset 會改到每一張引用它的地圖,改 tilemap 只改一個關卡。把 32 px 的圖集換成 48 px 的,每個索引照樣解得開,但每張地圖現在畫出來的縮放都不一樣,邊緣還可能取樣到隔壁的 tile。把 tileset 當成有版本號的對外介面來看待。

面向TilesetTilemap
它存什麼每一塊 tile 的像素資料每一層、每格一個索引
磁碟上是什麼一張圖,加上儲存格大小的定義一串整數,加上對 tileset 的引用
誰在編輯它美術關卡設計師或生成器
什麼時候會改美術風格或縮放改變時版面改變時,包括每一次試玩微調

步驟 1:挑一組 tileset,或自己做一組

你有兩條路:拿現成的圖集,或自己生成。現成的比較快,但你要繼承它的色盤、它的儲存格大小、它的授權。在拿它鋪四十張地圖之前先確認授權,也要確認它是網格圖集而不是打包圖集。打包圖集存的是每塊 tile 的矩形座標,不是統一的儲存格,索引會變難做,自動拼接也會很彆扭。

如果地形必須配合特定色盤,就自己生成。Agent Sprite Forge 能從一段文字描述產出 tile 圖集,儲存格大小一致,直接消掉最常見的錯位來源:圖集裡有一塊 tile 寬 33 px,只因為美術把高光畫到格子外面去了。

不管走哪條路,第一輪不是畫圖,是量測。用 100% 縮放打開圖集,數欄數和列數,把儲存格大小寫在團隊找得到的地方。

  • 統一的儲存格大小每一塊 tile 寬高都一樣,包括大部分是空白的 tile。32 px 圖集裡只要有一塊 33 px 的 tile,而且匯出工具是按閱讀順序打包,它之後的每個索引都會位移。
  • 真正的透明要 alpha,不要白色。圖集如果是不透明白底,在瀏覽器裡會在你的天空上畫出白色方塊。
  • 有記錄的網格記下欄數、列數,以及有沒有留邊距。索引算法是「列 × 欄數 + 欄」,從 0 開始,由左到右、由上到下。
  • 先決定要不要留縫有留縫的圖集會在儲存格之間加 1 或 2 px 來減少材質滲色,代價是取樣算法要多加一個偏移。第一筆畫下去之前就先決定用哪一種。

步驟 2:決定 tile 大小與網格

儲存格大小由三件事決定:玩家實際遊玩時的縮放、你的目標渲染解析度,以及你願意畫多少美術。16 px 的 tile 在 1920 px 寬的視口上,橫向有 120 格,一個畫面塞進很多關卡,但幾乎沒空間畫細節。64 px 的 tile 只有 30 格,像素多到能畫出一棵看得懂的樹。

真正硬的限制是算術。儲存格大小必須整除圖集。256 px 寬的圖集、32 px 儲存格剛好 8 欄;48 px 會變成 5.33 欄,最後一欄只有一小塊,它之後的每個索引都會偏移。圖集尺寸不是美感選擇,它是儲存格大小的倍數。

用整數縮放。如果視口不是網格的整數倍,儲存格會落在半像素上,濾波會取樣到隔壁兩塊 tile,整張地圖會出現一條一像素的接縫。兩端都要修:引擎用最近鄰濾波,鏡頭縮放用整數。

儲存格大小適合什麼要注意什麼
16 px小尺寸角色、每畫面高格數、用程式生成的地圖幾乎沒空間畫細節;三色的樹看起來只是一團
32 px俯視角與平台遊戲地形的中間值美術必須畫在 32 px 網格上,否則和其他 tile 擺在一起會很突兀
48 px較厚重的俯視角風格,道具看得清楚每畫面格數變少,稀疏的地圖會顯得空
64 px細節多的美術、低格數、要擠出成 3D 的地圖如果每格用一個碰撞器,碰撞手感會偏粗

步驟 3:先鋪地面,再補細節

分輪次畫,永遠先畫地形。地形是你之後會改的東西,裝飾是你不想移動的東西。先擺了六十棵樹,接著把海岸線往左移四格,那六十棵樹全站在水裡。

從單一 tile 開始。用同一個草地索引把整張地圖填滿,在遊戲縮放下看輪廓,然後才讓自動拼接處理邊緣。細節等形狀定案之後再加,碰撞等細節之後再做,因為發現某個道具可以走過去,那是碰撞要改,不是重畫。

玩家看得到的每一格都要畫。空格預設會顯示渲染器在地圖後面畫的東西,那通常不是你要的背景。在鏡頭上設一個背景色,比依賴清空過的畫布安全。

1

01

建立地面層,用同一個地形索引把整張地圖填滿。先不要自動拼接。

2

02

鋪形狀:先畫水,再畫崖,各用單一 tile。完全不管邊緣。

3

03

在遊戲縮放下檢查輪廓,不要用 400%。現在讀不出形狀,之後也讀不出來。

4

04

輪廓定案後,對每個地形跑一次自動拼接,之後每次動地形都要重跑。

5

05

加細節層:道具、貼花、草叢。保持稀疏,稀疏看起來才像刻意安排的。

6

06

碰撞層最後畫,依你實際留下的細節,而不是你原本計畫的細節。

步驟 4:加圖層、深度與碰撞

tilemap 一旦拆成圖層,就不再是平的。最小可用的堆疊是三層:密集的地面層、稀疏的細節層,以及完全不放圖的碰撞層。如果地圖裡有任何東西該遮住玩家,那疊在角色之上的覆蓋層要早點加。

深度來自同一個網格。俯視角地圖按每個物件的底邊排序:腳踩得最低的最後畫。對 tile 來說這是免費的,因為儲存格的 y 已經編碼了位置。對會移動的角色,你需要逐物件的排序,加上一個決定性的平手規則,通常是物件的 y 加上它在儲存格內的小數偏移。少了這一條,同一列的兩個物件會在畫格之間閃爍。

碰撞對應到網格上,就是一份同尺寸的平行陣列。在 tileset 裡給每塊 tile 一個實心旗標,畫牆的同時也就標了實心,再用碰撞層做單張地圖的例外覆寫。逐格旗標表達不了斜坡、單向平台,或儲存格內的薄牆。那些屬於疊在網格之上的獨立物件,不屬於 tilemap。

  • 地面層密集:每一格都存一個索引。這是唯一能安心自動拼接的圖層。
  • 細節層稀疏,空的地方透明。樹、石頭、貼花。這裡的東西不該不小心擋住移動。
  • 覆蓋層畫在角色之上:樹冠、橋、屋頂。任何該遮住玩家的東西。
  • 碰撞層不放圖。一個和地圖同尺寸的布林陣列,初始值來自 tileset 的實心旗標,例外的地方手動改。

步驟 5:自動拼接與 47 塊 tile 組

自動拼接就是那種會安靜出錯的部分。一塊地形 tile 有八個鄰居,就有 2^8,也就是 256 種相鄰組合。角只有在兩側相鄰都填滿時才重要,這個對稱性把 256 種情況收斂成 47 塊唯一的 tile。這就是為什麼多數引擎和編輯器每種地形都吃一組 47 塊的 blob 圖集,並按一份有記錄的版面排列。

你也會遇到 16 塊的組合,它只看四個邊鄰居、忽略角,還有 2x2 迷你 tile 組合,每格由四個四分之一塊畫成,13 到 16 塊迷你 tile 就能涵蓋所有情況。16 塊的組合比較好畫,但角會很鈍。迷你 tile 的做法用的圖更少,但強迫你把每種地形都拆成四等分來畫,會讓像素畫變軟。

怎麼做 tilemap 才能自動拼接又不留縫

遮罩就是整個機制。對每一格,用它的八個鄰居組成一個 8 位元整數:位元 0 是北、位元 1 是東北、位元 2 是東,依此類推順時針排。挑一個順序,寫在程式碼旁邊,然後永遠不要改。遮罩差一個位元還是會產出看起來合理的地形,這就是為什麼兩邊慣例不一致可以存活好幾個月,直到有人發現角是錯的。

然後把遮罩轉成 tile 索引。有兩種做法:一張完整的 256 項查表,生成起來輕鬆,除錯也容易,因為你可以把它印出來;或是 47 項的表加上一個對稱函式。除非目標有記憶體限制,否則就用完整查表。它直接消掉一整類的角錯誤。

接自動拼接之前,值得先知道的幾種失敗模式

地圖邊緣的接縫,來自對超出邊界的儲存格處理不一致。一次決定好地圖外的世界是空的、還是同一種地形,然後每個地形都套同一條規則。

第二種常見的失敗是覆寫。自動拼接會重寫它管轄的儲存格,所以你手畫的、為了特定造型的單塊 tile,下一輪就不見了。要嘛在自動拼接後鎖住地形層,要嘛把手動覆寫存在另一份最後才套用的清單裡。

1

01

在圖集裡為每種地形保留一塊 47 塊的區域,各種地形各自成塊,不要交錯擺放。

2

02

定義鄰居位元順序,並把它記在消費這份遮罩的程式碼旁邊的註解裡。

3

03

對每一格,用八個鄰居算出遮罩,超出邊界的格子按你選的規則處理。

4

04

拿遮罩去查那張 256 項的表,回傳該地形的 47 個索引之一。

5

05

某一格變動時,只重算它自己加上八個鄰居。每一筆筆刷都重建整張地圖,就是常見的效能問題。

6

06

地形滿意之後就凍結地形層,否則你手放的 tile 下一輪就會被覆寫。

可以直接打開來玩的 Tilemap 範例

讀一張能跑的地圖,比讀一段描述學到更多。The Cyclops' Island 是一張可遊玩的地圖,建在單一地地形組上,另有獨立的碰撞層。沿著海岸線走,看沙地轉水面的地方 tile 怎麼換:那些就是實際用到的 47 種 blob 情況。

Mini World 是比較小的例子。打開它看圖層堆疊,地面、細節與覆蓋,也看看要多少塊細節 tile,一張地圖才會讀起來像完成了,而不是空的。

3D game builder 用同一個網格擠出成立體。每一格變成一個方塊,碰撞層變成垂直的牆,y 排序變成 Three.js 場景裡真正的深度。2D 地圖如果是一致的,轉 3D 幾乎不花你什麼力氣;圖層如果混在一起,擠出之後馬上就露餡。

  • The Cyclops' Island一張可以走進去的地圖,用來在遊玩速度下、而不是編輯器縮放下,研究自動拼接後的地形邊緣。
  • Mini World一張小網格,不用捲動就能檢視圖層堆疊。
  • 3D game builder同一張 tilemap 擠出成方塊,碰撞層變成幾何,深度變成真的。
在瀏覽器裡一層一層畫出你的 tilemap。

Tileset 範本下載(PS / Aseprite 網格)

範本是畫圖的輔助,不是必需品。它是一張透明畫布,每一格有參考線,往內一像素有安全區標記,最上面一列與最左一欄有索引編號,讓你畫的時候看得出來索引會落在哪。畫在它上面,匯出前把它藏起來。

範本要配合專案。512×512 的畫布裝得下 16×16 格、每格 32 px。換成 16 px 儲存格,同一個檔案裝得下 32×32 格,這時候參考線要調淡,因為在那種密度下參考線會蓋掉圖。

1

01

建立畫布,尺寸用儲存格大小的倍數:32 px 儲存格就用 512×512,16 px 儲存格就用 256×256。

2

02

在 Aseprite 裡把網格大小設成你的儲存格大小,開啟貼齊,tile 才會落在完整的格子上。

3

03

在 Photoshop 裡用參考線版面,欄數對齊你的圖集,邊距與間距都設 0,或每 32 px 手動放一條參考線。

4

04

把範本留成獨立圖層,帶著參考線、1 px 內縮框與索引標籤,工作時壓在圖上方。

5

05

關掉抗鋸齒與工具平滑。帶抗鋸齒匯出的像素畫,邊緣沒辦法乾淨拼接。

6

06

隱藏範本圖層,以 PNG-24 含透明通道匯出,保留分層檔,下次編輯範本還在。

Crystal Cave — 完成品 tilemap,含四層視差。
The Cyclops' Island — 一張變成遊戲的 tilemap。

走進它所屬的那個世界

精靈沒有地方站。最後這一步是別人沒給的:把你剛做好的圖集放進一個有人能走來走去的世界——一座小島、一顆行星、一個下雨的街角。這個網站上的每個世界都是從一段文字描述做出來,發佈成一頁能玩的東西。

常見問題

什麼是 tilemap?+

一張索引網格,每一格指向 tileset 裡的一塊 tile。渲染器查出索引,把 tile 畫在儲存格位置上,所以 20×12、32 px 的地圖就是 240 個整數,覆蓋 640×384 像素。

tilemap 和 tileset 差在哪?+

tileset 是那張圖加上它的儲存格大小;tilemap 是引用它的擺放資料。改 tileset 會改到每一張用到它的地圖,改 tilemap 只改一個關卡。

tilemap 最適合用多大的 tile?+

任何能整除你的圖集、而且縮放是整數倍的大小。32 px 是 2D 地形的常見中間值,16 px 適合小角色與高格數,64 px 適合細節多、每畫面格數少的美術。

什麼是自動拼接,我一定需要 47 塊的組合嗎?+

自動拼接會依鄰居決定某一格要用哪一塊邊與角。47 塊的 blob 組合在對稱之後涵蓋全部 256 種八鄰居情況;16 塊只看邊的組合比較好畫,但角會很鈍。

我可以在瀏覽器裡免費做 tilemap 嗎?+

可以。Neta Studio 的編輯器在瀏覽器裡跑,你可以從一段文字描述生成地圖,或親手畫一張,不用安裝任何東西就能玩。

要怎麼把 tilemap 匯入我的引擎?+

把圖集匯出成 PNG,擺放資料匯出成索引的 JSON 或 CSV,然後確認儲存格大小、欄數、原點都和引擎預期一致。原點是左下而不是左上,地圖會上下顛倒。

tilemap 可以做等角嗎?+

可以。儲存格變成菱形,排序改成按「列 + 欄」而不是按 y。高度需要第二層,碰撞會變成錯位的網格,不再對應單純的矩形陣列。

要怎麼從零開始做 tile?+

用最終的儲存格大小來畫,絕對不要畫大再縮,每塊 tile 先在 3×3 的自身拼接裡測試,再繼續畫圖集剩下的部分。邊緣重疊留一像素,用一組小而定案的色盤,這樣不同時間做的 tile 才對得起來。

回到 3D Game Builder

31 個完成的 3D 世界、遊戲與場景都在同一頁——每一個都能玩。

平台:Neta Studio頁面:How to Make a Tilemap接著讀:/explore/tool/tile-map-editor · /app/free-tilesets · /explore/tool/ai-tileset-generator
×