FuruiTweetUnity入門のゲーム作成チュートリアル第4弾の「城防衛シューティングゲーム」です!襲来してくる敵を大砲で迎撃し、城を守りきることができれば勝利というゲームを作成していきます。完成イメージ※そのほかのゲーム作成記事に関する情報は以下記事をご参考ください。第2回の今回は「敵を自動生成する」方法をご紹介します。敵を生成するロジックを作成していきます。前回の「《第1回》大砲で弾を撃つ」では以下の処理を作成してきました。第1回をまだ完成させていない!という方は「《第1回》大砲で弾を撃つ」を参考にして処理を完成させてください。第2回の今回は以下の処理を作成していきます。敵を自動生成する以上を中心に進めます。敵生成スクリプト作成の順番で進めます。1の敵プレハブの作成は手短に完了させて敵生成プレハブの部分について詳しく解説していきます。今回もできる限りわかりやすく解説していきますので、ぜひご参考ください。※第1回で使用していた「Debug」オブジェクトは事前に削除しておきます。削除済みの場合は無視してください。Debugオブジェクト敵プレハブを作成するまずは敵プレハブを作成します。今回は敵のオブジェクトにはこだわらず、球体(Sphere)を敵オブジェクトに採用します。そのため流れとしては球体を作成してプレハブ化するのみです。今後Blenderを用いてアニメーション付きの敵を作成する方法をご紹介しますので乞うご期待ください!それでは作成していきます。オブジェクトを作成するまずはじめにSphereを作成して、名前をEnemyとしてください。作成したEnemyのScaleを全て「5」にしてください。それ以外のTransform値は任意です(後々スクリプトで決定するためどんな値でも問題ありません)。Enemyの設定Enemyタグ付けをする次に作成したEnemyオブジェクトを敵として認識するためにタグ付けをします。Enemyオブジェクトを選択したままインスペクターウィンドウのTagを選択して、新しいタグ「Enemy」を追加します。Emptyの右下の+を選択、「Enemy」を入力してSaveを選択するとタグが追加されます。以下GIFを参考にEnemyタグを作成してみてください。タグの追加方法タグを追加できたら、EnemyオブジェクトのタグをEnemyに変更します。再度Tagを選択すると、先ほど作成したEnemyタグが追加されていますので、そちらを選択してください。以下のように変更されていればタグ付けは完了です。Enemyタグ付け完了プレハブ化する最後に作成したEnemyをプレハブ化します。ここまで読み進めていただいた方には解説不要かと思いますが、もう一度だけ方法をご紹介します。ヒエラルキーウィンドウのEnemyをプロジェクトウィンドウのPrefabsフォルダにドラッグ&ドロップすれば、作成したオブジェクトをプレハブ化することができます。Enemyをプレハブ化プレハブ化したオブジェクトは上記GIFのようにオブジェクト横の立方体が青く変化します。これでプレハブ化は完了です。ヒエラルキーウィンドウに残っているEnemyは最初から出現していると邪魔ですので、削除しておいてください。敵生成スクリプトを作成する次に敵を自動生成するスクリプトを作成します。敵を作成するロジックは以下のような仕様にします。一定時間経過後(乱数で時間決定)、敵を生成する正面方向に生成する(位置はランダム)基本ロジックを作成するまずは特定の時間間隔で敵プレハブを生成する部分を記述します。新しいスクリプト「EnemyGenerator」をScriptsフォルダに作成して、以下のように変更してください。0f;}}}プログラムの解説をします。7行目〜12行目を見てください。0f;敵プレハブを格納するためのGameObject型の「enemyPrefab」を作成します。publicにすることでエディタからプレハブをアタッチすることができます。次に敵を生成する時間間隔を決めるfloat型の「interval」を作成します。こちらは後ほど乱数を生成することでランダムに敵を生成するようなロジックに変更します。最後に経過時間を計測するfloat型の「time」を作成します。18行目では作成したintervalの時間を設定しています。ここでは固定値ですが、後ほど乱数生成する処理に変更しますので数値は任意です。25行目を見てください。Time.deltaTime;時間を計測するためのロジックです。Update関数ではUpdate関数一周にかかった時間を「Time.deltaTime」に保管しておきます。このTime.deltaTimeを「+=」演算子でtimeに加算することで経過時間を計測することができます。参考記事)Time.deltaTimeを使って制限時間を設定する参考記事)代入演算子について27行目〜36行目を見てください。0f;}ここでは経過時間timeが敵生成時間間隔intervalを超えたときにif文の中を実行します。はじめに敵プレハブを「Instantiate」メソッドを利用してインスタンス化(オブジェクト生成)して、GameObject型の「enemy」に格納しています。これで敵を生成することができます。参考記事)Prefabを使ったオブジェクト生成これだけでは敵がどこに生成されるかがわかりませんので敵の座標を決定します。ここでは固定値ですが、後ほどランダムに位置を変更するためのロジックを作成します。最後に経過時間を初期化して再び敵プレハブが生成されるようにします。初期化を忘れるとUpdate毎に敵プレハブが生成されてしまうのでご注意ください。これで敵が自動的に生成されるようになりました。時間間隔をランダムにする次に敵プレハブを生成するタイミングをランダムにする処理を書き加えます。先ほど作成したEnemyGeneratorスクリプトを以下のように変更してください。maxTime);}}9行目〜12行目を見てください。5f;ここでは時間間隔の最小値と最大値を定義しています。これによってランダムに生成される時間間隔の幅を設定することができます。飛んで45行目〜49行目を見てください。maxTime);}float型のメソッド「GetRandomTime」はminTimeとmaxTimeを利用して乱数を返すメソッドです。「Random.Range(minTime,maxTime)」で指定した範囲の乱数を生成します。参考記事)Unityで乱数を生成する参考記事)メソッド(関数)とは上記で定義したメソッドを22行目と41行目で呼び出すことで敵プレハブを生成するタイミングをランダムにすることができます。出現位置をランダムにする次に出現位置をランダムにする処理を書き加えます。先ほど作成したEnemyGeneratorスクリプトを以下のように変更してください。Vector3(x,y,z);}}13行目〜24行目を見てください。ランダムな座標を設定するために、先ほど時間の最小値と最大値を決定したようにX~Zについて最小値と最大値をそれぞれ設定します。変数をpublicに定義することでUnityエディタから値を変更することができます。飛んで63行目〜73行目を見てください。Vector3(x,y,z);}Vector3型のメソッド「GetRandomPosition」は先ほど作成したX~Zの最小値・最大値を利用してランダムな座標を生成します。ロジックはいたってシンプルで、X~Zまでそれぞれランダムな値を生成してPositionの型であるVector3型で返すことでランダムな座標を生成します。このメソッドを49行目で呼び出すことでランダムな座標を敵プレハブに設定します。それではここまでの処理を実行して確認してみましょう。時間と位置がランダムになっていることが確認できました。Unityエディタ側のフィールド整理(おまけ1)おまけ1としてUnityエディタ側のフィールド(変数)整理方法をご紹介します。いうことかと言うと、現状EnemyGeneratorのインスペクターウィンドウは以下のようになっています。EnemyGeneratorのインスペクターエディタ側から変数の値を変更できるものの、非常に見づらく、使いづらい状態になっています。XとYを間違えてしまったり、最大値と最小値を逆にしてしまったり、想定以上に値を大きくしすぎてしまったりと、様々なエラーが想定されます。以上を改善するために「Header」と「RangeAttribute」を使います。EnemyGeneratorスクリプトのフィールド部分を以下のように変更してください。GetRandomTime();}・・・・・}解説する前にこれによってエディタがどうなったか確認してみましょう。フィールド整理前フィールド整理後それぞれのフィールドの簡易的な説明がつき、フィールドの値をスライダーで変更できるようになったため、見やすく使いやすいフィールドになりました。簡単にプログラムを説明します。「[Header(“任意の文字列”)]」でフィールドの前に説明を入れることができます。これによってそれぞれのフィールドがどのような役割を持っているのかわかりやすくなります。「[Range(最小値,最大値)]」で最小値と最大値の幅のスライダーを設定することができます。これによって想定外の数値の受付を拒否し、エラーを減らすことができます。ゲームを開発するだけでなく、このような工夫して自分以外の人も修正しやすくすることが大切です。変数のアクセス制限(おまけ2)おまけ2として変数のアクセス制限についてご紹介します。現状のプログラムではエディタ側からフィールドの値を設定するためにフィールドに「public」という修飾子をつけています。これは簡単に言うと、フィールドにアクセスすることができる範囲を決定するものです。publicなフィールドとはどんな場所からでもそのフィールドにアクセスすることができるということです。一見すると便利なように見えますが、実はとても危険な状態なのです。どのような状態なのか倉庫を例に説明します。鍵のない倉庫(publicなフィールド)まずはpublicなフィールドを「鍵のない倉庫」とします。そのフィールドを持つクラス「倉庫の所有者」と外部のクラス「隣人」が今回の登場人物です。以下の図を見てください。倉庫の所有者は所有する倉庫の中身は「VRゴーグル」が「3個」入った状態であると認識しています。(正確にはこのように思っているのはクラスではなくプログラマー側ですが...)では鍵のない倉庫だとどのような状態が起きるのか見ていきましょう。隣人Aが倉庫にしまってある「VRゴーグル」をイベントで使うために全て回収(フィールドをNullに変更)してしまいました。次に隣人Bが使い終わった「ARグラス」を倉庫にしまってしまいました。倉庫の所有者は何も知らずに倉庫からVRゴーグルを取り出して使おうとしますが、中身がARグラスに変わってしまいどこを探しても見つからなくなってしまいました。このような状態が起こってしまってはとても困ります。どのようにすればこのような事態を防ぐことができるのでしょうか。フィールドを「private」で宣言すれば問題解決です。鍵のついた倉庫(privateなフィールド)次に「鍵のついた倉庫」(privateなフィールド)を持つAの例を見てみましょう。(わかりづらいので鍵のない倉庫の所有者をCさんとします)まずは以下の図を見てください。鍵のついた倉庫の所有者であるAは先ほど隣人Cの倉庫から取り出した「VRゴーグル」を「3個」保有しています。鍵を持っている(アクセス権を持っている)のは所有者であるAのみです。そこに無くなってしまった「VRゴーグル」を探しに来た隣人Cがやってきました。Aの倉庫は鍵がついている(private)だったため中身を取り出すことはもちろん、中身を確認することすらできませんでした。して無事にAは「VRゴーグル」を取り出してイベントで使うことができました。フィールド(変数)をpublicにしておく危険性をご理解いただけましたでしょうか。このような問題から、プログラムでは原則フィールドをprivateにしておく必要があります。参考記事)アクセス修飾子についてまとめいかがでしたでしょうか。今回は敵を自動生成する方法をご紹介してきました。自動生成とは言うものの、基礎的な知識を利用するだけで実現することができます。おまけとしてフィールドの整理やアクセス修飾子についてもご紹介してきました。このようなちょっとした工夫がプログラミングの世界では非常に役に立ちますのでぜひご参考ください。gardenお問い合わせはこちらから※「XR-Hub」商標出願中CloseTwitterでAR/VRの最新情報を受け取る。