【バイオハザード風のゲームを作ってみよう。その17】
今回も下記動画をやっていきます。
youtu.be
今回はゾンビがプレイヤーを掴む動作を実装していきます。
・下記のアニメーションをmixamoのアニメーションをベースにvery animationで作成しました。
・ゾンビがプレイヤーを掴む動作→mixamoのzombieのhit reactionを改変。
・プレイヤーがゾンビに掴まれ、振り払う動作→mixamoのhit reactionをそのまま使用。
また、2つのアニメーション動作のタイミングを合わせます。
参考動画
youtu.be
・ゾンビの両手にコライダーをアタッチします。
・ゾンビがプレイヤーを追いかけ、距離が近い場合は掴むようにします。掴まれたプレイヤーはこれを振り払う動作をします。
public class ZombieCombatManager : MonoBehaviour //EP17追加 ゾンビにアタッチ { ZombieManager zombie; ZombieGrappleCollider rightHandGrappleCollider; ZombieGrappleCollider leftHandGrappleCollider; private void Awake() { zombie = GetComponent<ZombieManager>(); LoadGrappleColliders(); } //変数rightHandGrappleCollider/leftHandGrappleColliderにゾンビの右手/左手のcolliderを設定 private void LoadGrappleColliders() { ZombieGrappleCollider[] grappleColliders = GetComponentsInChildren<ZombieGrappleCollider>(); foreach(var grappleCollider in grappleColliders) { if (grappleCollider.isRightHandGrappleCollider) { rightHandGrappleCollider = grappleCollider; } else { leftHandGrappleCollider = grappleCollider; } } } //ゾンビ右手/左手のcolliderをONする public void OpenGrappleColliders() { rightHandGrappleCollider.grappleCollider.enabled = true; leftHandGrappleCollider.grappleCollider.enabled = true; //when/if collider contacts player, player is locked into grapple animation //zombie is locked into grapple animation //zombie and player face one another } //ゾンビ右手/左手のcolliderをOFFする public void CloseGrappleColliders() { rightHandGrappleCollider.grappleCollider.enabled = false; leftHandGrappleCollider.grappleCollider.enabled = false; } public void EnableRotationDuringAttack() { zombie.canRotate = true; } public void DisableRotationDuringAttack() { zombie.canRotate = false; } }
public class ZombieGrappleCollider : MonoBehaviour //EP17追加 ゾンビ右手/左手直下のRight Hnad grapple Collider/Left Hnad grapple Colliderにアタッチ { ZombieManager zombie; public Collider grappleCollider; public bool isRightHandGrappleCollider; private void Awake() { zombie = GetComponentInParent<ZombieManager>(); grappleCollider = GetComponent<Collider>(); } //右手/左手にコライダーが接触した場合、実行 private void OnTriggerEnter(Collider other) { //If we grab a collider on the "Player" layer,we proceed if (other.gameObject.layer == LayerMask.NameToLayer("Player")) { PlayerManager player = other.GetComponent<PlayerManager>(); if (player != null) { //if the player is not already performing an action, we proceed if (!player.isPreformingAction) { //Play the zombie's grapple animation, and set their walking movement at 0 zombie.ZombieAnimationManager.PlayGrappleAnimation("Zombie Grapple", true); zombie.animator.SetFloat("Vertical", 0f); //Play the player's grapple animation player.animatorManager.ClearHandIKWeights(); player.animatorManager.PlayAnimation("Player Grapple", true); //Mask the Zombie face it's target ゾンビを掴むターゲット(プレイヤー)方向に向ける Quaternion targetZombieRotation = Quaternion.LookRotation(player.transform.position - zombie.transform.position); zombie.transform.rotation = targetZombieRotation; //Mask the target face Zombie プレイヤーを掴まれたターゲット(ゾンビ)方向に向ける Quaternion targetPlayerRotation = Quaternion.LookRotation(zombie.transform.position - player.transform.position); player.transform.rotation = targetPlayerRotation; //FUTURE TO DO //PLAY DIFFRENT GRABS DEPENDING ON ANGLE OF TARGET //EX:If Zombie is behind the player, allow the zombie to grab player from behind //ROTATE SMOOTHILY OVER TIME IF PLAYER HAS TO ROATE } } } } }
public class ZombieAnimationManager : MonoBehaviour //EP12追加 ゾンビにアタッチ { (省略) //EP17追加 掴む動作を実行 public void PlayGrappleAnimation(string grappleAnimation, bool useRootMotion) { zombie.animator.applyRootMotion = useRootMotion; zombie.isPerformingAction = true; zombie.animator.CrossFade(grappleAnimation, 0.2f); } }
public class ZombieManager : MonoBehaviour //EP8追加 ゾンビオブジェクトにアタッチ { (省略) public bool canRotate; //EP17追加 trueの場合、ゾンビがプレイヤー方向に向くことができる。 }
public class ResetAnimatorBoolZombie : StateMachineBehaviour //EP11追加 ゾンビアニメータのoverrideレイヤーEmptyにアタッチ { // 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) { ZombieManager zombie = animator.GetComponent<ZombieManager>(); if (zombie != null) { zombie.isPerformingAction = false; zombie.canRotate = true; //EP17追加 } } }
public class PurseTargetState : State //EP8追加 ゾンビ直下のstatesオブジェクトにアタッチ { AttackState attackState; //EP10追加 private void Awake() { attackState = GetComponent<AttackState>(); //EP10追加 } public override State Tick(ZombieManager zombieManager) { //if the zombie is being hurt, or is in some action, pause the state if (zombieManager.isPerformingAction) //EP11追加 { RotateTwardsTargetWhilsAttacking(zombieManager); //EP17追加 zombieManager.animator.SetFloat("Vertical", 0f, 0.2f, Time.deltaTime); return this; } // Debug.Log("Running pursue target state"); MoveTowardsCurrentTarget(zombieManager); //EP10追加 RotateTowardsTarget(zombieManager); //EP10追加 if (zombieManager.distanceFromCurrentTarget <= zombieManager.maximumAttackDistance) //EP12追加 { zombieManager.zombieNavmeshAgent.enabled = false; //EP12追加 return attackState; } else { return this; } } private void MoveTowardsCurrentTarget(ZombieManager zombieManager) //EP10追加 { //walkアニメーションに切り替え zombieManager.animator.SetFloat("Vertical", 1f, 0.2f, Time.deltaTime); } //This roration method uses a navmesh agent private void RotateTowardsTarget(ZombieManager zombieManager) //EP10追加 { if (zombieManager.canRotate) //EP17追加 { zombieManager.zombieNavmeshAgent.enabled = true; //移動先に移動開始 zombieManager.zombieNavmeshAgent.SetDestination(zombieManager.currentTarget.transform.position); //ターゲット方向に回転 zombieManager.transform.rotation = Quaternion.Slerp(zombieManager.transform.rotation, zombieManager.zombieNavmeshAgent.transform.rotation, zombieManager.rotationSpeed / Time.deltaTime); } } //This rotation method will blindly rotate towards the target, ignoring collision checks EP17追加 //ゾンビが攻撃モーション中でも方向を変更可能にする。このメソッドが無い場合、ゾンビは攻撃時直進する。 private void RotateTwardsTargetWhilsAttacking(ZombieManager zombieManager) { if(zombieManager.canRotate ) { Vector3 direction = zombieManager.currentTarget.transform.position - zombieManager.transform.position; direction.y = 0; direction.Normalize(); //ゾンビがプレイヤー方向を向いている場合 if(direction== Vector3.zero) { //directionにVector3(0, 0, 1)を設定 direction = zombieManager.transform.forward; } //ゾンビをプレイヤー方向に向ける Quaternion targetRotation = Quaternion.LookRotation(direction); zombieManager.transform.rotation = Quaternion.Slerp(zombieManager.transform.rotation, targetRotation, zombieManager.rotationSpeed * Time.deltaTime); } } }
プレイ動画はこんな感じです。
youtu.be
今回は以上です。