【Unity】Animation Riggingでドアを自然に通過させる

投稿者: | 2023-11-26

キャラクターがドアを通るときに、頭や腕が壁を突き抜けることがあります。

Animation Riggingパッケージを使って、ドアを通過するときのアニメーションを動的に編集してみました。

Rigを設定

Animation Riggingでキャラを自然に振り向かせるとは別に空のゲームオブジェクトを作って、Rigコンポーネントを追加します。

キャラクターのルートに追加したRig Builderコンポーネントにアタッチします。

Chain IK Constraint

まずはRigの子として空のゲームオブジェクトを作り、頭と腕のためにChain IK Constraintコンポーネントを付けてみます。

Tipに頭、Rootに脊椎のボーンをアタッチします。このゲームオブジェクトのさらに子としてターゲット用の空のゲームオブジェクトを作り、Targetにアタッチしています。

ターゲットの位置を調節

ターゲットをプレイヤーの顔の前に置きました。

プレイモードでターゲットを動かすと頭から腰までのボーンが付いてきます。

左右にも動かせます。

腕も同様に、体の内側へ動かしました。

トリガー

ドアを通るときだけ、RigのWeightを上げて、ドアを抜けたらWeightを0まで下げます。ドアの前にBoxコライダーのトリガーを置き、敵のスクリプトのOnTriggerEnterとOnTriggerExitでWeightの変更を開始します。

  1. [SerializeField] Rig doorRig;
  2. [SerializeField] float doorRigMaxWeight = 0.538f;
  3.  
  4. IEnumerator IncreaseDoorRig()
  5. {
  6. while (doorRig.weight < doorRigMaxWeight)
  7. {
  8. doorRig.weight += Time.deltaTime;
  9.  
  10. yield return null;
  11. }
  12.  
  13. doorRig.weight = doorRigMaxWeight;
  14. }
  15.  
  16. IEnumerator DecreaseDoorRig()
  17. {
  18. while (doorRig.weight > 0f)
  19. {
  20. doorRig.weight -= Time.deltaTime * 0.8f;
  21.  
  22. yield return null;
  23. }
  24.  
  25. doorRig.weight = 0f;
  26. }

RigやコンストレイントのWeight、ターゲットの位置などで動きを調節できます。

Two Bone IK Constraint

今度は、Two Bone IK Constraintを使ってキャラクターの左手をドア枠に触れさせてみます。同じRigの子として空のゲームオブジェクトを作り「Two Bone IK Constraint」コンポーネントを追加しました。

Tipに左手のボーンをアタッチします。

コンテキストメニューを開いて、「Auto Setup from Tip Transform」をクリックします。

すると、左腕のボーンがアタッチされました。また、コンストレイントの子として、ターゲットとHintのゲームオブジェクトが作られて自動でアタッチされます。

ドア枠の位置に固定するために、ターゲットにはParent Constraintコンポーネントを付けました。ソースはスクリプトで設定します。

元々の左腕のコンストレイントはウェイトを0にしておきます。

ターゲットとヒントを調節

プレイモードでターゲットとヒントの位置や回転を調節しました。ヒントの位置で肘の向きを変えられます。

ターゲットの回転で手の向きを変えられます。

手を置く位置を設定

調節したターゲットの位置に空のゲームオブジェクトを起きます。これはドアのトリガーの子にしました。

トリガーにはスクリプトを付け、手を置くTransformを公開しておきます。

  1. using UnityEngine;
  2.  
  3. public class EnemyDoorTrigger : MonoBehaviour
  4. {
  5. [SerializeField] Transform armIKTarget;
  6. public Transform ArmIKTarget => armIKTarget;
  7. }

キャラクターのスクリプトでは、トリガーにEnter/Exitした時やウェイトが0になったときに、コンストレイントの有効無効を切り替えています。

  1. IEnumerator DecreaseDoorRig()
  2. {
  3. while (doorRig.weight > 0f)
  4. {
  5. doorRig.weight -= Time.deltaTime * 0.8f;
  6.  
  7. yield return null;
  8. }
  9.  
  10. doorRig.weight = 0f;
  11.  
  12. DisableHandPlacementOnDoorframe();
  13. }
  14. protected override void OnTriggerExit(Collider other)
  15. {
  16. base.OnTriggerExit(other);
  17.  
  18. if (other.tag == "DoorTrigger")
  19. {
  20.  
  21. //DisableHandPlacementOnDoorframe();
  22. StopCoroutine("IncreaseFoorRig");
  23. StopCoroutine("DecreaseFoorRig");
  24. StartCoroutine("DecreaseFoorRig");
  25. }
  26. }
  27.  
  28. [SerializeField] ParentConstraint leftArmTarget;
  29.  
  30. void EnableHandPlacementOnDoorframe(Transform target)
  31. {
  32. // ソースを作成
  33. var source = new ConstraintSource();
  34. source.sourceTransform = target;
  35. source.weight = 1f;
  36.  
  37. // 左腕のParentコンストレイントにソースを追加
  38. leftArmTarget.AddSource(source);
  39.  
  40. // コンストレイントを有効にする。
  41. leftArmTarget.constraintActive = true;
  42. }
  43.  
  44. void DisableHandPlacementOnDoorframe()
  45. {
  46. // ソースを削除
  47. leftArmTarget.RemoveSource(0);
  48.  
  49. // コンストレイントを無効にする
  50. leftArmTarget.constraintActive = false;
  51.  
  52. }

コメントを残す

メールアドレスが公開されることはありません。