Unity 6の2Dで徐々に加速・減速する移動を作る(Mathf.MoveTowards)

広告

この記事は「Unity 6 2D移動の総合ガイド」の一部です。前の記事では、キーを押すとすぐに最高速度で動きました。今回は、キーを押すと徐々に加速し、離すと徐々に停止する、少し慣性のある動きを作ります。乗り物や、ドシッとした操作感のキャラクターに使えます。

この記事で分かること

  • Mathf.MoveTowards()で、値を少しずつ目標に近づける方法
  • 加速と減速の強さを別々に設定する方法
  • Rigidbody2D.linearVelocityXで、横方向の速度だけを扱う方法

1. 完成する動き

  • Dキーを押すと、徐々に右へ加速していく
  • Aキーを押すと、徐々に左へ加速していく
  • キーを離すと、徐々に減速して停止する
白い四角いオブジェクトが加速・減速しながら左右に移動し、緑の壁(Wall)の手前で止まる動作

2. 準備

共通の準備は総合ガイドの「共通の準備」をご覧ください。この記事もRigidbody2Dを使うため、Playerに次のコンポーネントと設定を用意します。

  • Rigidbody 2D
  • Box Collider 2D
項目設定値理由
Body TypeDynamic物理演算に従って動くオブジェクトにする
Gravity Scale0横方向だけを制御するため、重力で落ちないようにする
Freeze Rotation Z有効回転しないようにする

前の記事のPhysicsMoveが付いている場合は、取り外してください。

3. スクリプトを作る

AccelerationMoveという名前でスクリプトを作り、Playerに取り付けます。

AccelerationMove.cs

using UnityEngine;
using UnityEngine.InputSystem;

public class AccelerationMove : MonoBehaviour
{
    [SerializeField] float maxSpeed = 5f;
    [SerializeField] float acceleration = 10f;
    [SerializeField] float deceleration = 15f;

    Rigidbody2D rb;
    float inputX;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        inputX = 0f;

        if (Keyboard.current == null)
            return;

        if (Keyboard.current.aKey.isPressed)
            inputX -= 1f;

        if (Keyboard.current.dKey.isPressed)
            inputX += 1f;
    }

    void FixedUpdate()
    {
        float targetSpeed = inputX * maxSpeed;

        float rate = inputX == 0f
            ? deceleration
            : acceleration;

        float newSpeed = Mathf.MoveTowards(
            rb.linearVelocityX,
            targetSpeed,
            rate * Time.fixedDeltaTime
        );

        rb.linearVelocityX = newSpeed;
    }
}

Inspectorで、Max Speed、Acceleration、Decelerationの3つの数値を変更できます。ゲームを再生しながら、動きの変化を確かめてみましょう。

4. コードの解説

① 3つの数値

変数意味初期値
maxSpeed最高速度5
acceleration1秒あたりに速度が増える量10
deceleration1秒あたりに速度が減る量15

② 目標の速度を決める

float targetSpeed = inputX * maxSpeed;

キーが押されているときは、最高速度(±5)が目標になります。離したときはinputXが0なので、目標は0になります。

③ 加速と減速を切り替える

float rate = inputX == 0f
    ? deceleration
    : acceleration;

これは条件演算子です。キーを押していない(inputX == 0f)ときは減速の強さを、押しているときは加速の強さを使います。

④ Mathf.MoveTowards()

Mathf.MoveTowards(
    現在の値,
    目標の値,
    1回で変化できる最大量
);

現在の値を、目標の値に向けて、最大量だけ近づけます。目標を行き過ぎることはありません。

たとえば現在の速度が0で目標が5の場合でも、一度に5にはなりません。accelerationが10でTime.fixedDeltaTimeが0.02なら、1回で増えるのは10 × 0.02 = 0.2だけです。これを繰り返すと、約0.5秒で最高速度に到達します。

減速は、目標が0になるだけで同じ仕組みです。decelerationが15なら、最高速度から約0.33秒で停止します。

⑤ rb.linearVelocityX

linearVelocityXは、Rigidbody2Dの速度のX成分だけを読み書きできるプロパティです。Y方向の速度には影響しません。前の記事のlinearVelocityは、1つのベクトルとしてXとYをまとめて扱いました。

このサンプルは横方向だけを制御するため、linearVelocityXが便利です。次のジャンプの記事でも、Y方向を別に扱うために使います。

⑥ 力(AddForce)との違い

このサンプルは、物理的な力を加えているのではなく、速度を直接、少しずつ変えています。物理的な力を使った加速は、⑫ AddForceで物理的に移動するで比較します。

この方法の利点は、加速と減速の強さを別々に設定できることです。

5. よくあるつまずき

症状確認すること
ゲーム開始と同時に落ちるGravity Scaleが0になっているか
動かないBody TypeがDynamicか。前の記事のスクリプトと競合していないか
加速しない・すぐ最高速度になるaccelerationの値が極端に大きくなっていないか
離しても止まらないdecelerationが0になっていないか
linearVelocityXでエラーが出るUnity 6以降であることを確認する

6. 練習問題

  1. accelerationとdecelerationをいろいろな値にして、動きの違いを比べてみましょう
  2. 右に進んでいるときAキーを押して左へ切り返すと、すぐに向きを変えられません。切り返しを速くする方法を考えてみましょう

ヒント

  • 2つ目では、現在の速度と入力の向きが逆になっているかどうかを調べます。
  • 逆向きの場合は、減速の強さを使います。
  • 現在の速度と入力を掛け算して、マイナスになるかどうかで判定できます。

解答例(まず自分で試してから見ましょう)

void FixedUpdate()
{
    float targetSpeed = inputX * maxSpeed;

    // 現在の向きと入力の向きが逆なら、掛け算がマイナスになる
    bool isTurning = rb.linearVelocityX * inputX < 0f;

    float rate = (inputX == 0f || isTurning)
        ? deceleration
        : acceleration;

    rb.linearVelocityX = Mathf.MoveTowards(
        rb.linearVelocityX,
        targetSpeed,
        rate * Time.fixedDeltaTime
    );
}

切り返すときは、まず強い減速で速度を落とし、その後で逆向きに加速します。

7. まとめ

  • Mathf.MoveTowards()で、速度を少しずつ目標に近づけられる
  • 目標速度を0にすると、徐々に減速して停止する
  • 加速と減速の強さを別々に設定できる
  • linearVelocityXを使うと、横方向の速度だけを扱える

次の記事では、横スクロールアクションで欠かせないジャンプを作ります。

参考:Unity公式ドキュメント

訪問数 5 回, 今日の訪問数 5回

広告