Unityで作る「シューティングゲーム」前回で敵の攻撃、それとHP管理の部分が完成していますね。
でも敵が1対だとつまらない。
今回はプレファブから敵を複数作っていきたいと思います。
その前に敵が出現する際、スタート位置に到着するまでダメージを受けないルール、見た目が不自然です。
定位置に到着するまではシールドを装備して、通常の動きをする前にシールドを外してあげましょう。
では早速作っていきます。
1,Enemy1 のシールドの準備
いつものように、取得済みの画像から素材を取り込みます。
①「2D Space Kit」の「Particles」から「ShieldBubble」というShieldの画像をhierarchyにドラッグ&ドロップ。
取得した画像を加工します。
②名前を「Enemy1Shield」にしておきます。
③Tagに「Enemy」をセット、Playerの攻撃を受け止めます。
④Transform コンポーネントでいったん [ Position ] を Enemy1 と同じにしておきます。
以前 Enemy1 を x:0,y:3 に仮置きしていると思いますのでその位置にしておきます。
各自調整しておきましょう。
さらに [ Scale ] でShieldの大きさを指定します。
X:0.4、Y:0.4 ぐらいがちょうどよさそうですね?これも各自調整して頂いて結構です。
⑤Sprit Renderer コンポーネント では [ Color ] で色を指定します 。
敵のミサイルが赤系なので、シールドも赤系にしておきます。
手本ではピンクに指定しました。
⑥さらにSorting Layer には Enemy をセットしておきます
続いてコンポーネントを1つ追加します。
⑦「Circle Collider2D」を追加して [ Edit Collider ] ボタンを押してコライダーの大きさを調整します。
⑧敵同士が当たって押し合いにならないように [ Is Trigger ] にチェックを入れておきます。
これで衝突判定ではなく侵入判定になるわけですよね。
続いて作成したシールドをEnemy1の子要素としてセットします。
⑨「Enemy1Shield」を「Enemy1」の上にドラッグ&ドロップで子要素として配置します。
⑩子要素になることで、Transform の[ Position ] は親要素に対する相対座標となります。
親の Enemy1 と同じ場所になるようにしたいので、X:0、Y:0 を指定しておきます。
これで、Enemy1 はシールドをつけたまま登場して移動していきます。
この間、プレイヤーの攻撃を受けても、全てシールドが受け止めてくれますよ。
あとは登場シーンが終わった時にシールドを削除してあげましょう。
スクリプトファイル「Enemy1Controller.cs」を改造していきます。
IEnumerator Move0(int n)
{
transform.position = new Vector3(18f * n, 10f, 0); //記述済み
enemyRd2d.velocity = new Vector2(-3f * n, -1f); //記述済み
yield return new WaitForSeconds(5); //記述済み
enemyRd2d.velocity = transform.up * 0; //記述済み
yield return new WaitForSeconds(0.5f); //記述済み
Destroy(transform.GetChild(0).gameObject); //❶シールドを削除
IsMove = true; //記述済み
}
void Start()
{
hp = 3; //記述済み
shot_speed = 800; //記述済み
//appPos = 1; //❷仮置きしていたものをコメントアウト
enemyRd2d = GetComponent<Rigidbody2D>(); //Rigidbody2D を取得
StartCoroutine(Move0(appPos)); //コルーチンを発動
StartCoroutine(Shot()); //記述済み
}
❶ コルーチン型の関数 IEnumerator Move0(int n){ } の最後のコードの1つ前に、シールドを削除するコードを記述します。
Destroy(transform.GetChild(0).gameObject); Desreoy(gameObject)
は指定したゲームオブジェクトを削除する関数でしたよね?
transform.GetChild(0) は一番上の子要素、という意味です。
今回はもともと1つしかないのですが・・・。1番目の子要素を削除するという命令になります。
❷ Start関数では仮置きしておいた appPos = 1; をコメントアウトしておきます。
あとでGameManager からこの値を指定するので、初期値は必要なくなります。
では実際に動かしてみましょう。登場シーンが完了して、∞の時に動き出す直前で、シールドが消滅すればOKです。
最後に、作成したEnemy1 をプレファブ化しておきます。
Hierarchy から [03_prefab] フォルダにドラッグ&ドロップするだけでしたよね?
Hierarchy上のオブジェクト、アイコンが青くなったと思いますが、不要なので削除しておきます。
これで準備はOKです。
2,Enemy1 を6体発生させてみる
ここではスクリプトファイル「GameManager.cs」を改造していきます。
[SerializeField] GameObject Enemy1; //❸Enemy1のプレファブ
public int enemyCount = 0; //❹敵の管理
IEnumerator CreateEnemy() //❺敵生成の関数を宣言
{
enemyCount = 6; //❻6体生成するので
yield return new WaitForSeconds(2);
//1セット目
Enemy1Controller e1 = Instantiate(Enemy1).GetComponent<Enemy1Controller>(); //❼敵e1生成
e1.appPos = 1; //❽e1 の[appPos]に 1 を代入
Enemy1Controller e2 = Instantiate(Enemy1).GetComponent<Enemy1Controller>(); //❾敵e2生成
e2.appPos = -1; //➓e2の[appPos]には -1 を代入
yield return new WaitForSeconds(2.2f); //⓫左右2体をを1セットとし、その後2.2秒待つ
//2セット目
Enemy1Controller e3 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e3.appPos = 1;
Enemy1Controller e4 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e4.appPos = -1;
yield return new WaitForSeconds(2.2f);
//3セット目
Enemy1Controller e5 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e5.appPos = 1;
Enemy1Controller e6 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e6.appPos = -1;
}
void Update()
{
if (enemyCount == 0)
{
StartCoroutine(CreateEnemy()); //⓬CreateEnemy()を発動
}
D = Random.Range(0, 2000); //記述済み
if (D == 0){CriateAsteroid(); } //記述済み
else if (D <= 8){CriateDebris();} //記述済み
}
❸ [SerializeField] で GameObject型の 変数:Enemy1 を宣言。
あとでInspectorから今回作成したEnemy1のプレファブをセットします。
❹ 敵の数を管理する整数型の 変数:enemyCount を宣言。
初期値に0を代入しておきます。
倒されるごとにこの値を減少させていけば、敵の出現を管理できそうですね?
❺ コルーチン型の関数 CreateEnemy() を作成します。
この関数では2体(左右1対ずつ)×3セット、合計6体の敵を生成します。
❻ enemyCount = 6; で生成する敵をカウントしておきます。
生成のたびにカウントしてもいいのですが、コードが長くなるので最初にカウントしておきましょう。
❼ Enemy1Controller e1 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
Enemy1Controller の class からインスタンスを生成 [e1]という名前を付けておきます。
さらに GetConponent<>() でEnemy1Controllerを取得して使えるようにしておきます。
この辺の概念、ちょっと難しいかもしれません。
オブジェクト指向の学習を進めていくと徐々に理解が深まってくると思いますが、詳しく知りたい方は教室までお問い合わせください!
❽ ❼で生成した[e1] の変数:appPos に (1) を代入しています。
この appPos 覚えていますか?
Enemy1生成の際、引数として引き渡され、
(1) だったら右から出現、左方向に移動する、
(-1)だったら左から出現、右方向に移動する、
という役割をする変数でしたよね?
今回の課題では❷のところで、(1)で仮置きしていた値をコメントアウトしておきました。
❾ここでは2体目のインスタンスを生成し、名前を[e2]に指定しました。
➓ ❾で生成した[e2]の変数:appPos に (-1) を代入しています。
[e1]と[e2]はほぼ同時に生成されたので、左右からセットとなって出現するようになっています。
⓫yield return new WaitForSeconds() を使って、1セット目の敵と2セット目の敵の間に時間を取ります。
以下の処理は2セット目、3セット目を作っているというプログラムになります。
これでCreateEnemy() は完成。あとはこの関数を使う方を指定してあげればよさそうですよね?
Update()関数で発動させてあげましょう。f (enemyCount == 0) もし変数:enemyCount が 0 つまり、まだ敵が生成されていなければ・・・。
⓬CreateEnemy() を発動させています。
もともとコルーチンで作った関数なので、 StartCoroutine(CreateEnemy());で発動させます。
これで今回のコードは完成。
最後はGameManagerのinspectorから、今回指定した変数:Enemy1に、Enemy1のプレファブを設定しておきましょう。
それでは実際に動かしてみましょう。
Enemy1が2体ずつ、合計6体出てくるのを確認することができたと思います。
教室では実際に通って頂いての授業の他、ちょっとしたお困りごとに対するオンライン授業やオンラインサポートも行っております。お困りごとのある方、ご興味がある方は、ぜひお問い合わせください。
お問い合わせは こちら から。
体験授業のお申込みは こちら から。