メモの穴

メモ化

UnityでIWBTGを3Dに -プレイヤー移動-

前: UnityでIWBTGを3Dに -ステージ作成- - メモの穴


前回はステージを作成した。

次はプレイヤーをつくっていく。

環境

Windows10
Unity 2018.2.2f1

プレイヤー作成

イワナのキッド君の判定は縦長の長方形になっているようなので、

f:id:memonoana:20180810160516p:plain:w200

こんな感じ。カメラを追従させたいので、カメラを子要素にしておく。

f:id:memonoana:20180810161233p:plain:w200

プレイヤー移動

次に移動処理を加える。

プレイヤー移動の実装アプローチはいくつかある。

tama-lab.net

他のサイトもいろいろ見てると、大体RigidbodyかCharactorControllerでやってるみたい。

とにかく簡単にやりたい場合はCharactorControllerを使ってる感じだけど、Rigidbody関係はプレイヤー移動以外でも使う機会は多そうなので、今回はRigidbodyを使っていく。途中で変える可能性はある。

Rigidbodyではvelocityを使って移動させていく。現実に近い挙動をさせる場合はAddForceを使うべきだということだけど、今回はそういう挙動は求めてないのでvelocityでやる。(なら別にRigidbodyじゃなくてもいいのでは?)

// 速度
private float velocity = 6f;
// 進む方向
private Vector3 direction = Vector3.zero;

void Update () {
  // WASDで移動
  if (Input.GetKey(KeyCode.W)) {
    direction += transform.forward;
  }
  if (Input.GetKey(KeyCode.S)) {
    direction -= transform.forward;
  }
  if (Input.GetKey(KeyCode.A)) {
    direction -= transform.right;
  }
  if (Input.GetKey(KeyCode.D)) {
    direction += transform.right;
  }
  if (Input.GetKeyUp(KeyCode.W) || Input.GetKeyUp(KeyCode.S) || Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.D)) {
    direction = Vector3.zero;
  }
}
void FixedUpdate () {
  direction.Normalize();
  // x、z方向の速度を変更
  rigidBody.velocity = new Vector3(direction.x * velocity, rigidBody.velocity.y, direction.z * velocity);
}

WASDで移動する。キー入力に応じて進む方向をdirectionに加算、direction.Normalize()で正規化する。x方向とz方向のdirectionに適当な値のvelocityを掛け、Rigidbody.velocityに反映させる。

f:id:memonoana:20180814004955g:plain:w300

InspectorでRigidbodyのUse Gravityにチェックを入れると、重力の影響を考慮してくれるようになるので、y方向の速度はそれに任せる。

f:id:memonoana:20180814005334p:plain

f:id:memonoana:20180814005225g:plain:w300

ジャンプ

次はジャンプを実装する。

private float velocityJump = 5f;
private bool isJumping = false;

void Update () {
  // スペースキーでジャンプ
  if (Input.GetKeyDown(KeyCode.Space)) {
    isJumping = true;
  }
}

void FixedUpdate () {
  if (isJumping) {
    // y方向の速度を変更
    rigidBody.velocity = new Vector3(rigidBody.velocity.x, velocityJump, rigidBody.velocity.z);
    isJumping = false;
  }
}

スペースキーを押すとジャンプする。シンプルにy方向の速度を変更するだけ。

f:id:memonoana:20180814011336g:plain:w300

ただ、このままだと

f:id:memonoana:20180814011821g:plain:w300

無限にジャンプができてしまう。ここでは2段ジャンプまでにしたい。

接地判定

まずは、空中ではジャンプできず、地上からしかジャンプできないようにしたい。そのためには、地に足がついているかどうかを判定する必要がある(接地判定)。

接地判定の方法はいくつかある。

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

今回はBoxCastを使う。BoxCastは特定の方向に箱状の判定を飛ばして、物体があるかどうかを判定してくれるもの。

private bool isGround = false;
private RaycastHit hit;
private float rayDistance, rayScale;

void Start () {
  // BoxCastのサイズ
  rayScale = transform.localScale.x * 0.5f;
  // 判定を飛ばす距離
  rayDistance = rayScale;
}

void Update () {
  isGround = Physics.BoxCast(transform.position, Vector3.one * rayScale, -transform.up, out hit, transform.rotation, rayDistance);
}

地上にいる時はisGroundがtrueになる。ちゃんと判定できているか、オブジェクトの色を変えて確かめてみる。

f:id:memonoana:20180814014418g:plain:w300

いけてそう。あとはスペースキーを押した時にisGroundがtrueの時だけisJumpingをtrueにすれば地上からしかジャンプできなくなる。

if (Input.GetKeyDown(KeyCode.Space)) {
  if (isGround) isJumping = true;
}

2段ジャンプ

次に2段ジャンプ。単純にジャンプした回数を記録して、指定回数以上はジャンプできないようにする。

private int jumpCountMax = 2;

void Update () {
  if (Input.GetKeyDown(KeyCode.Space)) {
    jumpCount++;
    // jumpCountがjumpCountMax未満の間だけジャンプ
    if (jumpCount < jumpCountMax) isJumping = true;
  }
}
void FixedUpdate () {
  // 地上でjumpCountを0に
  if (isGround) {
    jumpCount = 0;
  }
}

スペースキーを押した時にjumpCountを増やし、地上にいる時にjumpCountを0にする。そして、jumpCountがjumpCountMax未満の時のみisJumpingをtrueにしてジャンプを行うようにする。

f:id:memonoana:20180814142305g:plain:w300

このgifだとほんとに2段までで制限できてるのか怪しいな?

ジャンプの高さ変更

今のままだと、キーを押したらジャンプ、という判定だけなので、ジャンプの高さは常に一定となっている。次は、キーを押している長さによってジャンプの高さを変えたい。

これまではGetKeyDonwでスペースキーの判定をしていたが、GetKeyを使ってキーを押し続けている間も処理を行えるようにする。

private int jumpTimeMax = 20;

void Update () {
  if (Input.GetKey(KeyCode.Space) && jumpCount < jumpCountMax) {
    // キーを押している間、jumpTimeを増加
    if (jumpTime < jumpTimeMax) {
      jumpTime++;
      isJumping = true;
    // jumpTimeMaxを超えたらジャンプ終了
    } else {
      isJumping = false;
    }
  }
  // キーを上げたらジャンプ回数カウント、jumpTimeリセット
  if (Input.GetKeyUp(KeyCode.Space)) {
    jumpCount++;
    jumpTime = 0;
  }
}

jumpTimeの概念を設けて、キーを押し続けている間、jumpTimeを増やし続ける。jumpTimeがjumpTimeMax未満の間はisJumpingをtrueにし続ける。jumpTimeMax以上になると、キーを押していても強制的にジャンプを終了する。ジャンプ回数のカウントはGetKeyUpでキーを上げた時に行い、この時にjumpTimeもリセットする。

f:id:memonoana:20180814145604g:plain:w300

重力の変更

もう少し落下速度を速くしたい。

qiita.com

そもそもの重力の設定を変えたり、そのオブジェクトに上から力を加えたりとやり方はいろいろあるみたい。今回は後者でやる。

private Vector3 localGravity = new Vector3(0f, -30f, 0f);

void Start () {
  rigidBody.useGravity = false;
}
void FixedUpdate () {
  rigidBody.AddForce(localGravity, ForceMode.Acceleration);
}

AddForceで-y方向に力を加え続ける。RigidbodyのUse Gravityはつけたままでもいけるけど、localGravityだけで制御した方が分かりやすいのかな?

f:id:memonoana:20180814154102g:plain:w300

おわりに

移動とかジャンプは実装方法がいろいろあるので、ちゃんと使い分けられるようになりたい。


次:しばらく先