2011年11月10日

うにばな (講座みたいなもの 第五回)


すっかりご無沙汰していましたがトラックバックをつけてもらいました オブジェクトの非表示を
子供だけに行いたいということらしかったのですが 説明が不足してました
ゲームオブジェクトの親子の操作方法についてお話しします。

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+”+” で記事を拡大することができますので試してみてくださいね。

akinow at 18:48│Comments(4)TrackBack(0) Clip to Evernote シリーズ講座 | Unity3d

トラックバックURL

この記事へのコメント

1. Posted by える   2011年11月10日 23:28
いつも「うにばな」で勉強させてもらってます。文系の学生ながら四苦八苦しながら独学でjavascriptを終えたばかりで、次に何をどう組めば良いのかがまったく分からず……。
UniScriptという言葉があるように、どういった手順で、ぶぎょうさんはスクリプトのノウハウを得たんでしょうか?
2. Posted by ジュンキ   2011年11月11日 02:04
5 はじめまして。トラックバックさせていただいたジュンキというものです。
丁寧な解説ありがとうございました。さらにSetActiveRecursively()周りの理解が深まりました。
Unityは素晴らしいツールですが、ハマりポイントもあるので、実戦的なぶぎょうさんのブログはかなり参考にさせていただいています。
今回の記事でもTransform型はGameObject型の代わりにできるくだりやタグのチェンジの話は非常に参考になりました(特にタグの話は手法としては簡単ながら全く気づいてなかったので目からウロコでした)。
お忙しいとは思いますが、次の講座も楽しみにしております。
3. Posted by ぶぎょう17   2011年11月11日 03:39
えるさん>こんにちは コメントありがとうございます。
私がjavaとC#を憶え始めたのが去年の春頃なのですが、とにかく最初はチュートリアルや配布されている
ソースの解析をしました。その後にいきなりおおきなストライクウィッチのゲームを組みだしたのですが
そこでゲーム制作に必要なものだけをネットで(英語ですが)調べてスクリプトを書いて試すということを
繰り返しつつ今日に至る感じです。 
よくチュートリアルで単純なゲームを何本も載せている本などがありますが、小さな山に何度も登っても
大きな山に登れる保証はないというか無理です、逆に一度大きな山に登る経験をしてしまえば 小さな山は簡単に登れます。
ゲーム会社でいきなり大きなプロジェクトに新人を組み入れますが、要はそういうことだと思います。
長い冒険を終えたほうがそれが失敗であれ得られる経験値は大きいということです。がんばってみてください。
4. Posted by ぶぎょう17   2011年11月11日 03:48
ジュンキさん>はじめまして コメントありがとうございます。
トラックバックありがとうございました。Unityは簡単そうに見せかけていますが、意外に難しい部分がありますよねw
講座っぽいものを開いていますが やはり毎回悩みどころは どこがわからないかが人によって違う点ですね。
なので完全な解説というわけにはいかないのですが そこから調べていただければ解法は見つかると思います。
次の記事もなるべく早めに書く予定ですが、 そろそろデザイナーらしく絵作りの講座みたいなものも載せようかなあ
と考えています。 あまり期待しないで待っていてくださいw 

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔