【Unity】FPSプレイヤーをアニメーションさせる

投稿者: | 2020-09-15

キャラクターコントローラーで動かす一人称視点のプレイヤーをアニメーションで動かしてみます。直接Animaorコンポーネントをつけると問題があったので、アニメーションを付けた別のゲームオブジェクトに乗せて動かします。

まず乗り物になる空のゲームオブジェクトを作って、アニメーションウィンドウのCreateからアニメーターコンポーネントとアニメーターコントローラーを作ります。

アニメーションをつけるときは、FPSコントローラーを空のオブジェクトの子にして、両方とも位置と回転を0にしました。

FPSコントローラーが床の上に立っている状態にするために、乗り物のY座標を動かしています。この状態でシーンビューやゲームビューを確認しながらアニメーションが付けられす。普段は親子関係を解除しておきます。

アニメーションを付けたら、アニメーターコントローラーのEntryからまずアニメーションのないステートへ遷移するようにして、そこから今作ったアニメーションが付いたステートへ遷移して戻ってくるようにします。

トリガーパラメーターを作って、オレンジのデフォルトのステートから遷移する矢印のインスペクタでは、Has Exit Timeのチェックを切り、Transition Durationを0にして、Conditionsにトリガーパラメーターを設定します。

これでトリガーがセットされたときに遷移します。

戻るときは、Has Exit Timeのチェックを入れて、Fixed Durationのチェックを外し、Exit Timeを1、Transition Durationを0にします。Conditionsは空にします。これでモーションが一回再生されると遷移します。

スクリプト

FPSコントローラーのスクリプトでアニメーションを再生します。

// FirstPersonController
[SerializeField] Transform vehicle;
Animator vehicleAnimator;
VehicleStateMachine sm_vehicle;

// ---
// Start()
vehicleAnimator = vehicle.GetComponent<Animator>();
sm_vehicle = vehicleAnimator.GetBehaviour<VehicleStateMachine>();
sm_vehicle.sc_fps = this;

// ---
public void StopMotion()
{
    m_CharacterController.enabled = true; // キャラクターコントローラーをオン
    Quaternion rot = transform.rotation; // 今の回転値を保存
    transform.parent = null; // 親子関係を解除
    m_MouseLook.SetQuaternion(rot); // 回転値を設定
}

// ---
// Update()
if (Input.GetKeyDown(KeyCode.R))
{
    m_CharacterController.enabled = false; // キャラクターコントローラーをオフ
    vehicle.position = transform.position; // 位置を合わせる
    vehicle.rotation = transform.rotation; // 回転を合わせる
    transform.parent = vehicle; // プレイヤーを乗り物の子にする 
    m_MouseLook.ResetCharacterRot(); // 回転をリセット
    vehicleAnimator.SetTrigger("Trigger"); // トリガーをセット
}

キー入力があるとキャラクターコントローラーをオフにして、乗り物のゲームオブジェクトの位置と回転をプレイヤーに合わせます。そして、プレイヤーその子オブジェクトにして、MouseLookの回転をリセットしてからトリガーをセットします。

回転をリセットしないと子オブジェクトにしたときにプレイヤーの向きが変わってしまいます。

トリガーがセットされるとアニメーションが始まります。アニメーションが終わってそのステートを出ると、空のオブジェクトのアニメーターコントローラーに付けたステートマシンビヘイビアから、元に戻すためのメソッドを呼びます。

// ステートマシンビヘイビア
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class VehicleStateMachine : StateMachineBehaviour
{
    public UnityStandardAssets.Characters.FirstPerson.FirstPersonController1 sc_fps;

    // OnStateEnter is called before OnStateEnter is called on any state inside this state machine
    //override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateUpdate is called before OnStateUpdate is called on any state inside this state machine
    //override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateExit is called before OnStateExit is called on any state inside this state machine
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        if (stateInfo.IsName("State1"))
        {
            sc_fps.StopMotion();
        }
    }

    // OnStateMove is called before OnStateMove is called on any state inside this state machine
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateIK is called before OnStateIK is called on any state inside this state machine
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    
    //}

    // OnStateMachineEnter is called when entering a state machine via its Entry Node
    //override public void OnStateMachineEnter(Animator animator, int stateMachinePathHash)
    //{
    //    
    //}

    // OnStateMachineExit is called when exiting a state machine via its Exit Node
    //override public void OnStateMachineExit(Animator animator, int stateMachinePathHash)
    //{
    //    
    //}
}

プレイヤーのスクリプトのStart()で、ステートマシンビヘイビアに自分自身を渡しています。

// FirstPersonController
[SerializeField] Transform vehicle;
Animator vehicleAnimator;
VehicleStateMachine sm_vehicle;

// ---
// Start()
vehicleAnimator = vehicle.GetComponent<Animator>();
sm_vehicle = vehicleAnimator.GetBehaviour<VehicleStateMachine>();
sm_vehicle.sc_fps = this;

このメソッドでは、キャラクターコントローラーをオンにして、親子関係を解除し、プレイヤーの回転値を設定します。

public void StopMotion()
{
    m_CharacterController.enabled = true; // キャラクターコントローラーをオン
    Quaternion rot = transform.rotation; // 今の回転値を保存
    transform.parent = null; // 親子関係を解除
    m_MouseLook.SetQuaternion(rot); // 回転値を設定
}

回転値を設定しないと0に戻ってしまいます。

そして、MouseLookクラスに上の2つのメソッドを定義します。

// MouseLook

Vector3 vector3Zero;

// 体の回転値を設定
public void SetQuaternion(Quaternion q)
{
    vector3Zero.y = q.eulerAngles.y;
    m_CharacterTargetRot = Quaternion.Euler(vector3Zero);
    vector3Zero.y = 0f; // 0に戻す
}

// 体の回転値をリセット
public void ResetCharacterRot()
{
    m_CharacterTargetRot = Quaternion.Euler(vector3Zero);
}

毎回 new Vector3()を使うと重くなるそうなので、変数に入れて使いまわしています。参考:http://tsubakit1.hateblo.jp/entry/2016/06/20/222612

これでFPSキャラクターのアニメーションができました。

コメントを残す

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