今回は、主人公の攻撃で敵がダメージを受けた時に攻撃を受けた個所によってアニメーションを変更してみます。
アニメーションを変えるだけでなく、与えるダメージの変更機能も同じように追加する事が出来ます。
今回の機能を追加する前に
の記事のように部位によって当たり判定を分けておく必要があります。
当たり判定に使うコライダを設定する
当たり判定に使うコライダを設定します。
上のように部位ごとに空のゲームオブジェクトを作成しHit部位の名前をつけます。それぞれのHit~にはコライダを取り付けます。
今回は上のように当たり判定のコライダを用意しました。
アニメーターコントローラでダメージアニメーションを変更する
次は敵キャラのアニメーターコントローラーを修正します。
上のようにDamage、DamegeRight、DamageLeftを作成します。
Damageは元々あるダメージを受けた時の処理です。
アニメーションパラメータにDamageRightとDamageLeftをTriggerとして作成し、AnyStateからDamegeRight、DamageLeftにTransitionを繋げます。DamageRight、DamageLeftがそれぞれOnになった時に状態遷移するように条件に設定します。
その後に、DamageRight、DamageLeftからIdleにMakeTransitionで遷移を繋げ、条件はなしで、HasExitTimeにチェックを入れます。
Has Exit Timeにチェックが入っているので、アニメーションの再生が終わればIdleに遷移します。
DamageRightとDamageLeftに設定するアニメーションクリップはまったく別物を準備してもいいのですが、例えば体の右側をのけ反るアニメーションがあったならば、それをDamageRightに設定し、DamageLeftにも同じアニメーションを設定して、
上のようにMirrorにチェックを入れます。
そうするとDamageRightに設定したアニメーションとは反対のアニメーションになります。
左右対称のアニメーションにしたい場合はMirrorにチェックを入れれば簡単に出来ます。
これでアニメーターコントローラの修正は終了です。
ダメージ処理メソッド内でダメージアニメーションを振り分ける
次は敵に銃弾が当たった時の処理を修正します。
敵のダメージを受けた時の処理を修正
敵に銃弾が当たった時の処理は敵キャラに設定しているEnemyスクリプトのTakeDamageメソッドで、そこで状態変更メソッドSetStateメソッドを呼び出し、アニメーションパラメータのDamageをトリガーしていました。
1 2 3 4 5 6 | } else if (tempState == EnemyState.Damage) { animator.ResetTrigger("Attack"); animator.SetTrigger ("Damage"); agent.Stop (); |
ここのDamage部分をダメージを受けたコライダのゲームオブジェクト名で判断し分岐させます。
SetStateメソッド内を変更する前にSetStateメソッドを呼び出しているTakeDamageメソッドを変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public void TakeDamage(int damage, Vector3 attackPlace, Transform colTransform = null) { SetState(EnemyState.Damage, colTransform); handCollider.enabled = false; var damageEffectIns = Instantiate<GameObject>(damageEffect); damageEffectIns.transform.position = attackPlace; Destroy(damageEffectIns, 1f); enemyStatus.SetHp(enemyStatus.GetHp() - damage); if (enemyStatus.GetHp() <= 0) { Dead(); } } |
TakeDamageメソッドの第3引数にTransform型のcolTransformを追加します。第3引数に何も渡されなかった時はnullが設定されます。
colTransformは攻撃を受けたコライダのTransform情報を渡します。
SetStateメソッドの呼び出しで第2引数にcolTransformを渡します。
SetStateメソッド内を修正していきます。
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 55 56 | // 敵キャラクターの状態変更メソッド public void SetState(EnemyState tempState, Transform targetObj = null) { if (state == EnemyState.Dead) { return; } state = tempState; velocity = Vector3.zero; if (tempState == EnemyState.Walk) { arrived = false; elapsedTime = 0f; setPosition.SetNextPosition(); navMeshAgent.SetDestination(setPosition.GetDestination()); navMeshAgent.isStopped = false; } else if (tempState == EnemyState.Chase) { // 待機状態から追いかける場合もあるのでOff arrived = false; // 追いかける対象をセット playerTransform = targetObj; navMeshAgent.SetDestination(playerTransform.position); navMeshAgent.isStopped = false; } else if (tempState == EnemyState.Wait) { elapsedTime = 0f; arrived = true; animator.SetFloat("Speed", 0f); } else if (tempState == EnemyState.Attack) { animator.SetFloat("Speed", 0f); animator.SetBool("Attack", true); audioSource.PlayOneShot(attackSound); navMeshAgent.isStopped = true; } else if (tempState == EnemyState.Freeze) { elapsedTime = 0f; animator.SetFloat("Speed", 0f); animator.SetBool("Attack", false); } else if (tempState == EnemyState.Damage) { animator.ResetTrigger("Attack"); if (targetObj.name == "HitRightUpperFoot" || targetObj.name == "HitRightLowerFoot" || targetObj.name == "HitRightUpperArm" || targetObj.name == "HitRightLowerArm") { animator.SetTrigger("DamageRight"); } else if (targetObj.name == "HitLeftUpperFoot" || targetObj.name == "HitLeftLowerFoot" || targetObj.name == "HitLeftUpperArm" || targetObj.name == "HitLeftLowerArm") { animator.SetTrigger("DamageLeft"); } else { animator.SetTrigger("Damage"); } navMeshAgent.isStopped = true; } else if (tempState == EnemyState.Dead) { animator.ResetTrigger("DamageRight"); animator.ResetTrigger("DamageLeft"); animator.ResetTrigger("Damage"); animator.SetTrigger("Dead"); Destroy(this.gameObject, 3f); navMeshAgent.isStopped = true; } } |
EnemyState.Damageの時でSetStateの第2引数で受け取ったTransformのHit~という名前でアニメーションパラメータのトリガーするものを変更しています。
EnemyState.Deadの時はResetTriggerを使ってダメージのトリガーをリセットします。
遠距離攻撃スクリプトの修正
銃を撃った時等に敵の操作スクリプトのTakeDamageメソッドを呼んでいるのでその部分を修正します。
今までの記事をご覧いただいている方はShotスクリプトのJudgeShotメソッド内のTakeDamageメソッドを呼んでいる場所です。
1 2 3 4 5 6 7 8 9 10 11 12 13 | if (Physics.Raycast(ray, out hitPoint, myStatus.GetWeaponStatus().GetWeaponRange(), LayerMask.GetMask("EnemyHit"))) { if (distance > Vector3.Distance(muzzle.position, hitPoint.point)) { var enemyObj = hitPoint.collider.gameObject.transform.root; if (enemyObj.GetComponent<Enemy>().GetState() != Enemy.EnemyState.Dead) { var enemy = enemyObj.GetComponent<Enemy>(); enemy.TakeDamage(myStatus.GetWeaponStatus().GetShotPower(), hitPoint.point, hitPoint.collider.transform); } } } |
敵の操作スクリプトのTakeDamageメソッドを呼んでいる部分で第3引数にヒットしたコライダのTransformを渡しています。
近接攻撃スクリプトの修正
剣などの近接攻撃スクリプトの修正をしていきます。
以前の記事で作ったAttackSwordスクリプトを修正します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using UnityEngine; using System.Collections; public class AttackSword : MonoBehaviour { private MyStatus myStatus; private void Start() { myStatus = transform.root.GetComponent<MyStatus>(); } void OnTriggerEnter(Collider col) { if (col.tag == "EnemyHit") { var enemyScript = col.GetComponentInParent<Enemy>(); if (enemyScript.GetState() != Enemy.EnemyState.Damage && enemyScript.GetState() != Enemy.EnemyState.Dead) { enemyScript.TakeDamage(myStatus.GetAttackPower(), col.ClosestPointOnBounds(transform.position), col.transform); } } } } |
剣が当たった敵のコライダのTransformをTakeDamageの第3引数に渡しています。
近接攻撃でもアニメーションを分ける場合
近接攻撃でもアニメーションを分ける場合はAttackSwordのOnTriggerEnterメソッドで、
SetStateメソッドDeadの修正
最後にEnemyスクリプトのSetStateメソッドのDeadの時の処理を修正します。
1 2 3 4 5 6 7 8 9 10 | public void Dead() { SetState ("dead"); animator.ResetTrigger ("Damage"); animator.ResetTrigger ("DamageRight"); animator.ResetTrigger ("DamageLeft"); animator.SetTrigger("Dead"); Destroy (this.gameObject, 3f); } |
Dead状態になったらDamage系のトリガーをリセットする処理を追加します。
終わりに
出来上がったのでUnityの実行ボタンを押して確認してみましょう。
当たった部位によって敵のダメージアニメーションが変更されました。
今回は3パターンですが、右手と右足をわけたり、前からと後ろからの攻撃でも分けたりと細かく作り込む事も出来ます。