【CocosCreator】MapChipからAtlasを生成するツールを自作してみた。

# 概要
CocosCreatorで使用する素材を探しているとツクールやウディタ用のキャラチップやマップチップばかり見つけるので、Atlas化して使えるようにしたかった。
CocosCreatorではPlistファイルがAtlasの役割のようで、バラバラなPngからPlistを作るツールはあるようだったが、マップチップのPngからPlistを生成するツールはなさそうだったので、自作した。
Plistの例を見て、それと同じようなものを作るというかなり大雑把な設計なので注意。

あと個人でいろいろ試す用に作ったけど、ツクール用の素材をCocosで使うのはライセンス的に微妙なことがあるかも知れないので、公開する場合は注意が必要かも。

# 参考サイト
cocos2d-x Atlas化した画像の扱い
https://qiita.com/sawasaka/items/943c238d7491146104fb
PListのファイルフォーマットについて：
https://www.codeandweb.com/blog/2016/01/29/cocos2d-plist-format-explained
CocosCreatorでマップにオブジェクトを配置する
https://qiita.com/raichi/items/5955f3e98f5ae995e57f

# 方針とコード
C#でPNGを読み込んでPlistを生成する。
チップのサイズは判定し難かったので、後から入力する形式にした。
C#を使ってるのは完全な趣味。

```
using System;
using System.Drawing;
using System.IO;

namespace PlistMakerByChip
{
    struct Vector2
    {
        public int x;
        public int y;
    }

    class Program
    {
        private static int xSize;
        private static int ySize;

        static void Main(string[] args)
        {
            foreach (var pngPath in args)
            {
                Console.WriteLine($"input :{pngPath}");
                try
                {
                    MakePlist(pngPath);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"error : {e.Message}");
                }
            }
            Console.WriteLine("Finish");
            Console.ReadKey();
        }

        private static void MakePlist(string pngPath)
        {
            // チップサイズの入力受付。失敗したら返す。
            if (InputChipSize() == false) { return; }

            string plist = "";
            plist += GetBaseFirst();

            var pngSize = GetPngSize(pngPath);
            plist += GetBaseMeta(pngPath, pngSize);

            plist += GetFrameFirst();
            var chipXCount = pngSize.x / xSize;
            var chipYCount = pngSize.y / ySize;
            for (int y = 0; y < chipYCount; y++)
            {
                for (int x = 0; x < chipXCount; x++)
                {
                    plist += GetFrameMeta(pngPath, x, y, xSize, ySize);
                }
            }

            plist += GetBaseEnd();

            OutputPlist(pngPath, plist);
        }

        private static bool InputChipSize()
        {
            Console.WriteLine("１チップのXサイズを入力してください。");
            if (int.TryParse(Console.ReadLine(), out xSize) == false)
            {
                Console.WriteLine("有効な数字を入力してください。");
                return false;
            }

            Console.WriteLine("１チップのYサイズを入力してください。");
            if (int.TryParse(Console.ReadLine(), out ySize) == false)
            {
                Console.WriteLine("有効な数字を入力してください。");
                return false;
            }

            return true;
        }

        private static void OutputPlist(string pngPath, string data)
        {
            var dir = Path.GetDirectoryName(pngPath);
            var fileName = Path.GetFileNameWithoutExtension(pngPath);
            var outputPath = Path.Combine(dir, fileName + ".plist");

            File.WriteAllText(outputPath, data);
        }

        private static string GetBaseFirst()
        {
            return
                $"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                $"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
                $"<plist version = \"1.0\">\n" +
                $"    <dict>\n";
        }

        private static Vector2 GetPngSize(string pngPath)
        {
            var img = Image.FromFile(pngPath);
            return new Vector2() { x = img.Width, y = img.Height };
        }

        private static string GetBaseMeta(string pngPath, Vector2 pngSize)
        {
            var fileName = Path.GetFileName(pngPath);
            return
                $"        <key>metadata</key>\n"+
                $"        <dict>\n" +
                $"            <key>format</key>\n" +
                $"            <integer>2</integer>\n" +
                $"            <key>realTextureFileName</key>\n" +
                $"            <string>{fileName}</string>\n" +
                $"            <key>size</key>\n" +
                $"            <string>{{{pngSize.x},{pngSize.y}}}</string>\n" +
                $"            <key>smartupdate</key>\n" +
                $"            <string>$TexturePacker:SmartUpdate:.....$</string>\n" +
                $"            <key>textureFileName</key>\n" +
                $"            <string>{fileName}</string>\n" +
                $"        </dict>\n";
        }

        private static string GetFrameFirst()
        {
            return
                $"        <key>frames</key>\n" +
                $"        <dict>\n";
        }

        private static string GetFrameMeta(string pngPath, int xPos, int yPos, int xSize, int ySize)
        {
            var fileName = Path.GetFileNameWithoutExtension(pngPath);
            return
                $"            <key>{fileName}_{xPos}_{yPos}</key>\n" +
                $"            <dict>\n" +
                $"                <key>frame</key>\n" +
                $"                <string>{{{{{xPos * xSize},{yPos * ySize}}},{{{xSize},{ySize}}}}}</string>\n" +
                $"                <key>offset</key>\n" +
                $"                <string>{{0,0}}</string>\n" +
                $"                <key>rotated</key>\n" +
                $"                <false/>\n" +
                $"                <key>sourceSize</key>\n" +
                $"                <string>{{{xSize},{ySize}}}</string>\n" +
                $"            </dict>\n";
        }

        private static string GetBaseEnd()
        {
            return
                $"        </dict>\n" +
                $"    </dict>\n" +
                $"</plist>";
        }
    }
}
```

# まとめ
一応、これで作成したPlistと元PngをCocosCreatorに突っ込んだらAtlasみたいに使うことができた。
CocosCreatorを拡張して作れるようにした方が使い勝手が良かったかもと後から思った。