5 Tips for Better Platformers in Unity (日本語訳) | ジャンプ関連のTips

UdemyのUnityコースでよく参考にしているJames Doyle氏が
以下の動画を公開したので,学びつつ日本語に落とし込んでみます.

www.youtube.com

今回はジャンプに関連するTipsをまとめます.
SMALL JUMPS,HANG TIME (COYOTE TIME),JUMP BUFFERです.

SMALL JUMPS

Unity2Dゲームでジャンプ機能を実装する際,高さが一定であることが多いと思われます.
ただプレイヤーのUX的に小ジャンプが欲しい場面があります.
2Dゲームをやったことある人はその経験があるのではないでしょうか.

f:id:xrdnk:20200220221707g:plain

スペースキーをすぐ離しても離さなくても同じ高さを維持してジャンプしています.

変更前のコード

// 略

    private void Update()
    {
        // 略

        // ジャンプ
        if (isGround())
        {
            if (Input.GetKeyDown("space"))
            {
                Jump();
            }
            else
            {
                animator.SetBool("isJumping", false);
            }
        }
    }

このコードに付け加える形で小ジャンプを実装します.
動画のコードとは少し異なりますが,実装の考え方としては,
スペースキーを離した瞬間に,現在のy軸方向の速度を減速すればよいです.
よって,コードとしては以下の通りになります.

変更後のコード

// 略

    private void Update()
    {
        // 略

        // ジャンプ
        if (isGround())
        {
            if (Input.GetKeyDown("space"))
            {
                Jump();
            }
            else
            {
                animator.SetBool("isJumping", false);
            }
        }

        // NOTE : SMALL JUMPS
        // スペースキーを離したとき かつ 上向きに移動している時 
        if (Input.GetKeyUp("space") && rigidbody2D.velocity.y > 0)
        {
            // y方向の速度を現在の速度の半分する
            rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, rigidbody2D.velocity.y * .5f);
        }
    }

f:id:xrdnk:20200220222009g:plain

.5f は減速のためのマジックナンバーです.
このマジックナンバーは0より大きく1未満ならばなんでもよいですが,
James氏の経験則的に0.5で十分だといいます.

HANG TIME (COYOTE TIME)

滞空時間のことです.スラングCOYOTE TIMEといわれることがあるらしい.
コヨーテは動物のことです.どんな動物かはググってください.元ネタは以下の動画かららしい.

f:id:xrdnk:20200220223035g:plain

地面の端でジャンプできない現象が実装時あるあるです.

f:id:xrdnk:20200220223651g:plain

動画では端でジャンプしようとジャンプせずにそのまま落ちてしまうところがあります.
これもUX的にイラつきますねえ….その改善方法をまとめます.

変更前のコード

// 略

    private void Update()
    {
        // 略
        // ジャンプ
        if (isGround())
        {
            if (Input.GetKeyDown("space"))
            {
                Jump();
            }
            else
            {
                animator.SetBool("isJumping", false);
            }
        }
        
    }

このコードに付け加える形で滞空時間を実装します.
実装の考え方としては,コードを見た方が早いかと思います.

変更後のコード

// 略

    [SerializeField, Tooltip("滞空時間")]
    private float hangTime;
    /// <summary>
    /// 滞空カウンター
    /// </summary>
    private float hangCounter;

    private void Update()
    {
        // 略

        // COYOTE TIME
        if (isGround())
        {
            // 地面にいる時,滞空カウンターを滞空時間の初期値に設定する
            hangCounter = hangTime;
        }
        else
        {
            // 地面から離れている時,滞空カウンターを減らし続ける
            hangCounter -= Time.deltaTime;
        }

        // 滞空カウンターが0以上の場合,ジャンプ
        if (hangCounter > 0)
        {
            if (Input.GetKeyDown("space"))
            {
                Jump();
            }
            else
            {
                animator.SetBool("isJumping", false);
            }
        }
    }

ジャンプする前に以下を付け足します.

  • 地面にいる時,滞空カウンターに滞空時間の初期値を与え続ける
  • 地面にいない時,滞空カウンターを減らし続ける

ジャンプ時の条件を「地面にいる時 かつ スペースを押した時」から
滞空カウンターが0でない時 かつ スペースを押した時」に変更します.

そうするとCOYOTE TIMEを実装することができます.
hangTimeをいい感じに設定しましょう.こちらの動画では.2fに設定されています.

f:id:xrdnk:20200220225728g:plain

端でジャンプできるようになりました.

JUMP BUFFER

UX的に着地前にスペースキーを押してすぐにジャンプさせたいときがあります.
f:id:xrdnk:20200220234920g:plain

変更前のコード

// 略

    private void Update()
    {
        // 略

        // COYOTE TIME
        if (isGround())
        {
            // 地面にいる時,滞空カウンターを滞空時間の初期値に設定する
            hangCounter = hangTime;
        }
        else
        {
            // 地面から離れている時,滞空カウンターを減らし続ける
            hangCounter -= Time.deltaTime;
        }

        // 滞空カウンターが0以上の場合,ジャンプ
        if (hangCounter > 0)
        {
            if (Input.GetKeyDown("space"))
            {
                Jump();
            }
            else
            {
                animator.SetBool("isJumping", false);
            }
        }

        // SMALL JUMPS
        // スペースキーを離したとき かつ 上向きに移動している時 
        if (Input.GetKeyUp("space") && rigidbody2D.velocity.y > 0)
        {
            // y方向の速度を現在の速度の半分する
            rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, rigidbody2D.velocity.y * .5f);
        }
    }

実装方法としては,COYOTE TIMEの応用です.コードを見るとわかると思います.

変更後のコード

    // 略

    [SerializeField, Tooltip("JUMP BUFFER")]
    private float jumpBufferLength = .5f;
    /// <summary>
    /// ジャンプバッファカウンタ
    /// </summary>
    private float jumpBufferCounter;

    // 決まってない間隔で更新する場合
    private void Update()
    {
        // 略

        if (isGround())
        {
            // 地面にいる時,滞空カウンターを滞空時間の初期値に設定する
            hangCounter = hangTime;
        }
        else
        {
            // 地面から離れている時,滞空カウンターを減らし続ける
            hangCounter -= Time.deltaTime;
        }

        // JUMP BUFFER
        if (Input.GetKeyDown("space"))
        {
            jumpBufferCounter = jumpBufferLength;
        }
        else
        {
            jumpBufferCounter -= Time.deltaTime;
        }

        // 滞空カウンターが0以上の場合,ジャンプ
        if (hangCounter > 0)
        {
            // ジャンプバッファカウンタが0以上の場合
            if (jumpBufferCounter >= 0)
            {
                Jump();
                // 2段ジャンプ防止のためにカウンタをリセット
                jumpBufferCounter = 0;
            }
            else
            {
                animator.SetBool("isJumping", false);
            }
        }

        // SMALL JUMPS
        // スペースキーを離したとき かつ 上向きに移動している時 
        if (Input.GetKeyUp("space") && rigidbody2D.velocity.y > 0)
        {
            // y方向の速度を現在の速度の半分する
            rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, rigidbody2D.velocity.y * .5f);
        }
    }

考え方としては,

  • スペースキーを押した瞬間にバッファカウンタに初期値を入れる
  • 押し辞めたらバッファカウンタを減らす

そして,ジャンプ時の条件を「滞空カウンタが0でないとき かつ スペースを押した時」から
「滞空カウンターが0でない時 かつ バッファカウンタが0以上の時」に変更します.

注意としては以下を忘れないようにしてください.

  • ジャンプした瞬間,バッファカウンタをゼロリセットする

バッファの初期値は動画では0.5fにしております.

f:id:xrdnk:20200220235720g:plain

ちょっとしたコードでUXが変わりますね.こういうの感動する.

終わりに

次回,残りのLOOK AHEADとFOOT DUSTをまとめます.

こちらのUdemyコースのコードを利用させて頂きました.
Unity ゲーム開発入門:インディーゲームクリエイターが教える
マリオのようなゲームを作成する方法【スタジオしまづ】

https://www.udemy.com/course/studio_shimazu_sideview_action/

こちらのコースは8時間程度で簡単なUnity2Dゲームが作れます.
丁寧でわかりやすいのでおすすめです.