【Unity】2Dシューティングを作ってみる話 #10
記事をご覧いただき、誠にありがとうございます。
画にすると何となくイメージが伝わったでしょうか。
あとはx座標はEnemyGeneratorで、y座標がランダムなものになれば、敵の自動生成ポイントの出来上がりになります。
そしてPrefabsフォルダ内で、Enemyを複製します。
そして分かりやすいように色を変えておきます。
これらのEnemyをEnemyGeneratorオブジェクトのInspectorビューに設定します。
ではこれでゲームを実行して確認します。
投稿主の無能です。
前回は、敵オブジェクトを仮に作成して動かし、接触判定を持たせました。
今回は、敵が自動的に出てくる仕組みを作りたいと思います。
敵が自動で出てくる仕組みの考え方
仕組みを作るとは言っても、どうやったらその処理が実装できるかが想像つかないよ、と言う方もいらっしゃると思います。
ですので簡単な具体例を出してみたいと思います。
一例ですが、x軸の位置(x座標)は固定して、y軸の位置(y座標)がランダムであり、一定間隔で敵が出てくれば、敵が動く方向は一定なので、その処理が繰り返されている間は無限に敵が自動で出てきます。
敵が自動で出てくる仕組みの例
この処理を実装したいと思います。
敵の生成ポイントを作成する
そうと決まれば、早速敵の生成ポイントを作ります。
空のオブジェクトを作成し「EnemyGenerator」とします。
空のオブジェクトなので、PlayerFirePosと同様に視認できるようにしておきます。
そしてカメラの画角外に出しておきます。
EnemyGeneratorを作成して位置をカメラの画角外にする
ではスクリプトで処理を実装していきます。
敵の自動生成スクリプトの記述
ランダムな数は既にC#で作成できますが、ちょっと癖がありますので、その注意点を踏まえながら説明していけるようにします。
「EnemyGenerator」スクリプトを作成して、EnemyGeneratorオブジェクトへアタッチします。
EnemyGeneratorスクリプトを作成し、EnemyGeneratorオブジェクトへアタッチ
ではスクリプトを書いていきます。
このようになります。
EnemyGenerator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyGenerator : MonoBehaviour
{
[Header("敵の生成リスト")] [SerializeField] GameObject[] enemies;
[Header("敵生成の時間")] [SerializeField] float genDelay = 2f;
[Header("敵生成の間隔")] [SerializeField] float genInterval = 2f;
[Header("画面の余白(y軸方向)")][SerializeField] float marginY = 1f;
Vector2 min, max; // 画面サイズ取得用
void Start()
{
// 画面サイズの最小値・最大値を取得
min = Camera.main.ViewportToWorldPoint(Vector2.zero);
max = Camera.main.ViewportToWorldPoint(Vector2.one);
// 敵生成の関数を一定間隔でリピート
InvokeRepeating("EnemyGenarate", genDelay, genInterval);
}
// 敵を生成する
void EnemyGenarate()
{
// 敵を生成
Instantiate(enemies[Random.Range(0, enemies.Length)], // GameObjectの配列enemiesからランダムで生成する敵を選択
new Vector2(transform.position.x, Random.Range(min.y + marginY, max.y - marginY)), // x座標:EnemyGeneratorオブジェクトのpositionのx,y座標:取得した画面サイズの最小値+余白から最大値-余白までの間
Quaternion.identity); // 回転しない
}
}では見ていきましょう。
メンバ変数では敵の生成リスト、生成の時間と間隔、そして画面のy軸方向の余白を設定しています。
そして画面サイズの取得用のmin・maxがあります。
min・maxは背景の時に作ったような…?
そしてStart関数内では、最初に画面サイズを取得しています。
やっぱり背景の時と同じだと思った方はその通りで、背景と同じ処理で最小値・最大値を取得しています。
これは何故かと言うと、敵を生成するのは前述の通りy座標をランダムにして生成するので、生成時のy座標の範囲を知りたいからです。
こうする事で、例え画面サイズが拡大・縮小してy座標の範囲が変化したとしても、その範囲をスクリプトが取得できるようになっています。
x座標の方をランダムにしたいのであれば、x座標に処理を書けば良いので、どちらにしても画面サイズは取得しておきたいものになります。
そして次のInvokeRepeatingは、繰り返し指定した関数を呼ぶための関数になります。
MonoBehaviour.InvokeRepeating - Unity Documentation
使い方はドキュメントを参照すれば分かると思いますが、「"」(ダブルクォーテーション)で囲まれた関数名を、初回は第二引数の値で呼び出し、2回目以降は第三引数の間隔を空けて呼び出します。
ここではEnemyGenerate関数を、初回はgenDelayで呼び出し、以降はgenIntervalの間隔を空けて呼び出す、という処理になります。
では次にEnemyGenerate関数を見ていきます。
EnemyGenerate関数は、シンプルにオブジェクトを生成するinstantiate関数が呼ばれているだけなのですが、その中身が少々ややこしい事になっています。
instantiate関数の第一引数でクローン生成するオブジェクトを指定するのですが、配列の要素の番号の部分をランダムで指定しています。
Random.Rangeで括弧内の第一引数を最小値、第二引数を最大値に取って、その範囲内でランダムな数を生成します。
このRandom.Rangeが結構な曲者で、小数(float)の場合は最大値を含みますが、整数(int)の場合は最大値を含みません。
不等式で表すと
小数(float):最小値≦ランダムの範囲≦最大値
整数(int):最小値≦ランダムの範囲<最大値
という仕組みになっています。
例えると0から5の整数の範囲で値をランダムで取得したい場合は、(0, 6)になります。
今回の例であれば、配列の範囲は整数なのでenemies.Lengthに+1しなければなりませんが、そのままで大丈夫です。
何故かと言う理由については、配列の仕組みを考えれば分かると思います。
例を挙げると、配列の要素数が3だったとします。
enemies.Lengthで返される値は3ですが、最大値を含まないので、配列内の要素を指定する時は0から始まり、Lengthで返される値から-1した数が最大値となります。
例で言えば0,1,2が配列の要素を呼び出す時に指定する値ですね。
そしてRandom.Rangeでは最大値を含まない、不等号では未満という事になるので、0,1,2の範囲で問題無い、という事になります。
何となく理解出来ましたでしょうか?
ただこの処理は、あくまでも今回はたまたま配列の要素数とLengthで返される値で違いがあることを利用できただけなので、Random.Rangeでの処理は前述の小数と整数での違いを把握しておいてください。
そして次の生成する場所でもRandom.Rangeを使用しています。
x座標はEnemyGeneratorオブジェクトの場所ですが、y座標がランダムになるため、Start関数で取得した画面サイズの最小値・最大値がここで使われます。
minのy座標に余白を最小値であれば足し合わせ、最大値であれば引いています。
これはプレイヤーの弾の当たらない位置生成されることを防ぐためです。
範囲内だからと言って、あんまり上や下の方にギリギリで生成されてしまうと、それは無理だろ、というような位置に生成されてしまうので、プレイヤーの移動制限と同じ手法で余白を取っています。
最後に生成するオブジェクトの回転ですが、取り敢えず回転しないようにしてあります。
これは後程敵にも画像と弾の発射ポイントを付けるので、敢えて回転させていません。
という事で、ゲームを実行して確認する準備をします。
敵の自動生成の処理を確認する
ではEnemyをプレハブ化します。
Enemyをプレハブ化する
そしてHierarchyビューにあるEnemyは削除します。
HierarchyビューにあるEnemyを削除
今回の動作確認までの間なので、2つ複製すれば事足ります。
Enemyを2つほど複製
Enemyが赤なので、緑と黄色にしておきます。
Enemy1:緑
Enemy2:黄色
Enemiesという項目のリストの部分に、+ボタンがあるので項目を追加し、Prefabsフォルダ内のEnemyと複製したものを設定します。
Enemiesという項目のリストの部分に+ボタンがあるので項目を追加する
項目を追加した
Prefabsフォルダ内のEnemyを設定する
以降は繰り返し
3つのEnemyが設定できた
3つのEnemyが生成された
これで処理が実装出来ました。
ゲームで処理の確認ができたら、複製したEnemy1・2はPrefabsフォルダから削除します。
削除するとEnemyGeneratorオブジェクトのEnemiesに設定した項目がMissingになるので、-ボタンで項目を削除してください。
EnemyだけがEnemiesのリストに登録されている状態になればOKです。
InvokeRepeatingをUpdate関数内に書くと…
InvokeRepeatingは今回Start関数に記述しており、Update関数は使っていないので、その点だけ注意してください。
もしInvokeRepeatingをUpdate関数内に書いてしまうと、物凄い量のEnemyが一気に生成され、下手をすればUnityを強制終了させる羽目になります。
実際に無能はUpdate関数内に書いてUnityを強制終了させました。
まとめ
今回は
- 敵を自動で生成する処理を実装した
という事をやりました。
次回は、敵に画像を設定して、弾が発射出来るようにしたいと思います。
では、また次回!













コメント
コメントを投稿