Unityをスクリプトで動かしたい!

Unityでオブジェクトを操作する方法を紹介してます!

Unityカメラから目標が離れたら追従する処理の紹介(動画あり)

今回はタイトル通りカメラの追従処理を紹介していきたいと思います。

カメラをプレイヤーの子オブジェクトにすれば割と簡単に追従をしてくれますが、少し面白いカメラワークができると思いますので是非ご覧ください。

この処理の良いところは、プレイヤーの移動速度とカメラの移動速度をそれぞれ分けることができます。

~
public class CameraMove : MonoBehaviour
{
    [SerializeField]
    GameObject TargetObj;   // カメラの中心(目標)
    [SerializeField]
    float KeepDis;          // 目標から保つ距離
    [SerializeField]
    float CameraSpeed;      // カメラの速度
    [SerializeField]
    Vector2 CameraVec;      // カメラのxz位置
    [SerializeField]
    Vector2 TargetVec;      // 目標のxz位置
    [SerializeField]
    float DefaultHeight = 0;
    [SerializeField]
    bool NearFlag;          // 保つ距離よりも近い場合
    [SerializeField]
    bool FarFlag;           // 保つ距離よりも遠い場合


    void Start()
    {
        DefaultHeight = transform.position.y;
        // 目標を中心に見る
        transform.LookAt(TargetObj.transform.position);
        // カメラxz座標
        CameraVec = new Vector2(this.transform.position.x, this.transform.position.z);
        // 目標のxz座標
        TargetVec = new Vector2(TargetObj.transform.position.x, TargetObj.transform.position.z);
        // 目標から保つ距離を目標からカメラの距離の初期値を格納する
        KeepDis = Vector2.Distance(CameraVec, TargetVec);

        NearFlag = false;
        FarFlag = false;
    }
    void Update()
    {
        // 目標を中心に見る
        transform.LookAt(TargetObj.transform.position);


        // フラグが立っていないで、目標との距離が離れた場合
        if(!FarFlag&&Vector3.Distance(TargetObj.transform.position, this.transform.position)>KeepDis)
        {
            FarFlag = true;
        }
        // フラグが立っていないで、目標との距離が近い場合
        else if(!NearFlag&&Vector3.Distance(TargetObj.transform.position, this.transform.position)< KeepDis)
        {
            NearFlag = true;
        }


        // 遠い場合
        if(FarFlag)
        {
            // カメラxz座標
            CameraVec = new Vector2(this.transform.position.x, this.transform.position.z);
            // 目標のxz座標
            TargetVec = new Vector2(TargetObj.transform.position.x, TargetObj.transform.position.z);
            // カメラから目標のベクトル(x,z)
            Vector2 C_TVec = TargetVec - CameraVec;

            // カメラと目標の距離が1フレームの移動量よりも近くなった場合
            if (Vector2.Distance(TargetVec, CameraVec) - KeepDis<CameraSpeed)
            {
                // 保つ距離に移動
                this.transform.position = new Vector3(C_TVec.normalized.x * -1 * KeepDis, DefaultHeight, C_TVec.normalized.y* -1 * KeepDis)+TargetObj.transform.position;
                FarFlag = false;
            }
            else
            {
                // 目標に向かって進行
                this.transform.position += new Vector3(C_TVec.normalized.x * CameraSpeed,0, C_TVec.normalized.y * CameraSpeed);
            }
        }
        // 近い場合
        else if(NearFlag)
        {
            // カメラxz座標
            CameraVec = new Vector2(this.transform.position.x, this.transform.position.z);
            // 目標のxz座標
            TargetVec = new Vector2(TargetObj.transform.position.x, TargetObj.transform.position.z);
            // カメラから目標のベクトル(x,z)
            Vector2 C_TVec = TargetVec - CameraVec;

            // カメラと目標の距離が1フレームの移動量よりも遠くなった場合
            if (Vector2.Distance(TargetVec, CameraVec) - KeepDis < CameraSpeed)
            {
                // 保つ距離に移動
                this.transform.position = new Vector3(C_TVec.normalized.x * -1 * KeepDis, DefaultHeight, C_TVec.normalized.y * -1 * KeepDis) + TargetObj.transform.position;
                NearFlag = false;
            }
            else
            {
                //目標に向かって進行
                this.transform.position -= new Vector3(C_TVec.normalized.x * CameraSpeed, 0, C_TVec.normalized.y * CameraSpeed);
            }
        }
    }
}
~

f:id:SugieSan:20210220002126g:plain
目標との距離を常に計算して

  • 遠い場合は近付く
  • 近い場合は離れる

といった処理を書いています。

Y軸の位置を計算に入れてしまうと保つべき距離の戻し方が難しかったので基本的にXZ軸の位置を計算で使用しました。(一度Y軸も計算しながら書いてみましたが直せそうもないので諦めました。)

おまけ

プレイヤーのカメラの方向を見て移動するスクリプト

~
public class DireMove : MonoBehaviour
{
    [SerializeField]
    float Speed;            // 速度
    [SerializeField]
    GameObject CameraObj;   // カメラのオブジェクト

    float Horizontal;       // 横の入力用
    float Vertical;         // 縦(前後)の入力用
    // Update is called once per frame
    void Update()
    {
        //横移動キーが押されている場合右なら1が左なら-1が加算されり
        Horizontal = Input.GetAxisRaw("Horizontal");
        //上の前後版
        Vertical = Input.GetAxisRaw("Vertical");

        // カメラの前方方向(xz軸)ベクトルを取得
        Vector3 cameraForward = Vector3.Scale(CameraObj.transform.forward, new Vector3(1, 0, 1)).normalized;

        // 方向キーの値とカメラの向きから、移動方向を決定
        Vector3 moveForward = cameraForward * Vertical + CameraObj.transform.right * Horizontal;

        //移動
        transform.position+= moveForward * Speed;
    }
}
~

カメラの方向と入力の値で移動しています。

今回は以上です。