マガジンのアイテムを拾うと、銃の残弾数が増えるようにします。
まずマガジンのオブジェクトを新規作成して、コライダーとRigidbodyと新規スクリプトを付けました。
今回は衝突しないようにIs Triggerにチェックをいれて、Use Gravityのチェックを外します。
マガジンのアイテムに付けるスクリプトには、マガジンに入っている弾数を表すメンバ変数があり、マガジンが拾われるたびにこの値が減ります。
弾数が0になったら落ちているマガジンは消えます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AmmoScript : MonoBehaviour
{
public int ammo = 30;
public GunScript sc_gun;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
ammo = sc_gun.PickUpAmmo(ammo);
if (ammo <= 0)
{
Destroy(gameObject); // 弾数が0になったら消滅
}
}
}
}
マガジンのアイテムに含まれる弾数を減らす処理は銃を撃つスクリプトで行います。
// GunScript
public int PickUpAmmo(int ammo)
{
int v = allBullets - magazineSize - remaining; // 補充できる弾数
if (v >= ammo)
{
remaining += ammo;
bulletText.text = currentMagazine + " / " + remaining; // 所持している弾数を表示
sc_ammoText.displayText(ammo.ToString()); // 補充した弾数を表示
return 0;
}
else {
remaining += v;
bulletText.text = currentMagazine + " / " + remaining; // 所持している弾数を表示
if(v > 0) sc_ammoText.displayText(v.ToString()); // 補充した弾数を表示
return ammo - v;
}
}
持てる弾数に制限があるので、アイテムから全ての弾を拾えないこともあります。普通のFPSゲームと同じように、効率よく中途半端な数の弾薬を補充できるようにしています。
PickUpAmmo()という関数を作って、補充できる弾数を計算し、補充できなかった残りの弾は返すようにしています。マガジンのアイテムに入っている弾数よりも、補充できる数のほうが多ければ0が返るので、AmmoScriptによってマガジンは消えます。
補充できる弾数は、今銃についている使用中のマガジン以外に持てる弾数の最大値から実際に今のマガジン以外に残っている弾数を引いて計算しています。今のマガジンに中途半端に弾が残っているときに最大限補充しても、そのままリロードするとさらに補充できます。
落ちているマガジンはプレハブ化するので、GunScriptをインスペクタから直接アタッチできません。なので、スタート時にシーン上に落ちているマガジンのアイテムを探して、一つ一つにスクリプトからアタッチしています。
// シーン上のAmmoオブジェクトにGunScriptをアタッチする。
GameObject[] ammos = GameObject.FindGameObjectsWithTag("Ammo");
if (ammos.Length != 0)
{
foreach (GameObject ammo in ammos)
{
ammo.GetComponent<AmmoScript>().sc_gun = this;
}
}
弾を拾うと、新しく補充した弾数が表示されますが、テキストオブジェクトに付けたスクリプトでそれが徐々に透明になって消えていくようにしました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AmmoTextScript : MonoBehaviour
{
bool displaying = false;
Text text;
Color textColor;
// Start is called before the first frame update
void Start()
{
text = GetComponent<Text>();
textColor = text.color;
}
// Update is called once per frame
void Update()
{
}
public void displayText(string t)
{
text.text = t;
StopCoroutine("FadeAway");
textColor.a = 214f / 255f;
text.color = textColor;
StartCoroutine("FadeAway");
}
private IEnumerator FadeAway() // テキストを徐々に消す
{
yield return new WaitForSeconds(1.5f);
while (textColor.a > 40f/255)
{
textColor.a -= 0.1f;
text.color = textColor;
yield return new WaitForSeconds(0.1f);
}
text.text = "";
textColor.a = 214f / 255f;
text.color = textColor;
}
}
コルーチンの中でテキストのカラーのアルファ値を少し下げる処理を繰り返して、十分透明になったらテキストを空にしてアルファ値を元に戻します。
コルーチンが動いている時に新しいテキストを表示しようとすると、もともと動いているコルーチンが止まってアルファ値が元に戻って新しいテキストでコルーチンが最初から始まります。