Unityでバイオハザード風ガンシューティングの機能を作ってみる

記事内に広告が含まれています。

今回からUnityを使ってバイオハザード風ガンシューティングの機能を作っていきたいと思います。

あくまで風なので、バイオハザード2と同じバイオハザード4と同じ、というわけにはいきません。

キャラクターが銃を装備していたら、何か特定のキーを押している間は銃を構え、どこを狙っているかわかりやすい表示(レーザーポインタ)をして、敵にレーザーポインタが当たっていて銃を撃つキーを押せば敵にダメージを与えます。

また、次回以降に銃をかまえている間は上半身を少し動かし狙う角度の調整も出来るようにします。

なんだか盛りだくさんで嫌になりそうですが・・・(^_^;)

今回は銃を装備させ、銃を構えるようにしてみます。

今回の機能は以前作成した機能に処理を追加する形で作成されていますので、以前作成した機能について知りたい方は

Unityを使った3Dゲームの作り方(かめくめ)の歩き方
Unityを使った3Dゲームの作り方(かめくめ)で、はじめてUnityの学習をする時の当ブログの記事を読む順番を書きました。機能を積み上げていく形になるので便利かも?

の記事で今までの機能作成の流れを確認する事が出来ます。

スポンサーリンク

銃の3Dオブジェクトの準備とキャラクターに装備させる

銃はAsset Storeで準備しましょう。

3D モデル→小道具→武器→銃火器→[PBR] Makarov- Free Edition

をインポートさせていただきました。

バイオハザード0

キャラクターの右手の子要素にCreate Emptyで空オブジェクトを作り、名前をEquipとしています。

その子要素に銃を持たせます。

バイオ1

上のような感じに置きます。

上の階層ではEquipの子要素に装備する武器を並べていますが、武器をインスタンス化して配置する場合はMakrovだけになります。

バイオ2

Scaleを調整し、位置と角度を変更します。

Scaleは本来は銃のモデルのインスペクタのScale Factorの値を変更してサイズ調整をしたいところですが、モデル内部の部品でScale調整がされており、Scale Factorを使うと銃がバラバラになってしまう為、今回はScaleを調整しました。

Scale Factorを調整しても銃の部品に影響がなければScale Factorを使用して銃のサイズを調整してください。

銃の親要素であるEquipのTransformのScaleのX、Y、Zが1である事を必ず確認してください。

ここがそれ以外の値であると子要素である銃のTransformはそこからの相対値になるので、位置や角度を変更するとオブジェクトがゆがみます。

また銃をもっと正しく手の位置、角度と合わせたい時は

Unityでキャラクターに正確に武器を持たせる
Unityでキャラクターの手の位置に正確に武器を持たせるように調整します。なんとなく持たせる位置を設定していた人には朗報かも!?

も参考にしてください。

武器のステータス記憶用のスクリプトWeaponStatusを追加し、インスペクタでWeaponTypeをGunに変更します。

銃で殴るという場合も考えてCapsuleColliderを追加しチェックを外しておきます。

Is Triggerのチェックを入れておきます。

主人公の打撃攻撃の作成は

Unityで主人公キャラが敵を攻撃出来るようにする機能
Unityで主人公キャラが剣を振って敵キャラを攻撃出来るようにする機能を作成します

を参考にしてください。

バイオ3

回転をさせる場合は上の部分をクリックして操作すると視覚的にわかりやすいです。

武器の配置が出来たら名前をHandGunに変更しAssetsフォルダにドラッグ&ドロップしてプレハブにし、ヒエラルキー上のHandGunは削除します。

インスペクタでweaponsにプレハブのHandGunをドラッグ&ドロップします。

これで武器の切り替えをした時にHandGunが加わりました。

銃を構えるアニメーションの準備と設定

次に銃を撃つ時のアニメーションを用意してください。

AssetStoreでは見つけられませんでした(無料で)。ちゃんと探せばあると思いますが・・・。

アニメーションの作り方は

Blenderを使ってUnityで使うアニメーションを作成する
Unityで使用するキャラクター用のアニメーションをBlenderを使って作成していきます。作成方法を学べば自分のゲームに自作のアニメーションを使うことが出来ます。

を参考にして作成してみてください。

それではアニメーターコントローラーに構える状態を作ります。

主人公のアニメーターコントローラーにWaitShotを作成する

まずBool型のWaitShotというアニメーションパラメータを作成します。

上のようにWaitShotというステートを作り銃を構えるアニメーションクリップを設定し、Idle、Walk、Damageから遷移を繋げ、WaitShotがtrueになったらWaitShotステートに遷移するように条件を加えます。

WaitShotステートからはIdleに遷移を繋げ、条件にWaitShotがfalseになった時に設定します。

それぞれの条件ではHas Exit Timeのチェックを外しておきます。

これでアニメーションの流れが出来たので、スクリプトでアニメーション操作の処理を足していきます。

銃を構えるアニメーションに遷移させるスクリプトを作成する

構えるアニメーションにする為に押すボタンは「Fire2」に設定されているボタンにします。

Windowsパソコンの場合はデフォルトで右クリックになっています。

右クリックを離した時点で構えをやめるようにします。

これらのボタンの動作の処理はキャラクター操作スクリプトでやっているのでそちらに処理を加えていきます。

MyState.Normal状態の時は移動を行い、その中でFire1ボタンを押したら通常の打撃攻撃、銃を装備している時でFire2ボタンを押したら銃を構えるようにします。

MyState.WaitShot状態の時は銃を構えた状態なのでその中で、マウスの右ボタンを離した時はノーマル状態へと遷移させます。

マウスの右ボタンを離していない時でFire1ボタンを押したら銃を撃った時にする為、銃を撃つ処理をします。

shotに保存しているShotスクリプトのメソッド呼び出しを多く記述していますが、これらは後で作成します。

Shotスクリプトのメソッドは、

AbleLightは銃を発砲した時の光を点け、
DisableLightは銃を発砲した時の光を消し、
AbleRaserPointerは銃のレーザーポインターを表示し、
DisableRaserPointerは銃のレーザーポインターを消し、
PlaySEは銃の発砲音を鳴らし、
JudgeShotは弾が敵に当たったかどうかを判断するメソッドです。

さきほど紹介したスクリプトは以前の記事で作成したスクリプトを元にしているので、この記事単体ではわからない部分もあると思いますが、
キャラクター移動の条件だったり、キャラクターが銃を構える時の条件を記述しているだけです。

キャラクター操作スクリプトのTakeDamageメソッドとSetStateメソッドを変更します。

敵にダメージを受けた時はアニメーションパラメータのWaitShotをfalseにしています。

ここまででShotスクリプトを作成していないので主人公操作スクリプトはエラーが出る状態です。

銃のレーザーポインタの作成と銃を発砲した時の光

とりあえずShotスクリプトは後回しにして、次はレーザーポインタと銃を撃った時の光の準備をします。

バイオ5

銃の子要素にMuzzle(銃口)をCubeで作りサイズを調整して合わせます。Z方向青矢印が銃弾の飛んでいく先とします。

見た目はいらないのでMeshRendererのチェックを外し、BoxColliderもチェックを外しておきます。
空オブジェクトにしなかったのは位置を合わせる時にやりやすいからです。

バイオハザード20

MuzzleのZ方向の青矢印を銃弾の飛ばす位置として合わす時に、上の画像のように赤い四角の部分をクリックし、Local表示にして合わせてください。

Local表示にするとそのゲームオブジェクトの向きでX、Y、Zの軸の矢印が表示されるようになります。

MuzzleにAdd ComponetでLineRendererとLight、AudioSourceを追加します。
AudioSourceには発砲時に鳴らす銃声を設定し、PlayOnAwakeのチェックは外してください。

AudioSourceについては

Unityで敵キャラクター出現時に効果音を鳴らしてみる
Unityで敵キャラクターを出現させた時に効果音を鳴らして、出現した事をわかるようにしていきます。

を参照してください。

LineRendererは設定した点に線を引く為のコンポーネントです。

Muzzleの部分から銃口が向いている先の部分まで軌跡を表示することでレーザーポインタの表現が出来ます。

銃のMuzzleに設定したLineRenderer

Cast ShadowsをOffにしてレーザーポインターの影は落とさないようにします。

LineRendererはUnityのバージョンが違うと上の画像とは多少違います。

Widthがグラフで設定する仕様になっている場合はWidthを0.010~0.015にして横軸の数値が増えても値が変わらないように設定しておきます。

銃のレーザーポインタ用のLineRendererのWidth設定

Lightは発砲した時の光を表現します。

銃のMuzzleに設定したLight

設定は上のような感じにしました。

Lightは光の発生点から広がるPointにしました。

LineRendererに設定しているGunsRayというマテリアルを作成します。

ProjectタブのAssetsフォルダで右クリックしCreateからMaterialを選びます。

GunsRayのインスペクタでシェーダ―をParticle/Standard Unlitにし、Rendering ModeをAdditive、Color ModeをMultiplyに変更します。

Albedoの色を赤色にします。

銃のレーザーポインターのマテリアル

LineRendererにマテリアルを設定し、コンポーネントのチェックを外したらレーザーポインタの準備が完了です。

Lightもチェックを外してください。

敵にレーザーポインタが当たった時にわかりやすくする為、シューティングポイントを表示します。
それをシーン上にSphereとして作成します。

シューティングポイント用のゲームオブジェクトを作成

Sphereの名前をShotPointという名前に変更し、マテリアルを設定します。

マテリアルはレーザーポインタのマテリアルを作った時と同様の方法で作成します。

出来たらShotPointにマテリアルを設定します。

ShotPointは最初は見えなくしておきたいので、MeshRendererのチェックを外しておきます。

このShotPointは常にシーン上にあり、敵にレーザーポインタが当たるとそこに移動し、MeshRendererのチェックをいれるという感じで使用します。

ShotPointはプレハブ化し敵にレーザーポインタが当たった時にインスタンス化するという方法もありますが、毎回インスタンス化するのは処理に時間がかかりそうなので表示のオン・オフで対応しました。

銃を構えた時の処理スクリプトShotの作成

それでは銃を構えた時の処理を実行するスクリプトShotを作成していきます。

Shotスクリプトは銃自体に設定する事も出来ますが、今回は主人公キャラクター自身に設定する事にします。

フィールド宣言部とStartメソッド

まずはフィールド宣言

いきなり盛りだくさん・・・・(+_+)

rayRangeはレイを飛ばす距離。
equipはインスペクタで武器の親のゲームオブジェクトのTransformを指定します。
raserPointer、audioSource、shotLightは武器が銃に変わった時に銃に設定しているコンポーネントを設定します。
lightLimitは発砲の光を表示している時間。
lightElapsedTimeは銃を発砲してからの経過時間。
characterScriptは主人公キャラ操作スクリプト。
shotPointは銃のシューティングポイント。
myStatusは主人公のステータススクリプト。
hitFlagはレーザーポインターが何かに当たっているかどうか。
nearPointはレーザーポインターが当たった一番近いゲームオブジェクトまでの距離。
distanceはレーザーポインターが当たった距離を入れるフィールド。
muzzleは銃の子要素のMuzzleを設定するフィールド。

になります。

Startメソッド内コンポーネントの取得と初期設定です。

コンポーネントの有効・無効と設定処理

Shotスクリプトの簡単な部分から記述していきます。

これらはレーザーポインタの表示・非表示
発砲時の光の表示・非表示
音を鳴らす

という処理です。

銃を撃ったタイミングでこれらのメソッドを呼び出します。

これらは主人公操作スクリプトCharacterScriptで呼び出していたメソッドですね。

InitializeGunメソッドは武器を切り替えるスクリプトChangeEquipスクリプトから呼び出すメソッドで、引数で受け取った武器の子要素からコンポーネントを取得したり、Muzzleゲームオブジェクトを取得しています。

レーザーポインタを表示させる処理

次にレーザーポインタの表示処理を加えます。

銃を構えた状態の時にレーザーポインターの処理を行います。

LineRendererでは複数点を指定して線を引きますので、まずは最初の地点を指定します。

で最初の地点を指定します。

第1引数が0で最初の地点、1で次の地点となります。
この数を増やしていくと点を繋ぐ線が出来ます。

Rayはレーザー光線のようなもので位置と向きを指定します。

Muzzleの位置からMuzzleの前方に向かってレイを作成します。

MuzzleのZの位置を発射させる向きにしたのはmuzzle.forwardを使う為です。

次はレイが指定したレイヤーを持つゲームオブジェクトと接触したかどうか調べる部分を見ていきましょう。

Physics.RaycastはレイをrayRangeの長さ飛ばし、Fieldレイヤーが設定されたゲームオブジェクトに接触したら条件がtrueになります。

さらにhitに接触したゲームオブジェクトの情報が入り、hit.pointで接触した位置を取得する事が出来ます。

Fieldレイヤーとの接触の後にEnemyレイヤーを指定したものとの判定を行いますが、この場合のレイの距離は武器の射程距離にします。

こうすることで、武器の射程距離に満たない場合は敵にレイが届きません。

敵が死んだ状態でなければShotPoint(シューティングポイント)を表示し、hitFlagをtrueにし、敵に当たった事にします。

distanceには何も接触していない時はfloat.maxValueでfloat値の最大値が入り、Fieldレイヤーと接触していればそのゲームオブジェクトの距離が入っています。

Enemyレイヤーと接触した距離とdistanceの距離を比べ、Enemyレイヤーのゲームオブジェクトとの距離の方が短かった時はそちらにシューティングポイントを表示します。

シューティングポイントをhit.pointにするとコライダの位置にシューティングポイントが表示されますが、敵にかぶって見えづらい事もあります。

今後カメラをキャラクターの子要素に配置し、ラジコン操作で動かせるようにした場合はシューティングポイントを少し主人公キャラクターよりに表示した方が見やすいかもしれません。

シューティングポイントを主人公側に表示するには

↑のようにhit.pointからtransform.forward(主人公キャラクターの前方)の反対側に少し補正値を加えます。

この場合カメラがキャラクターの後ろにあればいいですが、ない場合はtransform.forwardの代わりにCamera.main.transform.forward(この場合はメインカメラ)を使ってカメラの方向を使うといいかもしれません。

hitFlagがtrueならば何らかのゲームオブジェクトにレイが当たっていたので、レーザーポインターの到達点を設定します。

ゲームオブジェクトに当たっていなければシューティングポイントをオフにし、到達点をrayRange先の位置に設定します。

発砲した時の光が一定時間経過したらDisableLightメソッドを呼んで光を無効にしています。

弾が当たったかどうかの処理

弾が当たったかどうかを判断するJudgeShotメソッドを作成します。

JudgeShotメソッドでもFieldレイヤーとEnemyレイヤーでEnemyレイヤーが近かったらダメージを与えるようにしてます。

TakeDamageで渡すダメージ値はMyStatusで保持している装備している武器の銃の威力にします。

敵キャラクターにレイヤーを設定する

ここでレイヤーについて見ていきます。

LayerMask.GetMask(“レイヤーの名前”)

でレイヤーの取得が出来ます。レイヤーはオブジェクトのインスペクタで設定が出来ます。

敵キャラクターのレイヤーをEnemyに設定します。
(レイヤーの設定はご自由に)

レイヤーがない場合は作成して追加してください。

バイオ10

レイヤーを変更する時に上のようなウインドウが出る事があります。

これは子要素のレイヤーも変更するかどうか聞かれています。
子要素のレイヤーを変更してしまうと不具合になる場合はNo, This Object Onlyをクリックしてください。

例えば敵キャラクターの子要素に主人公キャラを検知するサーチエリアを設定していた場合、
Yes, Change Childrenをクリックして子要素のレイヤーもEnemyにしてしまった場合、銃を撃って当たり判定をする時にサーチエリアの範囲も含めてしまうことになります。

なので、敵キャラクターの場合は子要素のレイヤーは変更しないようNo, This Object Onlyを選んでください。

万が一間違えて変更してしまっても子要素のゲームオブジェクトを選択しレイヤーを変更してあげれば大丈夫です。
ゲームオブジェクトを作成した時はDefaultレイヤーに設定されているので、特にレイヤーを設定する必要がないものはDefaultレイヤーに戻すといいと思います。

Enemyスクリプトの修正

敵のHPが0以下になった時にDead状態へと遷移させていますが、Dead状態になったら他の処理をしないように変更します。

まずはUpdateメソッドの最初でEnemyState.Dead状態であればreturnで処理をしないようにします。

次はSetStateメソッドです。

こちらも死んだ状態であればreturnで処理をさせません。

武器の位置、角度、サイズをWeaponStatusスクリプトに移す

武器の切り替えはChangeEquipスクリプトで行い、そこでは直にそれぞれの武器の位置や角度、サイズを設定していましたが、これをWeaponStatusに保存し、そこからデータを取って来るようにします。

WeaponStatusに

というフィールドを宣言し、それぞれのフィールドを返すメソッドを定義します。

武器のプレハブでそれぞれの値を設定します。

WeaponStatusにインスタンス化した時の位置や角度を保持する

ChangeEquipスクリプトに追記と修正をします。

武器のインスタンス化をした時にインスタンス化したゲームオブジェクトの名前をプレハブの名前にしました。

weaponStatusのゲッターでインスタンス化した時の位置、角度、サイズを取得し、それを設定します。

インスタンス化した武器が銃の時はShotスクリプトのInitializeGunメソッドで銃の初期化処理を行います。

レーザーポインタの移動が少し遅れる!?

次の記事の

Unityのゲームでバイオハザード風に照準を合わせられるようにする
Unityのゲームで初期のバイオハザード風に上半身の角度を変え、照準を合わせるような機能を作成していきます。

の機能を搭載すると、主人公が体を動かして照準を定める時にレーザーポインタが銃より少し遅れて移動しているように見えます。

バイオ18

上の画像のように銃の向きとレーザーポインタの出ている位置が少しズレています。
これは体の向きを変更するUpdateとレーザーポインタの点の位置を指定するUpdateのタイミングのせいで起きてると思われます。

そんなに問題があるわけではないですが、見た目的におかしいので修正します。
体の向きを変更するUpdateが終わった後にレーザーポインタの点の位置を指定すればいいので、Updateの部分をLateUpdateに変更します。

LateUpdateはUpdateが終了した後に実行されるので、体の向きが確定した後にレーザーポインタの位置を指定するようになり、不具合がなくなります。

バイオ19

これで銃を構えたらレーザーポインタを表示した時の処理、敵にレーザーポインタが当たった時の処理、発砲した時の処理が完成しました。

シューティング機能が出来たが、当たり判定個所が大雑把

細かい所を作りこめばなかなかいい感じに出来上がると思います。結構感動ものです!!

ですが・・・、現状では銃を構えた状態でその場で銃が向いている方向にしか打てません。

銃を構えた状態でも歩けるようにする事も出来ますので(そういう風に作れば)そういう作りにしていろいろな所を狙えるようにするのもいいかもしれません。

また当たっている部分が敵キャラのコライダの接触位置なので空間上になっています。

CharacterColliderの大雑把なコライダで判定している為にそうなってしまいます。

それは次回以降、部位に当たり判定個所(コライダ)を作成し、より細かく当たり判定が出来るようにしたいと思います。

銃を構えた状態で歩いて狙いを定めるのも魅力ですが、バイオハザード4やバイオハザード5あたりの構えた状態で狙いを定めるというのを次回から作ってみようと思います。

タイトルとURLをコピーしました