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があるのかなどをきにしていました。

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

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA