Unity Create a Game Series (E14. game over)をやってみました。

Unity Create a Game Series (E14. game over)をやってみました。

今回はゲームオーバー画面をuGUIで作成し、”Play again”ボタンで、シーンをリロードする仕組みを作りました。これは今までミニゲームを作ったりした際に経験していたので簡単でした。

ゲームオーバーシーンを表示
ゲームオーバーシーンを表示

この回で、基本的なゲームの仕組みは揃いました。これから先の目次を見ると、それぞれの機能を磨き上げる工程になるので、おそらくそこまで難しいものではないと思われるので頑張って進んでいきます。

  • パーティクル追加
  • 敵ウェーブの修正
  • リコイル・リロード
  • 武器の追加
  • UI改良、
  • オーディオ追加
  • メニュー

あとは、ライフバー、アイテム、インベントリーあたりを学べばさらに良くなりそうです。

このプロジェクトの配布

http://hajimete-program.com/games/Unity Create a Game Series (E14. game over).zip

 

 

Unity Create a Game Series (E12. finishing the map generator)をやってみました。

引き続き、「Unity Create a Game Series」をやりマップの自動生成の作業が完了し、第7回までに作ったトップダウンシューティングゲームに組み込みました。

マップ自動生成をゲームに組み込んだところ
マップ自動生成をゲームに組み込んだところ

今回の第12回は、障害物に高低差を付け、グラデーションを付けれるようにしました。高低差はScaleで変更できるのが容易に想像できますが、Materialをプログラムから操作するのは少ないので、このチュートリアルで扱えてよかったです。また、今回は、Game.unityシーンに、MapGeneratorのオブジェクトをコピーペーストしてゲームに反映させました。MapGenerator.unityはシーンとして独立して保存しているのでいろいろ修正が可能です。

002
Unityエディターで、各マップを設定できるようにしている

MapGeneratorスクリプトには、Mapクラスを作り、その配列をUnityエディターから操作できるようにしたので、ちょっとしたマップの修正を検証するのが簡単になりました。

マップ自動生成の基礎プログラミングを手に入れた

様々なパラメータを修正できる
様々なパラメータを修正できる

今回まで一番の収穫は、プロシージャル・ジェネレーションの基礎を学習できたことです。ローグライク系ゲームのように、フロアを自動生成するような仕組みに作り替えたりはまだできませんが、それをするためのメッシュ生成や配列操作などは学べました。

このプロジェクトの配布

http://hajimete-program.com/games/Unity Create a Game Series (E12. finishing the map generator).zip

Unity5でNavMeshAgentを使った敵の体当たりと攻撃方法

Sebastian LagueさんのYoutube動画チュートリアル「Unity Create a Game Series (E06. enemy attacks)」でUnityのナビゲーションの使い方がわかりましたが、いくつか計算方法が理解できなかったので、今回も小さなプロジェクトを作成して、再学習しました。

敵がプレイヤーに移動する方法

これはUnityのナビゲーションを使えば簡単です。

敵オブジェクトにNavMeshAgentコンポーネントをインスペクターで持たせて、プログラム上では、agent = GetComponent<NavMeshAgent>();で変数に保持して、agent.SetDestination(座標);で、敵が障害物を交わしながら移動するようになります。

ですがColliderを無効にした場合には、プレイヤーの中心座標が、ナビゲーションの到達位置なので、プレイヤーに埋まってしまいます。

002
Colliderが無効なため、敵が埋まってしまう例

もちろんColliderを有効にしている場合は正しく衝突します。ただゲームでは、体当たりする敵もいますが、プレイヤーの至近距離まで来て、武器や魔法を振り回すような敵もいます。このような場合、何らかの方法で一定の距離を保つ計算が必要になります。

一定の距離を保つ方法

先ほどのソースコードでは、ターゲットの中心位置なので、ターゲットに埋まってしまいました。なので衝突判定の半径を考慮すればよいです。

  1. 敵がプレイヤーに向かう方向を求める
  2. ターゲットの位置から、(ターゲットの衝突判定の半径+敵自身の衝突判定の半径)*向かう方向を引く

紫の敵が、赤のプレイヤーに接触せずにとどまる
紫の敵が、赤のプレイヤーに接触せずにとどまる

この仕組みは、Unityに限らずシューティングゲームやもっと単純なゲームでもオフセット計算などでよく使われます。つまりターゲット座標-offsetをしているだけです。

敵が攻撃する方法

先ほどやりかたで敵が一定距離まで近づくようにできました。敵が攻撃する方法も同様で、さらに手前の範囲で攻撃を繰り出すようにします。基本的な考え方は、現在のプレイヤーと敵の距離 < 攻撃開始の距離 が成り立ったら攻撃を開始するようにします。

平方根を回避してパフォーマンスをよくする

数学では、二点ABの長さを求めるには、三平方の定理によりA*A+B*B=C*Cの平方根を求めます。先ほどの「距離A<距離B」のように2つの長さを求めて比較する場合は、2回平方根の処理をしなければなりません。しかし、小数点の平方根を求める処理は重たい処理なため出来れば避けたいです。そのためのテクニックとしては、「距離A<距離B」の比較を「距離A*距離A < 距離B*距離B」として、二乗のままで計算します。

現在のプレイヤーと敵の距離の二乗 < 攻撃開始の距離の二乗

このテクニックを使うためにUnityではsqrMagnitudeが用意されていて、ベクトル型(Vector3)から二乗の値が簡単に取得できます。

この二乗のまま計算するテクニックを知っていないと、.sqrMagnitudeが出てきたり、Mathf.Pow(長さ、2)が出てくる意味が理解できません。これはパフォーマンスのためであって、本来は2つの長さの比較をしたいだけです。

このプロジェクトの配布

http://hajimete-program.com/games/Topdown Shooting A02 enemy attacks.zip

修正案

Sebastian Lagueさんの仕組みは、Unityだけではなくいろんなゲームで使える方法です。ですがUnityの場合ゲームオブジェクトの子要素を用意し、そこにColliderを持たせ、IsTriggerにより、トリガーイベントで、衝突判定が可能になります。この方法はUnityに依存しますが、これで攻撃判定をすると簡単にできそうな気がします。

まとめ

計算方法はわかってしまえば大したことはありませんが、以下のようなコードが出てきたときに方向を求めているのが分からず、なぜ.normalizedがあるのかなどをきにしていました。

またソースコードでいろいろ試す際に、衝突の半径で変数を使わず数字をハードコーディングしたり、半径の変数を削除したりすることで、理解を深めることができました。