パハットノート

※当サイトではGoogleアドセンス広告を利用しています

Unity Tilemapの作成の自動化





概要

以前の記事でTilemapの基本的な作成方法を紹介しました。
しかし、使用する画像がたくさんある場合はいちいちこの処理をするのは面倒です。
そこで、この記事ではこの処理を自動化する方法を紹介します。
以前の記事はこちらから
kiironomidori.hatenablog.com




使用するスクリプト

次のスクリプトを使用します。

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.Tilemaps;
using System.IO;
using System.Linq;

[CustomEditor(typeof(CreateTilePalette))]
public class CreateTilePaletteEditor : Editor
{
    CreateTilePalette createTilePalette;

    public override void OnInspectorGUI()
    {
        //元のInspector部分を表示
        base.OnInspectorGUI();

        //読み込む?
        serializedObject.Update();
        createTilePalette = target as CreateTilePalette;

        //ボタンを表示
        if (GUILayout.Button("タイル作成"))
        {
            //スライス
            foreach (var img in createTilePalette.imgs)
            {
                createTilePalette.Slice(img);
                createTilePalette.CreatePalette(img);
            }

            //リフレッシュ
            EditorApplication.ExecuteMenuItem("Assets/Refresh");
        }


        //変更を保存
        serializedObject.ApplyModifiedProperties();

    }
}


public class CreateTilePalette : MonoBehaviour
{    
    public List<Texture2D> imgs;//画像
    [SerializeField] int spritePixelsPerUnit;//unity上での長さ1に対応するピクセル数
    int row, column;//行数と列数
    [SerializeField] string exportParentFolder;//ファイルの出力先

    //画像を分割する
    public void Slice(Texture2D img)
    {
        //行数と列数を決定
        row = img.height / spritePixelsPerUnit;
        column = img.width / spritePixelsPerUnit;

        //srcのパスとからインポート設定を取得
        string imgPath = AssetDatabase.GetAssetPath(img);
        TextureImporter tI = AssetImporter.GetAtPath(imgPath) as TextureImporter;

        //テスクチャインポートプロパティを編集
        tI.spritePixelsPerUnit = spritePixelsPerUnit;//何ピクセルで1マスか
        tI.spriteImportMode = SpriteImportMode.Multiple;
        tI.filterMode = FilterMode.Point;
        tI.textureCompression = TextureImporterCompression.Uncompressed;

        //ループで分割
        var datas = new SpriteMetaData[row * column];
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < column; j++)
            {
                int index = i * column + j;
                int x = j * spritePixelsPerUnit;//pixelSize.x;
                int y = img.height - (i + 1) * spritePixelsPerUnit;
                Rect rect = new Rect(new Vector2(x, y), Vector3.one * spritePixelsPerUnit);

                datas[index] = new SpriteMetaData()
                {
                    name = $"{img.name}_{index}",
                    rect = rect
                };
            }

        }
        tI.spritesheet = datas;

        AssetDatabase.ImportAsset(imgPath, ImportAssetOptions.ForceUpdate);
    }

    //タイルパレットを作成
    public void CreatePalette(Texture2D img)
    {
        //空のゲームオブジェクトを作成
        GameObject prefabObjInstance = PrefabObjInstance();



        //フォルダが存在しなければ作成
        string exportFolder = $"{exportParentFolder}/{img.name}";
        if (!Directory.Exists(exportFolder))
        {
            Directory.CreateDirectory(exportFolder);
        }


        //タイルを追加
        CreateTile(prefabObjInstance, img, exportFolder);

        //アセット化したら、シーンから削除
        string exportObjPath = $"{exportFolder}/{img.name}.prefab";
        PrefabUtility.SaveAsPrefabAsset(prefabObjInstance, exportObjPath);
        DestroyImmediate(prefabObjInstance);

        //アセットにGrid Paletteを追加
        SetGridPalette(exportObjPath);
    }

    //プレハブのひな形を作成
    GameObject PrefabObjInstance()
    {
        //空のオブジェクトを生成
        GameObject obj = new GameObject("tmp_obj");

        //Gridを追加
        obj.AddComponent<Grid>();

        //子供のゲームオブジェクトを作成
        GameObject childObj = new GameObject("layer1");
        childObj.transform.SetParent(obj.transform);

        //「Tilemap」と「Tilemap Renderer」をアタッチ
        childObj.AddComponent<Tilemap>();
        childObj.AddComponent<TilemapRenderer>();

        //返す
        return obj;
    }

    //タイルを作成して、マップに追加
    void CreateTile(GameObject obj, Texture2D img, string exportFolder)
    {
        //Spriteを全取得
        string imgPath = AssetDatabase.GetAssetPath(img);
        var sprites = AssetDatabase.LoadAllAssetsAtPath(imgPath).OfType<Sprite>().ToArray();

        //rowとcolumnでループ
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < column; j++)
            {
                //タイルに使用する画像
                Sprite targetSprite = sprites[i * column + j];

                //タイルの作成
                Tile tile = ScriptableObject.CreateInstance<Tile>();
                tile.sprite = targetSprite;

                //アセットとして保存
                AssetDatabase.CreateAsset(tile, $"{exportFolder}/{targetSprite.name}.asset");

                //タイルマップに追加
                Vector3Int pos = new Vector3Int(j, row - i - 1, 0);
                obj.transform.GetChild(0).GetComponent<Tilemap>().SetTile(pos, tile);
            }
        }
    }

    //プレハブにGrid Paletteを追加
    void SetGridPalette(string exportObjPath)
    {
        //Grid Paletteを一時的に生成し、その文字列を読み込む
        string tmpGridPalettePath = "Assets/Palette Setting.asset";
        var gridPalette = ScriptableObject.CreateInstance<GridPalette>();
        AssetDatabase.CreateAsset(gridPalette, tmpGridPalettePath);

        //文字列を読み込む
        var text = File.ReadAllLines(AssetDatabase.GetAssetPath(gridPalette)).ToList();

        //一時的なオブジェクトなので消す
        AssetDatabase.DeleteAsset(tmpGridPalettePath);

        //プレハブのassetファイルを読み込むGrid Paletteを無理やり追加するか判断
        var objText = File.ReadAllLines(exportObjPath).ToList();

        //既に追加されている場合は除外
        if (objText[objText.Count - 1] != text[text.Count - 1])
        {
            for (int i = 2; i < text.Count; i++)
            {
                objText.Add(text[i]);
            }

            //上書き
            File.WriteAllLines(exportObjPath, objText);
        }
    }
}





使用例

1. 画像の準備

タイルに使用したい画像を準備します。
sample1.png


sample2.png



2.スクリプトのアタッチと設定

先ほど作成した「CreateTilePalette」を任意のゲームオブジェクトにアタッチします。
今回用意した画像は100×100ピクセルで1マスとし、「Assets/Tile」フォルダに出力したいので次のように設定をしたら、「タイルを作成」ボタンを押します。。



3. 実行結果の確認

先ほどの処理より2つの画像を利用したタイルパレットが作成されました。



また、アセット内に次のようなファイルが作成されています。