【Unity2D】ドット絵のオブジェクトの配置が捗るエディタ拡張【エディタ拡張】


この記事を書いたバージョン：Unity5.5.0f3（win64）

# 目次
1. 概要
2. 成果物
3. 使い方と解説
4. 工夫したところ
5. おわりに

#1. 概要

### この記事がターゲットにしている読者
* ドット絵のゲームをUnityで作っている人
* Unityでオブジェクトを配置するとき、きりのいい位置に配置したい人
* タイルマップエディタがいまいち使いにくい人


　きりのいい位置にオブジェクトを置くのが面倒なUnity。
特にドット絵のゲームを作るときは、数ピクセルのズレが世界観を台無しにします。

とは言え、大量にオブジェクトを配置するときにいちいちオブジェクトをクリックしてTransformをいじって…とやるのは骨が折れるもの。
そこで今回は、ドラッグアンドドロップの動作だけでキレイにオブジェクトを配置できるエディタ拡張を作りました。

### 参考にしました
今回の内容はこちらの素晴らしい記事を大いに参考にしました。
というかこちらの記事の内容にちょこっと手を加えただけです…
http://qiita.com/r-ngtm/items/bc0843e2f8a7c610353a

#2. 成果物

こちらからダウンロードしてそのまま使えます。
https://github.com/john95206/GridDrawer

#3. 使い方とコード


### 使い方

0. Projectに *Editor* という名前のフォルダを作り、そこに用意したコードを入れます。エディタ拡張のコードはすべてこのフォルダに入れなければなりません。
1. UnityEditorの上のタブからGridWindowタブを選択してウィンドウを表示する
![GridEditorOpen.gif](https://qiita-image-store.s3.amazonaws.com/0/157326/4c8a4a1b-7fd1-86fc-55e8-2a172e613b41.gif)

2. ウィンドウで好きな開始位置と面積を決め、チェックボックスにチェックを入れる

![GridEditorGrid.gif](https://qiita-image-store.s3.amazonaws.com/0/157326/d3f6e6b9-52ae-50d4-4646-97cea8ad82a4.gif)
3. 好きなオブジェクトをドラッグ

![GridEditorMove.gif](https://qiita-image-store.s3.amazonaws.com/0/157326/1ea5519c-9d46-1b7e-ee6d-8af60fe41c46.gif)

### コード

ほとんど元記事様そのままであり、その他は大したことはしていません。

グリッドをSceneビューに描画するスクリプトを用意し、これをEditorフォルダに入れます。

```csharp:DrawGrid.cs
using UnityEngine;
using UnityEditor;
using System.Collections;

/// <summary>
/// UnityEditorでグリッドを描画しオブジェクトをスナップさせるクラス
/// </summary>
[CustomEditor(typeof(Transform))]
public class DrawGrid : Editor {
	
	// グリッドの間隔
	public const float gridDistance = 0.1f;

	void OnSceneGUI()
	{
		// グリッドを非表示にする場合は処理を止める
		if (!GridEditWindow.isGridEnabled)
		{
			return;
		}
		
		// グリッドの色。
		Color color;

		// グリッド描画の開始地点をGridEditWindowから参照
		Vector3 originPos = GridEditWindow.originPos;
		
		// グリッドの本数　＝　面積÷間隔
		float numX = GridEditWindow.gridAreaX / gridDistance;
		float numY = GridEditWindow.gridAreaY / gridDistance;

		// 縦線を描画。開始位置から1本ずつ右に描画していく。
		for(int x = 0; x <= numX; x++)
		{
			// 線の開始位置を計算。
			Vector3 pos = originPos + Vector3.right * x * gridDistance;
			
			// 5の倍数は白にして目立たせる
			if (x % 5 == 0)
			{
				// 0.7をかけて色を落ち着かせる
				color = Color.white * 0.7f;
			}
			// それ以外は水色
			else
			{
				color = Color.cyan * 0.7f;
			}

			// 線を描画
			Debug.DrawLine(pos, pos + Vector3.up * GridEditWindow.gridAreaY, color);
		}

		// 横線を描画。開始位置から1本ずつ上に描画していく。
		for (int y = 0; y <= numY; y++)
		{
			Vector3 pos = originPos + Vector3.up * y * gridDistance;
			
			if (y % 5 == 0)
			{
				color = Color.white * 0.7f;
			}
			else
			{
				color = Color.cyan * 0.7f;
			}

			Debug.DrawLine(pos, pos + Vector3.right * GridEditWindow.gridAreaX, color);
		}

		// グリッドにぴったりと合わせるオブジェクトのトランスフォームを取得
		Transform objectTransform = target as Transform;

		// オブジェクトをスナップさせる処理
		Vector3 objectPosition = objectTransform.transform.position;
		objectPosition.x = Mathf.Floor(objectPosition.x / gridDistance) * gridDistance;
		objectPosition.y = Mathf.Floor(objectPosition.y / gridDistance) * gridDistance;
		objectTransform.transform.position = objectPosition;

		// 再描画
		EditorUtility.SetDirty(target);
	}

	private void OnDisable()
	{
		// 再描画
		EditorUtility.SetDirty(target);
	}
}
```

これでグリッドをSceneビューに描画できるようになりました。
このままでも初期位置などのパラメータをこのクラスで定義すれば使えるのですが、いちいち書き換えて調整したりする必要があり少し使いづらいです。
次に、グリッドのパラメータを管理するウィンドウを作ります。
これもEditorフォルダに格納します。

```csharp:GridEditWindow.cs
using UnityEngine;
using UnityEditor;
using System.Collections;

/// <summary>
/// グリッドのパラメータを制御するウィンドウ
/// </summary>
[CustomEditor(typeof(Transform))]
public class GridEditWindow : EditorWindow
{
	// NOTE: 
	// 各変数はDrawGrid.csで参照するためstaticにする
	// グリッドを表示するかどうか
	public static bool isGridEnabled = false;
	// グリッドの開始地点
	public static Vector2 originPos = Vector2.zero;
	// グリッドの面積の横の長さ
	public static int gridAreaX = 0;
	// グリッドの面積の縦の長さ
	public static int gridAreaY = 0;

	// エディタの上のメニュータブからウィンドウを呼び出せるようにする
	[MenuItem("GridEditorWindow/GridEditor")]
	static void Open()
	{
		EditorWindow.GetWindow<GridEditWindow>("GridEditor");
	}

	private void OnGUI()
	{
		// グリッドの開始地点を編集できるようにする
		originPos = EditorGUILayout.Vector2Field("Position", originPos);
		// グリッドの横の長さを編集できるようにする
		gridAreaX = EditorGUILayout.IntField("描画するX座標の範囲", gridAreaX);
		// グリッドの縦の長さを編集できるようにする
		gridAreaY = EditorGUILayout.IntField("描画するY座標の範囲", gridAreaY);

		// 間をあける
		EditorGUILayout.Space();
		EditorGUILayout.Space();
		EditorGUILayout.Space();
		
		// グリッドを描画するかどうかをチェックボックスで変更できるようにする
		isGridEnabled = EditorGUILayout.Toggle("Grid描画", isGridEnabled);
	}
}
```

以上です。
gridDistanceも GridEditWindow.cs で管理すれば、線の間隔も自由に変えられますね。

#4. 工夫したところ

### ウィンドウを連動させた
　参考にした記事では、グリッドの範囲や中心地点を変えたい時にスクリプトを編集しなければならず、デザイナーに配置してもらうには少し使いづらいところがありました。
　そこで、今回はこれらのパラメータを管理するウィンドウを新たに作り、エディタ内だけで編集を完結させられるようにしました。

### 面積を自由に変えられるようにした
　あまり範囲を大きくしすぎると全体が見にくくなるので、グリッドを設けたい場所を自由に決められるようにしました。

#5. おわりに
　Unity2Dはじわじわと充実しつあるものの、まだまだエディタは2Dゲーム作りに快適とは言えないのが現状かと思います。
　大抵は外部ツールのマップエディタを使ったりするようですが、マップチップを使わないドットゲーム開発では使いづらく、Untiyエディタでなんとかやりくりするしかありませんでした。
　元記事様に出会ったことで、ついに道が開けました。元記事様にもある通り、特定のオブジェクトだけをグリッド操作に適用することも可能ですし、この拡張はまだまだカスタムのし甲斐があるかと思います。
　この記事が少しでも自分のような悩みを抱えているドット絵ゲーム開発者の方々の力になれればと思います。