バーチャル3Dクリエイター神部まゆみです(*^-^*)
この記事はunityでライフ(HP)とダメージ処理を実装してみたメモです。
前回の記事はこちら。
動かしてみたバージョンはunity2022.3.22です。




まぁ特に新しい処理を使ったりはしていないはずだから、最近のunityバージョンなら大抵は動くと思います。
やりたいこと 敵のコライダーに当たったらライフを減らす
リアルにしたければ敵の腕とか銃の弾にコライダーを設定して、攻撃中のコライダーに当たったらライフを減らす…みたいにしたほうが良いんだろうけど。
とりあえず簡単なスフィアみたいなヤツを敵に見立ててゴールまでの道に配置し、当たったら食らうようにします。
とりあえず悲鳴っぽい効果音も鳴らすようにするw
ChatGPT先輩に聞いてみる
とりあえず彼に聞いておけば間違いないだろう…。




unityでTPSゲーム製作をしています。プレイヤーにHPを設定して(初期値100)、敵のコライダーに当たったら効果音を流してライフを減らすスクリプトが欲しいです。
HPの他にも後々攻撃力や防御力などのパラメーターを付与することになると思うので、プレイヤーのパラメーターを設定するスクリプトと、ライフを減らすスクリプトは分けてください。どちらのスクリプトもプレイヤーにアタッチする予定です。


それでは、プレイヤーのパラメーターを管理するスクリプトと、ライフを減らすスクリプトのサンプルコードを提供します。
コード
プレイヤーのパラメーターを管理するスクリプト PlayerStats.cs
using UnityEngine;
public class PlayerStats : MonoBehaviour
{
public int maxHP = 100;
public int currentHP;
public int attackPower = 10;
public int defensePower = 5;
void Start()
{
currentHP = maxHP;
}
public void TakeDamage(int damage)
{
int damageToTake = Mathf.Max(0, damage - defensePower);
currentHP -= damageToTake;
if (currentHP <= 0)
{
currentHP = 0;
Die();
}
}
void Die()
{
Debug.Log("Player is Dead");
// 死亡時の処理をここに記述
}
}
ライフを減らすスクリプト PlayerCollision.cs
using UnityEngine;
public class PlayerCollision : MonoBehaviour
{
public AudioClip damageSound;
private AudioSource audioSource;
private PlayerStats playerStats;
void Start()
{
audioSource = GetComponent<AudioSource>();
playerStats = GetComponent<PlayerStats>();
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Enemy"))
{
playerStats.TakeDamage(10); // ここでダメージ量を調整
if (damageSound != null)
{
audioSource.PlayOneShot(damageSound);
}
}
}
}


以下はスクリプトの説明です。
スクリプトの説明
PlayerStats.cs:
プレイヤーのHP、攻撃力、防御力などのパラメーターを管理します。
TakeDamage メソッドでダメージを計算し、HPを減らします。
HPが0以下になると Die メソッドが呼び出されます。PlayerCollision.cs:
OnTriggerEnter メソッドで敵のコライダーに当たったことを検出します。
敵に当たった際に TakeDamage メソッドを呼び出してダメージを与えます。
ダメージ音を再生します。注意点
プレイヤーオブジェクトには、PlayerStats と PlayerCollision の両方のスクリプトをアタッチします。
プレイヤーオブジェクトには AudioSource コンポーネントもアタッチしておいてください。
敵オブジェクトには “Enemy” というタグを設定しておきます。
このセットアップにより、プレイヤーが敵に衝突した際にHPが減少し、効果音が再生されます。攻撃力や防御力などの他のパラメーターも後から追加して管理できます。
おお…ChatGPTパイセン有能すぎる…。
でもこれだとライフが表示されなそうなので、ライフの表示も別スクリプトでお願いしてみます。
ライフゲージを表示させるようにしてみる
更に聞いてみます。




ライフを表示するようにもしたいのですが、こちらはUI関連の動作として別のスクリプトで管理したほうが良いでしょうか?


はい、ライフの表示はUI関連の動作として別のスクリプトで管理するのが良いでしょう。この方法で、UIの管理とゲームロジックを分離することができます。以下に、ライフを表示するためのスクリプトを示します。
ライフゲージを表示するコードや説明など
まず、UIを設定します。
Unityエディターでの設定:
①Canvas
を作成します。②
Canvas
の子としてText
オブジェクトを作成し、プレイヤーのライフを表示するために配置します。Text
オブジェクトには適切なフォントやサイズを設定します。次に、ライフを表示するスクリプトを作成します。
PlayerUI.cs
using UnityEngine;
using UnityEngine.UI;
public class PlayerUI : MonoBehaviour
{
public Text hpText;
private PlayerStats playerStats;
void Start()
{
playerStats = GetComponent<PlayerStats>();
}
void Update()
{
hpText.text = "HP: " + playerStats.currentHP;
}
}
スクリプトの説明
PlayerUI.cs:
hpText 変数には、ライフを表示する Text オブジェクトを設定します。
Start メソッドで PlayerStats コンポーネントを取得します。
Update メソッドでプレイヤーの現在のHPを表示します。スクリプトのセットアップ
プレイヤーオブジェクトに PlayerUI スクリプトをアタッチします。
Unityエディターでプレイヤーオブジェクトを選択し、PlayerUI スクリプトの HpText フィールドに Text オブジェクトをドラッグ&ドロップします。このセットアップにより、プレイヤーの現在のライフがリアルタイムでUIに表示されます。これで、プレイヤーのパラメーター管理、ダメージ処理、UI表示のそれぞれが分離され、管理しやすくなります。
さっそく実装してみる
とりあえず言われたとおりにやってみます。
しかしChatGPTパイセンを妄信しているとシレッとウソをつかれて落胆することも結構あるので、ダメなら軌道修正しつつやりますw
とりあえずスクリプトをコピペして作っておく
とりあえずスクリプトをコピペしておく。
スクリプトは向かって右上のボタンを押すとコピーできます!


スクリプトをプレイヤーにアタッチする
作ったスクリプト三つをプレイヤーにアタッチして、オーディオソースも追加しておく。
↓プレイヤーのインスペクターはこんな感じです。


Player Collisionにオーディオクリップを読み込むところがあるからオーディオソースは必要ないのかと思ったけど、後でやったらオーディオソースないとダメだった。
効果音を探して設定する
検索したら効果音ラボさんのやつがあったからこれにしよう。




↓ダメージを受けたらこの「キャー!」って感じの音声を流そうw
声優さんは音枝優日さんという方らしいです。
それで死んだらこっちの「ギャアアアアア」っていう音声を流そうw
ああ、でも死んだ場合の処理はまだ作っていないから、とりあえずダメージを受けた場合の「キャー!」だけ設定しておきます。


キャンバスを作って設定する
キャンバスは前回作ったのでこれを使えばいいかな…。
↓前回キャンバスとテキストを追加した時のやつ。
既にあるテキストは「ゴール!」と表示するのに使うので、コピペして使おうかな。
位置はこのあたりかな。スクリプトで表示するので、Lifeっていうテキストは消しておきます。


これでPlayer UIに設定すればOK。
敵を配置する
とりあえずカプセルでいいか…。
彼のコライダーに当たったらダメージを受けるようにしたいので、「トリガーにする(IsTrigger)」にチェックをいれておきます。


敵にEnemyタグをつけておく
これタグを分けておくと、特定のタグが付いたオブジェクトだけ動作させたりできる。
Enemyはなかったので追加した。


プラスボタンを押して名前を入力してsaveすれば追加できます。


これで動いた!
我ながらうるさw ※音が出ます
HPが0になった場合の処理はまだ作ってないです。
ちょっと気になる部分を直す
だいたいこれでも良いのだけど、ちょっと気になる部分があるので直します。
ここまででも良いならこれ以降は読む必要はありません。
敵をすり抜けてしまうのを直す
これはコライダーをトリガーにするとすり抜けてしまうようなので、もう一つコライダーを設置したら解決しました。
トリガーにするコライダーにちゃんと当たるよう、追加するコライダーは半径をちょっと小さめにしました。


敵に張り付いたままだと一度しかダメージ受けないのを直す
なんかずっと無敵時間みたいになっているので、敵に張り付いたままでも2~3秒程度の無敵時間経過後にまたダメージを受けるようにします。
ChatGPTパイセンに聞いたらすぐやってくれましたΣ(゚Д゚)有能すぎる…。




敵に接触したままの状態だと、最初にダメージを受けるだけで以降ダメージを受けることがありません。ダメージを受けてから2秒程度の無敵時間があるのは良いと思いますが、敵にずっと張り付いていても一度しかダメージを受けないのはちょっと不自然です。


敵に接触したままの状態で一定の間隔でダメージを受けるようにするには、無敵時間の設定とダメージを受けるタイミングを管理する機能を追加する必要があります。これを実現するために、ダメージを受けた後に一定時間ダメージを受けないようにするクールダウンタイムを実装します。
以下は、無敵時間の設定を含む修正された PlayerCollision
スクリプトの例です。
無敵時間を考慮して修正した PlayerCollision.cs のコード
PlayerCollision.csのスクリプトを↓に書き換えればOK。
using UnityEngine;
public class PlayerCollision : MonoBehaviour
{
public AudioClip damageSound;
public float invincibilityDuration = 2.0f; // 無敵時間
public int damageAmount = 10; // ダメージ量
private AudioSource audioSource;
private PlayerStats playerStats;
private bool isInvincible = false;
private float invincibilityTimer = 0.0f;
void Start()
{
audioSource = GetComponent<AudioSource>();
playerStats = GetComponent<PlayerStats>();
}
void Update()
{
if (isInvincible)
{
invincibilityTimer -= Time.deltaTime;
if (invincibilityTimer <= 0)
{
isInvincible = false;
}
}
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Enemy"))
{
ApplyDamage();
}
}
void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Enemy"))
{
ApplyDamage();
}
}
private void ApplyDamage()
{
if (!isInvincible)
{
playerStats.TakeDamage(damageAmount);
if (damageSound != null)
{
audioSource.PlayOneShot(damageSound);
}
isInvincible = true;
invincibilityTimer = invincibilityDuration;
}
}
}
スクリプトの説明
・新しい変数:
invincibilityDuration は無敵時間の長さ(秒)です。
damageAmount は受けるダメージの量です。
isInvincible は現在無敵状態かどうかを示します。
invincibilityTimer は無敵状態の残り時間を管理します。・Updateメソッド:
isInvincible が true のときに invincibilityTimer を減らします。タイマーが0以下になると、無敵状態が解除されます。
・OnTriggerEnterおよびOnTriggerStayメソッド:
敵のコライダーに当たったとき、または当たっている間に ApplyDamage メソッドを呼び出します。
・ApplyDamageメソッド:
無敵状態でないときにダメージを適用し、無敵状態に移行します。
このスクリプトにより、プレイヤーが敵に接触し続けている間、一定の間隔でダメージを受けるようになります。また、ダメージを受けた直後に短い無敵時間が設定されるので、過度なダメージを防ぐことができます。
これで無敵時間を指定するパラメーター(Invincibility Duration)が追加されていました。


これで敵に張り付いたままでも、無敵時間経過後にまたダメージ判定がされるようになりました。
おわりに
案外簡単に実装出来て良かった。
まぁ優秀なChatGPT氏のおかげだけど(;^_^A
あとはライフゲージをハートにしてUIを凝ったり、敵を動かしたりすればゲームっぽくなるかな…。
まぁもう少しいじってみます(*^-^*)