Unity学習記録 #012 プレイヤーの移動制御・ジャンプ制御

ゲーム開発の学習を始めたので、使ったコードを忘れても使えるようにメモを残していきます。今回はプレイヤーの「移動制御」と「ジャンプ制御」の基本的なコードを書いてみます。

移動やジャンプといった処理はどのようなゲームを作るかで記述するコードも変わってくるようなので、今回開発するゲーム条件をざっくり列挙しておきます。

【ゲーム開発条件】
・２Dのゲーム開発（マリオみたいなプレイヤーの動きを想定）
・プレイヤーにはリジッドボディを追加して物理特性を持たせる
・方向キーを使った水平方向の移動を制御
・プレイヤーが地面に接触しているときに、一回ジャンプができるようにする
・移動速度とジャンプ力をゲームプレイ中でも変更できるようにする

以上の条件を踏まえて、サンプルコードは次のように記述しました。
```csharp
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

//プレイヤーの移動とジャンプ制御
public class Player : MonoBehaviour
{
    //ゲームパラメータ関連の初期設定
    private Rigidbody2D rb;
    public float junpForce = 300.0f;
    public float speed = 8.0f;
    bool isGround;

    //ゲーム開始時に１回だけ実行される処理
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    //ゲーム実行中に繰り返し実行される処理
    void Update()
    {
        Move(); //移動メソッド呼び出し
        Jump(); //ジャンプメソッド呼び出し
    }

    //移動処理のメソッド
    void Move()
    {
        float xPos = Input.GetAxisRaw("Horizontal");
        transform.position += new Vector3(xPos, 0, 0) * Time.deltaTime * speed;
    }

    //ジャンプ処理のメソッド
    void Jump()
    {
        if (Input.GetKeyDown(KeyCode.Space) && isGround == true)
        {
            rb.AddForce(Vector2.up * junpForce);
            isGround = false;
        }
    }

    //地面との接触判定
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Ground")) isGround = true;
    }

}
```

## コード解説
上から順にコードを見てみます。
### C#とUnityが準備した機能を扱うための宣言
```csharp
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
```
このコードはC#とUnityが準備している機能を開発コードの中で使えるようにするための宣言のようなものです。配列の初期設定をすると変数を配列として扱うことができたり、オブジェクトに衝突判定などの物理演算処理が扱えるようになります。

### ゲームパラメータ関連の設定
```csharp
//ゲームパラメータ関連の初期設定
private Rigidbody2D rb; //リジッドボディ取得
public float speed = 8.0f; //移動速度
public float junpForce = 300.0f; //ジャンプ力
bool isGround; //プレイヤーと地面の接触判定に使う変数
```
プレイヤーオブジェクトにはリジッドボディを追加して物理的特性を持たせています。ジャンプ操作をしたときに、UP方向に力を加える処理をしたいので、リジッドボディをいつでも呼び出して操作できるように変数として取得しておきます。

プレイヤーの移動速度とジャンプ力の値をインスペクターから操作できるように変数をpublicとして設定しています。

プレイヤーと地面の接触判定をbool値を使って取得し、空中でのジャンプを防止するためのコードを作成します。

### デフォルトで設置されている関数（Start関数・Update関数）
```csharp
//ゲーム開始時に１回だけ実行される処理
void Start()
{
    rb = GetComponent<Rigidbody2D>();
}

//ゲーム実行中に繰り返し実行される処理
void Update()
{
    Move(); //移動メソッド呼び出し
    Jump(); //ジャンプメソッド呼び出し
}
```
Unityで新規にプロジェクトを作成したときはStart関数とUpdate関数がデフォルトで設置されています。Start関数では、ゲーム開始時にリジッドボディを取得しています。
Update関数では移動処理のメソッドとジャンプ処理のメソッドを呼び出しています。移動処理とジャンプ処理の中身はこの後説明します。

### 移動処理
```csharp
//移動処理のメソッド
void Move()
{
    float xPos = Input.GetAxisRaw("Horizontal");
    transform.position += new Vector3(xPos, 0, 0) * Time.deltaTime * speed;
}
```
左右の方向キーの操作を取得して変数 "xPos" に代入しています。この変数をプレイヤーオブジェクトのX座標に使用するとで、シーンが更新される度にxPosの座標の位置にプレイヤーが移動することになります。

"Time.deltaTime"はフレームレート (FPS) の異なるどのデバイスでプレイしても、プレイヤーの移動速度が一定に保たれるように記述されます。

プレイヤーの動きは使用するメソッドを使い分けることで、滑らかに移動させたり、パキっとした動きにしたりできます。
| メソッド | 特徴 |
|---|---|
| GetAxis | -1から1までの数値が滑らかに変動する |
| GetAxisRaw | -1, 0, 1いずれかの数値を取得するのでパルス的な動きになる |

### ジャンプ処理
```csharp
if (Input.GetKeyDown(KeyCode.Space) && isGround == true)
{
    rb.AddForce(Vector2.up * junpForce);
    isGround = false;
}
```
ここではジャンプできる条件を設定してジャンプ処理を実行します。

【ジャンプ処理ができる条件】
・スペースキーが押されたとき
・プレイヤーが地面に接触しているとき

論理演算子を使って上記２つの条件を同時に満たした時にジャンプ処理が実行されるように記述しています。

変数 "rb" でリジッドボディを呼び出して、AddForceメソッドでUp方向に力を加えてプレイヤーオブジェクトをジャンプさせます。up値は1なので、ユーザーが準備したjumpForceをかけて、ジャンプする高さを調整します。

ジャンプ中はisGroundにfalseが代入されてることで、if文の条件式がfalseを返すようにしています。これでジャンプ中の追加ジャンプを防止できます。

### 地面との接触判定
```csharp
//地面との接触判定
private void OnCollisionEnter2D(Collision2D collision)
{
    if (collision.gameObject.CompareTag("Ground")) isGround = true;
}
```
プレイヤーが地面に接触しているときにisGroundをtrueにすることで、ジャンプできる条件をセットしています。
OnCollisionEnter2DはUnity側で準備されている関数のようで、関数名は文字通りに記述しないとうまく機能しません。

またゲームオブジェクトが増えてくると、地面以外にもプレイヤーと接触するオブジェクトがでてきます。地面のゲームオブジェクトにタグを設定してプレイヤーと地面が接触したときに限ってisGroundがtrueになるように設定しています。
地面のタグはインスペクターから設定できます。

![tag.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3822122/6df00d41-5990-3ff7-86d0-de443742bc2d.jpeg)


今回の記事は以上です。コピペで汎用的に使えそうなコードはメモしていく予定です。