Unity 6でIgaguriを作る② ― クリックした方向へ飛ばして、パーティクルで演出する(PC版)

広告

この記事は、北村愛実 著『Unityの教科書 Unity 6完全対応版』(SBクリエイティブ)で扱われているIgaguri(第7章)制作を題材に、授業でつまずきやすい点や、コードの意味を補足するために作成した学習記事です。コードおよび制作手順の詳細は、書籍もあわせてご参照ください。

前回は、3Dの世界でイガグリを奥へ飛ばし、的に当たったらその場で止めて「刺さった」ように見せるところまで作りました。

Unity 6でIgaguriを作る① ― 3Dの世界でイガグリを飛ばして、的に刺す(PC版)

今回は、いよいよゲームらしくしていきます。画面をクリックした方向へイガグリを飛ばし、クリックするたびに新しいイガグリを作り、的に当たったらパーティクル(小さな粒)をパッと飛び散らせます。

回内容
前回(①)2Dと3Dの違い/シーンの準備/イガグリを前へ飛ばす/的に刺さって止まる
今回(②)クリックした方向へ飛ばす(Ray)/イガグリを何個も作る/当たったときのパーティクル演出

この記事で作るもの

  • 画面をクリックするたびに、イガグリが1個作られる
  • イガグリは、クリックした場所に向かって飛んでいく
  • 的に当たったら刺さって止まり、白い粒がパッと飛び散る

1. 前回のテスト用コードを片付ける

前回は動作確認のために、Start の中で Shoot を呼んでいました。今回からは「クリックしたとき」に飛ばすので、この行はコメントにしておきます。

void Start()
{
    Application.targetFrameRate = 60;

    // クリックで飛ばすようにするので、テスト用の発射はコメントにする
    // Shoot(new Vector3(0, 200, 2000));
}

また、シーンに置いたままのイガグリは、Hierarchyから削除しておきましょう。これからはPrefab(igaguriPrefab)から、クリックのたびに作ります。

2. イガグリ工場を作る(IgaguriGenerator)

CatEscapeで矢を降らせたときと同じように、Prefabからイガグリを作る「工場」を用意します。

Unity 6でCatEscapeを作る① ― 猫の移動と、Prefabで矢を降らせる仕組み(PC版)

  1. Hierarchyの + → Create Empty で空のオブジェクトを作り、名前を IgaguriGenerator にする
  2. Create → Scripting → MonoBehaviour Script で IgaguriGenerator スクリプトを作り、空のオブジェクトに付ける

ステップ1:クリックするたびにイガグリを作る

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

public class IgaguriGenerator : MonoBehaviour
{
    public GameObject igaguriPrefab;

    void Update()
    {
        // マウスの左ボタンが押された瞬間
        if (Mouse.current.leftButton.wasPressedThisFrame)
        {
            // Prefabからイガグリを1個作る
            GameObject igaguri = Instantiate(igaguriPrefab);

            // 作ったイガグリの Shoot を呼んで飛ばす(まずは前回と同じ方向)
            igaguri.GetComponent<IgaguriController>().Shoot(new Vector3(0, 200, 2000));
        }
    }
}

スクリプトを保存したら、Hierarchyの IgaguriGenerator を選び、Inspectorの Igaguri Prefab 欄に、Projectウィンドウの igaguriPrefab をドラッグ&ドロップします。

再生してクリックすると、そのたびにイガグリが作られ、同じ方向へ飛んでいきます。

ここで使っている igaguri.GetComponent<IgaguriController>().Shoot(...) は、「作ったイガグリに付いている IgaguriController を取り出して、その Shoot を呼ぶ」という意味です。前回 Shoot を public にしておいたのは、ここから呼ぶためでした。

イラスト:ScreenPointToRayでカメラからクリックした点へRayを作り、その向きにイガグリを飛ばす流れ

3. クリックした方向へ飛ばす(Ray)

今のままだと、どこをクリックしても同じ方向にしか飛びません。クリックした場所に向かって飛ばすには、Ray(レイ:光線)を使います。

ステップ2:Rayの向きに飛ばす(完成)

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 ray = Camera.main.ScreenPointToRay(Mouse.current.position.value);

            // Rayの向きに、強さ2000の力で飛ばす
            igaguri.GetComponent<IgaguriController>().Shoot(ray.direction * 2000);
        }
    }
}

ScreenPointToRay とは

画面は平らな2Dですが、ゲームの世界は3Dです。Camera.main.ScreenPointToRay は、カメラから、画面上のその点を通って奥へのびる光線を作ってくれるメソッドです。

使うもの意味
Mouse.current.position.valueマウスの画面上の位置(ピクセル)
Camera.mainTagが MainCamera のカメラ
ray.origin光線の出発点(カメラの位置)
ray.direction光線の向き。長さ1の Vector3

ray.direction は「向き」だけを表していて、長さはいつも1です。そこに 2000 を掛けることで、「クリックした方向へ、強さ2000の力」になります。

4. 数字で見る ― どこをクリックすれば当たる?

前回と同じように、ざっくり数字で確かめてみます。

  • 力の大きさは2000、力が加わるのは物理の計算1回分(0.02秒)、重さは1なので、飛び出す速さは 秒速40(向きはクリックした方向)
  • 画面の真ん中をクリックすると、Rayの向きは (0, 0, 1)。上向きの速さが0なので、的(23先)に届くまでの約0.58秒で、重力により約1.6下がる
  • イガグリの高さは1から約 -0.6 へ。的の板は y = -0.4〜3.4 なので、板の下の端をかすめて外れてしまう
  • 的の中心(y = 1.5)に当てるには、真ん中より少しだけ上(画面の高さの1割弱ほど上)をクリックするとちょうどよい

これは、本物のボールを投げるときに的の少し上を狙うのと同じです。物理で動かしているからこそ、こうした「それらしい」動きになります。

イラスト:当たった瞬間にParticleSystemをPlayして粒を飛び散らせる仕組みと設定

5. 当たったらパーティクルを飛び散らせる

最後に、当たったときの演出を加えます。ParticleSystem(パーティクルシステム)は、小さな粒をたくさん出して、煙や火花、爆発などを表現するコンポーネントです。

イガグリのPrefabにParticleSystemを付ける

  1. Projectウィンドウの igaguriPrefab をダブルクリックして、Prefabの編集画面を開く
  2. ルートのオブジェクト(Rigidbodyが付いているもの)を選び、Add Component → Effects → Particle System を追加する
  3. 次の表のように設定する
設定項目値意味
Duration11回の再生の長さ(1秒)
Loopingオフくり返さず、1回だけ出す
Start Lifetime1粒が1秒で消える
Start Speed8粒の飛ぶ速さ
Start Size1粒の大きさ
Play On Awakeオフ作られた瞬間には出さない
Emission → Rate over Time0時間とともに少しずつ出すのはやめる
Emission → BurstsCount 100(+ボタンで追加)再生した瞬間に、一気に100個出す
ShapeCone(Angle 25、Radius 1)円すいの形に広がる

Play On Awake がオンのままだと、クリックしてイガグリが作られた瞬間に粒が出てしまいます。オフにして、ぶつかったときにスクリプトから再生します。

IgaguriController にパーティクルの再生を追加(完成)

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));
    }
}

追加したのは GetComponent<ParticleSystem>().Play(); の1行だけです。Rigidbodyのときと同じように、同じオブジェクトに付いているコンポーネントを GetComponent で取り出して、Play で再生しています。

再生して的をクリックしてみましょう。イガグリが刺さった瞬間に、白い粒がパッと飛び散れば完成です。

6. よくあるつまずき

UnassignedReferenceException が出る

UnassignedReferenceException: The variable igaguriPrefab of IgaguriGenerator has not been assigned.

IgaguriGenerator の Igaguri Prefab 欄が空のままです。Projectウィンドウの igaguriPrefab をドラッグ&ドロップしましょう。

NullReferenceException が出る(Instantiate の次の行)

  • igaguriPrefab に IgaguriController が付いていない(シーンのイガグリにだけ付けて、Prefabに反映していない)
  • カメラのTagが MainCamera になっておらず、Camera.main が見つからない

Rigidbody を Start で取っておいたら、動かなくなった

GetComponent を毎回呼ぶのはもったいないと思って、次のように書き換えると、エラーになります。

Rigidbody rb;

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

public void Shoot(Vector3 dir)
{
    rb.AddForce(dir);  // ここで NullReferenceException
}

理由は、呼ばれる順番です。Instantiate で作ったイガグリの Start は、すぐには呼ばれず、次の更新のタイミングで呼ばれます。ところが IgaguriGenerator は、作った直後に Shoot を呼んでいるので、その時点ではまだ rb が空っぽなのです。

取っておきたい場合は、Start ではなく Awake を使いましょう。Awake は Instantiate の中ですぐに呼ばれるので、Shoot より先に準備ができます。

void Awake()
{
    rb = GetComponent<Rigidbody>();
}

クリックした瞬間に粒が出てしまう/粒が出続ける

ParticleSystemの Play On Awake がオンになっているか、Looping がオンになっています。どちらもオフにしましょう。

何も出ない

Emissionの Bursts を追加し忘れていると、Rate over Timeが0なので1個も出ません。Burstsの + ボタンで追加して、Countを100にします。

まとめ

  • Instantiate(igaguriPrefab) で、クリックするたびにイガグリを作る
  • Camera.main.ScreenPointToRay で、カメラからクリックした点を通る光線(Ray)を作る
  • ray.direction は長さ1の向き。× 2000 で力の強さを決めて Shoot に渡す
  • 重力で少し落ちるので、的の中心より少し上を狙うと当たる
  • ParticleSystemは Play On Awake と Looping をオフにし、Burstで一気に出す。当たった瞬間に Play()
  • Instantiate 直後に呼ぶメソッドで使う準備は、Start ではなく Awake で行う

これでIgaguriは完成です。2Dで学んだ「物理」「Prefab」「スクリプトどうしの連携」が、3Dでもそのまま使えることを実感できたのではないでしょうか。次の「AppleCatch」では、3Dの世界でリンゴをキャッチするゲームを作っていきます。

このシリーズの記事一覧(全10本)は、Unity 6 ゲーム制作 補足解説シリーズまとめからご覧いただけます。

参考書籍

北村愛実 著
『Unityの教科書 Unity 6完全対応版』
SBクリエイティブ
書籍サポートページ(サンプルファイル)

本記事では、書籍で扱われているIgaguri(第7章)制作を題材に、初学者向けの補足説明やUnity 6での学習上のポイントを加えて解説しています。

訪問数 1 回, 今日の訪問数 1回

広告