学習記事一覧 · Unity教科書_Unity6対応

Unity入門:3Dで的を狙え!Igaguriゲームを作りながら学ぼう!

対象読者:Unity学び始めの方・C#をこれから覚えたい方 このブログでは、実際のIgaguri(いがぐり)ゲームのコードを読み解きながら、Unityの3D物理演算・レイキャスト・パーティクルを学びます。


記事の目次

この記事はやや長めです。目的に合わせてジャンプして読み分けてください。

おすすめの読み方

セクション一覧

ポイント一覧


このゲームで何ができるの?

今回題材にするのは、画面をクリックした方向に「いがぐり」を発射して、的に当てる3Dアクションゲームです。

  • 🖱️ マウスでクリックした方向にいがぐりが飛んでいく
  • 🌰 いがぐりは物理演算で自然な放物線を描く
  • 💥 的に当たると動きが止まり、パーティクル(爆発エフェクト)が再生される

クリックした方向にいがぐりが飛び、的に当たる様子(イメージ)

たった 2つのスクリプト(合計約30行) でこれが実現できます。3Dレイキャスト物理演算という、3Dゲーム開発の重要テクニックが凝縮されています。一緒に読み解いていきましょう!


プロジェクトの構成

このプロジェクトのファイル構成はこうなっています。

Assets/
  ├── IgaguriGenerator.cs    # いがぐりを生成・発射するスクリプト
  ├── IgaguriController.cs   # いがぐりの動きと衝突を制御するスクリプト
  ├── igaguriPrefab          # いがぐりのプレハブ(Rigidbody・ParticleSystem付き)
  └── _Tanks/                # UnityのTanksサンプルアセット
        └── Scripts/         # 的の移動・ゲーム管理スクリプト群

chapter7では、UnityのサンプルアセットTanksの上に、オリジナルのいがぐり発射システムを追加しています。サンプルアセットを改造して新機能を組み込む、というゲーム開発のリアルな進め方が体験できます。


コードを全部見てみよう

IgaguriGenerator.cs(いがぐりの生成と発射)

using UnityEngine;
using UnityEngine.InputSystem;  // 入力を検知するために必要!!

public class IgaguriGenerator : MonoBehaviour
{
    public GameObject igaguriPrefab;

    void Update()
    {
        if (Mouse.current.leftButton.wasPressedThisFrame)
        {
            GameObject igaguri = Instantiate(igaguriPrefab);

            Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.value);
            igaguri.GetComponent<IgaguriController>().Shoot(ray.direction * 2000);
        }
    }
}

IgaguriController.cs(いがぐりの物理と衝突)

using UnityEngine;

public class IgaguriController : MonoBehaviour
{
    public void Shoot(Vector3 dir)
    {
        GetComponent<Rigidbody>().AddForce(dir);
    }

    void OnCollisionEnter(Collision collision)
    {
        GetComponent<Rigidbody>().isKinematic = true;
        GetComponent<ParticleSystem>().Play();
    }

    void Start()
    {
        Application.targetFrameRate = 60;
        // Shoot(new Vector3(0, 200, 2000));
    }
}

この2つのスクリプトには、合計6つの学びポイントがあります。順番に見ていきましょう!


ポイント①:2Dと3Dの物理コンポーネントの違い

GetComponent<Rigidbody>().AddForce(dir);

chapter6では Rigidbody2D を使いましたが、今回は Rigidbody(3D版) です。

コンポーネント 対応する空間 主な用途
Rigidbody2D 2D(X・Y軸) 2Dゲームの物理演算
Rigidbody 3D(X・Y・Z軸) 3Dゲームの物理演算

AddForce() の使い方は同じですが、3Dでは Vector3(X・Y・Z の3要素)でベクトルを扱います。これにより、奥行き(Z軸)方向への力も加えられるようになります。


ポイント②:Camera.main.ScreenPointToRay() で画面クリックを3D空間の方向に変換する

Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.value);
igaguri.GetComponent<IgaguriController>().Shoot(ray.direction * 2000);

これがこのゲームの核心です。画面上のクリック座標(2D)を3D空間の「方向」に変換しています。

画面(2D座標)
ScreenPointToRay()
Ray(カメラから飛び出す光線)
  └─ ray.direction = 光線の方向ベクトル(正規化済み)

Ray(レイ) はカメラの位置から画面のクリック点を通って3D空間に伸びる「光線」のようなものです。この光線の方向 ray.direction にいがぐりを飛ばすことで、「クリックした方向に発射する」という直感的な操作が実現できています。

ray.direction * 2000 → 同じ方向に、2000倍の力を加える

💡 ray.direction は長さ1の正規化されたベクトルです。これに大きな数を掛けることで発射の強さを調整しています。数値を大きくすると速く飛びます。


ポイント③:公開メソッドでいがぐりを「外から操作する」

// IgaguriController.cs
public void Shoot(Vector3 dir)
{
    GetComponent<Rigidbody>().AddForce(dir);
}
// IgaguriGenerator.cs
igaguri.GetComponent<IgaguriController>().Shoot(ray.direction * 2000);

IgaguriControllerShoot() メソッドは public で定義されています。これにより、別のスクリプト(IgaguriGenerator)から呼び出せます。

IgaguriGenerator(発射を指示する側)
    └─ .GetComponent<IgaguriController>()
         └─ .Shoot(方向ベクトル)  ← この橋渡しで2スクリプトが連携

メソッドに Vector3 dir という引数を持たせることで、「どの方向に飛ばすか」を呼び出し元が自由に指定できます。発射ロジックと「どこから飛ばすか」の決定を分離した、再利用しやすい設計です。


ポイント④:OnCollisionEnter() で3D衝突を検知する

void OnCollisionEnter(Collision collision)
{
    GetComponent<Rigidbody>().isKinematic = true;
    GetComponent<ParticleSystem>().Play();
}

OnCollisionEnter は3D空間で物体が衝突したときに自動的に呼ばれるメソッドです。

コールバック 次元 呼ばれるタイミング
OnCollisionEnter 3D 物体に物理的に衝突した瞬間
OnCollisionEnter2D 2D 物体に物理的に衝突した瞬間
OnTriggerEnter 3D トリガー領域に触れた瞬間
OnTriggerEnter2D 2D トリガー領域に触れた瞬間

何かに当たった瞬間に2つの処理が走ります。


ポイント⑤:isKinematic = true で物理演算を止める

GetComponent<Rigidbody>().isKinematic = true;

isKinematictrue にすると、そのRigidbodyは物理演算の影響を受けなくなります

isKinematic = false(デフォルト)→ 重力・力・衝突の影響を受ける(飛んでいる状態)
isKinematic = true              → 物理演算を無視して静止する(刺さった状態)

いがぐりが何かに当たった瞬間に isKinematic = true にすることで、当たった場所に「刺さった」ように静止する演出が実現できています。コードを書き換えることなく、実行中に物理状態を動的に切り替えられるのがポイントです。


ポイント⑥:ParticleSystem.Play() でエフェクトを再生する

GetComponent<ParticleSystem>().Play();

ParticleSystem はUnityの標準エフェクトシステムです。炎・爆発・煙・きらめきなど、様々な視覚的エフェクトを表現できます。.Play() を呼ぶだけでエフェクトが再生されます。

メソッド 動作
Play() パーティクルを再生する
Stop() パーティクルを停止する
Clear() 表示中のパーティクルを消去する

いがぐりのプレハブに事前に ParticleSystem コンポーネントをアタッチしておくことで、「当たった瞬間に .Play() を1行呼ぶだけ」という非常にシンプルなコードでエフェクトが実現できています。


2つのスクリプトの役割分担

【IgaguriGenerator】              【IgaguriController】
空のGameObjectにアタッチ          いがぐりプレハブにアタッチ
   ↓                                    ↓
クリックを検知                    Shoot()で力を加えて発射
ScreenPointToRay で方向を計算     OnCollisionEnter で衝突を検知
Instantiate でいがぐりを生成       → isKinematic = true で静止
Shoot() を呼んで方向を渡す         → ParticleSystem.Play() でエフェクト

コードの流れを整理しよう

【IgaguriGenerator の毎フレーム処理フロー】

① クリックされた?
   └─ YES → igaguriPrefab を Instantiate(生成)
            → ScreenPointToRay でクリック方向の Ray を取得
            → IgaguriController.Shoot(ray.direction * 2000) を呼ぶ

【IgaguriController の処理フロー】

Shoot(dir) が呼ばれた時
   └─ Rigidbody.AddForce(dir) → 指定方向に力を加えて飛ばす

② 何かに衝突した時(OnCollisionEnter)
   └─ isKinematic = true → 物理演算を止めて静止
   └─ ParticleSystem.Play() → エフェクトを再生

自分でカスタマイズしてみよう!

挑戦①:発射の強さを変える

igaguri.GetComponent<IgaguriController>().Shoot(ray.direction * 2000);
// 3000 にすると速く、1000 にするとゆっくり飛ぶ

挑戦②:いがぐりを連射できないようにする

// IgaguriGenerator に変数を追加して、最後の発射から一定時間後だけ発射できるようにする
float cooldown = 0;

void Update()
{
    this.cooldown -= Time.deltaTime;
    if (Mouse.current.leftButton.wasPressedThisFrame && this.cooldown <= 0)
    {
        this.cooldown = 1.0f; // 1秒のクールダウン
        // ... 発射処理
    }
}

挑戦③:衝突したオブジェクトの名前をログ出力する

void OnCollisionEnter(Collision collision)
{
    Debug.Log("衝突相手: " + collision.gameObject.name);
    // ...
}

挑戦④:コメントアウトされたコードを試す

void Start()
{
    Application.targetFrameRate = 60;
    Shoot(new Vector3(0, 200, 2000)); // コメントを外すと起動時に自動発射!
}

まとめ

今回のIgaguriゲームから学んだことを整理しましょう。

  • Rigidbody(3D)は Rigidbody2D(2D)と使い方は同じで、3D空間(Vector3)で動作する
  • Camera.main.ScreenPointToRay() で画面クリック座標を3D空間の光線(Ray)に変換できる
  • ray.direction は方向ベクトルで、これに大きな数を掛けて発射力にする
  • public メソッドに引数を持たせると、呼び出し元から発射方向を柔軟に指定できる
  • OnCollisionEnter は3D物体が衝突した瞬間に自動で呼ばれる(2D版は OnCollisionEnter2D
  • Rigidbody.isKinematic = true にすると実行中に物理演算を動的に止められる
  • ParticleSystem.Play() を1行書くだけでエフェクトを再生できる

2Dゲームから3Dゲームへの拡張として、座標の扱いが Vector2 から Vector3 になり、ScreenPointToRay という3D特有のテクニックが登場しました。「動く→コードを読む→カスタマイズする」 のサイクルを繰り返すことが、Unity上達の近道です。

次のステップとして、当たった的をカウントするスコア機能や、一定数当てたらゲームクリアになる仕組みを追加してみましょう!


最終更新:2026年4月