Unity UIライフゲージ管理システム ドキュメント
概要
本システムは、ゲーム内のモブ(敵キャラクターなど)のライフ(体力)を視覚的に表現するUI要素(ライフゲージ)を実装するためのものです。
- LifeGauge クラスは、個々のモブの現在のライフ状況をUIで表現し、常にモブの頭上に表示されるように位置を更新します。
- LifeGaugeContainer クラスは、シーン上に存在する複数のライフゲージを管理し、モブの生成や破棄に合わせて動的にライフゲージを追加・削除します。
LifeGauge クラス
概要
- 目的:
個々のモブの体力に応じたライフゲージUIを制御する。モブの体力変化に合わせてゲージの表示(残体力割合:fillAmount)を更新するとともに、モブのワールド座標からスクリーン座標、さらにローカル座標へ変換し、UI上に正しく配置する。
主なメンバ
- フィールド:
Image fillImage
: UIのImageコンポーネント。体力の割合によりfillAmountプロパティが更新される。RectTransform _parentRectTransform
: ライフゲージを配置する親UIのRectTransform。Camera _camera
: ゲージ表示対象のモブを映すカメラ。MobStatus _status
: 対象のモブの状態(体力など)を保持するスクリプト。
- メソッド:
Initialize(RectTransform parentRectTransform, Camera camera, MobStatus status)
- 機能:
渡されたパラメータ(親RectTransform、カメラ、モブの状態)を内部フィールドに保持し、初期状態の配置や表示を行うためにRefresh
を呼び出します。 - ポイント:
ゲージの位置計算や体力更新に必要な参照をここでセットすることで、後続の更新処理(Refresh)に利用します。 Refresh()
- 機能:
毎フレーム実行されるUpdate
内で呼び出され、以下の2点を実施します。
- 体力表示の更新:
_status.Life
(現在の体力)と_status.LifeMax
(最大体力)を用いて、fillImage.fillAmount
にライフゲージの割合を設定。 - ゲージの位置更新:
_camera.WorldToScreenPoint
を用いて、対象モブのワールド座標をスクリーン座標へ変換。RectTransformUtility.ScreenPointToLocalPointInRectangle
で、親UI上のローカル座標に変換。- ライフゲージがモブと重ならないように、上方向にオフセット(例:+80)を加えて配置。
- 補足:
これにより、ライフゲージは常に対象モブの上部に表示され、体力の変化に合わせたアニメーションが実現されます。
- 機能:
- 機能:
- Update メソッド:
毎フレームRefresh
を呼び出すことで、体力および位置の情報を常に最新の状態に保ちます。
LifeGaugeContainer クラス
概要
- 目的:
シーン内の全てのモブに対応するライフゲージを一元管理する。モブが生成される際には新たなゲージを追加し、モブが消滅する際には対応するゲージを破棄することで、UIの整合性を保つ。
主なメンバ
- シングルトン的実装:
public static LifeGaugeContainer Instance
: シーン上に1つのみ存在することを保証するための疑似シングルトン実装。- 注意点:
Awake
内で、既にインスタンスが存在する場合は例外を投げることで、重複インスタンスの生成を防ぎます。
- フィールド:
Camera mainCamera
: ライフゲージ表示対象のモブを映しているカメラ。LifeGauge lifeGaugePrefab
: ライフゲージのPrefab。RectTransform rectTransform
: 自身がアタッチされているUIコンテナのRectTransform。Dictionary<MobStatus, LifeGauge> _statusLifeBarMap
: キーにモブの状態、値に対応するライフゲージを保持するDictionary。複数のモブに対し、それぞれのゲージを管理するために用いられます。
- メソッド:
Awake()
- 機能:
シングルトンパターンの実装およびコンテナ自身のRectTransformの取得を行います。 - ポイント:
他のスクリプトから簡単にアクセスできるように、インスタンスを静的変数に格納しています。
- 機能:
Add(MobStatus status)
- 機能:
指定されたモブの状態に対応するライフゲージをPrefabから生成し、初期化(親RectTransform、メインカメラ、対象モブの状態をセット)して、Dictionaryに登録します。 - 補足:
これにより、モブがシーンに出現する際に、自動的にライフゲージが生成され、適切な位置に表示されます。
- 機能:
Remove(MobStatus status)
- 機能:
指定されたモブの状態に対応するライフゲージを破棄し、Dictionaryから削除します。 - 補足:
モブが消滅する際、もしくは必要なくなったときに呼び出し、メモリリークや不要なUI表示を防ぎます。
- 機能:
システムのワークフロー
- モブの生成時:
ゲーム内でモブ(敵キャラクターなど)が生成されたら、LifeGaugeContainer のAdd
メソッドが呼ばれ、該当するモブのMobStatus
を渡してライフゲージが生成・初期化されます。 - ライフゲージの更新:
各ライフゲージは LifeGauge クラス内のUpdate
メソッドで毎フレームRefresh
を呼び出し、- 体力の割合に基づき
fillImage.fillAmount
を更新。 - 現在のモブのワールド座標を元に、スクリーン上の正しい位置へゲージを移動(モブの上部に表示)。
- 体力の割合に基づき
- モブの破棄時:
モブが消滅した際は、LifeGaugeContainer のRemove
メソッドが呼ばれ、対応するライフゲージオブジェクトが破棄され、Dictionary から削除されます。
実装上のポイントと考慮事項
- 位置変換:
RectTransformUtility.ScreenPointToLocalPointInRectangle
を利用することで、ワールド空間の座標をUIキャンバス上のローカル座標に正確に変換しています。- ※CanvasのRender Modeが「Screen Space – Overlay」の場合、第3引数にnullを渡す点に注意。Screen Space – Cameraの場合は対象のカメラを渡す必要があります。
- シングルトンパターン:
LifeGaugeContainerはシーンに1つのみ存在させるため、インスタンスの重複生成を防ぐ工夫がされています。プロジェクト全体でライフゲージを一元管理できる点が利点です。 - 更新の最適化:
毎フレームUpdate内でRefresh
を呼び出していますが、体力の変化やモブの移動が頻繁な場合、必要に応じて更新頻度の調整やイベント駆動型の実装にすることでパフォーマンス最適化を検討できます。 - 拡張性:
- 今回は体力の変化のみを反映していますが、例えばダメージエフェクト、ライフゲージのアニメーション、色の変化(体力に応じた色変化など)を追加することで、UI表現をさらにリッチにすることが可能です。
- また、MobStatus クラスは外部依存のため、モブの状態がどのように変更されるかに応じた連動処理を追加する必要がある場合は、イベントリスナやObserverパターンを採用するとよいでしょう。
結論
本システムは、モブの体力表示を視覚的かつ動的に実現するための実装例です。
- LifeGauge クラスが各モブに対応したライフゲージを管理し、UI上に正しい位置で表示する。
- LifeGaugeContainer クラスが生成・破棄タイミングでのライフゲージ管理を担い、シーン全体の整合性を維持する。
このコードをベースに、ゲームの仕様に合わせた拡張やパフォーマンス最適化を図ることで、ユーザーにとって分かりやすいUI表現が可能となります。
以上が、提示されたコードに基づく詳細な資料の一例です。各セクションをプロジェクトの状況に応じて調整・拡充し、開発メンバー間で共有することで、より効果的な実装・運用を目指してください。
以下では、提示されたコードにおけるアルゴリズムの仕組みと各工程の詳細について解説します。コードは大きく分けて、個々のモブ(敵キャラクターなど)の状態に連動してライフゲージを更新する部分(LifeGauge クラス)と、各モブに対応するライフゲージの生成・破棄を管理する部分(LifeGaugeContainer クラス)から構成されています。
1. LifeGauge クラスにおけるアルゴリズム
1.1. 体力の割合計算とUI反映
- 目的:
対象のモブが持つ現在の体力と最大体力の値から、ゲージに表示すべき割合(fillAmount)を算出します。 - 処理の流れ:
- 体力割合の計算:
fillImage.fillAmount = _status.Life / _status.LifeMax;
現在の体力(_status.Life)を最大体力(_status.LifeMax)で割ることで、0.0~1.0の値(進捗バーの満たされる割合)を求めます。
- UIへの反映:
- この割合が
Image
コンポーネントのfillAmount
プロパティに設定されることで、UI上で見たときにライフゲージが体力の変化に応じて伸縮します。
- この割合が
1.2. 位置の更新(座標変換アルゴリズム)
- 目的:
モブのワールド座標に対応した位置に、UI上のライフゲージを配置する必要があります。これにより、モブが移動したときにライフゲージも追従できる仕組みが実現されます。 - 処理の流れ:
- ワールド座標からスクリーン座標への変換:
_camera.WorldToScreenPoint(_status.transform.position);
カメラの視点から、モブのワールド空間の位置(_status.transform.position)をスクリーン上の座標に変換します。
- スクリーン座標からUIのローカル座標への変換:
RectTransformUtility.ScreenPointToLocalPointInRectangle(_parentRectTransform, screenPoint, null, out localPoint);
この処理では、変換したスクリーン座標を、親UIのRectTransform
のローカル座標にマッピングします。- 注意点: CanvasのRender Modeが「Screen Space – Overlay」の場合、第3引数に
null
を指定する必要があり、カメラが不要です。Screen Space – Cameraの場合は対象のカメラを渡す必要があります。
- オフセットの適用:
transform.localPosition = localPoint + new Vector2(0, 80);
直接モブの位置に配置すると重なってしまうため、ライフゲージはモブの上部に表示されるように固定値(ここではY方向に80ピクセル)を加えています。
1.3. 更新タイミングについて
- 毎フレーム更新:
Update()
メソッド内でRefresh()
を呼び出す設計になっており、モブの体力や位置が変動するたびに、ゲージの状態をリアルタイムに反映させています。これにより、ゲームプレイ中に体力の減少や移動がUIに即座に反映される仕組みとなっています。
2. LifeGaugeContainer クラスにおけるアルゴリズム
2.1. シングルトンパターンによる一元管理
- 目的:
シーン上にライフゲージ管理用のオブジェクトを一つだけ生成し、どこからでもアクセスできるようにします。これにより、複数のモブのライフゲージの生成・破棄が一元管理され、重複生成や管理の煩雑さを防ぎます。 - 処理の流れ:
- インスタンス生成のチェック:
if (null != _instance) throw new Exception("LifeBarContainer instance already exists.");
すでにインスタンスが存在している場合は例外をスローすることで、シーン上に複数のLifeGaugeContainerが存在しないことを保証します。
- インスタンスの設定:
_instance = this;
クラス内でシングルトンとなる静的変数に、現在のインスタンスを割り当てることで、グローバルにアクセス可能にします。
2.2. ライフゲージの生成と破棄
- Add メソッド:
- 目的:
新たなモブがシーンに登場したときに、そのモブに対応するライフゲージを生成し、初期化します。 - 処理の流れ
- Prefabのインスタンス化:
var lifeGauge = Instantiate(lifeGaugePrefab, transform);
LifeGaugeのPrefabを現在のコンテナオブジェクトの子として生成します。
- 初期化:
lifeGauge.Initialize(rectTransform, mainCamera, status);
生成したライフゲージに、UI親のRectTransform、表示カメラ、対象のモブの状態(MobStatus)を渡し、内部で初期設定(位置、体力割合の更新など)を実施させます。
- 管理用のマッピング登録:
_statusLifeBarMap.Add(status, lifeGauge);
Dictionaryに、モブの状態と生成したライフゲージの参照を登録して、後の更新や破棄に対応します。
- 目的:
- Remove メソッド:
- 目的:
モブがシーンから消滅する際に、対応するライフゲージオブジェクトを破棄し、管理用マッピングから削除します。 - 処理の流れ:
- オブジェクトの破棄:
Destroy(_statusLifeBarMap[status].gameObject);
Dictionaryから取得したライフゲージのGameObjectを破棄します。
- マッピングからの削除:
_statusLifeBarMap.Remove(status);
Dictionary上から、対応するエントリを削除し、メモリリークや不要な参照を防ぎます。
- 目的:
3. アルゴリズム全体の流れと相互連携
3.1. ライフゲージの生成から更新まで
- 生成:
- モブが生成される際に、LifeGaugeContainerの
Add
メソッドが呼ばれ、該当モブの状態が渡されます。 - LifeGaugeのPrefabがインスタンス化され、初期化メソッドによって必要な参照(親UI、カメラ、モブ状態)がセットされます。
- モブが生成される際に、LifeGaugeContainerの
- 更新:
- 各ライフゲージは自らの
Update
メソッドによって毎フレーム呼ばれるRefresh
メソッドで体力割合と位置が再計算され、UIに即時反映されます。 - この更新処理は、モブの体力変化や位置移動がリアルタイムでユーザーに伝わることを保証します。
- 各ライフゲージは自らの
- 破棄:
- 対象のモブが消滅する際に、LifeGaugeContainerの
Remove
メソッドが呼ばれ、該当ライフゲージは削除されます。 - この一連の管理により、シーン上に常に最新かつ正確なライフゲージ表示が維持されます。
- 対象のモブが消滅する際に、LifeGaugeContainerの
3.2. 座標変換とUI表現の工夫
- 座標変換:
アルゴリズムの中核部分は、モブのワールド座標をUIのローカル座標に正確に変換することです。これにより、モブの移動に追随してライフゲージが正しい位置に配置され、ユーザーにとって視認性の高い表示が実現されます。 - オフセット:
モブの重なりを避けるために、一定のオフセット(ここではY軸方向に80ピクセル)を加えることで、ライフゲージがキャラクターの頭上に適切に表示されます。
4. パフォーマンスと拡張性の視点
- 毎フレーム更新の負荷:
現在、各LifeGaugeオブジェクトはUpdate()
で毎フレームRefresh()
を呼んでいます。- ゲーム内のモブ数が多い場合、更新処理が負荷になる可能性があります。
- イベント駆動型の更新(体力の変化や位置更新が起きた場合のみ更新)への切り替えも検討材料です。
- 拡張性:
- 現在の実装は体力の割合と位置更新に特化していますが、エフェクトやアニメーション、色変化などの追加要素を加えることで、より視覚的にリッチな表現に拡張可能です。
- また、ライフゲージの生成タイミングや破棄タイミングを最適化することで、さらなるパフォーマンス向上が期待できます。
まとめ
このアルゴリズムは、ゲーム内の各モブの体力と位置情報をもとに、UI上に正確で動的なライフゲージを表示するための仕組みです。
- LifeGauge は、個別モブの状態と連動して体力バーの表示と位置調整を毎フレーム実行。
- LifeGaugeContainer は、モブのライフゲージ生成・管理を一元化し、シーン全体での整合性を担保します。
これらの処理が組み合わさることで、ユーザーに対して常に最新の情報がわかりやすく伝えられるUIが実現され、直感的なゲーム体験の向上に寄与しています。
ディスカッション
コメント一覧
まだ、コメントがありません