しかし、もしアクセスするオブジェクトが子要素だったり、あるいは親要素であったりする場合、敢えてすべてのオブジェクトから検索をかける“GameObject.Find”よりも、親子関係から辿れることができればより処理の軽いプログラムになるのではないか?
と考えるのはプログラマーとして自然なことかと思います。
今回は親子関係を辿ることで、"GameObject.Find"よりも軽い処理にできるプログラムのご紹介です。
環境について
Unityバージョン:2019.4.18f1
Visual Studio Community 2019バージョン:16.9.1
親から子へのアクセス
親から子へアクセスするプログラムは私の知る限り二通りあります。
おすすめは一番目に紹介する"transform.Find"ですね!
transform.Find("string name")
みてわかる通り、Findを使ってますから、もうぱっと見で使い方がおわかりになるのではないでしょうか。
例として、こんな感じでUnityの2DオブジェクトのSpriteを配置してみました。"transform.Find"を使って、スクリプトからアクセスしてSpriteの色を変えてみます。
Testにアタッチしたスクリプトで、子オブジェクトのExamや孫オブジェクトのTrialの色を変えようとすれば、こんな感じです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestControll : MonoBehaviour
{
void Start()
{
transform.Find("Exam").GetComponent<SpriteRenderer>().color = Color.red;
transform.Find("Exam/Trial").GetComponent<SpriteRenderer>().color = Color.white;
}
注目すべきは、Trialにアクセスするときの"/"でしょうか。
これ実は、いけちゃうんですよね。Unityを勉強し始めたばっかりだと思いつきもしないと思うんですが…(ちなみに私も思いつかなかった…)
例には孫オブジェクトまでしか出してませんが、そのさらに下、ひ孫オブジェクトのNew Spriteにアクセスするのも、同様にできますよね。いやー、"transform.Find"便利!
transform.GetChild(int index)
子オブジェクトにアクセスしよう、と考えて検索をかけて、"transform.GetChild"にぶちあたった人は多いのではないでしょうか。
ぶっちゃけますと、こいつは先にあげた"transform.Find"より使いにくいです。物は試し、先ほどあげた例と同じ動作をするスクリプトを、"transform.GetChild"を使って作ってみましょう。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestControll : MonoBehaviour
{
void Start()
{
transform.GetChild(0).GetComponent<SpriteRenderer>().color = Color.red;
transform.GetChild(0).GetChild(0).GetComponent<SpriteRenderer>().color = Color.white;
}
こんな感じです。
まず、GetChildの後に続く数字ですけど、これはアクセスしたい子オブジェクトが、他の子要素と比して上から何番目なのかという数字でして、これを必ず記入する必要があります。
例えばTestオブジェクトの子オブジェクトの中で、Examオブジェクトは0番目だから、カッコのなかに0を入れます。C#は配列でもそうですが、だいたい集団の中の一番目は「0番目」とするので、まぁこれに違和感はないですかね…?
もしExamオブジェクトの下にもう一個、Testオブジェクトの子であるオブジェクトがあった場合、そのオブジェクトをアクセスしたい時は"GetChild(1)"ですね。
そして孫オブジェクトにアクセスしたい時の"GetChild"の使い方ですが、上のスクリプトは一番略した形で書いてあります。正しくは
transform.GetChild(0).gameObject.transform.GetChild(0).gameObject.GetComponent<SpriteRenderer>().color = Color.white;
ですね!なっがっ…!
まぁ省略形の方で考えるにしても、"GetChild"を何度も書かなければいけないのは普通に苦痛ですね…。
目次にもチラッと書きましたが、基本的には最初に紹介した"transform.Find"の方が使いやすいかと思います。
しかし"transform.Find"は"Find"の特性上、オブジェクトの名前を変えてしまうとアクセスできなくなるので、時と場合により"GetChild"でしょうか…?
…いや、"GetChild"だってオブジェクトの配置の順番を変えればエラーになるわけで、オブジェクトの配置順の変更とオブジェクトの名前変更を天秤にかければ、あきらかに後者の方が頻度が少ないだろうし…。"GetChild"はいらない子では…?
まぁ、"transform.Find"を使うにしても、"transform.GetChild"を使うにしても、それぞれ将来的にエラーを吐き出すかもしれないリスクを知ったうえで使うべきですね。
もしオブジェクトの名前を変更するかもしれない、オブジェクトの配置順も変えるかも、でもエラーは嫌!!って方がいたら、[SerializeField]しかもう手がないかなぁ。
オブジェクトをドラッグ&ドロップしないとエラーになるので、忘れん坊な私は極力使わないようにしておりますが、この辺は個人の裁量ですね。
ここまでが、親子関係のオブジェクトで、親から子へアクセスする方法のご紹介でした。
子から親へのアクセス
では逆方向、子オブジェクトにアタッチしたスクリプトから親オブジェクトへアクセスする方法ですね。
親から子へのアクセスは"transform.Find"が便利だったのですが、これに匹敵するようなアクセスの方法が残念ながら逆方向ではないようです。
いちおう、紹介しましょう。
transform.parent
先ほどの例でまたスクリプトを書いてみると、こんな感じになります。
このスクリプトを一番下の"New Sprite"にアタッチすると、今までと同様に色が変わるはずです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestControll : MonoBehaviour
{
void Start()
{
transform.parent.GetComponent<SpriteRenderer>().color = Color.white;
transform.parent.parent.GetComponent<SpriteRenderer>().color = Color.red;
}
"transform.parent"は先に出た"transform.GetChild"と同じで、正しくは"transform.parent.gameObject"が正しい形のようなんですが、もう面倒なので省略して書きました!
まぁ、そうですね。"transform.parent"は後のカッコに数字をいれるとか、そういう工程が不要な分、"transform.GetChild"よりは使いやすい印象でしょうか。
しかし、"transform.GetChild"でも出た問題、こちらは"parent"を何度も書かなければいけない問題が依然として発生するようです。
一個上の親ならまだしも、三つ上、四つ上の親オブジェクトをこれで取得するのは、ただただ面倒で長いスクリプトになりそうです。
transform.root
これは少し特殊なアクセスの方法となります。
またまた同じ例で、スクリプトを書いてみます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestControll : MonoBehaviour
{
void Start()
{
transform.root.GetComponent<SpriteRenderer>().color = Color.red;
}
こんな感じで使うのですが、これで色が変わるSpriteは一番上の"Test"になります。
"New Sprite"にアタッチしたスクリプトから、"Trial","Exam"通り越して"Test"にアクセスするというわけです。
これは形も短いので、便利かもしれません。
ただ使うか、と言われると私は微妙かな…。
以上が、親子関係のオブジェクトで、子から親へアクセスする方法のご紹介でした。
最後に
親子関係を辿ってオブジェクトにアクセスする、というのは悪い考え方ではないと思います。
しかし実用とするとなると、親オブジェクトで一括管理して、"transform.Find"を使う方が明瞭なのかな、というのが私の所感です。
皆さんのお役に立てたら幸いです~。
ではまた。
0 件のコメント:
コメントを投稿