Hatena::ブログ(Diary)

Ideals and Reality このページをアンテナに追加 RSSフィード Twitter

2012-08-10

Unityの核であるMonoBehaviourについて

Unityを使っている人なら誰でも見たことがあるであろう、MonoBehaviorクラス。

巷ではMonoBehaviourを使うとC#の機能が使えなくなるとか、コードビハインド出来なくてMVCモデル的な作りが出来ないとか、極力MonoBehaviourは使うな!とまで言われたりしています。

私は逆にUnityを使うのにMonoBehaviourを使わないなんてとんでもない!と思っています。

と、いうかMonoBehaviourを使うことがUnityを使う一番の理由になると思ってるくらいに。

その潜在能力の高さを1度知ってしまうと使わないなんて考えられなくなってしまいます。


1.MonoBehaviourの持つコルーチンが超強力

これもう本当に強力。

おもむろに

yield return 0;

と書けばそのフレームの処理をそこで終了し、次のフレームはそこから処理を再開するのである。

yield return new WaitForSeconds(1f);

と書けばなんと処理を終了し一秒後にはそこから処理を再開してくれるというのが簡単に書ける。

これを使えば非同期処理は簡単に書けるし、何かを待ってステート進行させるというのが一瞬で出来てしまう。

スタートしたコルーチンは簡単に止めることも出来るので、コルーチン中でも対応が出来る。

ここらへんはもう誰でも使っているようなレベルだろう。

が、Unityのコルーチンの強力さはそれだけではない。

本来UnityのコルーチンはMonoBehaviourのUpdate()関数内では使えないが、実はStart()関数無限ループしつつyieldを実行するとUpdate()内で実質的に同じことをやっているようなことが出来る。

http://answers.unity3d.com/questions/8908/is-function-update-short-for-function-start-whilet.html


void Start()
{
	while (true) {
		// 毎フレーム行う処理
		yield;
	}
}

こんな反則技がよく許されたもんだと思いつつもこれでAIのステート管理が超絶的なまでに楽になる。

実際このテクを使ってAIを記述しているケースも多いようだ。


2.OnXxxXxx系のコールバックで各種処理のフックが超簡単

例えばマウスでクリックされたという情報がとりたければOnMouseDown()を呼び出せばそれだけでマウスボタンのイベントが処理出来る。

このコールバックイベントはマウスだけでなくあらゆるものに対応しており、コリジョンのヒット時判定、レンダラーの描画ONOFF時、新しいシーンが読み込まれた時、描画が完了した時など、あらゆる状況で呼ばれる。

これがあるおかげであらゆる状況で処理をフックさせることが出来る。

実際にゲームを作っていると、「あの状況で処理を割り込ませたい…」という状況は多々発生する。

もちろん全てのケースに対応しているということはないだろうが、ほぼ大抵の状況に対応するほどの量は用意されている。

特にカメラ描画内に存在しているかいないかというのは非常に重要でAIの動きの制御や描画の最適化にも使用されるので知っておいて損はない。


3.MonoBehaviourが持つメッセージ機能が超汎用的

SendMessage("FuncName")というような具合で、MonoBehaviourが持つGameObject全体にFuncName()という名前の関数があれば呼び出すことが出来る。

これはそのGameObjectに対象となるスクリプトがアタッチされている必要があるが、やりようによってはかなり汎用的なことが出来る。

これだけならまぁありがちな感じがするが、Unityアニメーションエディターとアニメーションイベントを使ったメッセージが凄い。

UnityアニメーションエディターはGUIで編集する汎用的なものですが、ここで起きるアニメーションイベントにMonoBehaviourのスクリプトがアタッチ出来る。

ここであらかじめGameObjectのヒエラルキー上に位置情報を示すロケーターObjectを配置しておき、イベントが起きた際に

Transform[] transArray = gameObject.GetComponentsInChildren<Transform>();
foreach (Transform trans in transArray) {
	if (trans.name == eventNameString) {
		PlayEffectEvent(eventNameString, trans);
	}
}

上記のようなコードが呼ばれるようにしておく。

次は各GameObjectが持つTransformを取得し、GameObjectにはあらかじめ発生させたいイベント名などをつけておく。

そしてイベント発生時のMessage関数にそのイベント名の文字列を渡しておき、特定のアニメーションクリップに対して指定したタイミングでこの位置に対して汎用的なイベントを起こすということが出来る。

上記の方法では特定の位置のGameObject Transformの名前がイベント名文字列と一致した場合はその位置に対してエフェクトを発生させるというイベントを発生させている。

これはあらゆるものに応用が可能であり、エフェクトだけではなく、SE、カットシーン演出でのカメラ移動やAIアニメーションベースにステート管理させるといったことが簡単に出来るようになる。

ぶっちゃけこの仕組みだけでゲームの動きと演出と制御がかなり出来てしまう。

それくらいに恐しい仕組みであることは間違いない。


4.MonoBehaviourに揃っているコンポーネントたちが超豊富

MonoBehaviourはTransformなど当然のようなコンポーネントを持っているが、それ以外にも剛体物理を実現するrigidbody、カメラ制御をするcamera、ライト担当のlight、音担当のaudio、コリジョン担当のcolliderなどなど実に豊富なコンポーネントがアタッチ出来る。

これらはGetComponent()を使えばどこでも取得出来るし、自身がGameObjectであるのならAddComponet()でいつでも追加も出来る。

もちろん全部のコンポーネントを使うことは間違いなくないが、いつでもそれらを使うことが出来るのがMonoBehaviourの魅力であることは間違いない。

Unityコンポーネント指向という考え方はMonoBehaviourをベースに作られているということでMonoBehaviourの重要さがわかったのではないかと思う。

とはいえこれでもまだMonoBehaviourの魅力としては一部だと思っているし、私自身もまだまだ色々なことが応用出来るのではないかと思っています。

コルーチンと各種コールバック、メッセージなどは全て混ぜて使うことも出来るし、応用すればもっと凄いことが簡単に出来るはずです。

これで少しでもMonoBehaviourを「もっと使ってみたい!」と思ってもらえれば光栄だし、「もっとこんな使い方してる!」とかあればぜひ教えてください。


追記

改めてみても説明がわかりにくい。

そしてUnityの説明はコードや文章だけでは伝えにくいですね…

動画とか撮るべきなんだろうか。

           2014/07/01 05:26 全然。わかりやすいですよ
助かりました

aaaa 2014/12/18 22:35 3.がよくわかりませんでしたが、大変参考になりました。
ありがたいです。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

リンク元