前回までの作業で弾を発射したときの処理が一応できました。しかし現状ではいくらでも弾を撃てるので撃ちっぱなしでも良いということになり、FPSとしては面白くありません。
そこでここでは弾薬の数に制限を設けて「一定時間が経過するたびに弾薬が全回復する」という処理を実装していきましょう。
弾薬ゲージ等のUIの作り方
まず、はじめに
- 弾薬ゲージ
- 弾薬回復までの残り時間を示すゲージ
の2つのUIを用意しておきます。シーンに新しいキャンバスを作り、名前を「Ammo Canvas」にしてその子としてゲージを作っていきましょう。
ゲージの作り方
ゲージの作り方は主に
- スライダーを使う方法
- 画像を重ねて配置し、上の画像だけ変化させる方法
の2通りがあるのですが、今回は一番簡単な2番目の方法でゲージを作ります。
最初にゲージの下地の画像を用意したいので、キャンバスの子として新しいImageを作って下の画像のように設定してください。
できたら、次はゲージ本体を作ります。今作った下地の子として新しいImageを作り、下の画像のように設定しましょう。
ゲージ本体の方はピボットを(0, 0.5)にするのをお忘れなく。そうしないとゲージを伸縮させたときに変な動き方になってしまいます。
さてそうしたら1つ目のゲージを複製し、それぞれのゲージの位置や幅・色などを調整して下のお手本のように配置してください。
あと、弾薬ゲージの左にある弾薬アイコンには下の素材を使ってください。
弾発射処理のC#スクリプトの変更
では次に、第3回で作った弾の発射処理のC#スクリプトに色々と変更を施していきます。まずは変更後のC#スクリプトを掲載しますので、「★変更その2」と書かれた部分を参考にしてスクリプトを書き換えてみてください(※無関係な部分は省略してあります。変更その1のときのコメントも残っているので間違えないように注意)。
using System.Collections; using UnityEngine; using UnityEngine.UI; // ★変更その2 public class FpsGunControler : MonoBehaviour { // 省略 // ★変更その1 [SerializeField] ParticleSystem muzzleFlashParticle = null; [SerializeField] GameObject bulletHitEffectPrefab = null; // ★変更その2 [SerializeField] float resupplyInterval = 10; [SerializeField] Image ammoGauge = null; [SerializeField] Image resupplyGauge = null; bool fireTimerIsActive = false; RaycastHit hit; WaitForSeconds fireIntervalWait; // ★変更その2 int currentAmmo = 0; bool resupplyTimerIsActive = false; // ★変更その2 public int CurrentAmmo { set { currentAmmo = Mathf.Clamp(value, 0, maxAmmo); float scaleX = currentAmmo / (float)maxAmmo; ammoGauge.rectTransform.localScale = new Vector3(scaleX, 1, 1); } get { return currentAmmo; } } void Start() { fireIntervalWait = new WaitForSeconds(fireInterval); // WaitForSecondsをキャッシュしておく(高速化) // ★変更その2 CurrentAmmo = maxAmmo; } void Update() { if (Input.GetButton("Fire1")) { Fire(); } // ★変更その2 if (!resupplyTimerIsActive) { StartCoroutine(nameof(ResupplyTimer)); } } // 弾の発射処理 void Fire() { // ★変更その2 if (fireTimerIsActive || CurrentAmmo <= 0) { return; } // ★変更その1 muzzleFlashParticle.Play(); if (Physics.Raycast(bulletSpawn.position, bulletSpawn.forward, out hit, maxRange, hitLayers, QueryTriggerInteraction.Ignore)) { BulletHit(); } StartCoroutine(nameof(FireTimer)); // ★変更その2 CurrentAmmo--; } // 省略 // ★変更その2。一定時間経過ごとに弾薬を全回復するタイマー IEnumerator ResupplyTimer() { resupplyTimerIsActive = true; float timer = 0; while (timer < resupplyInterval) { resupplyGauge.rectTransform.localScale = new Vector3(timer / resupplyInterval, 1, 1); timer += Time.deltaTime; yield return null; } CurrentAmmo = maxAmmo; resupplyTimerIsActive = false; } // ★変更その2。弾薬回復タイマーをキャンセルする処理 public void StopResupplyTimer() { StopCoroutine(nameof(ResupplyTimer)); resupplyTimerIsActive = false; } }
変更部分の解説
今回の変更では、
- 弾薬の数を制限し、残弾数が0の時は射撃できないようにする
- 弾を撃ったら残弾数を1つ減らす
- 残弾数を変更したときに、それが弾薬ゲージに反映されるようにする
- 弾薬を全回復するタイマーを作動させる
といった処理を盛り込みました。特に難しいことはやっていないので、変更部分のスクリプトをよく読んで具体的にどんな処理になっているかを確認しておいてください。
ちなみに弾薬回復タイマーをキャンセルする処理は、まだ使いませんが後々敵キャラに攻撃されたときの処理に使うことになるでしょう。
テストプレイして動作を確認しよう
変更できたら「FpsGunController」コンポーネントの新しい設定欄にゲージ本体のImageを登録してテストプレイしてみましょう。下のGIFのようにゲージがきちんと動作していればOKです。
次のページ→敵キャラのアニメーションの設定方法