すっかりご無沙汰していましたがトラックバックをつけてもらいました オブジェクトの非表示を
子供だけに行いたいということらしかったのですが 説明が不足してました
ゲームオブジェクトの親子の操作方法についてお話しします。
var object:GameObject = gameObject.find("オブジェクトネーム")
これは ゲームオブジェクトを取得することができます。
objectの階層下の子供を取得したい場合は
transform.Find("子供の名前")を使用します。
階層が深い場合は
transform.Find( 直下の子供の名前/・・ /取得したい子の名前)というように
ツリー構造をファイル操作のディレクトリと同じように記述します。
例)
function Update() {
aFinger = transform.Find("LeftShoulder/Arm/Hand/Finger");
aFingerに対する実行文
}
指定オブジェクトに操作をおこなうときはgameObject .transform.Find()のように 指定するゲームオブジェクトの後につづけて記述します。
で 問題の点ですがGameObjectを消さないで操作を行いたいという点です。
gameObject.SetActiveRecursively(false);
を使用するとgameObjectの階層は全て消えてしまいますので次回から
Findでのサーチができなくなるという点です
そこでtransformの下にはgameObject自分本体の指定が格納されているということを利用して
transform.gameObject.SetActiveRecursively(false);
を使用したらよいのではということですね これでも問題ないと思います。
わたしの場合は高速化のためにゲーム中で低速なFind関数を使用せずにstart()の中で一度
var Player:GameObject;
start(){
Player = GameObject.Find("player");
Player.SetActiveRecursively(false);
}
として表示の時は
Player.SetActiveRecursively(true);
というように変数に一旦格納して表示させるのでこのような問題にあったことがありませんでした。
ほかにもプレファブを使用する場合は
var prefab:GameObject;
var object:GameObject = Instansiate(prefab,transform.position,transform.rotation);
objectはプレファブのコピーです
などというように 一度配列や変数にとってしまったほうが効率よくスクリプトかけるような気がします。
注)SetActiveRecursively()はRendererがコンポーネント登録されていないと機能しません。
注目点はTransform型はGameObject型の代わりに使用することができて
transform.gameObject と gameObject(this.gameObject)
が同じものを示しているというところです。
よくUnityのスクリプトでvarにモデルを登録するのがGameObjectではなくTransformだったりするのはtransform.gameObjectで代用できるからなのですね。
ゲームオブジェクトのtransformの下にはrootやparentといった階層のルート(一番上の階層)のtransformや親階層(階層の一つ上)のtransformが格納されています。
例えば transform.parent = transform
とすれば 親子構造を作ることができます。この場合transformはゲームオブジェクトの自分自身です
親から切り離されたいときは transform.parent = null;
としてやればよいです。
他にも例えば 子を破壊せずに切り離したいときはTransform.DetachChildrenを用いて
transform.DetachChildren();
Destroy(gameObject);
のようにします。 これは公式のFPSチュートリアルでロケットランチャーから爆発前にトレイル煙を切り離す部分に使用されています。
■子の検索
子の検索はGetComponentInChildren()を使用して
var allChildren:Transform[] = gameObject.GetComponentsInChildren(Transform);
for (var child : Transform in allChildren) {
実行文
}
のように行います。allChildrenはTransformの配列型指定である点に注意してください。
何度も呼び出されるこのような実行部分はstatic関数にしてしまうと効率が良いです。
例)
static function FindTransform(parent:Transform, name:String)
{
if (parent.name == name ) return parent;
for (var child in parent)
{
result:Transform = FindTransform(child, name);
if (result != null) return result;
}
return null;
}
そして例えば子だけを削除してしまいたい場合は
for(var child in allChildren) Destroy(child);
Destroy()文をかえれば
スクリプト系の場合
child.active = false;
または
Rendererなど表示系の場合
child.enabled = false;
万能な非表示系
child.SetActiveRecursively(false);
というように子を非表示にすることが出来ます。
ここでallChildrenは配列型ですが Transform型かGameObject型かで書き方を
変えなければいけません。
例)
var allChildren:Transform[];
allChidren = gameObject.GetComponentsInChildren(Transform);
for (var child in allChildren)
{
Destroy(child.gameObject);
}
この場合Transform型でallChildrenに登録していますので child=子 はTransform型なので.gameObjectをつけてオブジェクト本体を指定します。
その他
■タグのチェンジ
ゲームオブジェクトのタグを変更する場合。インスペクタに
登録されているタグを付け替えることができます。
gameObject.tag = "Player";
または
transform.gameObject.tag = "Player";
など 同じオブジェクトを用いて敵と自機を分けたいときなどに使用出来ます。
■レイヤーチェンジ
例)
function ChangeLayersRecursively(var trans : Transform, var name : String)
{
for (var child : Transform in trans)
{
child.gameObject.layer = LayerMask.NameToLayer(name);
ChangeLayersRecursively(child, name);
}
}
この例のスクリプトをどこで見たのか忘れてしまいましたがLayerMask.NameToLayerを使用してオブジェクトのレイヤーも変更することができます。
この例ではtransのに子のTransformをいれてレイヤーの名前をnameにいれて
コールするとレイヤーを変更します。for文の中で再帰的な呼び出し(関数が自分自身を呼び出すこと)をしています。
ということでした。久しぶりの記事なのでちょっとボリュームたりませんでしたかね?
記事の文中おそらく間違えているところも色々あると思いますので指摘していただいてかまいませんよー。
ちなみにどこかのブログで現役プログラマーと紹介されていましたが わたしCGデザイナーです。
あとこのブログはライブドアのテンプレートで書いているのですがフォントサイズが小さいという指摘を
以前受けました。現在たいていのブラウザは ctrl+”+” で記事を拡大することができますので試してみてくださいね。