今回は記事の修正をしていて気付いた事を新しく記事として作成することにしました。
以前の記事で主人公が敵キャラを攻撃出来る機能を作成しました。

主人公に装備させた剣のコライダのオン・オフはアニメーションイベントを使って行っていましたが、
例えば主人公が攻撃中に敵から攻撃を受けた場合に、すぐさま主人公のダメージアニメーションへと遷移させていると主人公の攻撃アニメーションの攻撃終了のアニメーションイベントが再生されず、実行されない事がありました。
そこで今回はアニメーションイベントが実行されない時を考慮してビヘイビアを設定し、それに対応出来るようにします。
ビヘイビアとは
ビヘイビアはアニメーターコントローラーの状態に設定出来るスクリプトで、Animatorの状態等を変更する時に使用すると便利です。

アニメーションイベント受け取りスクリプトの修正
主人公キャラクターのアニメーションイベント受け取りスクリプトはProcessMyAttackとしていたのでまずはこちらを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | using UnityEngine; using System.Collections; public class ProcessMyAttack : MonoBehaviour { private Player player; [SerializeField] private Collider weaponCollider; // 装備品の親のTransform [SerializeField] private Transform equip; private AudioSource audioSource; [SerializeField] private AudioClip attackSound; void Start () { player = GetComponent<Player>(); weaponCollider = equip.GetComponentInChildren <Collider>(); audioSource = GetComponent <AudioSource> (); } void AttackStart() { if (weaponCollider != null) { weaponCollider.enabled = true; if (equip.GetChild (0).CompareTag ("Sword")) { audioSource.PlayOneShot (attackSound); } } } public void AttackEnd() { if (weaponCollider != null) { weaponCollider.enabled = false; } } void StateEnd() { player.SetState(Player.MyState.Normal); } void EndDamage() { player.SetState(Player.MyState.Normal); } public void SetCollider(Collider col) { weaponCollider = col; } public void ReadyShot() { player.SetReadyShot (); } } |
ProcessMyAttackは↑のようになっていて、コライダのオフをしているのはAttackEndメソッドなので、外部スクリプトから呼び出せるようにアクセス修飾子をpublicにします。
主人公用のビヘイビアの作成
主人公のアニメーターコントローラーのAttack状態を選択し、インスペクタでAdd Behaviourを押します。
そこでPlayerAttackStateBehaviourという名前のビヘイビアスクリプトを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | using UnityEngine; using System.Collections; public class PlayerAttackStateBehaviour : StateMachineBehaviour { private ProcessMyAttack processMyAttack; // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state //override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks //override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateExit is called when a transition ends and the state machine finishes evaluating this state override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { if (processMyAttack == null) { processMyAttack = animator.transform.GetComponent <ProcessMyAttack> (); } // アタック状態を抜け出す時に武器のコライダも無効化する processMyAttack.AttackEnd (); } // OnStateMove is called right after Animator.OnAnimatorMove(). Code that processes and affects root motion should be implemented here //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateIK is called right after Animator.OnAnimatorIK(). Code that sets up animation IK (inverse kinematics) should be implemented here. //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} } |
ProcessMyAttackを保持するフィールドを作成し、OnStateExitメソッド内でanimatorから取得します。
OnStateExitメソッドはこの状態を抜けた時に呼ばれるので、その時にprocessMyAttack.AttackEnd()を実行し、攻撃用コライダのオフを強制します。
主人公の攻撃アニメーションを分けている場合はそれらの状態にもPlayerAttackStateBehaviourを取り付けます。
敵キャラ用のビヘイビアを作成
敵キャラのAttack状態も主人公と同じように作成しますが、敵キャラ用のアニメーションイベント受け取りスクリプトはProcessAttackとしていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | using UnityEngine; using System.Collections; public class ProcessAttack : MonoBehaviour { private Enemy enemy; [SerializeField] private SphereCollider sphereCollider; void Start () { enemy = GetComponent<Enemy>(); } void AttackStart() { sphereCollider.enabled = true; } public void AttackEnd() { sphereCollider.enabled = false; } public void StateEnd() { enemy.SetState ("freeze"); } public void EndDamage() { enemy.SetState("walk"); } } |
攻撃状態に関しては主人公と同じなので敵のAttack状態用のビヘイビアは割愛します。
敵がダメージを受けた後EndDamageのアニメーションイベントを受け取り状態をEnemyState.Walk状態へと遷移させていますが、Damage状態に設定したアニメーションの最後にEndDamageアニメーションイベントを作成せず、ビヘイビアを取り付けてEndDamageメソッドを呼び出すようにする事も出来ます。
ProcessAttackのEndDamageメソッドのアクセス修飾子にpublicを付けます。
敵のDamage状態にEnemyDamageStateBehaviourを作成し取り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | using UnityEngine; using System.Collections; public class EnemyDamageStateBehaviour : StateMachineBehaviour { private ProcessAttack processAttack; // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state //override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks //override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateExit is called when a transition ends and the state machine finishes evaluating this state override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { if (processAttack == null) { processAttack = animator.transform.GetComponent <ProcessAttack> (); } processAttack.EndDamage (); } // OnStateMove is called right after Animator.OnAnimatorMove(). Code that processes and affects root motion should be implemented here //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} // OnStateIK is called right after Animator.OnAnimatorIK(). Code that sets up animation IK (inverse kinematics) should be implemented here. //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // //} } |
アニメーションイベントのEndDamageはアニメーションの最後にイベントを発生させているだけなので、ビヘイビアを使った方がアニメーションイベントを取り付ける必要もなく、
元のアニメーションを他のキャラクターと共有する場合にアニメーションイベントの受け取りスクリプトを用意しなくてもよくなるので便利かもしれません。
主人公のDamage状態も同じような感じで作成出来ます。
終わりに
アニメーションイベントは便利ですが、アニメーションが最後まで再生されないような時はイベントが発生しないので、こういった対処が必要になりますね。
知らないうちに敵がバッタバッタと倒れたのでなんでだろう?と思ったんですが、剣のコライダがずっと有効になってたんですね。
(^_^;)