今シリーズの最終回。例のごとく、Unity Gemsからの翻訳をどうぞ!
----------------
http://unitygems.com/quaternions-rotations-part-1-c/
October 14, 2012
コルーチンを使用してアニメショーンを待機する
すでに範囲内にあれば攻撃のコルーチンが開始される。
ここで実現したいことは通常の動作をポーズさせて、攻撃アニメショーンを再生してアニメショーンが半分進んだところで、攻撃がヒットしてダメージを適用することだ。次の方法でこれを実現する:
最初に - ルーチンをより便利なものとするため、Attack をコールしたときに敵をウェイクアップするようにする。これは敵同士で衝突した時も Attack をトリガー出来るので便利だ。
IEnumerator Attack(Transform victim) { sleeping = false; _busy = true; target = victim; _attack.enabled = true; _attack.time = 0; _attack.weight = 1; //Wait for half way through the animation yield return StartCoroutine(WaitForAnimation(_attack, 0.5f)); // 範囲内にまだいるかチェック if(victim && (victim.position - _transform.position).sqrMagnitude < _maximumAttackEffectRangeSquared) { // ダメージを適用 victim.SendMessage("TakeDamage", 1 + Random.value * 5, SendMessageOptions.DontRequireReceiver); } // アニメショーン終了を待機 yield return StartCoroutine(WaitForAnimation(_attack, 1f)); _attack.weight = 0; _busy = false; }_busy = true とセットすることでルーチンを実行している間はUpdateを無効にする。 _attack はこちらで有効化して制御するアニメショーンであり、最初にセットして、重み付けの weight = 1 とする。これでアニメショーンが再生開始される。次が素晴らしいところだが、アニメショーンをモニタリングする新しいコルーチンを実行して、半分まで完了するのを待機する。ルーチンはこの後に見ていく。
アニメショーンが 50% 完了すると、攻撃した被害者 (victim) がすでに死亡してないかチェックして、まだ範囲内にいるか、さらにはそれらの条件が満たされてる場合はTakeDamage メッセージを渡してランダムな量のダメージが反映される。
次にアニメショーン終了を待機してから busy ステータスを外して、アニメショーンを無効化する。
このアニメショーンを待機するコルーチンについて見ていこう。
public static IEnumerator WaitForAnimation(AnimationState state, float ratio) { state.wrapMode = WrapMode.ClampForever; state.enabled = true; state.speed = state.speed == 0 ? 1 : state.speed; while(state.normalizedTime < ratio-float.Epsilon) { yield return null; } }見ての通りかなり簡単だ。最初にアニメショーンがループやリセットしないようにする。セットしないと、終了のところを逃がすことがあるためだ。さらに enabled を true にセットし、speed がゼロとなることを確実にして、ルーチンが終わらないような不具合に陥らないようにあらかじめ手当てする。
次にループは .normalizedTime を待機して渡した値より大きいか等しくなるまで待機する。(浮動小数点の誤差を吸収する係数)
様々なステート
これで攻撃およびダメージのメッセージを送信出来るようになったため、メッセージをハンドリングする方法を見ていく。このデモでプレイヤーは無敵だが、敵同士はダメージを与えることができる。
敵キャラは TakeDamage を受け取ると次の動作を行う。
void TakeDamage(float amount) { StopCoroutine("Attack"); health -= amount; if(health < 0) StartCoroutine(Die()); else StartCoroutine(Hit()); }まずは現在の攻撃は全て取り止めて、ダメージを与えて、Hit または Die コルーチンのどちらかを開始する。
IEnumerator Die() { _busy = true; _animation.Stop(); yield return StartCoroutine(PlayAnimation(_die)); Destroy(gameObject); } IEnumerator Hit() { _busy = true; _animation.Stop(); yield return StartCoroutine(PlayAnimation(_hit)); _busy = false; }両方のコルーチンはアニメショーン終了まで再生し、Die はオブジェクトを破棄して、Hit はそれを再び有効化する。
さて、ようやくこれでこのチュートリアルは終わりまで一息だ。RotateToFaceTargetは初期に作成した回転スクリプトを置き換え、常にプレイヤーをみるのではなくターゲットの位置をみるようにするので、内容は良くみてほしい。この仕組みによって敵同士がターゲットとなりえる。他に注目すべきは WalkingAnimationだ:
using UnityEngine; using System.Collections; public class WalkingAnimation : MonoBehaviour { Transform _transform; Vector3 _lastPosition; AnimationState _walk; public float minimumDistance = 0.01f; // Use this for initialization void Start () { _transform = transform; _lastPosition = _transform.position; _walk = animation["walk"]; _walk.layer = 2; } // Update is called once per frame void Update () { var moved = (_transform.position - _lastPosition).magnitude; _lastPosition = _transform.position; if(moved < minimumDistance) { _walk.weight = 0; } else { _walk.weight = moved * 100; _walk.enabled = true; _walk.speed = 1; } } }このスクリプトは敵が移動する速度にもとづいて歩行アニメショーンをブレンドする。
最後に
このチュートリアルご役立ったならば何よりだ。コメントを残すのは自由で、他にもどんな機能を紹介したら良いかなどもコメントあると有難い。
Mike(whydoidoit)氏
-----------
今シリーズはいかがだっただろうか。筆者自身はUnity Gemsから色んなことを学べて感謝しているが、やはりプロジェクトサンプルをもとに自分のアイデアを加えて色々なテストをしてみるのがベストだとおもう。
今年はUnityは日本語情報も充実してきているぜ!
今年はUnityは日本語情報も充実してきているぜ!
0 件のコメント:
コメントを投稿