目標に向かって走るキャラクター

環境:Unity 2019.2.13f1

カメラは平行移動と中心座標を回転する。キャラクターは一定の距離が開くと中心座標に向かって走る。

カメラのコード

クラス名はCameraController2で、前回のコードを差し替える形で作成。
キャラクターとカメラ

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class CameraController2 : MonoBehaviour
{
    public Vector3 cameraRotation = new Vector3();
    Vector3 currentCamRotation = Vector3.zero;
 
    public float armLength = 4.0f;
    public float speed = 2.0f;
 
    public Vector3 target = new Vector3();
    Vector3 currentLookAtPos = new Vector3();
 
    // Start is called before the first frame update
    void Start()
    {
         
    }
 
    // Update is called once per frame
    void Update()
    {
        // ゲームパッド右スティックからの値を加算する
        cameraRotation += new Vector3(-Input.GetAxis("Vertical2"), -Input.GetAxis("Horizontal2"), 0) * 0.05f;
 
        // X軸回転の制限
        cameraRotation.x = Mathf.Clamp(cameraRotation.x, 30 * Mathf.Deg2Rad, 75 * Mathf.Deg2Rad);
 
        // 遅延用の角度との差分をとる
        Vector3 diff = cameraRotation - currentCamRotation;
        currentCamRotation += WrapAngle(diff) * 0.2f;
 
        // 角度からベクトルを計算する
        Vector3 craneVec = new Vector3
        (
            Mathf.Cos(currentCamRotation.x) * Mathf.Cos(currentCamRotation.y),
            Mathf.Sin(currentCamRotation.x),
            Mathf.Cos(currentCamRotation.x) * Mathf.Sin(currentCamRotation.y)
        );
 
        // ゲームパッドの左スティックのベクトルを取得する
        Vector3 direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
 
        // カメラのY軸角度から回転行列を生成する
        Quaternion rot = Quaternion.Euler(0, (cameraRotation.y * Mathf.Rad2Deg + 90), 0);
 
        // 逆行列を生成する
        Matrix4x4 m = Matrix4x4.TRS(Vector3.zero, rot, Vector3.one);
        Matrix4x4 inv = m.inverse;
 
        // 回転行列をかけたベクトルに変換する
        direction = inv.MultiplyVector(direction);
 
        target += direction * direction.magnitude * Time.deltaTime * speed;
 
        // 注視点の座標
        Vector3 lookAtPos = target + new Vector3(0, 0, 0);
        currentLookAtPos += (lookAtPos - currentLookAtPos) * 0.2f;
 
        // カメラの座標を更新する
        this.transform.position = currentLookAtPos + craneVec * armLength;
 
        // プレイヤーの座標にカメラを向ける
        this.transform.LookAt(currentLookAtPos);
    }
 
    // 角度を0~360°に収める関数
    Vector3 WrapAngle(Vector3 vector)
    {
        vector.x %= Mathf.PI * 2;
        vector.y %= Mathf.PI * 2;
        vector.z %= Mathf.PI * 2;
 
        return vector;
    }
}

プレイヤーのコード

カメラの中心座標を目標にキャラクターが追従していくコード。PlayerController2というクラスで作成。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
// ステート
public enum StateType
{
    Idle,
    Follow,
}
 
public class PlayerController2 : MonoBehaviour
{
    public float rotationSpeed = 360.0f;
    public float moveSpeed = 1.0f;
 
    GameObject camera;  // 外部のオブジェクトを参照する
    Animator animator;
 
    Vector3 pos = new Vector3();
    Vector3 currentPos = new Vector3();
 
    // アニメーションのブレンドに使う変数
    float speed;
 
    // 追従フラグ
    bool isFollow;
 
    private StateType state;
 
    // Start is called before the first frame update
    void Start()
    {
        camera = GameObject.FindGameObjectWithTag("MainCamera");
        animator = this.GetComponentInChildren<Animator>();
    }
 
    // Update is called once per frame
    void Update()
    {
        // 他のオブジェクトのスクリプトを読み込む(スクリプトはクラス扱い)
        CameraController2 cameraScript = camera.GetComponent<CameraController2>();
 
        // Slerpは球面線形補間、Vector3.Angleは二点間の角度(degree)を返す
        Vector3 forward = Vector3.Slerp(this.transform.forward, (cameraScript.target - pos), rotationSpeed * Time.deltaTime / Vector3.Angle(this.transform.forward, (cameraScript.target - pos)));
 
        // 目標との距離
        float distance = (pos - cameraScript.target).magnitude;
 
        // ステートマシン
        switch(state)
        {
            // 待機
            case StateType.Idle:
                // 距離が離れていたら追いかけるフラグを立てる
                if (distance > 2.0f)
                {
                    state = StateType.Follow;
                }
                else
                {
                    speed -= 2.0f * Time.deltaTime;
                    if (speed <= 0) speed = 0;
                }
                break;
 
            // 追跡
            case StateType.Follow:
 
                // ベクトル方向へ向かせる
                transform.LookAt(pos + forward);
 
                // 減速
                if (distance < 1.5f)
                {
                    speed -= 1.0f * Time.deltaTime;
                    if (speed <= 0) speed = 0;
                }
                // 加速
                else
                {
                    speed += 0.5f * Time.deltaTime;
                    if (speed > 1.0f) speed = 1.0f;
                }
 
                pos += this.transform.forward * speed * moveSpeed * Time.deltaTime;
                this.transform.position = pos;
 
                // 立ち止まるフラグ
                if (distance < 0.5f)
                    state = StateType.Idle;
 
                break;
        }
 
        // アニメーターコントローラへ値を渡す(最大が1になるベクトルの長さ)
        animator.SetFloat("Blend", speed);
    }
}
タイトルとURLをコピーしました