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; //④敵の管理
//⑤敵生成 enemy1controller のappPos = 1 をコメントアウト
IEnumerator CreateEnemy()
{
enemyCount = 6; //⑥6体生成するので
yield return new WaitForSeconds(2);
//⑦[Enemy1Controller]型のインスタンス:e1を生成
Enemy1Controller e1 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e1.appPos = 1; //⑧e1 の[appPos](方向を決める引数に入る変数) に 1 を代入
//⑨2体目のインスタンス:e2 を生成
Enemy1Controller e2 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e2.appPos = -1; //⑩e2の[appPos]には -1 を代入、これで左から出現
yield return new WaitForSeconds(2.2f);
Enemy1Controller e3 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e3.appPos = 1;
Enemy1Controller e4 = Instantiate(Enemy1).GetComponent<Enemy1Controller>();
e4.appPos = -1;
yield return new WaitForSeconds(2.2f);
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() を使って時間を置き、2セット目、3セット目を作っているというプログラムになります。
これでCreateEnemy() は完成。
あとはこの関数を使う方を指定してあげればよさそうですよね?
Update()関数で発動させてあげましょう。
f (enemyCount == 0) もし変数:enemyCount が 0 つまり、まだ敵が生成されていなければ・・・。
⑪CreateEnemy() を発動させています。もともとコルーチンで作った関数なので、
StartCoroutine(CreateEnemy());
で発動させます。
これで今回のコードは完成。
最後はGameManagerのinspectorから、今回指定した変数:Enemy1に、Enemy1のプレファブを設定しておきましょう。
それでは実際に動かしてみましょう。
Enemy1が2体ずつ、合計6体出てくるのを確認することができたと思います。
教室では実際に通って頂いての授業の他、ちょっとしたお困りごとに対するオンライン授業やオンラインサポートも行っております。
お困りごとのある方、ご興味がある方は、ぜひお問い合わせください。
お問い合わせは こちら から。
体験授業のお申込みは こちら から。
留言