Unityで作る「シューティングゲーム」10回目の今回は、敵の機能を追加していきます。
敵がミサイルを撃てるようにしてみましょう。
さらに敵にHPを追加して、当たったらHPを減、HPが 0 になったら消滅するように改造したいと思います。
では早速作っていきましょう。
1,Enemy1 の修正
今回は敵の攻撃を作るので、「敵」と「敵の弾」が当たってはいけないですね。
Tag を使って互いを認識します。
まずは前回作った「Enemy1」に Tag を追加します。
「Enemy」という名前で Tag を作って、セットしましょう。
それと、一部修正をしておきます。(修正しなくてもちゃんと動きますが、今後の改造等の為に・・・)
「Enemy1」の向きですが、前回は Transform の [Scale] のY座標の値を -1 にして下向きにしました。
それをもとの 1 に戻しておいて、[Rotation] のZの値を180度にして、つまりZ軸(画面の手前から奥に伸びる軸)を180度回して下向きにします。
2,敵のミサイルの作成
続いて敵のミサイルを作っていきます。
プレイヤーのミサイル「PlayerBulletPrefab」を複製して改造しましょう。
①オブジェクトの複製の方法はちょっと独特です。
[03_Prefab] フォルダ内でコピペでいければそのまま複製してOKです。
できない場合は「PlayerBulletPrefab」をドラッグした状態で「Controlキー」を押します。
そのままフォルダ内にドロップしましょう。
②複製された方のプレハブを修正します。
ドロップしたほうが元の素材なので間違えないように。(私も間違えてしまいました)
Inspectorで「PlayerBulletPrefab 1」の名前を確認し、「OpenPrefab」を押します
③まずは名前を変更します。「EnemyBulletPrefab」にしておきましょう。
④Tagに先ほど作成した「Enemy」をセットします。
⑤Transformコンポーネントの[Rotation]のZ軸を180 にしてミサイルを下向きにします。
※ScaleのY座標で反対向きにすると、飛ぶ方向を反対に設定する必要があるので、プログラムが大変・・・。
⑥ミサイルの色を変えておきます。「Sprit Renderer」コンポーネントの[Color] で色を指定します。
各自好きな色を設定しましょう。手本では赤系の色にしました。
⑦同じく「Sprit Renderer」コンポーネントの[Sorting Layer] で見た目のレイヤーを指定します。
「Enemy」をセットしておきます。
⑧「Trail Renderer」の[Color] も変更します。
これはミサイルの尾の部分の色ですね。
ミサイルと同じ系統の色にしておきましょう。
続いてプログラムを作っていきます。
「02_Script」 フォルダ内に「EnemyBullet」というスクリプトファイルを作成します。
以下のコードを記述します。
public GameObject shoot_effect; //発射時ののエフェクト
public GameObject hit_effect; //当たった時のエフェクト
void Start()
{
transform.localScale = new Vector3(3, 3, 1); //❶弾の大きさ
Instantiate(shoot_effect, transform.position, Quaternion.identity); //エフェクト生成
Destroy(gameObject, 3f); //3秒後に消滅
}
//衝突判定
void OnTriggerEnter2D(Collider2D col)
{
if (col.tag != "Enemy") //❷タグが Enemy で無かったら
{
Instantiate(hit_effect, transform.position, Quaternion.identity); //ヒットエフェクト生成
Destroy(gameObject); //当たったら消滅
}
}
これはプレイヤーの弾を作った時の動きと同じですね?
❶ transform.localScale = new Vector3(3, 3, 1);
敵の弾が見えやすいように、PlayerBullet よりちょっとだけ大きくしておきます。
❷ if (col.tag != “Enemy”)
もし、衝突(侵入)した対象のオブジェクトが持っているタグが “Enemy” でないなら、
これを入れておかないと、発射された瞬間に敵に衝突して消えてしまいますよね?
⑨スクリプトファイルができたら、EnemyBulletPrefab に追加します。
先に今ついている「PlayerBullet」を外して、「EnemyBullet」を追加します。
Publicの変数で指定した[Shoot_effect] に「PlayerMuzzleFlash」を、[Hit_effect]に「Hxplosion」をセットしておきます。
3,敵の改造
このステップで行うのは、次の2つです。
1,作成済みの敵ミサイルと定期的に発射するプログラムの作成
2,HPを持たせ、Player の攻撃が当たるたびにHPを減算、0になったら消滅
ということで、Enemy1Controller を修正していきます。
一気にやっていきますよ。以下のコードを追加してください。
float shot_speed; //❸弾の速さ
float shotDelay; //❹弾を撃つ間隔
int hp; //❺ヒットポイント
[SerializeField] GameObject EnemyBullet; //❻EnemyBulletを格納
[SerializeField] GameObject explosion; //❼爆発エフェク
IEnumerator Shot() //❽敵の攻撃
{
yield return new WaitForSeconds(6); //❾動き出すまでの時間待つ
while (true)
{
shotDelay = Random.Range(0.5f, 4f); //➓発射間隔を乱数で指定
yield return new WaitForSeconds(shotDelay); //⓫待って次の処理へ
GameObject Laser = Instantiate(EnemyBullet, transform.position, transform.rotation); //⓬
Laser.GetComponent<Rigidbody2D>().AddForce(EnemyBullet.transform.up * shot_speed); //⓭
}
}
private void OnTriggerEnter2D(Collider2D collision) //侵入判定
{
if (collision.gameObject.tag == "Projectile" && IsMove) //⓮衝突条件
{
Destroy(collision.gameObject); //弾の削除
hp--; //HPの減算
if (hp <= 0)
{
//爆発エフェクトの生成
GameObject effect = Instantiate(explosion, transform.position, transform.rotation);
Destroy(effect, 1.5f); //爆発エフェクトの削除
Destroy(gameObject); //Enemyの削除
}
}
}
void Start()
{
hp = 3;
shot_speed = 800;
appPos = 1; //記述済み
enemyRd2d = GetComponent<Rigidbody2D>(); //記述済み
StartCoroutine(Move0(appPos)); //記述済み
StartCoroutine(Shot()); //コルーチン発動
}
では解説です。
まず数値の変数を3つ、GameObject型の変数(プレハブ)を2つ指定しています。
❸ 変数[shot_speed] は発射するミサイルの速度です。
Start関数で 800 をセットします。
❹ 変数[shotDelay] はミサイルを発射する間隔です。
のちに乱数で設定します。
❺ 変数[hp] は敵のHPです。
Start関数で 3 をセットします。
❻ 変数[EnemyBullet] は今回作成した敵のミサイルプレハブです。
❼変数[explosion] はミサイルが当たった時に発生する爆発エフェクトです。
GameObject 型の変数2種類は、あとでエディタから設定します。
❽ IEnumerator Shot() 関数は、コルーチンを活用して作成するミサイルを発射するときの関数です。
❾ で6秒待っていますが、これは前回作成した登場時の時間5秒と待機時間0.5秒、さらに0.5秒をたした値です。
➓ 変数[shotDelay] にRandom.Range(0.5f, 4f) で、0.5秒から4秒の乱数を指定しています。
0.5秒から4秒待ってミサイルを発射する準備。
ここは好きな数字を指定してください。
⓫ ➓で取得した変数だけ待機します。
⓬ Instantiate()関数を使って、ミサイルのプレハブを自分の場所に生成し、それをGameObject型の変数として保存します。
⓭ なぜ⓬でいったん保存したか、というと生成した弾に速度を与えるためです。AddForce(EnemyBullet.transform.up * shot_speed) で弾の向きに 変数[shotDelay] つまり800の速度を与えています。
これで弾が飛んでいくというわけですね。
これでミサイル発射のコルーチンを使った関数は出来上がりました。
Start関数の最後に StartCoroutine(Shot()); を指定して起動させましょう
続いて衝突(侵入)判定でPlayeのミサイルに当たった時の動きを作っていきます。
⓮ if (collision.gameObject.tag == “Projectile” && IsMove)
if文の条件、カッコ内の前半は、衝突したオブジェクトが持っているタグが「Projectile」つまりPlayer の弾だったらですね?
さらに「&&=かつ」を挟んだ後半部分は、関数 IsMove() がTrue なら という意味になります。
前回作成した IsMove() は登場シーンが終わったらTrue に変ります。
ということは登場後は当たり判定が有効になる、逆に登場シーンは当たり判定は無効、という意味です。
後は以前「いん石」の動きを作成する際に学習した、HPが0になったら消滅する動きですね?
説明は省略しますが、不安な方は過去のブログをみて確認してみてください。
これで今回のプログラムは完成です。
最後は[SerializeField] で指定した変数に各プレハブをセットします。
⑩ 「EnemyBullet」に EnemyBulletPrefab をセット
「Explosion」に Explosion をセット
これで動かしてみてください。
敵がしっかり攻撃してきますよね?
さらに敵に3回攻撃をあてれば消滅、また敵の攻撃に当たると自身のHPも減るのを確認できたと思います。
次回は敵の演出です。
出現するときにダメージを受けない、というのは不自然なので、シールドをつけてあげたいと思います。
教室では実際に通って頂いての授業の他、ちょっとしたお困りごとに対するオンライン授業やオンラインサポートも行っております。お困りごとのある方、ご興味がある方は、ぜひお問い合わせください。
お問い合わせは こちら から。
体験授業のお申込みは こちら から。