i-school - 3D宝石集めアクションゲーム 手順16
 ゲーム実行中に、宝石を自動生成する機能を実装します。

 この部分も少しずつ処理を作っていきますので、合計3回の手順に分けて実装します。

 こちらは今回の手順で実装する部分です。一定時間ごとに同じ位置に宝石を生成させます。


<実装動画>
動画ファイルへのリンク



 最終的な手順で実装する、完成したときの動画です。(手順18まで終了したときの状態です)
ステージ内のプレイヤーの移動可能な範囲内において、ランダムな位置に対して、一定時間おきに宝石を生成します。


<実装動画>
動画ファイルへのリンク


 この完成形のイメージを持ちながら、順番に処理を作っていきます。



 以下の内容で順番に実装を進めていきます。

手順16 ー宝石の自動生成機能の追加ー
1.宝石プレハブのプレハブバリアントを作成する
2.ゲーム開始時に宝石を生成する機能を作成する
3.一定時間おきに宝石を生成する(自動生成)機能を作成する



<新しく学習する内容>
 ・プレハブバリアント
 ・メソッドの活用方法



1.宝石プレハブのプレハブバリアントを作成する

1.プレハブバリアントを作成する


 宝石のプレハブ・ゲームオブジェクトを、もう一度プレハブにします。

 Project 内に Prefabs フォルダを新規作成し、その中に、ヒエラルキーにある宝石のプレハブ・ゲームオブジェクトをドラッグアンドドロップしてください。
プレハブをどのようにして処理するか確認のポップアップが開きますので、Prefab Variant を選択します。


確認のポップアップ




 Prefabs フォルダ内に、宝石のプレファブ・ゲームオブジェクトを元にした、宝石のプレハブバリアントが作成されます。
バリアントの場合、プレハブのアイコンも変化します。

プレハブバリアントのアイコン



Prefabs フォルダ内のプレハブバリアント



インスペクター画像




 プレハブバリアントとは、元々のプレハブの特徴を引き継ぎつつ、バリアント独自の特徴を持つことができます。
そして元のプレハブが変更された場合、バリアントにも元のプレハブの変更が適用されますが、バリアント独自の特徴は変更されません
これが大きな特徴の1つです。

 今回であれば、宝石のプレハブ・ゲームオブジェクトを元のプレハブとし、
その特徴を持ちつつ、ヒエラルキーにあった宝石のプレハブ・ゲームオブジェクトだけが持つ新しい機能を持ったプレハブを作ることが出来ます。


参考サイト
Unity 公式マニュアル
プレハブバリアント
くろくまそふと 様
ゲーム作り方ガイド 【Unity】プレハブ(Prefab)とは?プレハブの作り方・編集方法まとめ
Unityの使い方|初心者からわかりやすく
【Unity】プレハブバリアントを使う


2.シーン内の宝石を削除する


 宝石のプレハブバリアントが出来ましたので、ヒエラルキーにある宝石のゲームオブジェクトを削除します。
間違えて Prefabs フォルダ内のプレハブバリアントを削除しないようにしてください。


ヒエラルキー画像



Game ビュー画像



 ゲーム内から宝石がなくなりました。
次はゲームの実行後に宝石を自動生成する機能を作成していきます。


2.ゲーム開始時に宝石を生成する機能を作成する

1.設計


 宝石がゲーム内から削除されましたので、ここから、動的な生成機能の実装を行います。
動的とは、ゲーム実行中において処理される機能のことです。宝石に関していえば、最初からゲーム内に置いておくのではなく、
ゲームが始まってから生成されることによって存在するようになることを指します。

 宝石の生成機能の最終的な目的は、以下と通りです。

 1.ステージ内に
 2.プレイヤーの移動できる範囲内に
 3.一定時間おきに
 4.ランダムな位置に対して
 5.宝石を生成する

 日本語で書けば1行でかけてしまう処理であっても、プログラムではそうは行きません。
上記のように、1つの処理として考えるのではなく、これらは複数の処理の塊で出来ていることを認識し、そのためにも処理ごとに分解して考えていきます。



 この手順ではまず、


 1.ステージ内に
 5.宝石を生成する

 この処理を作成します。

 この処理が完成したら、続いて、


 1.ステージ内に
 3.一定時間おきに
 5.宝石を生成する

 この処理を作成します。
残りの処理は次の手順で作成します。



 日本語で考えた処理をプログラムに直していくことが、最大の難関であると同時に、アレンジはすべてエンジニアのスキル次第とも言えます。
とはいえ、最初から1〜5の処理をすらすらと書ける人はいませんし、書けなくても問題ありません。

 大切なことは、自分に書ける処理があるのか、仕分けして考える、という認識を持つことです。

 先ほどのように、作りたい処理を分割したら、その処理の中に、自分の知っている処理、つまり、プログラムを書ける処理があるかを見極めます
そして、その処理をまずは書いて動かしてみます。そうすることで、どのような処理が足りていないのかが見えてきます。

 理解できていないプログラムを書くことは出来ませんので、まずはこのように、自分のできることと、出来ないことを仕分けしましょう
その上で学習すべき部分 = 理解できていない部分がわかってきますので、それを補うために学習をします。
そうやって徐々に理解を深めて、処理を組み立てて動くようにしていくようにします。
 

2.GemSpawner スクリプトを作成する


 それでは、先ほど分割した処理を見ながら、処理を考えてみてください。

 1.ステージ内に
 5.宝石を生成する

 この処理を実装するには、どのような変数が必要になるのか、どのような処理が必要になるのかを考えてみましょう。
そして動くか動かないかは別にして、まずは一人で処理を書いて動かしてみましょう。


GemSpawner.cs

<= クリックすると開きます


 スクリプトを作成したらセーブします。


3.GemSpawner ゲームオブジェクト ゲームオブジェクトを作成し、GemSpawner スクリプトをアタッチして設定を行う


 ヒエラルキーの空いている場所で右クリックをしてメニューを開き、Create Empty を選択します。
新しい空のゲームオブジェクトが作成されますので、名前を GemSpawner ゲームオブジェクト に変更します。


ヒエラルキー画像




 作成した GemSpawen スクリプトをドラッグアンドドロップして GemSpawen ゲームオブジェクトにアタッチしてください。
アタッチ後は必ず、ゲームオブジェクトを確認して、スクリプトがアタッチされているかを確認してください。


GemSpawen ゲームオブジェクト インスペクター画像




 SerializeField 属性で宣言している変数が表示されていますので、
このスクリプトにより、生成を行いたいゲームオブジェクトのプレハブをこちらにドラッグアンドドロップしてアサインします。
どのゲームオブジェクトにアタッチされているコンポーネントを操作したいのか考えて、ドラッグアンドドロップして情報を登録してください。


GemSpawen ゲームオブジェクト アサイン後のインスペクター画像



 以上で設定は完了です。


4.ゲームを実行して動作を確認する


 どのような処理が動けば正常に動作しているのか、理解した上でゲームを実行してみてください。


<実装動画>
動画ファイルへのリンク


 この時点では、宝石のプレハブバリアントが置いてあった位置に、宝石が生成されれば制御成功です。

 上手くいかない場合のエラーについては、宝石自体が生成されないのか、あるいは生成されるものの位置が悪いのか、を見極めてから
修正方法を考えていくようにしてください。


3.一定時間おきに宝石を生成する(自動生成)機能を作成する

1.設計


 現在は Start メソッド内において宝石の生成処理を実行しているため、ゲーム実行時に1つだけ宝石の生成が行われます。
これは生成処理が正常に実行できるかどうかのデバッグも兼ねた実装であったため、この処理を別の処理に置き換えます。
 
 Update メソッドを利用し、一定時間おきに宝石の生成を行う処理を作成します。

 一定時間おき、というのは、ゲーム内の時間を計測し、それが一定値を超えたら、という形で実装出来ます。
色々な計測方法がありますが、まずは一般的な Update メソッドと Time.deltaTime 変数を利用した処理を使います。

 一定値を超えた際に宝石の生成を行いますが、宝石の生成についてはすでにメソッドで定義してありますので
今回追加する処理としては、時間の経過を測る処理と、宝石の生成とをつなげる処理です。

 また、一定時間おき、の場合、計測した時間をリセットする処理も必要になります。
同じ変数をタイマーのような形で繰り返し利用していく手法が作りやすいです。


2.GemSpawner スクリプトを修正する


 最初に分割した部分の続きを行います。

 1.ステージ内に
 3.一定時間おきに
 5.宝石を生成する

 ここでは「3.一定時間おきに」という部分を考慮した上で、宝石を生成する機能を追加します。



 どのような変数があれば「一定時間おき」という計測するための情報が作れるのかを考えてみてください。
処理のロジックが浮かぶのであれば、まずは、自分1人で書いてみることにチャレンジしてみましょう。

 宝石を生成する処理はすでにメソッドとして用意してありますので、同じ処理は書かず、メソッドを実行して宝石を生成するようにします。

 また、Start メソッドで実行していた「ゲーム実行時に1個だけ宝石を生成する」処理は、この手順では不要になります。
コメントアウトするか、削除してください。


GemSpawner.cs

<= クリックすると開きます


 スクリプトを修正したらセーブします。


3.<メソッドの活用方法>


 実行する処理はメソッド単位に分割して定義しておきます。
特にすぐに試してみたい処理については、Start メソッド内で実行することにより、効率のよいデバッグを行うことが出来ます。



 デバッグには色々なやり方があるため、上記のようにすぐに処理を動かして試したいケース以外にも、
一部の処理を一時的に停止しておきたいケースもあります。

 例えば、4行ある処理をメソッド化せずに直接 Start メソッドや Update メソッドに書いた場合、
デバッグのために、その処理を一旦停止するためには4行すべてをコメントアウトする必要があります。

 ですがメソッド化しておくことにより、処理の実行命令を1行だけコメントアウトすれば処理の停止が行えます。


<メソッド化していない場合、複数行の処理のコメントアウトが必要>
    void Update() {

        //timer += Time.deltaTime;

        //if (timer >= spawnInterval) {
            //timer = 0;
            //SpawnGem();
        //}
    }

<メソッド化している場合、1行のコメントアウトで完了>
    void Update() {
        //SpawnTimer();
    }

 今回 Start メソッドや Update メソッドに直接処理を書かずにメソッド化して利用しているのは、
このように処理を一時的に止めたいケースも想定しているためでもあります。

 デバッグには多くの時間を取られてしまうため、少しでも効率化を図れるよう工夫をこらしましょう。



 処理をメソッド単位で分割して定義している場合、同じ処理を実行したいときには、
メソッドの実行命令を1行書くだけで処理を実装出来ます。

<宝石の生成機能をメソッド化している>
    /// <summary>
    /// 宝石の生成
    /// </summary>
    public void SpawnGem() {

        // 生成
        Instantiate(gemPrefab);

        Debug.Log("宝石生成");
    }

 そのため


<メソッド化している場合、1行の処理を書くだけで実装完了>
    void Start() {

        // 宝石の生成
        //SpawnGem();  // <= この1行で生成命令が実装できる
  }

    /// <summary>
    /// 時間経過による宝石の生成
    /// </summary>
    private void SpawnTimer() {
        timer += Time.deltaTime;

        if (timer >= spawnInterval) {
            timer = 0;
            SpawnGem();  // <= この1行で生成命令が実装できる
        }
    }

 しかも、同じ処理であれば、上記のように、異なるメソッド内でも繰り返し利用することが出来ます。
特にメソッド内の処理が多いほど効果的です。

 適切な処理単位に区切ってメソッドを定義しておくことにより、処理の読み書きの両方にメリットがあります。

 こういった細かな配慮の積み重ねが、良質なコーディングスキルを養うことにつながります。


4.GemSpawner ゲームオブジェクトの設定を行う


 ヒエラルキーにある GemSpawner ゲームオブジェクトを選択して、インスペクターより GemSpawner スクリプトを確認します。
新しく宣言した変数のうち、public 修飾子で宣言している spawnInterval 変数が表示追加されていますので、
こちらの値を 0 から別の値に変更します。この値が「一定時間ごと」の部分の秒数を指す値です。
2 とすれば、2秒ごとに、3 とすれば 3秒ごとに、という値としてプログラム内で利用されます。


GemSpawner ゲームオブジェクト インスペクター画像



5.ゲームを実行して動作を確認する


 新しく GemSpawen スクリプトに記述した処理の内容を見直しどのような処理が実行されるのかを確認した上でデバッグを行います

 とりあえず実行してみて、というデバッグの手法は止めてください

 教材とはいえ、自分で処理をすべて書いているのですから、書いた内容をしっかりと理解した上でゲームを実行するようにしましょう。



 一定時間おきに、同じ位置に宝石を生成するようになれば成功です。
同じ位置に生成されるので、宝石に侵入して獲得する処理や、スコアの更新処理も正常に動作するはずですので
それらも合わせてデバッグしておいてください。

 GemSpawner スクリプトの spawnInterval 変数の値はゲーム実行時に変更しても適用されます。
こちらを 0 以外の値に変更し、一定時間の間隔(秒数)が変化するかもデバッグしましょう。


<実装動画>
動画ファイルへのリンク



 以上でこの手順は終了です。

 => 次は 手順17 ーランダムに選択した宝石を自動生成する機能ー です。