nimanji’s blog

20代の最後は手のひらに楽しいゲームを産み落とす。それができるまでを記した日記。

ゲームを作りやすいようにHierarchyを整理する

ゲームを作ったことがある、もしくは作ろうとしたという経験がある人は、あることで一度は挫折しかけた、挫折してゲームを作らなくなってしまった、というのがあるのではないでしょうか。
私の場合はゲームを作らなくなってしまうまではいきませんが、プロジェクトを何度も破棄しては新しく作成を繰り返しています・・・。

その「あること」というのは、日をまたいでプロジェクトを開くと、どういう構造になっていたか忘れてしまったというものです。・・・私だけでしょうか?
今回はそうならないために、きちんと整理して、見ただけである程度は思い出せるようにするよう、私なりのHierarchy整理方法をまとめます。

設置するObject単位のCanvasの座標を整理する

Hierarchyではいろいろ整理するときに親子関係を使いますが、私はそこにZ座標での管理を取り入れています。いつも作っているのは2Dのゲームですが、それでもこのZ座標管理は重要です。
まずプロジェクトつくりたての状況のHierarchyをみてみます。今回はScene名をHierarchyArrangeとしています。

f:id:nimanji:20180412144256p:plain

はい、まっさらです。
次にここに、ゲームで使う要素を入れていきます。今回はこの3つです。

  • UI
  • キャラクター
  • 背景

この3つに対応するGameObjectを作成し、それぞれに以下の設定のCanvasを持たせます。

f:id:nimanji:20180412145101p:plain

注意する点としては、実際に表示するときの重なりを意識する必要があるため、Plane Distanceの値を各GameObjectごとに変更します。変更する数値はそれぞれこんな感じです。

  • UI ... 10
  • キャラクター ... 20
  • 背景 ... 30

これを設定したあと位置関係を視覚的に把握するため、Scene表示を2Dから3Dに変更するとこのように表示されます。
(今回は説明のため、UIを赤、キャラクターを緑、背景を青にしています)

f:id:nimanji:20180412145458p:plain

これで今後は、キャラクターを作るときにはこのGameObject、背景はこのGameObjectと見やすくなり、レイヤー関係も一目でわかるようになりました。

スクリプトからGameObjectを作るときの注意点

前回の記事では、Resources配下の画像を元にしてGameObjectを作成していましたが、この方法を用いる場合だと座標がおかしなことになってしまいます。
試しに以下のスクリプトで、キャラクターレイヤーにGameObjectを生成してみます。

public class TestScript : MonoBehaviour
{
    void Awake()
    {
        // 親となるGameObjectを取得
        GameObject parent_object = GameObject.Find("Character");
        // Resourcesディレクトリから画像を取得
        Object[] resources_images = Resources.LoadAll("", typeof(Sprite));
        // 取得した画像を1個ずつGameObjectとして生成する
        foreach (Sprite sprite in resources_images) {
            // GameObjectを読み込んだSprite名で生成
            GameObject instance_object = new GameObject(sprite.name);
            // GameObjectの親子関係、アンカー位置などを設定
            instance_object.transform.parent = parent_object.transform;
            instance_object.AddComponent<RectTransform>().anchoredPosition = new Vector2(0, 0);
            instance_object.GetComponent<RectTransform>().localScale = new Vector2(10, 10);
            // GameObjectSpriteを適用し、アスペクト比と画像サイズの設定を行う
            instance_object.AddComponent<Image>().sprite = sprite;
            instance_object.GetComponent<Image>().preserveAspect = true;
            instance_object.GetComponent<Image>().SetNativeSize();
        }
    }
}

作成したスクリプトを、スクリプト設置用に作成した空のGameObject(今回はTestScript)に入れて実行すると、このような結果になります。

f:id:nimanji:20180412151132p:plain

このように、Characterレイヤーに設定したはずなのに、画像はUI上に表示されてしまいました。
このとき、画像の座標は(0, 0, -1600)となっており、明らかにおかしいです。

原因は、スクリプト内で作成したGameObjectの親を指定しているこの部分です。

instance_object.transform.parent = parent_object.transform;

これの解決方法をいろいろ探していると、この記事を見つけました。

www.hildsoft.com

この記事を参考に、GameObjectの親の指定方法を以下に変更します。

instance_object.transform.SetParent(parent_object.transform, false);

これで実行すると、きちんとCharacterレイヤーに画像が表示されました。画像の座標(0, 0, 0)となっており、Characterレイヤーの中心点を基準として配置されています。

f:id:nimanji:20180412152057p:plain

さいごに

レイヤーごとに分けたり親子関係を築いたりすると多少スクリプトの修正も必要ですが、日をまたいで作業を再開したとしても、3D表示とHierarchyの構成がスッと頭に入ってきて思い出せるかと思います。
また、今回使用したプロジェクトデータはGitHubに公開していますので、実際にHierarchyがどう構成されているかを見たい場合は以下をCloneして展開してみてください。

github.com