Unityで敵キャラが主人公に近づいた時に攻撃をしてくる機能

前回までで主人公が敵キャラの検知エリアに入った時に追いかけてくるところまで作りました。

Unityで主人公キャラクターが敵キャラクターに近づいたら敵が主人公に近づいてくるようにしたいと思います。

今回はさらに主人公との距離が縮まったら敵キャラが主人公を攻撃してくる機能を作ってみます。

まずは前回まで敵の移動スクリプトをMoveEnemyとしていましたが、攻撃機能も取り付けるのでファイル名とクラス名をEnemyに変更します。

それではAsset Storeでアニメーション用のデータをインポートしましょう。

3Dモデル→キャラクター→トゥーン→Cartoon Zombie

をインポートしました。キャラクターに付いているattackというアニメーションを使います。

スポンサーリンク

アニメーションクリップの設定をする

ゾンビのキャラクターを選択したらインスペクタ上でRigがHumanoidになるようにし、次にAnimationsをクリックします。

Attack用のアニメーションRigをHumanoidにする

atack01を選択したら赤く印をつけた場所にチェックを入れます。

アニメーションの動きによってオブジェクトに回転や移動を加えないようにし、スクリプトで制御する為です。

アニメーションのPoseにチェックを入れる

アニメーションイベントを作成する

次はアニメーションの再生位置でイベントを発生させるようにしてみます。

アニメーションイベントを追加する

上のようにEventの所をクリックし、下のマークをクリックします。

アニメーションイベントの設定をする

新しいウインドウが出てくるのでAttackStartとAttackEnd、StateEndというイベントを作り、赤でマークをした位置に移動させます。

これは攻撃判定開始時と判定終了時、攻撃状態の終了を設定する為にこの位置にしています。(微調整してください)
FloatやIntはそのイベント発生時に渡せる引数の値です。特に渡さない場合は変更しなくて大丈夫です。

これでこのアニメーションが再生され、イベントの個所にくるとAnimatorが設定されているオブジェクトにAttackStart、AttackEnd、StateEndというイベントが送られます。
このイベントを受け取るスクリプトはあとで作成します。

これでアニメーションの途中でイベントを投げる事が出来るようになりました。

敵キャラが攻撃をする為のスクリプトを作成

Enemyスクリプトに処理を加えます。

Updateメソッドに敵キャラの攻撃遷移処理を追加

次は敵キャラが攻撃に遷移するスクリプト部分をEnemyスクリプトのUpdateメソッド内に追加します。

EnemyStateに攻撃状態と攻撃後のフリーズ状態を作ります。

また攻撃後のフリーズ状態を続ける時間をインスペクタで設定出来るようにします。

状態がEnemyState.Chaseの時に主人公と1mの距離内に入ったらEnemyState.Attack状態にします。

距離の計算はVector3.Distanceで計算出来ます。

SetStateメソッドに攻撃状態と攻撃後状態を追加

SetStateメソッド内にEnemyState.Attack状態と攻撃後のEnemyState.Freeze状態へ変更する処理を追加します。

アタック状態、フリーズ状態ともにvelocityの値をVector3.zeroで0にして、移動処理を行わないようにします。

またアニメーションパラメータのSpeedも0にしておきます。

SetStateでEnemyState.Freeze状態に変更されるのは攻撃アニメーションが終わった時にイベントとして受け取ったメソッドで呼び出します。

アニメーターコントローラーで攻撃の状態と遷移を作成

次にAnimatorControllerの設定をしていきます。

まずはアニメーションパラメータAttackをBoolとして作成します。

敵のAnimatorに攻撃状態を作成

新しいアニメーションのatack01をアニメーターウインドウ上にドラッグ&ドロップし、Walk、Idleを選択し右クリックしてatack01にMake Transitionします。

アニメーション遷移条件を設定する

ConditionsにAttackを追加し、WalkとIdleからatack01への遷移条件に『Attackがtrue』の時を入れます。

遷移のインスペクタでHas Exit Timeのチェックを外しておきます。
このチェックが入っていると条件がOnになっても元のアニメーションの再生が終わらないと次のアニメーションに行きません。

atack01からIdleへMake Transitionを繋げます。インスペクタ上のHas Exit Timeのチェックを外し、条件にAttackがfalseになった時を入れておきます。
攻撃が終了したら何もしていない状態に遷移させる為です。

敵キャラの攻撃の当たり判定部分(コライダ)を作る

アニメーターの設定が終わったので、次は敵キャラの攻撃の当たり判定部分を作成していきます。

プレハブを修正するので、一旦、敵キャラのプレハブをヒエラルキー上にドラッグ&ドロップし、修正します。

アニメーションイベントの受け取りスクリプトを取りつける

敵キャラ本体にProcessAttackスクリプトを新規で追加し、

右手に攻撃用のコライダを設定

↑のように敵キャラの右手の部分にSphereColliderを追加します。

SphereColliderはスクリプトでOn・Offするので最初はチェックを外しておきます。

敵の手に攻撃の当たり判定をつける

AttackZombieという名前で新しいスクリプトを作成し、SphereColliderの設定してある右手の手の部分に設定します。

AttackZombieスクリプトは後で作成します。

実際の手の攻撃の当たり判定

SphereColliderを上のような感じで設定し当たり部分を大きめに取ります。
この部分が主人公のCharacterControllerのコライダに当たったら攻撃が当たったという処理をします。

修正が終わったら敵キャラのインスペクタ上にあるPrefabのApplyボタンをクリックしプレハブに反映させておきます。

反映させたらヒエラルキー上の敵キャラはいらないのでチェックをはずすか削除しておきます。

アニメーションイベントを受け取り、当たり判定のオン・オフをするスクリプト

ProcessAttackスクリプトはアニメーションのイベントを受け取るスクリプトになります。

Start関数内でEnemyMoveスクリプトとSphereColliderを取得しています。

GetComponentInChildrenはこのスクリプトが設定されているオブジェクトの子要素のコンポーネントを取得する時に使います。

敵の子要素に他にもコライダが設定されている場合はインスペクタでコライダを設定出来るようにした方がいいかもしれません。

コンポーネントの取得に関しては

Unityのスクリプトでゲームオブジェクト、コンポーネントを階層を辿って取得、タグを使って取得、コンポーネントの型で取得等、色々試してみます。

こちらで詳しく解説しています。

AttackStartとAttackEndはさきほど設定したアニメーションから送られてくるイベントを受け取りますので、AttackStartを受け取ったらコライダをOnにし、当たり判定を有効にします。

AttackEndを受け取ったら、コライダをOffにし、当たり判定を無効にします。

攻撃後(StateEnd)はEnemyState.Freezeに設定します。

アニメーションイベントの問題?

このアニメーションイベントで全てうまくいきそうですが、場合によっては呼ばれない事があります。

それは例えば敵が攻撃開始後すぐに主人公に攻撃を受けて攻撃アニメーションのアニメーションイベント部分までの再生がされず、ダメージアニメーションへ遷移してしまう時です。

AttackEndが呼ばれないとすると敵の手のコライダがオフにならないままになってしまいます。

そんな時はビヘイビアを使用するとうまくいきます。

Unityでアニメーションを即時遷移させているとアニメーションイベントが実行されない時があります。そんな時にビヘイビアを設定しておくと確実に処理を実行する事が出来ます。

攻撃の当たり判定をするスクリプト

次はAttackZombieスクリプトです。

Playerタグを持つインスタンスに当たったらキャラクター操作スクリプトMoveのTakeDamage関数(ダメージ処理関数)を実行させます。

引数としてこのスクリプトが設定されているオブジェクトのルート(敵キャラ)のTransform情報(位置情報)を渡しています。
つまり主人公キャラのMoveスクリプトのTakeDamage関数に敵キャラのTransform情報を渡すという事になります。

これで敵キャラの攻撃の処理が出来ました。

ただ、攻撃された主人公キャラ側の処理をまだ作っていないので、攻撃されても主人公は棒立ち状態のままです。

主人公側の攻撃を受けた時の処理スクリプト

それでは攻撃を受けた主人公の処理をMoveスクリプトに追加します。

さきほど攻撃を受けた時にTakeDamage関数を実行する処理を記述したので、主人公側で攻撃を受けた時の処理を書いていきます。

まずはフィールド部分です。

主人公側でも今何をしている状態か?の状態の列挙体と記憶しておくフィールドstateを作ります。

TakeDamage関数が呼ばれたら、状態stateをダメージを受けている状態MyState.Damageに変更し、主人公キャラのアニメーションパラメータのDamageトリガーをOnにします。

また攻撃を受けた際に敵の向いている方向に動かしたい時は、コメントアウトしている部分を有効にします(今回は攻撃を受けても動かしません)。

EndDamage関数はアニメーションでイベントを作るので、それを受け取る関数です。

主人公はダメージを受けた直後はMyState.Normalに設定します。

キャラクター操作処理部分を修正する

次にMoveスクリプトのUpdateメソッド内を修正します。

ダメージを受けている時に方向キー等を押した場合、ダメージを受けながら移動してしまいますので、そうならない為の条件を加えます。

キャラクターの状態がMyState.Normalの時だけ移動処理を行います。

アニメーターコントローラにダメージ状態と遷移を作成する

主人公キャラクターのAnimatorControllerを修正します。

主人公にDamage状態を追加したAnimatorController

敵キャラのアニメーターコントローラーとほぼ同じで、アニメーションパラメータにTrigger型のDamageのパラメータを作成し、
Damage状態を作り、DamageトリガーがOnになったらAny StateからDamageに遷移するように作ります。

今回の記事とは関係ないですが、Walk→IdleのSettingsのInterruption SourceをNext Stateに変更し、何もしていない状態から歩き状態への遷移をスムーズにします。

Any State→Damageの遷移条件はHas Exit Timeのチェックを外し、Damageがトリガーされた時に遷移するようにします。

Damage→Idleの遷移のインスペクタは

Damage→Idleへの遷移条件

↑のようになります。

Damage→Walkの遷移条件はHas Exit Timeのチェックを外し、SpeedがGreaterで0.1を設定します。

Damage→Walkの遷移条件

主人公用のダメージアニメーションにアニメーションイベントを追加

最後にダメージアニメーションでイベントを発生させておきます。

DamageEndアニメーションイベントを追加する

アニメーションが終了した時にDamageEndイベントを発生させています。
ダメージアニメーションは

最初にインポートしたCartoon Zombieのdamageアニメーションを使用します。

終わりに

これで敵の攻撃と主人公が攻撃を受けた時の処理が出来ました。

敵が主人公を攻撃するサンプル

当たり判定の大きさと主人公キャラとの距離の調整をすればそれなりに見えるんではないかと・・・・・。

今回の作業はいろいろな個所の設定が必要なので、慣れてない人はどれがどれだか解らないという状態になるかもしれません。

説明下手なもので、飛び飛びの解説になってしまいました・・・・。(;_;)

次回は攻撃されてばかりではストレスがたまるので主人公も攻撃を出来るようにしてみます。

スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます