【Unity】スワイプ量に比例して移動量を調整するFPSコントローラのスクリプト

2023年5月7日

どうも、だらはです。
先日はFPSコントローラの作り方を紹介しましたが、今回は機能追加です。
スワイプ量に比例して移動量を調整するよう変更しました。
※追記(2023.4.16)
HTML化によるバグでソースコードが改変されていましたので修正しました。

◆FPSコントローラの作り方

スポンサーリンク

実装方法

早速ですが実装方法です。
上述の◆FPSコントローラの作り方を実施したのち、Player.csを以下のものに変更します。

◆Player.cs

using UnityEngine;
using UnityEngine.EventSystems;

public class Player : MonoBehaviour
{
    //移動操作を受け付けるタッチエリア
    [SerializeField] DragHandler _moveController;

    //移動速度(m/秒)
    [SerializeField] float _movePerSecond;

    //移動操作としてタッチ開始したスクリーン座標
    Vector2 _movePointerPosBegin;
    Vector3 _moveVector;

    [SerializeField] Camera _camera;

    //カメラ操作を受け付けるタッチエリア
    [SerializeField] DragHandler _lookController;

    //カメラ速度(°/px)
    [SerializeField] float _angularPerPixel = 1f;

    //カメラ操作として前フレームにタッチしたキャンバス上の座標
    Vector2 _lookPointerPosPre;

    //アニメーター制御用
    [SerializeField] GameObject objPlayerModel;
    Animator animPlayer;

    //微小移動判断のためのドラッグ量閾値
    float lenDragThreshold = 0.05f;

    //微小移動判断のための長さ初期化
    float lenScreen = 1f;
    float lenDrag = 1f;

    private void Awake()
    {
        _moveController.OnBeginDragEvent += OnBeginDragMove;
        _moveController.OnDragEvent += OnDragMove;
        _moveController.OnEndDragEvent += OnEndDragMove;
        _lookController.OnBeginDragEvent += OnBeginDragLook;
        _lookController.OnDragEvent += OnDragLook;
    }

    void Start()
    {
        animPlayer = objPlayerModel.GetComponent<Animator>();
        lenScreen = (new Vector2(Screen.width, Screen.height)).magnitude;
    }

    void Update()
    {
        UpdateMove(_moveVector);
    }

    //移動操作
    //ラッグ操作開始(移動用)
    void OnBeginDragMove(PointerEventData eventData)
    {
        //タッチ開始位置を保持
        _movePointerPosBegin = eventData.position;
    }

    //ドラッグ操作中(移動用)
    void OnDragMove(PointerEventData eventData)
    {
        //タッチ開始位置からのスワイプ量を移動ベクトルにする
        var vector = eventData.position - _movePointerPosBegin;
        _moveVector = new Vector3(vector.x, 0f, vector.y);

        //移動ベクトル量の長さを取得
        lenDrag = vector.magnitude;
    }

    void UpdateMove(Vector3 vector)
    {
        float spdGain = 1;
        float lenRatio = lenDrag/lenScreen;

        //対画面比でドラッグ量が少なければ微小移動

        if(lenRatio < lenDragThreshold)
        {
            //ドラッグ量に応じて減速量を調整
            spdGain = 1f/lenDragThreshold * lenRatio;
        }

        //現在向きを基準に、入力されたベクトルに向かって移動
        Vector3 nextPos = transform.rotation * vector.normalized * _movePerSecond * Time.deltaTime * spdGain;
        float tagP = Mathf.Pow(transform.position.x + nextPos.x, 2) + Mathf.Pow(transform.position.y + nextPos.y, 2) + Mathf.Pow(transform.position.z + nextPos.z, 2);
        float nowP = Mathf.Pow(transform.position.x, 2) + Mathf.Pow(transform.position.y, 2) + Mathf.Pow(transform.position.z, 2);

        //アニメーションにSpeedを渡す(平方根の計算が重いかも)
        animPlayer.SetFloat("Speed", Mathf.Sqrt((Mathf.Abs(tagP - nowP))));
        transform.position += nextPos;
    }

    //ドラッグ操作終了(移動用)
    void OnEndDragMove(PointerEventData eventData)
    {
        //移動ベクトルを解消
        _moveVector = Vector3.zero;
    }

    //カメラ操作
    void OnBeginDragLook(PointerEventData eventData)
    {
        _lookPointerPosPre = _lookController.GetPositionOnCanvas(eventData.position);
    }

    void OnDragLook(PointerEventData eventData)
    {
        var pointerPosOnCanvas = _lookController.GetPositionOnCanvas(eventData.position);
        //キャンバス上で前フレームから何px操作したかを計算
        var vector = pointerPosOnCanvas - _lookPointerPosPre;
        //操作量に応じてカメラを回転
        LookRotate(new Vector2(-vector.y, vector.x));
        _lookPointerPosPre = pointerPosOnCanvas;
    }

    void LookRotate(Vector2 angles)
    {
        Vector2 deltaAngles = angles * _angularPerPixel;
        transform.eulerAngles += new Vector3(0f, deltaAngles.y);

        //縦方向の回転角度制限
        Vector3 mXAxiz = _camera.transform.localEulerAngles;
        var x = mXAxiz.x + deltaAngles.x;

        if (x >= 180)
        {
            x = x - 360;
        }

        if (x >= -60 && x <= 60)
        {
            mXAxiz.x = x;
            _camera.transform.localEulerAngles = mXAxiz;
        }
    }
}

 

変更点は以下の通り。

  1. 対画面比でドラッグ量が少なければ微小移動。(spdGainで調整)
  2. アニメーションへの"Speed"の格納値の算出方法を修正(バグ修正and高速化)

コメントに処理内容を記載しましたが、もし設計思想が分からなければコメントしただけたらご説明させて頂きます。

最後に

いかがでしたでしょうか。
本機能により、スマホ用FPSコントローラの移動処理がほぼ完成したかな?
もし抜けてる機能があったら教えてくださいー!

以上、だらはでした。

追記(2023.5.7)

接地確認の機能Upしました。

スポンサーリンク

応用

Posted by daraha_gm