LoginSignup
2
1

色々なジャンプの処理を実装する

Posted at

この記事ではUnityで複数のジャンプ方法を実装します。具体的には壁キック、2段ジャンプ、ヒップドロップを実装していきます。過去に書いた以下のURLの記事の続きから進めていきます。
https://qiita.com/holy_r_e9620202/items/dd4a21031295d7b88c08

壁キック

アクションゲームで時々見かける、壁の方向に向かってジャンプして、キャラクターが壁と接触した瞬間にタイミングよくジャンプボタンを押すと、壁を蹴って反対方向へジャンプする処理です。この壁キックを繰り返して2つの壁の間を登っていけるようにします。
Hierarchyウィンドウを右クリックして3D ObjectからCubeを2つ作ります。2つのCubeを壁として、サイズや間隔を調整して以下の画像のように配置します。
image1.png
さらに、Inspectorビューから両方の壁のTagの名前をWallに設定しておきます。
壁を配置したらキャラクターにアタッチされているスクリプトPlayerController.csを以下のように書き変えます。

PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{
    public float moveSpeed;
    public float dashSpeed;
    public float jumpPower;
    private bool isWallJumping = false; //壁キック判定の変数
    private CharacterController controller;
    private Vector3 moveVelocity;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        if (!isWallJumping) //壁キック中でない場合に操作を受け付ける
        {
            if (Input.GetKey(KeyCode.Z))
            {
                moveVelocity.x = Input.GetAxis("Horizontal") * dashSpeed;
                moveVelocity.z = Input.GetAxis("Vertical") * dashSpeed;
            }
            else
            {
                moveVelocity.x = Input.GetAxis("Horizontal") * moveSpeed;
                moveVelocity.z = Input.GetAxis("Vertical") * moveSpeed;
            }
        }

        transform.LookAt(this.transform.position + new Vector3(moveVelocity.x, 0, moveVelocity.z));

        if (controller.isGrounded) 
        {
            isWallJumping = false; //着地したら壁キック判定をfalseに戻す

            if (Input.GetKeyDown(KeyCode.Space))
            {
                moveVelocity.y = jumpPower;
            }
        }
        else
        {
            moveVelocity.y += Physics.gravity.y * Time.deltaTime;
        }

        controller.Move(moveVelocity * Time.deltaTime);
    }

    //壁キックの処理
    void OnControllerColliderHit(ControllerColliderHit collider)
    {
        if (collider.gameObject.tag == "Wall" && !controller.isGrounded) //壁に接触していてかつ地面に設置していない場合
        {
            if (Input.GetKeyDown(KeyCode.Space)) //スペースキー入力で壁キック実行
            {
                var direction = transform.forward; //キャラクターの向きを取得
                isWallJumping = true; //壁キック判定をtrueにする
                moveVelocity.x = -direction.x * 5; //壁とはx軸逆向きに移動
                moveVelocity.y = jumpPower;        //y軸方向はジャンプの場合と同じように移動
                moveVelocity.z = -direction.z * 5; //壁とはz軸逆向きに移動
            }
        }
    }
}

実行すると、壁に向かってジャンプして当たった時にスペースキーを押すと、キャラクターが壁を蹴ったように壁と反対方向にジャンプします。壁キックを繰り返すと2つの壁の間を登っていくことが出来るので確認してください。

2段ジャンプ

空中でもう1回ジャンプできるやつです。
jumpCountという変数を追加してジャンプした回数を管理することによって、空中で1回だけジャンプできるようにしました。PlayerController.csを以下のように修正しました。

PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{
    public float moveSpeed;
    public float dashSpeed;
    public float jumpPower;
    private bool isWallJumping = false;
    private CharacterController controller;
    private Vector3 moveVelocity;
    private byte jumpCount = 0; //ジャンプした回数

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        if (!isWallJumping)
        {
            if (Input.GetKey(KeyCode.Z))
            {
                moveVelocity.x = Input.GetAxis("Horizontal") * dashSpeed;
                moveVelocity.z = Input.GetAxis("Vertical") * dashSpeed;
            }
            else
            {
                moveVelocity.x = Input.GetAxis("Horizontal") * moveSpeed;
                moveVelocity.z = Input.GetAxis("Vertical") * moveSpeed;
            }
        }

        transform.LookAt(this.transform.position + new Vector3(moveVelocity.x, 0, moveVelocity.z));

        if (controller.isGrounded) 
        {
            isWallJumping = false;
            jumpCount = 0; //着地したら0に戻す

            if (Input.GetKeyDown(KeyCode.Space))
            {
                moveVelocity.y = jumpPower;
                jumpCount++; //ジャンプしたら1増やす
            }
        }
        else
        {
            if (jumpCount < 2) //接地していなくてもジャンプ回数が2より小さい場合
            {
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    moveVelocity.y = jumpPower;
                    jumpCount++; //ジャンプしたら1増やす
                }
                else
                {
                    moveVelocity.y += Physics.gravity.y * Time.deltaTime;
                }
            }
            else
            {
                moveVelocity.y += Physics.gravity.y * Time.deltaTime;
            }
        }

        controller.Move(moveVelocity * Time.deltaTime);
    }

    void OnControllerColliderHit(ControllerColliderHit collider)
    {
        if (collider.gameObject.tag == "Wall" && !controller.isGrounded)
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                var direction = transform.forward;
                isWallJumping = true;
                moveVelocity.x = -direction.x * 5;
                moveVelocity.y = jumpPower;
                moveVelocity.z = -direction.z * 5;
                jumpCount++; //壁キックしたら1増やす
            }
        }
    }
}

修正出来たらジャンプして空中でもう1回スペースキーを押してジャンプできることを確かめてください。

ヒップドロップ

次にヒップドロップを実装します。キャラクターを勢いよく落下させて敵とかブロックを踏み潰せるあれです。PlayerController.csを以下のように書き変えて実装しました。

PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{
    public float moveSpeed;
    public float dashSpeed;
    public float jumpPower;
    private bool isWallJumping = false;
    private bool isHipdrop = false; //ヒップドロップ判定
    private CharacterController controller;
    private Vector3 moveVelocity;
    private byte jumpCount = 0;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        if (!isWallJumping)
        {
            if (Input.GetKey(KeyCode.Z))
            {
                moveVelocity.x = Input.GetAxis("Horizontal") * dashSpeed;
                moveVelocity.z = Input.GetAxis("Vertical") * dashSpeed;
            }
            else
            {
                moveVelocity.x = Input.GetAxis("Horizontal") * moveSpeed;
                moveVelocity.z = Input.GetAxis("Vertical") * moveSpeed;
            }
        }

        transform.LookAt(this.transform.position + new Vector3(moveVelocity.x, 0, moveVelocity.z));

        if (controller.isGrounded) 
        {
            isWallJumping = false;
            isHipdrop = false; //着地したらヒップドロップ判定をfalseに戻す
            jumpCount = 0;

            if (Input.GetKeyDown(KeyCode.Space))
            {
                moveVelocity.y = jumpPower;
                jumpCount++;
            }
        }
        else
        {
            if (jumpCount < 2)
            {
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    moveVelocity.y = jumpPower;
                    jumpCount++;
                }
                else
                {
                    moveVelocity.y += Physics.gravity.y * Time.deltaTime;
                }
            }
            else
            {
                moveVelocity.y += Physics.gravity.y * Time.deltaTime;
            }

            //Bキーを押すとヒップドロップ実行
            if (Input.GetKeyDown(KeyCode.B))
            {
                Hipdrop();
            }
        }

        controller.Move(moveVelocity * Time.deltaTime);
    }

    void OnControllerColliderHit(ControllerColliderHit collider)
    {
        if (collider.gameObject.tag == "Wall" && !controller.isGrounded)
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                var direction = transform.forward;
                isWallJumping = true;
                moveVelocity.x = -direction.x * 5;
                moveVelocity.y = jumpPower;
                moveVelocity.z = -direction.z * 5;
                jumpCount++;
            }
        }

        //ヒップドロップ中にブロックと衝突した場合
        if (collider.gameObject.tag == "Block" && isHipdrop)
        {
            Destroy(collider.gameObject); //衝突したオブジェクトを消す
        }
    }

    void Hipdrop()
    {
        isHipdrop = true; //ヒップドロップ判定をtrueにする
        moveVelocity.y += Physics.gravity.y * Time.deltaTime * 100; //落下スピードを通常時よりも早くする
    }
}

これでキャラクターがヒップドロップできるようになりました。空中でBキーを押すとヒップドロップが実行され、普段より落下速度が速くなります。またTagの名前をBlockに設定したオブジェクトを設置して、そのオブジェクトに対してヒップドロップを当ててみてください。Blockオブジェクトが消滅すれば成功です。

参考文献

https://papyrustaro.hatenablog.jp/entry/2020/06/17/121100
https://futabazemi.net/unity/jump-wall-up

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1