上次說了一些使用Unity TileMap的方法,今次的學習筆記會説一下如何製作Scriptable Tile;Scriptable Tile是也一個蠻好玩的東西,可以讓開發者利用程序定義Tile的內容,例如在RPG常用的自動化地形生成 (Terrain Tile);
這次筆記會先説説簡單的Scriptable Tile,讓大家理解一下基本的做法;下次才説Terrain Tile那些比較複雜的Scriptable Tile。
學習重點:
- 什麼是Scriptable Tile?
- Scriptable tile 能做什麼?
- 如何製作簡單的Scriptable Tile: ColorTile
- 其他Scriptable Tile例子
什麼是Scriptable Tile?
其實Scriptable Tile並不是什麼特別的東西,當我們把Sprite拉到Tile Palette時,其實已經使用了Unity提供的Scriptable Tile來生成一個TileAsset了;那個Scriptable Tile就是Tile Class;
Tile class 相關文檔 :https://docs.unity3d.com/Manual/Tilemap-ScriptableTiles-Tile.html
Tile Asset相關文檔 : https://docs.unity3d.com/Manual/Tilemap-TileAsset.html
當默認的Tile不能滿足我們的需要時,就可以創造我們自己的Scriptable Tile來處理。
另外,說說Scriptable Tile的本質
- Scriptable Tile是繼承TileBase來製作;
- 由於TileBase繼承於ScriptableObject,所以其實Scriptable Tile也是Scriptable Object; 所以不會直接使用Scriptable Tile,而是使用Scriptable Tile生成出來的TileAsset;
所以Scriptable Tile不會像MonoBehaviour那樣,可定義Update, Start 那些邏輯;
Scriptable Tile, Tile Asset,Tile Palette 和 TileMap之間的關係
雖然有點複雜,但是大概是通過TilePalette拿出Tile,然後放在Tilemap繪畫;
TileMap便紀錄了不同位置(Grid)用了什麼TileAsset,而TileMapRender也用該TileAsset的資料來進行Render;
Scriptable Tile可作什麼?
自定義的Scriptable Tile可以做到以下的東西:
- 定義顯示的圖像,顏色,Transform(Rotation),例如Color Tile
- 定義碰撞的做法: 沒有碰撞 / Grid為碰撞範圍 / Sprite為碰撞範圍
- 動態Tile,例如移動的小花或瀑布
- 動態改變Tile的內容;例如Terrain Tile,Rule Tile
如何製作簡單的Scriptable Tile: ColorTile
ColorTile是一個讓TileMap的Grid填上顏色的Tile, 主要參數是Sprite和指定的顏色;
效果如下:
製作重點
- ScriptableTile需要繼承TileBase類
- 需要定義GetTileData, 而且需要定義tileData.sprite, 否則不能正常顯示相關的Tile
- 需要定義CreateTile方法來創建Tile的Asset
- 因為ScriptableTile是不會直接使用,TileMap只使用TileAsset來進行處理;
製作步驟
- 建立ColorTile類
- 定義以下properties :
public Color customColor; // 這樣可以讓TileAsset定義顏色; public Sprite customSprite; // TilePalette, TileMap用來顯示 public bool isPassable = true; // 指定是否能通過
- 定義GetTileData
這是其中一個必要實現的方法,告訢TileMap要用畫什麼Sprite和配什麼顏色;
public override void GetTileData(Vector3Int location,
ITilemap tileMap, ref TileData tileData)
{
tileData.color = customColor; // the main input
tileData.sprite = customSprite; // mandatory to show something
tileData.colliderType = isPassable ? Tile.ColliderType.None : Tile.ColliderType.Grid;
tileData.flags = TileFlags.LockAll;
}
定義CreateTile
這是另一個必要實現的方法,令ScriptableTile可以生成Tile Assets
#if UNITY_EDITOR
[MenuItem("Assets/Create/Custom Tile/Color Tile")]
public static void CreateTile()
{
string path = EditorUtility.SaveFilePanelInProject("Save ColorTile",
"ColorTile", "asset", "Save ColorTile", "Assets");
if (path == "") {
return;
}
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<ColorTile>(), path);
}
#endif
- 建立使用的Sprite;
使用 Asset -> Create -> Sprites -> Square 來創建;成功後,會生成一張4×4的Texture;
如果CellSize是1, 把相關Sprite的PPU(Pixel Per Unit)改為4;
如果CellSize不是1,需要把PPU改為其他數值,公式: ppu = 4 / cellSize
- 使用 Asset -> Create -> Custom Tile -> Color Tile來創建新的tileAsset
- 設定TileAsset
把剛剛生成的Sprite拉到TileAsset設定中;
設定顏色和passable
- 最後把tileAsset拉到tilePalette就完成;
- 選定目標的Tile Layer和用Dropper選擇該Tile, 就能畫在tileMap上了。
其他Scriptable Tiles
Transform Tile
Tile把Sprite進行不同的Rotation;
參考代碼:
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
// Set the Matrix4x4 using Quaternion and SetTRS
Quaternion quaternion = Quaternion.Euler(0f, 0f, -rotateDegree); // ken: rotate using Z-axis
// degree > 0: clockwise
Matrix4x4 mat = Matrix4x4.identity;
mat.SetTRS(Vector3.zero, quaternion, Vector3.one);
// Define the new Matrix
tileData.transform = mat;
// Define the sprite, the image to be rotated
tileData.sprite = customSprite; // manadatory to show something
// using default Setting
tileData.color = color;
tileData.colliderType = Tile.ColliderType.None;
// Confirm the change
tileData.flags = TileFlags.LockAll; // need to make the tiled filled with a color
}
備註: 把Rotation轉為Quaternion,並放在Matrix4x4,然後在tileData.transform進行設定;
Animation Tile
動態Tile:利用多張Sprite (Frame Animation技術)令Tile出現動畫,例如瀑布,被風吹的花草;
參考代碼:
public override bool GetTileAnimationData(Vector3Int location, ITilemap tileMap, ref TileAnimationData tileAnimationData)
{
if (spriteList.Length == 0) {
return false;
}
tileAnimationData.animatedSprites = spriteList;
tileAnimationData.animationSpeed = animationSpeed;
tileAnimationData.animationStartTime = startTime;
return true;
}
備註:
- 定義用reference傳入的tileAnimationData,並設定主要數值:
- animatedSprites : 動畫frame sprite
- animationSpeed : 播放速度,(fps – 一秒出多少個frame)
- animationStartTime: 開始播放的時間
Random Tile
隨機Tile:當繪畫tile時,隨機使用多張Sprite其中一張,例子:花,草
參考代碼:
public override void GetTileData(Vector3Int location, ITilemap tileMap, ref TileData tileData)
{
//tileData.transform = tileMap.GetTransformMatrix (location); // Matrix4x4.identity;
int index = Random.Range (0, spriteList.Length);
Sprite selectedTile = spriteList [index];
tileData.sprite = selectedTile;
tileData.flags = TileFlags.LockAll;
}
備註: 利用 Random.Range,就能找出一個隨機數!
文章相關代碼
https://github.com/tklee1975/UnityTileExample
延伸閱讀
發表留言