2013年3月6日水曜日

AI開発&クォータニオン入門~4.テキストをカメラの方向に向かせる

関連記事

例のごとく、Unity Gemsからの翻訳をどうぞ!

----------------

http://unitygems.com/quaternions-rotations-part-1-c/
October 14, 2012


テキストをカメラの方向に向かせる


さあ、サンプルゲーム作成をもう一歩進めてみることにする。敵の動作はまだ単純すぎるので AI の要素を加えてみることにする。最初にすることはプレイヤーが近づくまでスリープ状態にすることだ。ここでは、スリープ状態を視覚的に分かるように頭上に Zzzzz とイビキをかいてる様子を描画してみることとする。

チュートリアルのシーン5

ここでは、まず初歩的なFSM (ステートマシン) を各々の敵に追加する。これは  MovementStateMachine に含まれる。
using UnityEngine;
using System.Collections;
 
public class MovementStateMachine : MonoBehaviour {
 
    public bool sleeping = true;
    public Transform sleepingPrefab;
 
    // Use this for initialization
    IEnumerator Start () {
        var t = transform;
        while(true)
        {
            yield return new WaitForSeconds(Random.value * 3f + 2);
            if(sleeping)    
            {
                Instantiate(sleepingPrefab, t.position + Vector3.up * 3f, t.rotation);
            }
        }
    }
}

これで、スリープ状態か判別する単純なステートマシンが得られた。ただし、これだけだとウェイクアップしたときに何も処理が行われない。さらにはウェイクアップさせる条件なども何も決めてない。ただ、それでもアイテムを回転させてカメラの方向に向ける動作は十分に実現出来る。

スクリプトの起動時にコルーチン処理を開始して、もしスリープ状態とスクリプトで判定すれば数秒おきに敵の頭上にプレハブをインスタンス化する。

コルーチンを使用するとき、ローカル変数にコンポーネントをキャッシュする方法があることに注目してほしい。

プレハブそのものは単にテキストメッシュとメッシュレンダラ、時間の経過とともに上昇するようにな」っているスクリプト、シーン1のBasicLookAtPlayer スクリプトから構成される。

テキストを上昇させるスクリプトもまた自明で簡単なものだ。
using UnityEngine;
using System.Collections;

public class GentleRiseAndDestroy : MonoBehaviour {

    public float timeToLive = 2f;
    Transform _transform;

    // Use this for initialization
    void Start () {
        _transform = transform;
        Destroy(gameObject, timeToLive);
    }

    // Update is called once per frame
    void Update () {
        _transform.position += Vector3.up * Time.deltaTime;
    }
}
スクリプトは数秒後にオブジェクトを破棄して、毎フレーム毎にゆっくりとテキストを上昇させる。

期待している動作は Zzzzzz の記号が、カメラの位置に関わらず画面上に表示されることだ。プレイヤーが動くことでテキストの裏側に回り込めるのは論外だ。しかし、ここで解決しないといけない課題がいくつかある。

まず Zzzzzz は逆向きに表示されるが、その理由はUnityによりテキストメッシュの forward がカメラから離れる方向と判断してテキストを左から右へと読めるようにしようとするためだ。

Unity では、オブジェクトの向きに関して変な仕様がいくつかある。Unity で生成した Plane は forward ではなく up に向く。また、テキストメッシュは通常と逆に感じる - forward 方向に向く。

敵に近づいたとき、もう一つの問題に気付くことになるが、Zzzzzz は画面から外の方向に向かない。多くの人がこれで混乱する (私もその一人だった) 。LookAt 関数でカメラに向けたつもりが「何で上手く行かないの?」、と。

Transform ベクトルの修正


LookAt の問題は、実際にはカメラの位置をみていることだ。しかしカメラはワールド座標の固定位置にありながら、それと同時に Focal Area = 焦平面(シャッターの範囲)にある映像が投影される仕組みだ。オブジェクトは自らの位置にもとづいて固定の位置をみているので、カメラによりレンダリングされる位置とズレが生じることを学習する必要がある。

チュートリアル シーン6

このあたり巧いテクニックがある。但しいつでも使えるものではなく次のセクションでは別のアプローチも見ていきたい。transform.forward によりワールド座標でのVector3.forward と同様にオブジェクトの向きを表現できることはご存知のはずだ。意外にも知られていないのは transform.forward をセットしてオブジェクトを回転出来ることだ。

次にやるべきことはカメラの位置を見ることをやめて、テキストメッシュにカメラのFocal Area(焦平面)への向きを定義することだ。

テキストメッシュが反転されてることを覚えてほしい。通常のモデルであれば -transform.forward としないとカメラと逆方向を向いてしまう。
using UnityEngine;
using System.Collections;

public class ReversedCameraDirection : MonoBehaviour {

    Transform _transform;
    Transform _cameraTransform;

    // Use this for initialization
    void Start () {
        _transform = transform;
        _cameraTransform = Camera.main.transform;
    }

    // Update is called once per frame
    void Update () {
        _transform.forward = _cameraTransform.forward;
    }
}
Zzzzz のスリープ状態テキストのプレハブに ReverseCameraDirection を BasicLookAtPlayer の代わりにアタッチすることでようやく準備は万端だ。

transform のベクトルを forward, up, right の方向をセットする機能は強力であり、回転でなくベクトルをベースに考えることが出来て便利だが、注意すべきことがある。これらの値の一つをセットした場合、他のベクトルは制御出来ておらず、ときどきおかしな向きに反転したり回転していることがある。
-------
次に続くぜ!


関連記事

0 件のコメント:

コメントを投稿

ブックマークに追加

このエントリーをはてなブックマークに追加

自己紹介

自分の写真
Unity3D公式マニュアル翻訳やってる人がスマホ(iPhone, Android)のゲーム開発しています。気軽に面白く初心者が遊べる内容がモットー。Blogでは開発情報をひたすら、Twitterではゲーム作成の過程で参考にしている情報を中心につぶやきます

ページビューの合計

過去7日間の人気投稿