多脚戦車から弾を出してみる

 さまよえる蒼い弾丸

珍しく予告通り、弾を出します。

しかし、ただ弾を出すだけでは芸がない。
幸い、前回から使用している↓コレには射撃時モーションが同梱されているので、これを活用したい。

assetstore.unity.com

用意するモノ

まずは前回参照。今回はこれの変更である。

尚、使用するUnityは2018.2.11f1にした。
常に最新を使うスタイル。

himatsubushi-industry.hatenablog.com

尚、今回は以下のサイトを参考にした。

https://uni.gas.mixh.jp/unity/prefab.html

アパム!弾もってこい!アパーム!

弾モデルをPrefab化してみる

弾を出すには、当然だが弾のモデルを用意せねばならない。
しかし弾をイチから作るのも面倒だし、Sphereあたりでお茶を濁すのも、画の統一感を著しく欠くので頂けない。

幸いにして、このモデルには弾がちゃんと用意されている。
薬莢とセットであるが。

弾頭だけ用意するのは難易度が上がるし、薬莢付いたまま飛ばしたところでまともに見えないし、気にするのはミリオタぐらいだろうという舐めた判断の元、薬莢付きで飛ばすことにした。

まず、Hierarchyの"Player/ASC17/root/baseBone/base"を選択し"CTRL+D"でGameObjectを複製。
マテリアルの設定その他一切合切をそのまま流用する為である。
名前は"Bullet"とでもしておこう。

次に"Bullet"のMesh Filerを"sh1"に置き換え、"Rigidbody"と"Capsule Collider"を追加し、適当にパラメータを与えた後、"Bullet"をAssets上にDnDすればPrefab化完了である。
"Rigidbody"の"Use Gravity"だけは忘れず指定しておこう。

尚、Hierarchy上の"Bullet"は必要ないので削除する。

弾を動的生成してみる

 あとは、ボタンを押したタイミングで"Instantiate"メソッドを呼び出し、"Bullet"の実体(以下、"Bullets"とする)を動的生成すれば良いだけだが、問題は何処に生成してどう飛ばすかである。

というわけで、前述のサイトを参考にして発射点"Mazzle"を空のGameObjectとして生成し、砲身の先端に配置。

尚、発射元である多脚戦車の位置に追従せねばならんので、Hierarchyの"Player/ASC17/root/baseBone/headBonde/head/gun001"下に"Mazzle"を配置する。

しかし、弾の座標系的に弾頭がX軸方向に向いているため、そのままでは弾が横向きに飛んでしまう。

事前に"Mazzle"をグローバル座標系に置いて、Y軸を270度転回させておこう。

"Bullets"生成時に"Mazzle"の平行移動量と転回量を反映すれば、希望の位置に弾が現れることになる。

当然、これだけでは弾は地面に落ちるだけである。
"Bullets"に力を加え、飛ばす必要がある。

やり方はRoll-a-ballの時と同じく、"Bullets"のRigidbodyにAddForceメソッドで文字通り力を加えるのだが、中途半端な力では小便以下の飛距離となるのでガツンとデカい値を入れておこう。

himatsubushi-industry.hatenablog.com

また、力を加えるベクトルについて、"Mazzle"の座標軸的にX軸が弾の進行方向であるため、"forward"プロパティでベクトルを求めるとZ軸方向、すなわち砲身から見て左向きに弾が飛ぶので、"right"プロパティを使用しよう。

狙い撃つぜ!(ネライウツゼ!ネライウツゼ!)

Animation Controllerを複製してみる

さて、これで弾は飛ぶようになったので、Animationの割り付けに移ろう。

アセット同梱のAnimation Controllerは各Animationが排他、すなわちいずれかのAnimationが一つだけしか再生されない。
そのため、弾を撃っている間は歩行モーションが使えないため、静止しなければならない...ではあまりにもお粗末である。

幸いUnityにはAnimationを階層化して、上書きしたり追加したりする機能が備わっている。

docs.unity3d.com

尚、これを行うためには、Animation Controllerをいじる必要があるが、オリジナルの状態は残しておきたいので、"CTRL+D"で複製を作成することとした。
名前は"ACS_Anim_Custom"である(ジムスナイパーカスタム的な)。

弾を撃つアニメーションを別階層に作ってみる

さて、"ACS_Anim_Custom"を選択した状態でAnimatorでAnimation Controllerを編集しよう。

前述リンク先記述に従い"Addtive Layer"を追加し、Blendingを"Addtive"に設定する。
Weightは"1"を指定しよう。

1+1で200だ!10倍だぞ10倍。

弾を撃つアニメーション遷移を構築してみる

次にAnimator右側の方眼図がステートマシン図になるので、これにStateを生成して配置し、相互に遷移線で結ぶ。

今回は何もしない"ACS_NoAction"と、弾を撃つ"ACS_Attack_OneShot"をステートマシン図に置き、Entryから"ACS_NoAction"への遷移と、"ACS_NoAction"と"ACS_Attack_OneShot"間の相互遷移を設けた。

docs.unity3d.com

で、各stateの設定を行うことになるのだが、"ACS_NoAction"のMotionは何も指定せんでもええやろと"none"のままにすると、ループもしてくれない。

というわけで、空のAnimation”ACS_NoAction.anim”を生成し、InspectorでLoop Timeのチェックを入れ、これを"ACS_NoAction"のMotionに割り当てる。

一方、"ACS_Attack_OneShot"は"ACS_Attack.anim"を使用することになるが、こちらはループされては困るので、"ACS_Attack.anim"を"CTRL+D"で複製。
InspectorでLoop Timeのチェックを外し、これを"ACS_Attack_OneShot"のMotionに割り当てる。

名前は"ACS_Attack_OneShot.anim"としておこう。

stateを配置し、それぞれを遷移線で結び終えたならば、次は各stateを結ぶ遷移線の設定を行う。
各遷移線を選択し、Inspector上で遷移時のAnimation切り替えタイミングや、過渡的なAnimationのブレンドの調整を行ったりする。

"ACS_Attack_OneShot"への遷移はボタン押下で直ちに反応させたいので、Has Exit Timeのチェックを外す。

一方、"ACS_NoAction"への遷移は最後まで装填モーションを出し切りたいのでHas Exit Timeのチェックは入れ、Exit Timeは"1"を指定する。

Trandition DurationとTrandition Offsetは今回"0"で良い。
混ざり合うAnimationがないからね。

弾を撃つアニメーションをボタンで開始してみる

最後に、ボタン押下をトリガに、"ACS_Attack_OneShot"へ遷移を行う仕組みを設ける。
AnimatorのParameterタブを選択し、リスト右上の+アイコンからTriggerを選択し、新規にパラメータを生成。"ACS_Attack_OneShot"としておこう。

再び、"ACS_Attack_OneShot"への遷移線を選択し、InspectorのConditionsに"ACS_Attack_OneShot"を追加。これで下準備は完了である。

Hierarchy上の”Player/ACS17”を選択し、"Animator"のcontrollerを"ACS_Anim_Custom"に置き換え、Scriptから"ACS_Attack_OneShot"を"true"にすれば射撃モーションが開始する。

今回のソース

設定編集は色々やったがコード上の変更箇所は少ないので、差分箇所だけ紹介する。

        public GameObject Bullet;
        public Transform Muzzle;
        public float speed = 1000.0f;

発射する弾と発射位置、弾速は設定変更可能とするため、前述の情報参考元と同じくクラスメンバとしてPublic定義し、Inspectorから編集可能としている。

実行時にはそれぞれ割り当てを行う必要があるので注意しよう。

"Bullet”は、ProjetctよりPrefab化した"Bullet"を、"Muzzle"は、Hierarchy上の空GameObjectの"Muzzle"を指定する。

            if (controls[5].WasPressed)
            {
                GameObject Bullets = Instantiate(Bullet) as GameObject;
                Bullets.transform.position = Muzzle.position;
                Bullets.transform.rotation = Muzzle.rotation;
                Vector3 force = Muzzle.right * speed;
                Bullets.GetComponent<Rigidbody>().AddForce(force);
                animator.SetBool("ACS_Attack_OneShot", true);
            }

弾の生成と射撃モーションの開始は、ボタン押下時の処理にこれだけ記述すれば良い。

ステップ数にしてたった9ステップの改造結果がこちらである。

vimeo.com

ふむ、なかなかに良いではないか(自画自賛)。

尚、発射した弾が残り続け、リソースを食いつぶすのは見なかったことにしよう。

次回予告

弾が出るなら的に当てたいし、的に当てれば爆発もさせたい。発砲炎も出したい。
というわけで、パーティクルに手を出したいと思う。