Unityのアクションゲームで攻撃時に敵の方向をむかせる機能

今回は主人公キャラクターが武器を構えた時に一番近い敵の方向を向くようにします。

今まではユーザーが主人公キャラクターを操作し、敵の方向を向かせ、攻撃をしていました。
しかし、もっと単純に武器を構えたら一番近い敵の方向を向かせて、左右の方向キーを押したら別の近い敵にターゲットを変更します。

市販のゲームで言うと昔のバイオハザードみたいな感じになります。
昔のバイオハザードがどんな感じだったか今となってはあまり覚えていないんですが・・・・(^_^;)
あとはSIRENも近いかも!?

スポンサーリンク

敵の方向を向く機能の実現方法を考える

まずは機能を実現する為の方法を考えます。

主人公の子要素に敵をサーチするエリアを作成し、そのエリアに入った敵をゲームオブジェクトの配列に保存します。
格納された敵のゲームオブジェクトの中から主人公と一番近い敵を最初のターゲットに設定します。

次に一番近いターゲットを狙っている時に左右の方向キーを押したら別の敵をターゲットにします。

ユーザーが左の方向キーを押したら左側、右の方向キーを押したら右側にいる敵を調べ、
主人公から見て一番角度が小さい敵を次のターゲットにします。

敵をサーチするエリアから敵が出た場合はゲームオブジェクトの配列からその敵のゲームオブジェクトを削除します。

敵をサーチするエリアの作成

それではまず主人公の子要素に敵をサーチするエリアを作成していきましょう。

ターゲット選択1

主人公キャラクターの子要素に右クリック→Create Emptyで空のゲームオブジェクトを作成し名前をSearchEnemyとします。
SearchEnemyにインスペクタのAdd Component→Physics→Sphere Colliderを追加します。

ターゲット選択2

コライダは衝突させず検知するだけのエリアとして使うのでIs Triggerにチェックを入れておきます。

Sphere ColliderのRadiusはご自分の好みに合わせて変更してください。
ここで注意しなければいけないのはBox Collider等の角ばったコライダを設定してはいけない事です。

例えばBox Colliderをキャラクターに設置した場合、キャラクターが回転している間に敵がサーチエリアを出てしまうからです。
Sphere Colliderならば回転している間も範囲から外れる事がないので大丈夫です。

また敵をサーチするSearchEnemyスクリプトを新しく作り設定します。

ターゲット選択3

上がSphere Colliderの範囲です。
Sphere Colliderは上の画像のように丸いのでキャラクターが回転中も敵が範囲外に出る事はありません。

ターゲットを選択するスクリプトSearchEnemyの作成

それではターゲットを選択するスクリプトSearchEnemyを作成していきます。

enemyListとnowTargetをpublicにしたのはUnityの実行中に値を確認する為です。
enemyListはサーチする人数のsearchNum分だけオブジェクトを作成します。

まずは敵をサーチし、ゲームオブジェクト配列に登録する処理を見ていきます。
OnTriggerStay関数はサーチエリア内に何らかのコライダを持つゲームオブジェクトがいる時に実行されます。

Debug.DrawLineを使って、レイを視覚的にわかるようにしておきます。
進入してきたコライダを持つゲームオブジェクトに設定されたタグがEnemyであるものだけに限定しています。

また、進入してきたゲームオブジェクトに主人公からレイを飛ばし、間に壁(Fieldレイヤーを持つもの)がなければ、ゲームオブジェクト配列にその進入したゲームオブジェクトを登録します。

すでに登録されている場合は何もせずreturnします。

人型キャラクターの基底値は足元になっているので、Vector3.upを使って1mだけ上に移動した位置からレイを飛ばします。

これはDebug.DrawLineでレイを視覚的に確認出来るのでどこからどこにレイを飛ばしているか確認してください。

ターゲット選択4

Unityの実行中にレイを確認するにはGizmosを有効にすると確認出来ます。
(Gizmosの右の下矢印を押すと視覚化するものを選択出来ます)

主人公の位置にVector3.up(Vector3(0, 1, 0))を足した位置からサーチエリア内にいる敵の位置+Vector3.upの位置にレイが飛んでいます。

OnTriggerExitはサーチエリア外に敵が出た時にゲームオブジェクト配列からそのゲームオブジェクトを削除します。
現在ターゲットに選択されていた場合はターゲットをnullにします。

最後にUpdate関数内を見ていきます。

主人公の攻撃準備をしていない時(歩いてる時等)に敵が壁とかぶっていたらゲームオブジェクト配列から削除する処理をします。
最初のターゲットは主人公から一番近い敵に設定します。

主人公の攻撃準備が出来ている時は主人公が現在次のターゲットに向けて回転中でなく、左右キーが押された時に次のターゲットを探します。

主人公が見ている方向から左側は180~360、右側は0~180が角度として返ってくるので、
その値を使って向いている方向から一番近い敵を探します。

ゲームオブジェクト配列分探し、押した方向の一番近い角度(距離ではなく角度)のゲームオブジェクトをターゲットに設定します。

これで敵をサーチし、ターゲットを選定する処理が出来ました。

キャラクター操作スクリプトに処理を追加

次はキャラクター操作スクリプトを修正します。

キャラクター操作スクリプトで攻撃構えボタンを押したらGetNowTarget関数を呼び出し、
ターゲットを調べてそちらの方向にキャラクターを向けさせます。

↑のように攻撃準備中の状態の処理の時にターゲットが設定されていれば、ターゲットの方向に体を向けさせます。
searchEnemyはSearchEnemyスクリプトを参照している変数です。

ターゲットに方向を変換中は次のターゲットを選択させたくないので、ロックします。
このロック変数charaRotateLock変数はGetCharaRotateLock関数で値を取得出来るようにしておきます。

さきほど作成したSearchEnemyスクリプトでGetCharaRotateLock関数を呼び出しロック中は左右キーを押した時に他の敵をターゲットに変更しないようにしています。

コメント化していますが、3通りのやり方で向きを変える事が出来ます。

LookAtは一気に向きを変えるのでカメラがすぐに切り替わり一瞬どうなったかわからなくなります。
RotateTowardsは一定で角度が変わっていきます。
Lerpは最初と最後がゆっくり変わるようになります。

Quaternion.Lerp(transform.rotation,
Quaternion.LookRotation(searchEnemy.GetNowTarget().transform.position – transform.position),
はキャラクターの角度から敵がいる方向への回転を滑らかにする処理です。

LookRotationはその方向の角度を計算する事が出来るので

敵のいる位置 – キャラクターがいる位置

でその方向を算出し、その方向を使ってLookRotationでその方向の角度を算出します。

Mathf.Absで現在のキャラクターのY座標の角度と目的の方向の角度がunLockAngle(インスペクタで設定)より小さくなったら向きを一気に変更しUnLockCharaRotate関数を呼び出しアンロック処理を行います。

UnLockCharaRotate関数はキャラクター操作スクリプト内に記述します。

ターゲットにする敵を変更出来るか確認する

これで処理が出来たので確認してみましょう。

ターゲット選択5

上のようにキャラクター操作スクリプトのインスペクタでunLockAngleを5、charaRotateSpeedを2に設定します。

キャラクターの上半身の角度を変えて敵を攻撃する処理がある場合は無効にしておきます。
またカメラを寄せる機能も無効にしておきます。
(バイオハザード系シューティングの記事で機能を作成している方限定です)

ターゲット選択6

上のように左右の方向キーを押すとターゲットにする敵を変更します。

が、これだと人の下に回転盤でもあるかのようにクルッと回転してしまうので、ターゲットに向けて回転している間は
下半身のアニメーションを足踏みのものに変更しましょう。

体の一部のアニメーションを変更して違和感をなくす

体の一部のアニメーションを変更する方法は

Unityのレイヤー、アバターマスクを使って体の一部分を別のアニメーションにする
体の一部分だけのアニメーションを変更したい場合はAnimatorControllerのレイヤーとアバターマスクを使う事で実現出来ます。

を参照してください。

ターゲット選択7

上のようにLower Layerという名前でアニメーターのレイヤーを作成します。

ターゲット選択9

Assetsエリアで右クリック→Create→Avatar Maskを選択し名前をLower Avatarとし、インスペクタで上のように設定します。

ターゲット選択8

Lower Layerの右の歯車を押して、上の画面を開きLower Avatarを設定します。
Weightは1に設定しておきます。

ターゲット選択10

Lower Layerの状態遷移を上のように作成します。
あ・・・名前を変更するのを忘れてNew Stateのままになっていますが・・・、Idle等のわかりやすい名前を付けてください。

New Stateのアニメーションクリップは何も設定しません。

Rotate Walkのアニメーションクリップは足踏みをするようなアニメーションを選択します(歩くアニメーションでOK)

アニメーションパラメータにRotateWalkをbool型で作成しておき、RotateWalkがtrueになったらRotateWalkに遷移するようにします。
RotateWalkがfalseになった時にNew Stateに遷移させます。

ターゲット選択11

上がNew State→Rotate Walkの遷移のインスペクタです。

最後にキャラクター操作スクリプトでアニメーションパラメータのRotateWalkのOn・Offの処理を追加します。

ターゲットにキャラクターを向ける時にアニメーションパラメータのRotateWalkをtrueにします。

キャラクターの回転中のロックを解除する関数UnLockCharaRotate内にRotateWalkをfalseにする処理を追加します。

UnLockCharaRotate関数を呼び出すタイミングとしては攻撃準備を解除した時(歩きだしたりした時)やキャラクターがターゲットの方向を向き終わった時になります。

これで体の一部のアニメーション変更処理が終わったのでUnityの実行ボタンを押して確認してみましょう。

ターゲット選択12

上のように下半身は歩くアニメーションが再生されるようになりました。
もっと細かく作りたい場合は左向きに回転する時、右向きに回転する時のアニメーションを変更するといいかもしれません。

細かいアニメーション設定をしたい方は

UnityアニメーターのBlendTreeで細かい動作をさせる
Unityのブレンドツリーを使ってアニメーションの切り替えを細かく設定し、向きを変える時の角度によってアニメーションを変更するようにします

を参考にしてください。

これでUnityのアクションゲームで攻撃時に敵の方向をむかせる機能が完成しました。

左右の方向キーを押した時にターゲットを変更する処理が結構大変でした・・・(^_^;)
今回のターゲットの変更の仕方は向いている方向に一番近い敵ですが、方向ではなく一番近い距離にいる敵とする事も出来ます。

その場合は回転でターゲットを選択するのではなく距離で計算する事で実現できますので、やってみてください。