Unity入門8
Space Shooter⑤
(スペースシューター)
- 前回までで【敵】がまっすぐ下りてくるところまで出来ました。
- この【敵】を動きをサンプルゲームのようにしたいと思います。
- サンプルゲームは以下の動きです。※プレイヤーは消しています。
- よく見ると、それぞれがランダムで複雑な動きしているのがわかるでしょうか?
状況確認

敵の動き
- では、早速作っていきます。
- 今ついている【Mover】は使わないので外しましょう。【Remove Component】ですね。
- 新しいスクリプトを作成してください。名前は【Evasive】(イブイシブ:回避)としておきます。
-
scriptフォルダの中に作るのを忘れないでください。
- 次へ。
-
scriptフォルダの中に作るのを忘れないでください。


敵の動き
- まずは変数を用意しましょう。
- たくさんありますね。それだけ設定項目が多い、つまり複雑な動きということです。
- 変数の横のコメントは、本来はいりませんが、書いておいた方が後々ラクです。

敵の動き
- 次に、Start()メソッドです。以下のように実装してください。
- メソッドの中の1行目、【rb = GetComponent<Rigidbody>();】は前にもやった通り、コンポーネントを何度も探さないように、変数に保存して、処理を軽くしています。
- 2行目の【rb.velocity = new Vector3(0,0,1) * speed;】は【Mover】ファイルと同じで、z座標(上から下)に対しての速度を設定しています。つまり、下への動きの部分です。
- 3行目の【StartCoroutine();】(スタートコルーチン)メソッドは【コルーチン】と呼ばれる特殊な処理を開始するメソッドで、引数の【Evade()】(イベイドゥ:避ける)がコルーチンの名前です。
- コルーチンも普通のメソッドと同じように、名前は自由です。【Evade()】にしているだけです。
- ただ、コルーチンは普通のメソッドとはかなり違う動きをします。
- まずは、ざっとコルーチンに関して学んでおきましょう。次へ。

コルーチン
- 【コルーチン】と呼ばれる特殊なメソッドの動きですが、一言で言うと【一定時間ごとに、実行したい処理をカンタンに書ける】ものです。
- つまり「処理1」→「ちょっと待つ」→「処理2」→「ちょっと待つ」→「処理3」のようなコードが書きやすいと言うことです。
- 一番のポイントが、「ちょっと待つ」の部分を柔軟に設定できる点です。
- コルーチンを使いこなすと、【イケてるコード】になりますので、ぜひ覚えましょう。
- まず基本的な書き方です。以下のコードを【Evasive】ファイルの追加してください。

- 【IEnumerator】(アイニューメレーター)の部分が【コルーチン】の宣言部分です。
-
言い方を変えれば【IEnumerator型のメソッド】が【コルーチン】と考えてOKです。※Unityの場合。
- 次へ。
コルーチン
- 続いて、以下のようにしてみましょう。
- 【while()】(ホワイル)は繰返しでしたね。引数がtrueの間くり返すので、(true)になっているということは無限ループです。
- Unityの場合はストップボタンで外から処理を止めれるので、このように書いても大丈夫です。
- この繰返しの中の【yield】(イールド)が、ポイントです。
- これは【①処理を一旦戻して(ループを抜けて)】から【②待ち時間が終わったら、このyieldの下から処理を始める】という動作をします。
- 【return】が戻り値の指定でしたね。【null】ということは「戻り値はない」ということです。
- 【Debug.Log()】はコンソールに出力するメソッドでしたね。("あ")なので、”あ”が表示される事になります。
- これで、一度試してみましょう。※コンソール画面に注目。

コルーチン
- 以下のようになると思います。※右側の数字が実行された回数です。
- 現時点のコードでは【1フレーム】ごとに実行されるコルーチンになっています。
- これを【1秒ごと】に実行されるコードに変えてみます。
- これにはUnityでは便利なメソッドがあるので、それを使います。【yield】の戻り値を以下のように変えてください。


- これで試してみると、1秒ごとに実行されるようになると思います。
コルーチン
- また、コルーチンは基本的にメソッドなので、引数も使えます。
- この場合は、当然呼び出す時も引数を指定しなければなりません。
- 上記のようにすると、【1から10までだけ】表示させることもできます。


コルーチン
- さらに発展させましょう。
- 【Evasive】ファイルに、以下のコードも追加してください。
- この状態で、動かしてみると、【コルーチンの外だよ◯】が大量に出力されると思います。
- その下の方、大体【"コルーチンの外だよ51"か、"52"】辺りで、【1】が表示されていると思います。次へ。



コルーチン
- コルーチンを使えるようになるためには、先ほどの動きを理解しなければいけません。
- まず、コルーチン(Evade())は【yield return new WaitForSeconds (1);】の部分で【1秒待つ】としていますね?
- 実は、その間は、処理全体が止まるわけではなく、【コルーチンだけが1秒止まる】のです。
- そのコルーチンが止まっている1秒間で【FixedUpdate ()】メソッドが【コルーチンの外だよ◯】を表示し続けます。
- ※デフォルトでは1秒間に50回くり返されます。誤差が出るのは1秒のカウントが少しズレがあるからです。
-
そして、1秒後にコルーチンは【yield return new WaitForSeconds (1);】の下、つまり【num++;】から処理を開始して、【Debug.Log(num);】で数字を表示させます。
- 以上をループさせていますね。
- 現在はコルーチンは10をカウントしたら終わるようにはしていますが、【while(true)】に戻せば、ゲームを終了するまで、カウントします。
- なんとなく雰囲気を掴んだでしょうか?
- 次は、もう一歩すすめたコルーチンの使い方です。
コルーチン
- コルーチンに下記を足してみましょう。
- どんな結果になるかわかりますか?
- 試してみるとわかりますが、今度は【1】や【2】などの数字の間に【”やぁ!”】が出力されるはずです。※2回目以降の【”やぁ!”】は、まとめられて表示されます。
- このように【yield】は、【処理を抜けた場所】を記憶しており、待ち時間が終わったら、その抜けた場所(【yield】の場所)の下から、処理を再開させます。
- これがコルーチンの重要なポイントです。


コルーチン
- コルーチンに関して、だいぶ理解が出来たんじゃないかと思います。
- コルーチンはUnityだけではなく、色々なプログラムで良く使われますので、ちゃんと理解しておきましょう。
- 尚、コルーチンは、今やったこと以外にも、特定の条件でストップさせたり、コルーチンの中にコルーチンをネストしたり、他にも色々な使い方ができます。
- また必要な際にやりたいと思います。
コルーチン
- さて、スペースシューターの敵の動きに戻ります。
- ぶっちゃけコルーチンさえ理解すれば、後はカンタンです。
- 現在【Evasive】ファイルは色々テストした後の状態だと思うので、それぞれのメソッドを以下のようにしてください。変数は、前に設定したままです。
- ※色々試した内容は消すよりも、コメントアウトしておいた方が、後で確認し直せるので便利です。

敵の左右移動の到着地点
- 現時点では、コルーチンに【yield return new WaitForSeconds (1);】(1秒待つ)となっています。ここは【敵が出現してから、左右に動き始めるまでの待ち時間】です。
- さらに追加して、以下のようにループを追加してください。

- 【targetPoint】は【左右移動の到着地点】用の変数でしたね。
- 【Random.Range (1, 3)】はもうお馴染みの乱数ですね(1,3)なので、1か2の数字になります。
- その横の【Mathf.Sign ()】は初登場です。
- これは【正負を返す】メソッドで、マイナスをつけて【-Mathf.Sign ()】とすることで、【マイナスはプラスに、プラスはマイナスに】変換できます。
- つまり引数の【rb.position.x】(つまり今のx座標)がマイナスならプラスに、プラスならマイナスに変換し、それを【Random.Range (1, 3)】と掛け合わせて、到着地点にしています。
- こうすることで、必ず【今いるx座標の反対側の座標】に到着地点が設定されます。
敵の左右移動の到着地点
- 次に、ループの中に以下のように追加してください。
-
【yield return new WaitForSeconds (1));】(1秒待つ)が2行と、それに挟まれて、【targetPoint】(左右移動の到着地点)に0が代入されていますね。
- これは、到着地点を削除しているということです。(左右移動をやめるということ)
- つまり、このループの中の動きは【到着地点を決める】、【1秒待つ】、【到着地点を削除する】、【1秒待つ】が繰り返されることになります。
- ここで使われるコルーチンはこれが全部です。言い方を変えれば、【到着地点を決めたり、削除したりするコルーチン】を作っているわけです。
- 後は、このコルーチンで設定される【到着地点】に【実際に移動する】コードを書けば良いのです。


敵の左右移動
- 次は、【FixedUpdate】メソッドにコードを追加して、左右移動を作っていきます。
- まずは以下のようにしてください。
- 1行目の【Vector3 position】は、お馴染みの座標を入れる型の変数に、今の座標を入れています。
- 2行目の、新登場のメソッド【Mathf.MoveTowards】は、【開始位置から、目標の位置まで、一定の速度で動く】ということ、指定できるメソッドです。
- 第1引数に、開始位置
- 第2引数に、目標位置
- 第3引数に、速度(加速度)
- をそれぞれ指定します。
- これを1行目で作った変数のx座標に代入しています。
- 3行目の【rb.position = position】で現在の座標に代入しています。こうすることで【Mathf.MoveTowards】で指定したように動きます。
- ※【smoothing】を、0.05ぐらいに設定して、試してみましょう。

敵の左右移動
- ちゃんと動いたとは思います。これが基本的な【Mathf.MoveTowards】の使い方です。
- 後は、左右に移動した際に、敵が傾くようにしたいですが、今の動かし方は【poition】を動かしているので、【移動】と【傾き】を一致させるのが、うまくいきません。
- そのため、【Mathf.MoveTowards】の使い方を少し変更します。まずは下のようにしてください。

- 【Mathf.MoveTowards】を【velocity】(加速度)に対して使っています。
- この状態で動かしてください。先ほどと同じ動きになると思います。
- 次へ。
敵の左右の傾き
- 後は、傾きを追加するだけです。
- これは何度も出てきていますが、【velocity】の増減に合わせて、傾きも変化させているコードですね。
-
これで試してください。良い感じになるはずです。
- ※tiltの値は50ぐらいでいいかと思います。

- 実は敵の動きには、まだ少し問題点が残っています。
- それは【画面外に飛んでいってしまう可能性がある】ということです。
- 試しに下のように設定してみてください。
敵の左右の傾き


- 下の感じになりましたよね?
- これだと問題ですので、直しておきましょう。
敵の左右の傾き

試してみよう
- 下の動画のように、どんな設定値にしても、敵が画面外に飛んでいかないように設定してください。
- ヒント:プレイヤーの動きでやっているのと同じです。ただし、画面の下からは画面外に行けるようにすること。

残りの変数の使い道
- これで敵の動きは完成しました。のですが、そういえばまだ使っていない変数がありますね。
- 以下の4つの変数です。

- この変数達も正しく使ってあげることで、もっと柔軟に値を変更することが出来ますね。
- また、現在は【コルーチンでの待ち時間】はすべて1になっているので、ランダム時間で待つようにしてあげましょう。
- その際に、上記の変数も適切に使ってあげればすべて使いきれそうです。次へ。
試してみよう
- まだ使っていない変数を正しい場所に使ってあげてください。同時に、コルーチンの待ち時間もランダムに変更してください。
- ヒント:【Vector2】型の変数は、
- 【yield return new WaitForSeconds (Random.Range (startWait.x, startWait.y))】
- のように使うことが出来ます。
- 【yield return new WaitForSeconds (Random.Range (startWait.x, startWait.y))】
- ヒント:【Vector2】型の変数は、
- ※完成したら必ず見せてください。
- 尚、インスペクタビューでの設定値はお好みで良いですが、例では以下の数値に進めます。
- ※敵の出現位置は後でランダムに設定します。今は真ん中からでOKです。

敵のPrefab化
- これで、敵の動きが完成しました。
- では、この敵もPrefab化して、ドンドン出てくるようにしちゃいましょう。
- 次へ。
試してみよう
- 以下の動画のように敵をPrefab化して、どんどん出てくるようにしてください。※Prefab化したら、元のオブジェクトは削除してください。
- ヒント:岩と同じように処理すればOKです。※つまり3つの岩と、敵の4種類の内どれかがランダムで、定期的に出現します。

試してみよう
- 敵がカメラ外に消えたら、削除されるようにしてください。
- ヒント:z軸が-70以上ぐらいで、カメラ外の判定になります。※カメラの位置によりますが。

試してみよう
- 【敵とプレイヤー】にぶつかったら、プレイヤーが爆発して消えるようにと、【敵とプレイヤーの弾】がぶつかったら、敵が爆発して消えるようにしてください。
- ヒント:岩と同じ感じです。※ただし、敵の爆発には【explosion_enemy】エフェクトがあるので、それを使ってください。

敵の弾を作る
- 次は、敵が飛ばす弾を作りましょう。
- 基本的には、プレイヤーと同じで良いので、Prefabにある【Bullet】(プレイヤーの弾)を、Hierarchyビューに持ってきて、オブジェクトにしてください。
- オブジェクトしたら名前を変更しておきます。【EnemyBullet】にでもしておきましょう。

敵の弾を作る
- 見た目だけ変更しておきたいので、Projectビューの【Materials】フォルダを開いてください。
- プレイヤーの弾として使ったのが【fx_bolt_orange】というマテリアルでしたが、敵用の弾マテリアルは用意されていません。
- そのため、【Materials】フォルダを右クリックし【Create】→【Material】を選択してください。

- 新しいマテリアルが追加されていますので、名前を【fx_bolt_cyan】にしておきましょう。※(cyanはシアン色ということ)
- 次に、inspectorビューから以下の項目を変更します。
- 次へ。

敵の弾を作る
- 【Standard】の項目をクリックすると、メニューが開きますので、【Mobile】→【Particles】→【Additive】を選択してください。
- 下のようになればOKです。次へ。


敵の弾を作る
- これで後は画像を設定するだけです。次に、下の画面の【Select】をクリックしてください。
- 画像を選択するウィンドウが開きますので【fx_lazer_cyan_diff】を選択してください。


- これで、敵の弾のマテリアルは完成です。
敵の弾を作る
- マテリアルの変更します。
- マテリアルの変更は【Mesh Renderer】から行います。
- 【EnemyBullet】のinspectorビューの【Mesh Renderer】の中の【Materials】を開くと以下のようになっていると思います。
- 赤枠のところを押すと、マテリアルを選ぶウィンドウが開きますので【fx_bolt_cyan】を選択してください。
- これで、敵の弾が完成しました。
- 出来た敵の弾は、Prefabにして、元のオブジェクトは削除しておきましょう。
- また、Tagが【Bullet】になっていると思いますので、【EnemyBullet】などに変更しておきましょう。
- 後は、この敵の弾を作り出すスクリプトを作ればOKですね。次へ。

敵の弾を作る
- 新しいスクリプトを作成し、名前を【EnemyBullet】などにしておきましょう。
- まずは、以下のように書いてください。
- 新しいメソッドを使っています。
- この【InvokeRepeating】(インヴォークリピーティング:繰返しを呼び出す)メソッドは、【特定のメソッドを、特定の間隔でくり返す】ためのメソッドです。
- 「ん?どっかで聞いたぞ?」と思った方、正解です。つまりはコルーチンをカンタンに作れるメソッドと思ってOKです。
- 次へ。
- 「ん?どっかで聞いたぞ?」と思った方、正解です。つまりはコルーチンをカンタンに作れるメソッドと思ってOKです。

敵の弾を作る
-
【InvokeRepeating】使い方はシンプルです。
- 第1引数に、呼び出すメソッド名※string型で指定しないといけないので""で囲んで呼び出します。
- 第2引数に、1回目を呼び出すまでの時間(秒)
- 第3引数に、2回目以降、呼び出すまでの間隔(秒)
- を指定するだけです。
- ちなみにコルーチンにすると下の感じです。※書かなくてOK
- 尚、【delay】【fire】の部分は変数でなくても良いです。
- 今回は、inspectorビューから変更できるように、public変数にしています。

試してみよう
- 下の動画のように敵が弾を打ってくるようにしてください。
- ヒント:完成までのステップは以下です。
- 【EnemyBullet】スクリプトに【Fire()】メソッドを作る。※【Fire()】メソッドはプレイヤーが弾を撃つところを参考にしてください。合わせて、変数も追加する必要があります。
- 【EnemyBullet】スクリプトを正しくアタッチし、変数【delay】【fire】に値を設定する。
- 弾の進む方向も調整する。
- ヒント:完成までのステップは以下です。

試してみよう
- 敵の弾にプレイヤーが当たると、爆発してゲームオーバーになるようにしてください。
- ただし、敵の弾が【敵】【岩】【プレイヤーの弾】に当たっても何もおきない(素通りする)ようにする必要があります。
- これには色々な方法が考えられます。単純に新しいスクリプトで判定と取ればカンタンではありますが、今回は新しいファイルは増やさずに、すでに敵や岩の辺り判定のために使っている【DestroyByContact】の【void OnTriggerEnter(Collider co)】の中身を変更して、実装してください。
- 元々のコードを追加するだけでなく、書き換えてもOKです。※別のところに不具合が出ないように注意してください。
- 必要に応じて、スクリプトのアタッチや値の設定、タグの設定なども行ってください。
-
少し発想の転換が必要なので、意外と難しいのですが、時間の許す限りトライしてみましょう。
- ※出来たら見せてください。
-
少し発想の転換が必要なので、意外と難しいのですが、時間の許す限りトライしてみましょう。
-
ヒント:メソッドは【return;】が実行された時点で、そのメソッドの処理を終わらすことが出来ます。※(returnだけ(返す値がない)でも使うことができます。void型の場合は値があるとエラーです)
- 例えば【OnTriggerEnter()】メソッドには①②③という処理がまとめられているとします。
- この場合【OnTriggerEnter()】を呼び出すと、①②③が実行されるはずですが、もし①の処理の中で【return;】が実行されると、②と③の処理は行わずにメソッドの処理は終わります。
- これを使えばシンプルに書くことが可能です。
お疲れ様です
- 以上で、敵の動きは完成しました。
- 次回は最終段階として、ゲームに音を足して、タイトル画面も作りましょう。
- 【スペースシューター⑥】へ続く。
スペースシューター5
By kinocode
スペースシューター5
- 1,179