【バイオハザード風のゲームを作ってみよう。その5】

今回もやっていきましょう。
今回は武器(今回はハンドガン)毎に特定の手の位置に設定する方法を勉強していきます。

参考動画
youtu.be

[動画の流れ]
・「Package Manager」内の「Animation Rigging」をインストール。

UnityではスクリプトからIKを使って人型キャラクターの手や足の位置や角度を操作し、動かすことが出来ましたが、このAnimation Riggingを使うとスクリプトから操作せず自分でRigを設定しアニメーションをさせることが出来ます。
詳細は下記参照。
gametukurikata.com

参考2:
amidamangrove.hatenablog.com


・プレイヤーに「Rig Bulider」コンポーネントを追加します。

Rig BuilderはAnimatorコンポーネントを持つゲームオブジェクトに取り付けAnimatorコンポーネントと共存してRigを構築するコンポーネントです。

・プレイヤー直下に空オブジェクト「RigLayer」を作成し、「Rig」コンポーネントを追加。

Rigコンポーネントは取り付けたゲームオブジェクトの子要素に設定したリグのウエイトを設定出来ます。

・プレイヤー「Rig Builder」の「RigLayers」に上記作成の「「RigLayer」を設定。

・プレイヤー直下の「RigLayer」の直下に空オブジェクト「RightHandIk」「LeftHandIk」を作成。

・「RightHandIk」「LeftHandIk」それぞれに、「Two Bone Ik Constraint」コンポーネントを追加。

・「RightHandIk」の「Two Bone Ik Constraint」の「Root:Midの親オブジェクト」「Mid:Tipの親オブジェクト」「Tip:右手」を設定。(「LeftHandIk」も同様に左腕を設定)


(「Source Objects」のTragetには、ゲームプレイすると後述するハンドガン内のRighrHandIKが設定されます。)

Two Bone IKを使用すると二つのボーンのFKをIKとHintで制御できるようにします。
Weightはウエイト
Rootは二つのボーンのルートとなるゲームオブジェクトを設定
Midは二つのボーンの間のゲームオブジェクトを設定
Tipは二つのボーンの先のゲームオブジェクトを設定
Source Objectsの

TargetにはIKのターゲットとなるゲームオブジェクトを設定
HintにはIKHintに使用するゲームオブジェクトを設定

FK/IKについては下記参照。
ryowaks.com

・ハンドガンプレハブの「Transformオブジェクト」の直下に空オブジェクト「RightHandIk」「LeftHandIk」を作ります。そして、それぞれにスクリプト(RightHandIkTarge.cs/LeftHandIkTarge.cs)をアタッチします。


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RightHandIkTarget : MonoBehaviour //EP5追加。ハンドガンプレハブのRightHandIkにアタッチ。
{
    // This script is just a way to reference the IK transform.   
}

LeftHandIkTargetスクリプトも同じ内容です。

・プレイ中に右手、左手を調整出来るようにスクリプトで「RightHandIk/leftHandIk」オブジェクトの「Two Bone Ik Constraint」コンポーネント内のTargetに該当オブジェクト(今回はハンドガン)を設定します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Animations.Rigging; //EP5追加

public class AnimatorManager : MonoBehaviour
{
    
   (省略)

    //EP5追加.PlayerEquipmentManagerで呼出し。
    public void AssignHandIK(RightHandIkTarget rightTarget, LeftHandIkTarget leftTarget)
    {
        //ハンドガンプレハブのRightHandIk/LeftHandIkオブジェクトをプレイヤー下のオブジェクトRightHandIk/lefttHandIkのTwoBoneIkConstraintコンポーネントのTargetに設定。
        rightHandIK.data.target = rightTarget.transform;
        leftHandIK.data.target = leftTarget.transform;
        rigBuilder.Build(); //設定を完了。Build()しないと設定が完了しない。
    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerEquipmentManager : MonoBehaviour //EP4追加.playerにアタッチ
{
    AnimatorManager animatorManager;
    WeaponLoaderSlot weaponLoaderSlot;

    [Header("Current Equipment")]
    public WeaponItem weapon;
    RightHandIkTarget rightHandIk; //EP5追加
    LeftHandIkTarget leftHandIk; //EP5追加

    //public SubweponItem ;//knife,stun grenads ect

(省略)

    void LoadCurrentWepon()
    {
        //LOAD THE WEPON ONTO PLAYERS HANDS
        weaponLoaderSlot.LoadWeaponModel(weapon);

        //CHANGE OUR PLAYERS MOVEMENT/IDLE ANIMSTIONS TO THE WEPONS MOVEMENT/IDLE ANIMATIONS
        animatorManager.animator.runtimeAnimatorController = weapon.weponAnimatior;

        //EP5追加
        //右手/左手の武器の子オブジェクトRightHandIk/LeftHandIkを取得。
        rightHandIk = weaponLoaderSlot.currentWeaponModel.GetComponentInChildren<RightHandIkTarget>();
        leftHandIk = weaponLoaderSlot.currentWeaponModel.GetComponentInChildren<LeftHandIkTarget>();
        animatorManager.AssignHandIK(rightHandIk ,leftHandIk);
    }
}


・ゲームプレイすると、エラー発生。
調べてみると、「アニメーション リギングを使用してキャラクターに武器を追加する際の問題」として下記を見つけました。
forum.unity.com

どうやら、ハンドガンプレハブ内に同じ名前があることが問題らしく(私の場合、M1911が2つある)、子のオブジェクトを「M1911_body」に変更した所、エラーがなくなりました。


・エラーは消えましたが、武器と手の位置が変なことになっていると思います。プレイ中にハンドガン下のオブジェクト「RightHandIK/LeftHandIk」のPosition/Rotationを調整してコピーし、ハンドガンプレハブの「RightHandIK/LeftHandIk」のTransformに貼り付けます。


・Idle時のポーズは出来ましたが、歩くと両手がくっついて変な動きになっていると思いますので、歩行時のみ上記の設定になるようにスクリプト(InputManager.cs)を修正します。

 private void HandMovementInput()
    {
        horizontalMovementInput = movementInput.x;
        verticalMovementInput = movementInput.y;
        animatorManager.HandleAnimatorValues(horizontalMovementInput, verticalMovementInput, runInput);

        //EP5追加。TEMP
        if(verticalMovementInput !=0 || horizontalMovementInput != 0)
        {
            animatorManager.rightHandIK.weight = 0;
            animatorManager.leftHandIK.weight = 0;
        }
        else
        {
            animatorManager.rightHandIK.weight = 1;
            animatorManager.leftHandIK.weight = 1;
        }
    }

今回は以上です。