LoginSignup
1
0

【Unity】ShadowCaster2DのShapeを自動で作るEditor拡張

Posted at

はじめに

動画のように1クリックでShadowCaster2Dの影の範囲を作ってくれるEditor拡張を作りました。

ソースコード

作ったわけ

2Dゲーム作ってる友達が『毎回チマチマ設定するのめんどくさいな~』と嘆いていたので作りました。
機能は

  • SpriteRendererのMeshに対応した形でShapeを作る
  • CompositeCollider2DからTilemapの形でShapeを作る
  • 作った形をまとめて消す

があります。

解説

既存のShadowCaster2Dを拡張する

今回は既存のインスペクターの見た目の下に自分の追加項目を付け足すのが目標です。
ShadowCaster2Dは最初からUnityにあるComponentで、これをEditor拡張するには

[CustomEditor(typeof(ShadowCaster2D))]
public class ShadowCaster2DAutoShapeEditor : Editor
{
    var loadAssembly = Assembly.Load("Unity.RenderPipelines.Universal.Editor");
    var type = loadAssembly.GetType("UnityEditor.Rendering.Universal.ShadowCaster2DEditor");
    if (type == null)
    {
        return;
    }
    var editor = CreateEditor(target, type);
    editor?.OnInspectorGUI();

    // この下に自分で付け足したいEditor拡張内容を書く
}

とします。

var loadAssembly = Assembly.Load("Unity.RenderPipelines.Universal.Editor");

をアセンブリが違うのでこうしないとtypenullになります。

public override void OnInspectorGUI()
{
    base.OnInspectorGUI();
}

にすると標準のインスペクターの見た目ではなく、Debugモードでの見た目になるので使いません。

SpriteRendererのMeshに沿ってShapeを作る

// 重心を使って頂点を時計回りにソートする
Vector2 center = Vector2.zero;
foreach (Vector2 vertex in vertices)
{
    center += vertex;
}
center /= vertices.Length;

Array.Sort(vertices, (v1, v2) =>
{
    float angle1 = Mathf.Atan2(v1.y - center.y, v1.x - center.x);
    float angle2 = Mathf.Atan2(v2.y - center.y, v2.x - center.x);
    return angle2.CompareTo(angle1);
});

ここが一番重要です。SpriteRendererのクラスから簡単に頂点情報は手に入れれますが、これをそのままShadowCaster2Dに代入するとShapeの形が変になります。
これは頂点情報の格納されてる順番がぐちゃぐちゃなので起きます。

ぐちゃぐちゃな並び順を一周回るようにソートします。

重心を求めて、重心から頂点の角度を計算し、それでソートします。
凸型だったり、特殊形状だとこの方法はおそらくうまくいきません。

Vector3[] hogePath = new Vector3[vertices.Length];
for (int i = 0; i < vertices.Length; i++)
{
    hogePath[i] = vertices[i];
}
shapePathField.SetValue(shadowCaster2d, hogePath);
shapePathHashField.SetValue(shadowCaster2d, UnityEngine.Random.Range(int.MinValue, int.MaxValue));
meshField.SetValue(shadowCaster2d, new Mesh());

あとはShadowCaster2DにSetして完了です。Vecter3じゃないとうまくSetできなかったのでVecter3にしてます。

CompositeCollider2DからShapeを作る

SpriteRendererの時ほど難しくないです。

for (int i = 0; i < tilemapCollider.pathCount; i++)
{
}

最初のForはPathの分だけ繰り返します。これはタイルマップは宙に浮いているマスなどがあるので、浮いているマスの分だけ別々にGameObjectを作って処理するからです。
CompositeCollider2Dから頂点情報をGetすると並び順に問題はないのでさっきのようにソートする必要性は無いです。
GetしてShadowCaster2DにSetして完了です。

保存できるようにする

折角Shapeを作ったのに保存できなかったら意味が無いです。

EditorUtility.SetDirty((ShadowCaster2D)target);

これを書いて保存できるようにします。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0