Unity & C# 学習教材

チュートリアル: アイテム収集

方向キーで動く球体(プレイヤー)が、フィールドに配置されたアイテムに触れると回収(削除)されるゲームを実装します。これまでに学んだ Rigidbody・AddForce・Collider・Prefab を組み合わせて、インタラクティブなゲームの基本構造を作ります。

学習目標

前提知識


1. シーンを準備する

ステージ(地面)を作る

  1. メニューバーから GameObject → 3D Object → Cube を追加し、名前を Stage にする
  2. Inspector で Transform を設定する
プロパティ
Position X=0, Y=0, Z=0
Scale X=10, Y=0.5, Z=10

プレイヤーを作る

  1. GameObject → 3D Object → Sphere を追加し、名前を Player にする
  2. Position を X=0, Y=0.75, Z=0 に設定する(ステージの上面に乗せる)
  3. Inspector の Add Component → Physics → Rigidbody で Rigidbody を追加する

ステージとプレイヤーの配置


2. プレイヤーを動かす

Player GameObject に Player スクリプトを作成してアタッチします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Player.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class Player : MonoBehaviour
{
    private Rigidbody _rigidbody;

    private void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }

    private void Update()
    {
        var move = Vector3.zero;

        if (Keyboard.current.rightArrowKey.isPressed) move.x += 1f;
        if (Keyboard.current.leftArrowKey.isPressed)  move.x -= 1f;
        if (Keyboard.current.upArrowKey.isPressed)    move.z += 1f;
        if (Keyboard.current.downArrowKey.isPressed)  move.z -= 1f;

        _rigidbody.AddForce(move);
    }
}

Play ボタンを押して方向キーで球体が動くことを確認しましょう。


3. アイテムを作る

アイテムの形を設定する

  1. GameObject → 3D Object → Cube を追加し、名前を Item にする
  2. Inspector で Transform を設定する
プロパティ
Position X=2, Y=0.75, Z=2
Rotation X=45, Y=45, Z=45
Scale X=0.5, Y=0.5, Z=0.5

アイテムを回転させる

Item GameObject に Item スクリプトを作成してアタッチします。Transform.Rotate() は現在の向きに回転量を加算するメソッドです。Update 内で繰り返し呼ぶことで継続的な回転アニメーションになります。

1
2
3
4
5
6
7
8
9
10
// Item.cs
using UnityEngine;

public class Item : MonoBehaviour
{
    private void Update()
    {
        transform.Rotate(0, 1f, 0, Space.World);
    }
}

Space.World を指定すると、オブジェクト自身の傾きに関わらず世界座標の Y 軸を中心に回転します。

Is Trigger をオンにする

Item GameObject の Box Collider コンポーネントを開き、Is Trigger にチェックを入れます。これで Player が Item に触れてもぶつかって弾かれず、交差を検知できるようになります。

Box Collider の Is Trigger にチェック


4. アイテムをプレハブ化する

Hierarchy ビューの Item を Project ビューの Assets フォルダーにドラッグ & ドロップして、プレハブとして保存します。

Item をドラッグ & ドロップ

プレハブを保存したら、Project ビューの Item プレハブを Scene ビューにドラッグ & ドロップして複数配置します。

複数のアイテムを配置したシーン


5. アイテムを回収する

Player スクリプトに OnTriggerEnter を追加して、アイテムへの接触時に削除します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Player.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class Player : MonoBehaviour
{
    private Rigidbody _rigidbody;

    private void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }

    private void Update()
    {
        var move = Vector3.zero;

        if (Keyboard.current.rightArrowKey.isPressed) move.x += 1f;
        if (Keyboard.current.leftArrowKey.isPressed)  move.x -= 1f;
        if (Keyboard.current.upArrowKey.isPressed)    move.z += 1f;
        if (Keyboard.current.downArrowKey.isPressed)  move.z -= 1f;

        _rigidbody.AddForce(move);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Item"))
        {
            Destroy(other.gameObject);
        }
    }
}

CompareTag("Item") は、触れた相手のタグ"Item" かどうかを調べます。これにより、Is Trigger がオンの別のオブジェクト(例: ゴールゾーンなど)を誤って削除することを防げます。

タグの設定: Item プレハブを選択し、Inspector 上部の Tag ドロップダウンから Add Tag…Item タグを追加し、Item プレハブに設定してください。


完成コード

Player.cs(完成版)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using UnityEngine;
using UnityEngine.InputSystem;

public class Player : MonoBehaviour
{
    private Rigidbody _rigidbody;

    private void Start()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }

    private void Update()
    {
        var move = Vector3.zero;

        if (Keyboard.current.rightArrowKey.isPressed) move.x += 1f;
        if (Keyboard.current.leftArrowKey.isPressed)  move.x -= 1f;
        if (Keyboard.current.upArrowKey.isPressed)    move.z += 1f;
        if (Keyboard.current.downArrowKey.isPressed)  move.z -= 1f;

        _rigidbody.AddForce(move);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Item"))
        {
            Destroy(other.gameObject);
        }
    }
}
Item.cs(完成版)
1
2
3
4
5
6
7
8
9
using UnityEngine;

public class Item : MonoBehaviour
{
    private void Update()
    {
        transform.Rotate(0, 1f, 0, Space.World);
    }
}

課題

課題 1: アイテムに得点を追加する

アイテムを回収するたびに得点が加算されるようにしましょう。

ヒント: Player スクリプトにスコアフィールドを追加し、OnTriggerEnter の中でカウントアップします。Debug.Log でスコアを表示してみましょう。

解答を見る
1
2
3
4
5
6
7
8
9
10
11
private int _score = 0;

private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("Item"))
    {
        Destroy(other.gameObject);
        _score++;
        Debug.Log($"スコア: {_score}");
    }
}

課題 2: アイテムごとに得点を変える

アイテムによって得点が異なるようにしてみましょう。

ヒント: Item.cs[SerializeField] public int point = 1; フィールドを追加し、Player.csOnTriggerEnter 内で other.GetComponent<Item>().point を読み取ります。

解答を見る
1
2
// Item.cs に追加
[SerializeField] public int point = 1;
1
2
3
4
5
6
7
8
9
10
11
// Player.cs の OnTriggerEnter
private void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("Item"))
    {
        var item = other.GetComponent<Item>();
        _score += item.point;
        Debug.Log($"スコア: {_score}");
        Destroy(other.gameObject);
    }
}

課題 3: 制限時間を設ける

Time.time を使って制限時間を実装しましょう。一定時間が経過したらゲームを停止して最終スコアを表示します。

ヒント: [SerializeField] private float _timeLimit = 30f;private float _startTime; を組み合わせます。Start_startTime = Time.time; を記録し、UpdateTime.time - _startTime_timeLimit を超えたら Debug.Log でスコアを表示して enabled = false; でスクリプトを止めます。


課題 4(発展): 別種類のアイテムを追加する

色の異なる別の Item プレハブを作り、触れると残り時間が増えるアイテムを実装してみましょう。


まとめ


理解度チェック

  1. _rigidbody = GetComponent<Rigidbody>()Update ではなく Start に書く理由は何ですか?
  2. CompareTag("Item") を使わずに Destroy(other.gameObject) だけ書いた場合、何が問題になりますか?
  3. アイテムを 20 個に増やしたいとき、プレハブを使うメリットは何ですか?
解答を見る
  1. GetComponent はコストのかかる処理であり、毎フレーム呼ぶとパフォーマンスへの影響が積み重なるため。Start で一度だけ取得してフィールドに保持する。
  2. Is Trigger がオンのオブジェクトすべてに触れると削除してしまう。ゴールゾーンや罠ゾーンなども削除されてしまう可能性がある。
  3. プレハブを1か所変更するだけで20個すべてに変更が反映される。個別に修正する必要がなく、変更漏れが起きない。

次のステップ

UnityEngine.Random で乱数を生成する では、ゲームでよく使う乱数生成の基本を学びます。