本ページにはプロモーションが含まれます
Unity

【Unity】Polygon Collider 2Dの形状を保存・読み込みする方法

この記事は約7分で読めます。

Polygon Collider 2Dの編集ツールのデータを読み書きしたい

ステージ毎に読み込んだデータを元に、Polygon Collider 2Dの形状を変更したかった。
ヒエラルキーで編集したPolygon Collider 2Dの形状データを読み書きするためVector2[]のデータのjson化がうまくいかなかったのでその対処メモ。

エディタ上でPolygon Collider 2Dの形状を変更したのでそのデータを読み書きできるようにしたい。

うまくいかなかった

    // Polygon Collider 2Dを持つGameObjectの参照
    public GameObject objectWithCollider;
    // 保存するデータのキー
    private string Vector2ArrayKey = "Vector2ArrayKey";
    // Polygon Collider 2Dを取得し、その頂点座標を保存するメソッド
    public void SaveColliderData()
    {
        PolygonCollider2D collider = objectWithCollider.GetComponent<PolygonCollider2D>();
        if (collider != null)
        {
            Vector2[] vectorArray= collider.points;
           
            // Vector2[]を文字列にシリアライズ
            string serializedVectorArray = JsonUtility.ToJson(vectorArray);
            // なにかしら保存処理…
           
        }
    }

でいけると思ったんです。だがしかし、JSONが空になる。

JsonUtility.ToJson()メソッドは、標準のUnityシリアライゼーションシステムを使用してオブジェクトをJSON形式にシリアライズします。
ただし、JsonUtility.ToJson()は、配列を直接シリアライズすることができません。
そのため、Vector2[] の配列を直接シリアライズすると、空の文字列が返されます。

なるほど、わからん。

試行錯誤で動くようになった

using System;
using UnityEngine;
[System.Serializable]
public class Coordinates
{
    public Vector2[] points;
}
public class ColliderEditor : MonoBehaviour
{
    // 保存するデータのキー
    private const string Vector2ArrayKey = "Vector2ArrayKey";
    // Polygon Collider 2Dを持つGameObjectの参照
    [SerializeField]
    public GameObject objectWithCollider;
    // 書き込み
    public void SaveColliderData()
    {
        PolygonCollider2D collider = objectWithCollider.GetComponent<PolygonCollider2D>();
        if (collider != null)
        {
            Vector2[] vectorArray = collider.points;
            String coordinateString = string.Join(",", vectorArray);
            // PlayerPrefにセット
            PlayerPrefs.SetString(Vector2ArrayKey, coordinateString);
            // PlayerPrefsの変更を保存
            PlayerPrefs.Save();
        }
    }
    // 読み込み
    public void LoadColliderData()
    {
        // 座標の文字列をJSON形式にシリアライズして保存
        string json = SerializeCoordinates();
        // JSON形式の文字列をデシリアライズしてVector2[]に変換
        Vector2[] vertices = DeserializeCoordinates(json);
        // 反映させるよ
        PolygonCollider2D collider = objectWithCollider.GetComponent<PolygonCollider2D>();
        if (collider != null && vertices != null)
        {
            collider.points = vertices;
        }
    }
    // 座標をJSON形式にシリアライズして返すメソッド
    string SerializeCoordinates()
    {
        // (0.76, 22.51),(-22.92, 8.70),(-20.42, -10.27),(-0.11, -24.03),(17.21, -11.18),(26.12, 2.14) のようなデータ
        string coordinateString = PlayerPrefs.GetString(Vector2ArrayKey);
        // 座標の文字列をカンマと括弧で分割
        string[] coordinatePairs = coordinateString.Split(new char[] { '(', ')', ',' }, System.StringSplitOptions.RemoveEmptyEntries);
        // Vector2の配列を作成
        Vector2[] vertices = new Vector2[coordinatePairs.Length / 2];
        for (int i = 0; i < coordinatePairs.Length; i += 2)
        {
            float x, y;
            // 各座標のxとyを取得してVector2に変換
            if (float.TryParse(coordinatePairs[i], out x) && float.TryParse(coordinatePairs[i + 1], out y))
            {
                vertices[i / 2] = new Vector2(x, y);
            }
            else
            {
                // なんかデータがおかしい時の処理
            }
        }
        // 座標をCoordinatesクラスにセット
        Coordinates coordinates = new Coordinates();
        coordinates.points = vertices;
        // CoordinatesオブジェクトをJSON形式にシリアライズして返す
        return JsonUtility.ToJson(coordinates);
    }
    // JSON形式の文字列をデシリアライズしてVector2[]に変換するメソッド
    Vector2[] DeserializeCoordinates(string json)
    {
        // JSON形式の文字列をCoordinatesクラスにデシリアライズ
        Coordinates coordinates = JsonUtility.FromJson<Coordinates>(json);
        // CoordinatesクラスからVector2[]を取得して返す
        return coordinates.points;
    }
}

おわりに

ステージごとにCSVから取得したデータを元にPolygon Collider 2Dの形状を動的に変更することができるようになりました。
小数点誤差とか気にしない。そこまで精度を保証する必要がないものを作っているので、これでよし!なんでもよし!
もっと良い方法があると思うので、誰か教えてください。

エディタ上で読み書きできるツール作った。