キャラクターがドアを通るときに、頭や腕が壁を突き抜けることがあります。
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の変更を開始します。
[SerializeField] Rig doorRig;
[SerializeField] float doorRigMaxWeight = 0.538f;
IEnumerator IncreaseDoorRig()
{
    while (doorRig.weight < doorRigMaxWeight)
    {
        doorRig.weight += Time.deltaTime;
        yield return null;
    }
    doorRig.weight = doorRigMaxWeight;
}
IEnumerator DecreaseDoorRig()
{
    while (doorRig.weight > 0f)
    {
        doorRig.weight -= Time.deltaTime * 0.8f;
        yield return null;
    }
    doorRig.weight = 0f;
}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を公開しておきます。
using UnityEngine;
public class EnemyDoorTrigger : MonoBehaviour
{
    [SerializeField] Transform armIKTarget;
    public Transform ArmIKTarget => armIKTarget;
}キャラクターのスクリプトでは、トリガーにEnter/Exitした時やウェイトが0になったときに、コンストレイントの有効無効を切り替えています。
   IEnumerator DecreaseDoorRig()
    {
        while (doorRig.weight > 0f)
        {
            doorRig.weight -= Time.deltaTime * 0.8f;
            yield return null;
        }
        doorRig.weight = 0f;
        DisableHandPlacementOnDoorframe();
    }
    protected override void OnTriggerExit(Collider other)
    {
        base.OnTriggerExit(other);
        if (other.tag == "DoorTrigger")
        {
            //DisableHandPlacementOnDoorframe();
            StopCoroutine("IncreaseFoorRig");
            StopCoroutine("DecreaseFoorRig");
            StartCoroutine("DecreaseFoorRig");
        }
    }
    [SerializeField] ParentConstraint leftArmTarget;
    void EnableHandPlacementOnDoorframe(Transform target)
    {
        // ソースを作成
        var source = new ConstraintSource();
        source.sourceTransform = target;
        source.weight = 1f;
        // 左腕のParentコンストレイントにソースを追加
        leftArmTarget.AddSource(source);
        // コンストレイントを有効にする。
        leftArmTarget.constraintActive = true;
    }
    void DisableHandPlacementOnDoorframe()
    {
        // ソースを削除
        leftArmTarget.RemoveSource(0);
        // コンストレイントを無効にする
        leftArmTarget.constraintActive = false;
    }



































