【学習】落ち物キャッチゲーム(ミニゲーム実践①)
これまでの学習では、
- プレイヤーを動かした
- プレハブでオブジェクトを生成した
- 当たり判定を設定した
- UI でスコアを表示した
という形でゲームの要素を学んできました。
しかし、それらを1つのゲームにまとめる実践はまだしていません。
今回は落ち物キャッチゲームを作って、学んだことを総合的に使います。上から落ちてくるアイテムを、プレイヤーでキャッチするゲームです。
この記事の進め方
- Unity Hub で新しいプロジェクトを作成して始めます(プロジェクト名:CatchGame、テンプレート:Universal 2D)
- 作る順番は プレイヤー → スコア表示 → アイテム → スポナー です。各手順の中でスクリプトを作ってからアタッチするので、上から順に進めればゲームが完成します
- スクリプトの作り方は「C# スクリプトの作成とアタッチ」、入力の設定は「プレイヤーを動かす」、プレハブは「プレハブと生成」、UI は「UI(Canvas)の基本」で確認できます
今日作るもの
- プレイヤーが左右に動く
- 上からアイテムが落ちてくる
- プレイヤーがアイテムに触れるとスコアが増える
- スコアを UI に表示する
必要なオブジェクト
| オブジェクト | 役割 |
|---|---|
| Player | 左右キーで動く。Collider2D(Trigger)、Rigidbody2D |
| Item(プレハブ) | 上から落ちる。Collider2D(Trigger)、Rigidbody2D |
| Spawner | 一定間隔で Item を生成する空オブジェクト |
| Canvas / Text | スコア表示 |
| Main Camera | ゲーム画面を写す |
手順1:プレイヤーを作る
- Hierarchy の「+」→ 2D Object → Sprites → Square で四角形を作成し、名前を Player にする
- Transform の Position を (0, -4, 0) にして、画面の下に置く
- Add Component で Rigidbody2D を追加し、Gravity Scale を 0 にする(プレイヤーが落ちないようにするため)
- Add Component で Box Collider 2D を追加し、Is Trigger をオンにする
- Inspector 上部の Tag を Player にする(最初から用意されているタグです)
- Add Component で Player Input を追加し、Actions に InputSystem_Actions、Default Map に Player を設定する。Behavior は Send Messages のままにする
- PlayerController スクリプトを作成して次のコードを書き、Player にアタッチする
PlayerController.cs
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
[SerializeField] private float speed = 5f;
private Vector2 moveInput;
void OnMove(InputValue value)
{
moveInput = value.Get<Vector2>();
}
void Update()
{
float moveX = moveInput.x * speed * Time.deltaTime;
transform.Translate(moveX, 0, 0);
}
}
OnMove は、Player Input が移動キー(A / D キーや矢印キー)の入力を受け取ったときに呼ばれます。ここで ▶ を押して再生し、プレイヤーが左右に動くことを確認しておきましょう。
別の書き方:Keyboard.current でキーを直接調べる
Input System では、以前の Input Manager の Input.GetKey と同じように、キーが押されているかを直接調べる書き方もできます。この書き方なら、手順6の Player Input を追加しなくても動きます。
PlayerController.cs(Keyboard.current 版)
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
[SerializeField] private float speed = 5f;
void Update()
{
var keyboard = Keyboard.current;
if (keyboard == null) return; // キーボードがない環境への備え
// ← キーまたは A キー / → キーまたは D キー
bool left = keyboard.leftArrowKey.isPressed
|| keyboard.aKey.isPressed;
bool right = keyboard.rightArrowKey.isPressed
|| keyboard.dKey.isPressed;
float x = 0f;
if (left) x = -1f;
if (right) x = 1f;
transform.Translate(x * speed * Time.deltaTime, 0, 0);
}
}
isPressed は「押している間ずっと true」です。以前の書き方との対応は次のとおりです。
| 旧 Input Manager | Input System |
|---|---|
| Input.GetKey(KeyCode.A) | Keyboard.current.aKey.isPressed |
| Input.GetKeyDown(KeyCode.Space) | Keyboard.current.spaceKey.wasPressedThisFrame |
| Input.GetKeyUp(KeyCode.Space) | Keyboard.current.spaceKey.wasReleasedThisFrame |
| Input.GetMouseButtonDown(0) | Mouse.current.leftButton.wasPressedThisFrame |
Keyboard.current 版は、どのキーを調べているかがコードからすぐ分かるのが長所です。一方、OnMove 版はキーボードだけでなくゲームパッドにもそのまま対応でき、キーの割り当ても後から変えられます。どちらを使っても、このゲームは同じように動きます。
手順2:スコアを表示する
アイテムのスクリプトは ScoreManager を使うので、先にスコア表示を作っておきます。
- Hierarchy の「+」→ UI → Legacy → Text でテキストを作成し、名前を ScoreText にする(Canvas と EventSystem も自動で作られます)
- ScoreText の Rect Transform で Width を 300、Height を 60 に広げ、Text の Font Size を 36、Color を白にする。Scene ビューで画面の左上あたりに移動する
- Hierarchy の「+」→ Create Empty で空の GameObject を作り、名前を ScoreManager にする
- ScoreManager スクリプトを作成して次のコードを書き、ScoreManager にアタッチする
- ScoreManager の Inspector にある Score Text 欄に、Hierarchy の ScoreText をドラッグする
ScoreManager.cs
using UnityEngine;
using UnityEngine.UI;
public class ScoreManager : MonoBehaviour
{
[SerializeField] private Text scoreText;
private int score = 0;
void Start()
{
// ゲーム開始時に「スコア: 0」を表示する
scoreText.text = "スコア: " + score;
}
public void AddScore(int points)
{
score += points;
scoreText.text = "スコア: " + score;
}
}
Start でゲーム開始時に「スコア: 0」を表示し、AddScore が呼ばれるたびに表示を更新します。今回は日本語をそのまま表示できる Legacy の Text を使います。
手順3:アイテムのプレハブを作る
- Hierarchy の「+」→ 2D Object → Sprites → Circle で円を作成し、名前を Item にする。Sprite Renderer の Color を黄色などに変えると、プレイヤーと見分けやすくなります
- Add Component で Rigidbody2D を追加する(Gravity Scale は 1 のまま。重力で落ちていきます)
- Add Component で Circle Collider 2D を追加し、Is Trigger をオンにする
- ItemController スクリプトを作成して次のコードを書き、Item にアタッチする
- Hierarchy の Item を Project ウィンドウへドラッグしてプレハブにする。プレハブができたら、Hierarchy の Item は削除する
ItemController.cs
using UnityEngine;
public class ItemController : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
FindFirstObjectByType<ScoreManager>().AddScore(10);
Destroy(gameObject);
}
}
void Update()
{
if (transform.position.y < -6f)
Destroy(gameObject); // 画面外で削除
}
}
Player に触れたら AddScore(10) でスコアを加算して自分を削除し、画面の下(y が -6 より下)まで落ちたときも自分を削除します。
手順4:スポナーを作る
- Hierarchy の「+」→ Create Empty で空の GameObject を作り、名前を ItemSpawner にする
- ItemSpawner スクリプトを作成して次のコードを書き、ItemSpawner にアタッチする
- ItemSpawner の Inspector にある Item Prefab 欄に、Project の Item プレハブをドラッグする
ItemSpawner.cs
using UnityEngine;
public class ItemSpawner : MonoBehaviour
{
[SerializeField] private GameObject itemPrefab;
[SerializeField] private float interval = 1.5f;
void Start()
{
InvokeRepeating("Spawn", 1f, interval);
}
void Spawn()
{
float x = Random.Range(-4f, 4f);
Instantiate(itemPrefab, new Vector3(x, 6, 0), Quaternion.identity);
}
}
InvokeRepeating で、1秒後から 1.5 秒ごとに Spawn を呼び出します。Spawn は x 座標をランダムに決めて、画面の上(y = 6)に Item を生成します。
動作確認
▶ を押して再生し、次の4つを確認しましょう。
- 左右キーでプレイヤーが動く
- 上からアイテムが次々に落ちてくる
- アイテムに触れるとスコアが 10 ずつ増える
- 取り逃したアイテムが画面の下で消える(再生中の Hierarchy で Item(Clone) が増え続けなければ OK)
プログラムの流れ
重要ポイント
落ち物キャッチゲームは、これまで学んだ要素の集大成です。
- プレイヤー … 入力で左右移動
- プレハブ … Item を Instantiate で生成
- 当たり判定 … OnTriggerEnter2D でキャッチを検知
- UI … スコアを Text で表示
- Destroy … キャッチした Item と画面外の Item を削除
発展アイデア
- ゲームオーバー … 一定時間で終了、または落ちたアイテムが一定数超えたら終了
- 複数種類のアイテム … 得点が違う、悪いアイテム(マイナス)など
- 効果音 … キャッチ時に SE を再生
- ハイスコア … PlayerPrefs で保存
- 移動範囲の制限 …
Mathf.Clampでプレイヤーが画面の外に出ないようにする
補足:次の第17回について
第17回の横スクロールアクションは、新しいプロジェクト(ActionGame)で作ります。今回の CatchGame プロジェクトは上書きされないので、そのまま残しておけます。








ディスカッション
コメント一覧
まだ、コメントがありません