はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】全て(特定)の子オブジェクトに操作を加える

はじめに

今回は全て(特定)の子オブジェクトに操作を加える記事になります!

Unityでは親子関係が重要な考え方のひとつになります。

公式のレファレンスではこのように表記されています。

最上位のオブジェクトかシーンは「親オブジェクト」と呼ばれます。その下にグループ化されているすべてが「子オブジェクト」または「子」と呼ばれます。

ヒエラルキーウィンドウ - Unity マニュアル

f:id:hanaaaaaachiru:20190522140129p:plain

この画像を見てみると、Child 1 と Child 2 は Parent の子オブジェクト、
Child 3 は Child 2 の子オブジェクトということになります。

一番シンプルな子オブジェクトに操作を加える方法

一番シンプルな方法は素直に子オブジェクト全てをforeachで探すという手法だと思います。
UnityEngine.Transform - Unity スクリプトリファレンス

using UnityEngine;

public class ChildTest : MonoBehaviour
{
    //操作を加えたい子オブジェクトの親オブジェクトのTransformコンポーネントをインスペクターから選択する
    [SerializeField] private Transform _parentTransform;

    private void Start()
    {
        foreach(Transform childTransform in _parentTransform)
        {
            //全ての子オブジェクトの座標を(0,0,0)にする
            childTransform.position = new Vector3(0, 0, 0);

            //タグが"Enemy"である子オブジェクトを削除する
            if(childTransform.tag == "Enemy")
            {
                Destroy(childTransform.gameObject);
            }
        }
    }
}

ただこの方法では特定の子オブジェクトを選びたいとき、foreach内にif文を用いる必要があります。

なのでネストが深くなり、可読性が悪くなる場合があるかもしれません。

もう一つの方法

GetComponentsInChildren<T>()メソッドを用いることで子オブジェクトの持つ特定のコンポーネントを配列で受け取ることができます

using UnityEngine;

public class ChildTest : MonoBehaviour
{
    //操作を加えたい子オブジェクトの親オブジェクトのTransformコンポーネントをインスペクターから選択する
    [SerializeField] private Transform _parentTransform;

    private void Start()
    {
        //全ての子オブジェクトが持つTransformコンポーネントの参照の配列を取得
        var childTransforms = _parentTransform.GetComponentsInChildren<Transform>();

        foreach(var item in childTransforms)
        {
            //全ての子オブジェクトの座標を(0,0,0)にする
            item.position = new Vector3(0, 0, 0);

            //タグが"Enemy"である子オブジェクトを削除する
            if (item.tag == "Enemy")
            {
                Destroy(item.gameObject);
            }
        }
    }
}

こちらは前と比べて長くなってしまうと感じるかもしれません。

しかし、この方法が優れているところはLINQが使えるところにあると思います。
【Unity】LINQについてかるくまとめてみた - はなちるのマイノート

LINQを組み合わせて使ってみる

特定の子オブジェクトに操作を加えたい場合はこのように書くこともできます。

using UnityEngine;
using System.Linq;      //これを忘れずに追加する

public class ChildTest : MonoBehaviour
{
    //操作を加えたい子オブジェクトの親オブジェクトのTransformコンポーネントをインスペクターから選択する
    [SerializeField] private Transform _parentTransform;

    private void Start()
    {
        //tagが"Enemy"である子オブジェクトのTransformのコレクションを取得
        var childTransforms = _parentTransform.GetComponentsInChildren<Transform>()
            .Where(t => t.tag == "Enemy");

        foreach(var item in childTransforms)
        {
            //タグが"Enemy"である子オブジェクトを削除する
            Destroy(item.gameObject);
        }
    }
}

このようにすることでより柔軟かつ可読性の高いコードを作ることができます。

LINQにはたくさんのメソッド・利点があるので積極的に使うほうが良いかもしれません。

さいごに

2種類の子オブジェクトに操作を加える方法を紹介しました。

全ての子オブジェクトの操作をしたいときは前者、条件つきの子オブジェクトを操作したいときは後者がいいのかな?と思います。