シンプルなアクションゲームを作ってみよう18-プレイヤーを攻撃する大砲を作成する-

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

シンプルなアクションゲームを作ってみようの第18回です。

今回は大砲を作成し、大砲から弾を飛ばしてプレイヤーに当たったらダメージを与える機能を作成していきます。

前回はプレイヤーキャラクターのHPを管理するアセットの作成とHPをUIに表示する機能を作成しました。

シンプルなアクションゲームを作ってみよう17-キャラクターのHPを表示する-
シンプルなアクションゲームでプレイヤーのHPをScriptableObjectで作成してUIに表示し、敵に接近されたらHPを減らす機能を作成していきます。

シンプルなアクションゲームを作ってみようの他の記事は

シンプルなアクションゲームを作ってみよう

シンプルなアクションゲームを作るのを通してUnityの使い方を学ぶカテゴリです。

から参照出来ます。

スポンサーリンク

大砲を作成する

今回作成する大砲はUnityのプリミティブな図形のCubeを使って作成します。

大砲のゲームオブジェクトを作成する

まずは大砲の形状を作成していきます。

Environmentゲームオブジェクトを選択した状態で右クリックからCreate Emptyを選択し、名前をCannonとします。

大砲のベースとなるCannonゲームオブジェクトを作成する

Cannonは空のゲームオブジェクトなので大砲のベースとするゲームオブジェクトとして使用します。

次に大砲の土台を作成します。

Cannonを選択した状態で右クリックから3D Object→Cubeを選択し、名前をGunMountとします。

CannonにGunMountゲームオブジェクトを付ける

GunMountを選択し、インスペクタのTransformの値を変更します。

GunMountの形状を変更する

シーンビューでは以下のようになりました。

シーンビューで見たGunMountの形状

Cannonの位置がプレイヤーキャラクターと被っているので、Cannonの位置をずらし見やすい場所に移動させます。

CannonのインスペクタのTransformのXは-3.38にしました(シーンビューでCannonのX軸をドラッグしてもOK)。

とりあえず見やすければ問題ないです。

次に砲台部分のゲームオブジェクトを作ります。

ヒエラルキーでCannonを選択した状態で右クリックから3D Object→Cubeを選択し、名前をBarrelとします。

大砲のBatteryゲームオブジェクトの作成

Barrelゲームオブジェクトを選択し、インスペクタのTransformの値を変更します。

BatteryのインスペクタのTransformの設定

シーンビューで確認すると以下のようになりました。

大砲の途中経過の形状

これで大砲の形状が出来たように思いますが、大砲の砲身部分であるBarrelは回転してキャラクターの方向を向いて弾を発射出来る機能を取り付ける予定です。

しかし、砲身であるBarrelはCubeゲームオブジェクトから作成したのでBarrelを回転するとBarrelの中心がCubeの真ん中にあるため中央で回転してしまいます。

Barrelを選択し、Pivot表示にしてシーンビューを見るとわかりやすくなります。

Barrelの中心はCubeの真ん中にある

つまりスクリプトで回転処理をさせようと思うと上のシーンビューの赤い四角の部分を中心に回転してしまいます。

そこでBarrelの根本部分から回転出来るようにちょっとした工夫を加えたいと思います。

砲身の基点のゲームオブジェクトの作成

砲身であるBarrelが根本で回転するように、Barrelの根本の部分に空のゲームオブジェクトを作成し、その空のゲームオブジェクトの子要素にBarrelを移動して、空のゲームオブジェクト自体を回転させれば子であるBarrelも相対的に回転するので砲身の根元から回転しているように見えます。

そこでBarrelの根元のゲームオブジェクトを作成します。

Cannonを選択した状態で右クリックからCreate Emptyを選択し、名前をBasePointOfTheBarrelとします。

BasePointOfTheBarrelの位置

BasePointOfTheBarrelの位置は砲身であるBarrelの根本の位置に移動させます。

またHandle LotationがLocalであることを確認し、ローカル軸の青い矢印(そのゲームオブジェクトの前方)が砲身の先を向くように回転させます。

BasePointOfTheBarrelの前方の向きを砲身の先にする

わたくしの場合はBasePointOfTheBarrelのTransformを以下のようにしました。

BasePointOfTheBarrelのTransformの設定

これでBarrelの根本であるBasePointOfTheBarrelが出来ました。

次にBarrelをドラッグしてBasePointOfTheBarrelの子に移動させます。

BarrelをBasePointOfTheBarrelの子にする

弾を飛ばす位置の作成

次は砲身から弾を飛ばす時の、弾を発射する位置を作成します。

Barrelゲームオブジェクトを選択した状態で右クリックからCreate Emptyを選択し、名前をLaunchPositionとします。

次にHandle PositionをLocalにし、LaunchPositionの移動と回転を行います。

LaunchPositionの位置と回転の変更

上のような位置に移動させ、ローカル軸の青い矢印(そのゲームオブジェクトの前方)が弾が飛んでいく方向に向けます。

変更したLaunchPositionのTransformは以下のようになりました。

LaunchPositionのインスペクタの設定

位置は弾のインスタンスの大きさによっては変更する必要が出てくるかもしれません。

砲身を回転させるスクリプトの作成

次に砲身を回転させるスクリプトを作成していきます。

ここでは砲身と言っていますが、実際には砲身の根本であるBasePointOfTheBarrelを回転させます。

Assets/Scriptsフォルダに新しくCannonRotationScriptという名前のスクリプトを作成し、BasePointOfTheBarrelゲームオブジェクトに取り付けます。

rotatableは砲身を回転させるかどうかで、インスペクタでオン・オフを切り替えられます。

rotationSpeedは砲身の回転スピードです。

playerはプレイヤーキャラクターのTransformを入れます。

rigidBodyはBasePointOfTheBarrelに取り付けるRigidbodyを入れます。

viewingQuaternionは砲身を向ける角度を入れます。

StartメソッドでGameObject.FindWithTagメソッドを使ってPlayerタグを取り付けられたプレイヤーキャラクターを探し、そのTransformを取得してplayerに入れます。

rigidbodyを自身から取得します。

viewingQuaternionには最初Quaternion.identityを入れます。

Quaternion.identityは親の軸の回転に合わせるか、ルートの親(一番の親)である場合はワールド軸の回転していない状態と同じです。

UpdateメソッドではQuaternion.Slerpメソッドを使って第1引数のQuaternion値を徐々に第2引数のQuaternion値に変更します。

値は第3引数で指定した値で補間されます。

第3引数の値は0~1の間の数値に変換され0であれば第1引数のQuaternion、1であれば第2引数のQuaternionと一致します。

その間の数値であれば第1引数と第2引数の間のQuaternionが得られるという感じになります。

今回の場合は第1引数のrigidBody.rotationの値がプレイヤーの方向を向くように変化していきますので、第3引数は回転スピードのrotationSpeedとTime.deltaTimeを掛けたものを指定しています。

rotationSpeedを大きくしても最大で1にしかならないので1の場合はプレイヤーキャラクタの方向を完全に向いた回転を得られます。

仮に毎回Updateメソッドが0.02秒毎に呼ばれるとしたらrotationSpeedを2とした場合に

となるのでrigidBody.rotationとQuaternion.LookRotation(player.position – rigidBody.position + Vector3.up * 0.8f)の間の0~1の割合の0.04の回転を得られるという感じになります。

イメージとしては以下のようになります。

大砲の砲身の向きを徐々に変えていく時のイメージ

現在の砲身の回転はどんどん更新されていきますが、現在の回転と目的の回転の割合の0.04の部分の回転を取得している感じです。

Quaternion.LookRotationは引数で指定した方向の回転を得られます。

ここではプレイヤーの位置から砲身の位置を引いてプレイヤーの方向を指定していますので、プレイヤーの方向の回転が得られます。

Vector3.upはnew Vector3(0f, 1f, 0f)と同じでそれに0.8fを掛けて補正値としています。

これはplayer.positionはキャラクターの足元が基点となっているので、キャラクターのお腹の辺りに砲身を向ける為に補正値を加えています。

FixedUpdateメソッドでは計算した回転にRigidbodyのMoveRotationメソッドを使って回転させています。

これで砲身を回転させるスクリプトが出来ました。

砲身はスクリプトからRigidbodyを介して回転させますのでRigidbodyコンポーネントを取り付けます。

BasePointOfTheBarrelゲームオブジェクトのインスペクタのAdd ComponentからPhysics→Rigidbodyを選択し取り付けます。

BasePointOfTheBarrelにRigidbodyを取り付ける

CannonRotationScriptのRotatableにチェックを入れてみます。

RigidbodyのIsKinematicにチェックを入れてスクリプトから操作するようにします。

弾のプレハブの作成

次は砲身から飛ばす弾のプレハブを作成します。

ヒエラルキー上で右クリックから3D Object→Sphereを選択し、名前をBulletとします。

Bulletゲームオブジェクトの作成

Bulletゲームオブジェクトを選択し、インスペクタで設定をしていきます。

まずはAdd ComponentからPhysics→Rigidbodyを選択し取り付けます。

TransformのScaleのXYZを全て0.2にします。

RigidbodyのMassを0.1にし、Use Gravityのチェックを外し重力を働かせないようにします。

Bulletのインスペクタの設定

次にAssets/Scriptsフォルダに新しくBulletScriptスクリプトを作成し、Bulletゲームオブジェクトに取り付けます。

attackPowerは与えるダメージです。

gameManagerはGameManagerを入れます。

StartメソッドではGameManagerゲームオブジェクトを探してGameManagerスクリプトを取得しgameManagerに入れています。

で弾が登場してから(Startメソッドが呼ばれてから)Destoryメソッドを使って自身のゲームオブジェクトを10秒後に消します。

これは弾が登場してからずっと残っていても無駄で処理も遅くなっていくからです。

OnCollisionEnterメソッドは弾のコライダに他のコライダが衝突した時に呼ばれるメソッドです。

GameManagerのGameOverプロパティがtrueの時はゲームオブジェクトを削除してreturnでその後の処理をしません。

その後衝突した相手のCollision型のcollisionのゲームオブジェクトのタグがPlayerだった時にそのゲームオブジェクトからPlayerControllerスクリプトを取得し、TakeDamegeメソッドを呼び出してダメージを与えます。

その後、相手のRigidbodyコンポーネントを取得し、AddForceメソッドでtransform.forwardで弾の前方を取得し、その方向に力を加えています。

オプションとしてForceMode.VelocityChangeを指定し、質量を無視してRigidbodyに即座に力を加えています。

この処理は弾がプレイヤーに当たった時にプレイヤーを少し力で押す感じにしたい為に入れました。

最後に、何らかのコライダと衝突した場合は弾を消したいのでDestoryメソッドで自身のゲームオブジェクトを消しています。

つまり、弾は何らかのゲームオブジェクトと衝突したら消えますが、衝突しなくても最終的に10秒後には消えます。

これで弾のゲームオブジェクトが出来上がりました。

弾をプレハブにする

弾のゲームオブジェクトが完成しましたが、大砲から弾を継続的に発射する予定です。

なので、あらかじめたくさんの弾をヒエラルキー上に配置して飛ばすよりも、弾のゲームオブジェクトをプレハブにしておき、スクリプトから弾のプレハブをインスタンス化し、大量生産出来るようにした方が簡単です。

Assetsフォルダに新しくPrefabsフォルダを作成し、ヒエラルキーのBulletゲームオブジェクトをドラッグ&ドロップします。

これでAssets/PrefabsフォルダにBulletプレハブが出来ました。

Bulletプレハブを作成する

ヒエラルキーにあるBulletは使わないので削除してください。

定期的に弾を飛ばすスクリプトの作成

飛ばす弾のプレハブが出来たので次は定期的にBulletプレハブからインスタンスを生成し飛ばすスクリプトを作成していきます。

Assets/Scriptsフォルダに新しくFireBulletScriptを作成しヒエラルキーのCannonの子要素のLaunchPositionゲームオブジェクトにドラッグ&ドロップして取り付けます。

gameManagerはGameManagerを入れます。

bulletは先ほど作ったBulletプレハブをインスペクタで設定します。

fireIntervalは次の弾を発射するまでの間隔時間です。

powerは弾に加える力です。

nowTimeは経過時間を入れます。

StartメソッドではGameManagerゲームオブジェクトを探しGameManagerスクリプトを取得しています。

Updateメソッドでは最初にゲームオーバーであればreturnでそれ以降の処理をしません。

nowTimeにTime.deltaTimeを足していき、経過時間を計算します。

経過時間がfireIntervalの時間以上になったらFireメソッドを呼んで弾を飛ばします。

弾を飛ばしたら経過時間を0にします。

FireメソッドではInstantiateメソッドを使ってbulletを自身の位置(LaunchPositionゲームオブジェクトの位置)と回転に設定してインスタンス化しそれをins変数に入れています。
ins変数からGetComponentを使ってRigidbodyを取得し、AddForceメソッドを使ってtransform.forwardでLaunchPositionゲームオブジェクトの前方(青い矢印の方向)に力を加えています。

ForceMode.Forceオプションは質量を利用して継続的に力を加えるモードです。

LaunchPositionゲームオブジェクトのFireBulletScriptのBulletにBulletプレハブを設定します。

LaunchPositionゲームオブジェクトのFireBulletScriptのBulletにBulletプレハブを設定する

これで大砲の機能が出来ました。

大砲をプレハブ化する

大砲の機能が出来ましたがゲームステージにいくつか大砲があることも考えられます。

ヒエラルキー上で大砲をCtrl+Dキーで複製してもいいですが、どうせならプレハブにしておきましょう。

Assets/PrefabsフォルダにCannonゲームオブジェクトをドラッグ&ドロップしてプレハブにします。

Cannonゲームオブジェクトをプレハブにする

今後大砲を追加したい場合はAssets/PrefabsフォルダのCannonプレハブをヒエラルキーやシーンビューにドラッグ&ドロップすることで配置出来ます。

今回は3つの大砲を配置し、以下のようなTransformにしました。

CannonのTransformの設定

またCannonとCannon(2)の子要素のBasePointOfTheBarrelのCannonRotationScriptのRotatableのチェックは外して回転しないようにします。

シーンビューで見ると以下のような位置に配置されています。

大砲を配置した様子をシーンビューで確認する

実行して確認してみる

機能が出来たので実行して確認してみましょう。

上のようになりました。

大砲から定期的に弾が発射されていますね、また右の大砲の砲身はキャラクターの方向を向いて打ってきます。

終わりに

今回は弾を発射する大砲を作成しました。

ゲームっぽくなってきましたね。(^_^)v

次回はプレイヤーキャラクターにジャンプ機能を取り付けます。

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