この記事ではUnityで複数のジャンプ方法を実装します。具体的には壁キック、2段ジャンプ、ヒップドロップを実装していきます。過去に書いた以下のURLの記事の続きから進めていきます。
https://qiita.com/holy_r_e9620202/items/dd4a21031295d7b88c08
壁キック
アクションゲームで時々見かける、壁の方向に向かってジャンプして、キャラクターが壁と接触した瞬間にタイミングよくジャンプボタンを押すと、壁を蹴って反対方向へジャンプする処理です。この壁キックを繰り返して2つの壁の間を登っていけるようにします。
Hierarchyウィンドウを右クリックして3D ObjectからCubeを2つ作ります。2つのCubeを壁として、サイズや間隔を調整して以下の画像のように配置します。
さらに、Inspectorビューから両方の壁のTagの名前をWallに設定しておきます。
壁を配置したらキャラクターにアタッチされているスクリプト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を以下のように修正しました。
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を以下のように書き変えて実装しました。
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