【Unity】Cinemachineで作成した3人称カメラにリセット機能を実装する

はじめに

BodyをFraming TransposerでAimをPOVに設定した3人称カメラにリセット機能を実装を実装していきます

3人称カメラの作成は下記記事を参考にしました https://raspberly.hateblo.jp/entry/UnityAdventCalendar2022_24#fn-d34631a8

環境は Unity 2021.3.25f1です

Universal Render Pipeline を使用しています。

スクリプト作成

Cinemachineやカメラのパラメータは設定してある前提です

一瞬で視点をリセットさせる

CinemachinePOVのHorizontalAxis.ValueにとキャラのeulerAngles.yを一緒にすることで視点をリセットできます

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class TestCamera : MonoBehaviour
{
    [SerializeField]
    CinemachineVirtualCamera mVirtualCamera;
    CinemachinePOV mPov;

    [SerializeField]
    Transform characotr;
    private void Start()
    {
        if (mPov == null)
        {
            mPov = mVirtualCamera.GetCinemachineComponent<CinemachinePOV>();
        }
    }

    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.R))
        {
            ResetRot();
        }
    }

    /// <summary>
    /// 視点のリセット
    /// </summary>
    public void ResetRot()
    {
        mPov.m_HorizontalAxis.Value = characotr.transform.eulerAngles.y;
        mPov.m_VerticalAxis.Value = 0;
    }
}

徐々に視点をリセットさせる

基本的には角度をLerpで変化させてるだけですが角度-180~180の範囲なのでそこだけ注意する必要があります

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class TestCamera : MonoBehaviour
{
    [SerializeField]
    CinemachineVirtualCamera mVirtualCamera;
    CinemachinePOV mPov;

    [SerializeField]
    Transform characotr;

    //カメラリセットパラメーター
    bool ImsRest = false;//カメラの向きをリセットするか
    [SerializeField, Range(0, 2)] float mResetTime = 0.3f;//リセット終えるまでにかかる時間
    private float mCurrentCameraHorizontalAngles = 0;
    private float mCurrentCharactorHorizontalAngles = 0;
    private float mCurrentTime = 0;
    private void Start()
    {
        if (mPov == null)
        {
            mPov = mVirtualCamera.GetCinemachineComponent<CinemachinePOV>();
        }
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))
        {
            //ResetRot();
            StartReset();
        }
        if (ImsRest)
        {
            ResetUpdate();
        }
    }
    public void StartReset()
    {
        var dire = Vector3.SignedAngle(transform.forward, characotr.transform.forward, Vector3.up);
        //正面に向いていたら
        if (dire == 0)
        {
            return;
        }

        ImsRest = true;
        mCurrentTime = 0;
        //現在の角度を保存
        mCurrentCameraHorizontalAngles = mPov.m_HorizontalAxis.Value;
        mCurrentCharactorHorizontalAngles = Mathf.Repeat(characotr.transform.eulerAngles.y + 180, 360) - 180;//-180~180に変換
    }
    /// <summary>
    /// リセット更新
    /// </summary>
    void ResetUpdate()
    {
        var targetY = mCurrentCharactorHorizontalAngles;
        var targetX = 0;

        mCurrentTime += Time.deltaTime;
        //リセット完了
        if (mCurrentTime >= mResetTime)
        {
            mCurrentTime = 0;
            ImsRest = false;
            mPov.m_HorizontalAxis.Value = targetY;
            mPov.m_VerticalAxis.Value = targetX;
            return;
        }
        var nextHorizontal = 0f;

        //本来は右回転(Playerは右向き)だがカメラが左回転になってしまう場合
        if (mCurrentCameraHorizontalAngles - targetY >= 180)
        {
            targetY += 360;
            nextHorizontal = Mathf.Lerp(mCurrentCameraHorizontalAngles, targetY, mCurrentTime / mResetTime) - 360;
            mPov.m_HorizontalAxis.Value = nextHorizontal;
        }//本来は左回転(Playerは右向き)だがカメラが右回転になってしまう場合
        else if (mCurrentCameraHorizontalAngles - targetY <= -180)
        {
            targetY -= 360;
            nextHorizontal = Mathf.Lerp(mCurrentCameraHorizontalAngles, targetY, mCurrentTime / mResetTime) + 360;
            mPov.m_HorizontalAxis.Value = nextHorizontal;
        }//通常回転
        else
        {
            mPov.m_HorizontalAxis.Value = Mathf.Lerp(mCurrentCameraHorizontalAngles, targetY, mCurrentTime / mResetTime);
        }
        //縦軸の回転
        mPov.m_VerticalAxis.Value = Mathf.Lerp(mPov.m_VerticalAxis.Value, targetX, mCurrentTime / mResetTime);
    }

    /// <summary>
    /// 視点のリセット
    /// </summary>
    public void ResetRot()
    {
        mPov.m_HorizontalAxis.Value = characotr.transform.eulerAngles.y;
        mPov.m_VerticalAxis.Value = 0;
    }
}