コードを使用してゲームのUIを制御する

イントロ

このチュートリアルでは、キャラクターをライフバーに接続し、その健康状態の表示をライブバーで行います。

../../_images/lifebar_tutorial_final_result.gif

ここで作成するのは、キャラクタがヒットしたときにバーとカウンターをアニメーションするものです。プレイヤーが死ぬとと消えます。

次の方法について学習します:

  • シグナルを使ってキャラクターをGUIに 接続 する方法
  • GDscriptを使用してGUIを 制御する 方法
  • Tweenノードを持つライフ バーをアニメーション化する方法

代わりにインターフェイスを設定する方法を学びたい場合は、ステップバイステップのUIチュートリアルを参照してください:

  • メインメニュー画面の作成
  • ゲーム ユーザーインターフェイスの作成

ゲームをコーディングするときには、最初にゲームプレイのコアとなる部分、つまり動作のメカニズム、プレイヤーの入力、勝敗条件を構築しなければなりません。その後にUIを設計します。可能であれば、プロジェクトを構成するすべての要素を別々にしておきます。各キャラクタは、独自のスクリプトを持つ独自のシーンに存在する必要があり、UI要素も同様です。これにより、バグを防ぎ、プロジェクトを管理しやすくし、さまざまなチームメンバーがゲームのさまざまな部分で作業できるようになります。

中核となるゲームプレイとUIの準備ができたら、何らかの方法でそれらを接続する必要があります。この例では、一定の時間間隔でプレイヤーを攻撃する敵がいます。プレイヤーがダメージを受けたときにライフバーが更新されるようにします。

これを行うには、 シグナル を使用します。

注釈

シグナルは、ObserverパターンのGodotバージョンです。メッセージを送信することができます。ノードはシグナルを 発信 して、情報を受信する別のオブジェクトに接続できます。これは、ユーザーインターフェイスと実績のあるシステムで多用される強力なツールです。ただし、それらを全ての場所で使用する必要はありません。 2つのノードを接続すると、ノード間のカップリングが追加されます。接続が多いと、その管理が難しくなります。詳細については、GDquestの signals video tutorial <https://youtu.be/l0BkQxF7X3E> _をご覧ください。

スタートプロジェクトをダウンロードして参照する

Godotプロジェクトをダウンロード(ui_code_life_bar.zip)してください。チュートリアルに必要なすべての素材やスクリプトが入っています。zipアーカイブを解凍して、2つのフォルダ startend を取得します。

Godotに start プロジェクトを読み込みます。 ファイルシステム ドックで、LevelMockup.tscnをダブルクリックして開きます。 2人のキャラクターが向かい合っているRPGゲームのモックアップです。ピンク色の敵は、死ぬまで一定の時間間隔で緑色の正方形を攻撃し、ダメージを与えます。ゲームを試してみてください: 基本的な戦闘の仕組みはすでに機能しています。ですが、キャラクターはライフバーに接続されていないため、GUI は何もしません。

注釈

これは、ゲームのコーディング方法の典型です。最初にコアゲームプレイを実装し、プレイヤーの死を処理してから、インターフェイスを追加します。それは、UIがゲーム内で起こっていることに耳を傾けているからです。ゲームプレイのプロトタイプを作成してテストする前にUIを設計すると、うまく機能しない可能性があり、そうなると最初から作成し直す必要がある場合があります。

シーンには、背景スプライト、GUI、および2つの文字が含まれています。

../../_images/lifebar_tutorial_life_bar_step_tut_LevelMockup_scene_tree.png

子を表示するように設定されたGUIシーンを含むシーンツリー

GUIシーンは、ゲームのすべてのグラフィカルユーザーインターフェイス(GUI)をカプセル化します。シーン内に存在するノードへのパスを取得するベアボーンスクリプトが付属しています:

onready var number_label = $Bars/LifeBar/Count/Background/Number
onready var bar = $Bars/LifeBar/TextureProgress
onready var tween = $Tween
public class Gui : MarginContainer
{
    private Tween _tween;
    private Label _numberLabel;
    private TextureProgress _bar;

    public override void _Ready()
    {
        // C# doesn't have an onready feature, this works just the same.
        _bar = (TextureProgress) GetNode("Bars/LifeBar/TextureProgress");
        _tween = (Tween) GetNode("Tween");
        _numberLabel = (Label) GetNode("Bars/LifeBar/Count/Background/Number");
    }
}
  • number_label は、残り体力を数値として表示します。 これは Label ノードです
  • bar はライフバーそのものです。 これは TextureProgress ノードです
  • tween は、他の任意のノードから任意の値またはメソッドをアニメートおよび制御できるコンポーネントスタイルのノードです

注釈

このプロジェクトは、ゲームジャムや小さなゲームに適したシンプルな構造を使用しています。

プロジェクトのルートの res :// フォルダに LevelMockup があります。これがメインのゲームシーンであり、ここで作業します。ゲームを構成するすべてのコンポーネントは、 scenes/ フォルダにあります。 assets/ フォルダには、ゲームのスプライトとHPカウンタのフォントが含まれています。 scripts/ フォルダには、敵のスクリプト、プレイヤーのスクリプト、GUIコントローラのスクリプトがあります。

シーンツリーのノードの右側にあるシーン編集アイコンをクリックして、エディタでシーンを開きます。 「LifeBar」と「EnergyBar」はそれ自体サブシーンです。

../../_images/lifebar_tutorial_Player_with_editable_children_on.png

プレーヤシーンがその子を表示するように設定されたシーンツリー

プレイヤーのmax_healthを使用してライフバーをセットアップする

プレイヤーの現在の状態を何らかの方法でGUIに伝え、ライフバーのテクスチャを更新し、残りの体力を画面左上のHPカウンターに表示する必要があります。そのために、プレイヤーがダメージを受けるたびに、プレイヤーの体力をGUIに送信します。GUIは、この値で Lifebar ノードと Number ノードを更新します。

ここで数字を表示することもできますが、正しい比率で更新するには、バーのmax_valueを初期化する必要があります。最初のステップは、 GUI に緑のキャラクタの max_health を伝えることです。

ちなみに

バーの TextureProgress では、デフォルトで max_value100 になっています。 キャラクターの体力を数字で表示する必要がない場合は、その max_value プロパティを変更する必要はありません。代わりに、 Player から GUI にパーセンテージを送信します: health / max_health * 100

../../_images/lifebar_tutorial_TextureProgress_default_max_value.png

シーンドックの GUI の右側にあるスクリプトアイコンをクリックしてスクリプトを開きます。 _ready 関数では、プレイヤーの max_health を新しい変数に格納し、それを使って barmax_value を設定します:

func _ready():
    var player_max_health = $"../Characters/Player".max_health
    bar.max_value = player_max_health
public override void _Ready()
{
    // Add this below _bar, _tween, and _numberLabel.
    var player = (Player) GetNode("../Characters/Player");
    _bar.MaxValue = player.MaxHealth;
}

内訳を見てみましょう。 $"../Characters/Player" は、シーンツリーの1つ上のノードに移動し、そこから Characters/Player ノードを取得する短縮形です。それは私達にノードへのアクセスを与えます。ステートメントの2番目の部分、 .max_health は、Playerノード上の max_health にアクセスします。

2行目は、この値を bar.max_value に割り当てます。 2行を1つにまとめることもできますが、チュートリアルの後半では player_max_health をもう一度使用する必要があります。

Player.gd はゲーム開始時に healthmax_health に設定するので、これで作業できます。なぜ max_health を使用しているのですか? 2つの理由があります:

health が常に max_health と等しいという保証はありません。体力が回復しないで次のステージに進むようなゲームでは、プレイヤーがすでに体力をいくらか失った状態が読み込まれる可能性があります。

注釈

ゲームでシーンを開くと、Godotはシーン・ドック内の順序に従って、上から下にノードを1つずつ作成します。 GUIPlayer は同じノードブランチの一部ではありません。相互にアクセスするときに両方が存在することを確認するには、 _ready 関数を使用する必要があります。Godotは、すべてのノードをロードした直後、ゲームを開始する前に _ready を呼び出します。すべてを設定してゲームセッションを準備するのに最適な機能です。_readyの詳細は:doc:`scripting_continued`を参照して下さい。

プレイヤーがヒットしたときにシグナルで体力を更新する

GUIは Player から health 値の更新を受け取る準備ができています。これを実現するために、シグナルを使用します。

注釈

enter_treeexit_tree のように、すべてのノードがそれぞれ作成されたり破棄されたりしたときに出力する便利な組み込みシグナルがたくさんあります。 signal キーワードを使用して独自のものを作成することもできます。 Player ノードには、作成した2つのシグナル diedhealth_changed が表示されます。

_process 関数で Player ノードを直接取得し、体力値を確認してみませんか?この方法でノードにアクセスすると、ノード間に緊密な結合が作成されます。これは控えめにやればうまくいくかもしれません。しかし、ゲームが大きくなると、より多くの接続が可能になりますが、この方法でノードを取得して行くと、すぐに複雑になってしまいます。問題はそれだけではありません: _process 関数で常に他のノードの状態変化を確認する必要があります。このチェックは(60FPSのゲームなら)1秒間に60回行われ、コードの実行順序によってゲームが中断される可能性があります。

特定のフレームで、更新「前」に別のノードのプロパティを参照すると、最後のフレームから値が取得されます。これは、修正が難しい不明瞭なバグにつながります。一方、信号は変化が起こった直後に発せられます。新しい情報を 確実 に入手できます。また、変更が行われた「直後」に、接続されたノードの状態を更新します。

注釈

Observerパターンは、シグナルの派生元であるにもかかわらず、ノードのブランチ間に結合を追加します。しかし、一般的には、2つの異なるクラス間で通信するためにノードに直接アクセスするよりも軽量で安全です。親ノードが子から値を取得することは問題ありません。しかし、2つの別々のブランチを使って作業している場合には、シグナルを優先する必要があります。Observerパターンの詳細については、Game Programming Patternsの`Observer pattern <http://gameprogrammingpatterns.com/observer.html>`_を参照してください。full bookはオンラインで無料で入手できます。

これを念頭に置いて、 GUIPlayer に接続しましょう。まずシーンドックの Player ノードをクリックして選択します。インスペクタに移動し、「ノード」タブをクリックします。これは、選択したノードをリッスン(シグナルを受信)するためにノードを接続する場所です。

最初のセクションでは、 Player.gd で定義されているカスタムシグナルを一覧表示します:

  • キャラクターが死んだときに died が出力されます。 そのシグナルは、すぐにUIを非表示にするために使用します。
  • health_changed は、キャラクタがヒットしたときに放出されます。
../../_images/lifebar_tutorial_health_changed_signal.png

「health_changed」シグナルに接続しています

health_changed を選択し、右下隅の「接続」ボタンをクリックして、「シグナルの接続」ウィンドウを開きます。左側で、この信号をリッスンするノードを選択できます。 GUI ノードを選択します。画面の右側では、オプションの値を信号でパックできます。それについては、すでに `` Player.gd``で処理しました。通常は、このウィンドウを使用して引数を追加しすぎないようにすることをお勧めします。これらの引数は、コードから実行するよりも不便です。

../../_images/lifebar_tutorial_connect_signal_window_health_changed.png

GUIノードが選択された「Connect Signal」ウィンドウ

ちなみに

必要に応じて、コードからノードを接続できます。ただし、エディタから実行することには、次の2つの利点があります:

  1. Godotは接続されたスクリプトで新しいコールバック関数を書くことができます
  2. シーンドックで信号を放出するノードの横にエミッタアイコンが表示されます

ウィンドウの下部に、選択したノードへのパスが表示されます。"Method in Node"と呼ばれる 2 行目に注目して下さい。これは、シグナルが出力されるときに呼び出される GUI ノード上のメソッドです。このメソッドは、シグナルと共に送信された値を受け取り、それらを処理できるようにします。右側を見ると、デフォルトで「関数を作成」ラジオボタンがオンになっています。ウィンドウの下部にある接続ボタンをクリックします。Godot は GUI ノード内にメソッドを作成します。スクリプトエディタが開き、新しい _on_Player_health_changed 関数内にカーソルが置かれます。

注釈

エディタからノードを接続すると、Godotは _on_EmitterName_signal_name のパターンでメソッド名を生成します。既にメソッドを作成している場合は、「関数を作成」オプションを選択するとメソッドが保持されます。この名前は任意の名前に置き換えることができます。

../../_images/lifebar_tutorial_godot_generates_signal_callback.png

Godotがコールバック・メソッドを作成し、呼び出します

関数名の後の括弧内に、 player_health 引数を追加します。プレイヤーが health_changed シグナルを発信すると、現在の health を一緒に送信します。コードは次のようになります。

func _on_Player_health_changed(player_health):
    pass
public void OnPlayerHealthChanged(int playerHealth)
{
}

注釈

エンジンはPascalCaseをsnake_caseに変換しません。C#の例では、メソッド名にPascalCaseを使用し、メソッドパラメータにcamelCaseを使用します。これは公式のC#命名に従います 。 `C#命名規則 <https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions> `_

../../_images/lifebar_tutorial_player_gd_emits_health_changed_code.png

Player.gdでは、Playerがhealth_changedシグナルを放出すると、その体力値も送信します

_on_Player_health_changed 内で、 update_health と呼ばれる2番目の関数を呼び出して、 player_health 変数を渡します。

注釈

`LifeBar`と`Number`の体力値を直接更新できます。 代わりにこの方法を使用する理由は2つあります:

  1. この名前は、プレイヤーがダメージを受けたときに GUI の体力(health)カウントを更新することを、将来の自分自身やチームメイトのために明確にします
  2. この方法は少し後で再利用します

_on_Player_health_changed の下に新しい update_health メソッドを作成します。唯一の引数としてnew_valueを取ります:

func update_health(new_value):
    pass
public void UpdateHealth(int health)
{
}

このメソッドは以下を行う必要があります:

  • Number ノードの text を文字列に変換された new_value に設定します
  • TextureProgressvaluenew_value に設定します
func update_health(new_value):
    number_label.text = str(new_value)
    bar.value = new_value
public void UpdateHealth(int health)
{
    _numberLabel.Text = health.ToString();
    _bar.Value = health;
}

ちなみに

str は、ほぼすべての値をテキストに変換する組み込み関数です。 Numbertext プロパティには文字列が必要なので、それを new_value に直接割り当てることはできません

Also call update_health at the end of the _ready function to initialize the Number node's text with the right value at the start of the game. Press F5 to test the game: the life bar updates with every attack!

../../_images/lifebar_tutorial_LifeBar_health_update_no_anim.gif

Playerがヒットすると、NumberノードとTextureProgressの両方が更新されます

Tweenノードを使用した、自機損失のアニメーション

このインターフェイスは機能していますが、いくつかのアニメーションを使用することができます。これは、プロパティをアニメーション化するために不可欠なツールである Tween ノードを導入する良い機会です。 Tween は、一定の期間にわたって開始状態から終了状態まで、必要なものをアニメーション化します。たとえば、キャラクタがダメージを受けたときに、 TextureProgress の体力(health)を現在のレベルから Player の新しい health にアニメートできます。

GUI シーンには、 tween 変数に格納されている Tween 子ノードが既に含まれています。それでは、それを使用してみましょう。 update_health にいくつかの変更を加える必要があります。

Tween ノードの interpolate_property メソッドを使用します。引数は7つあります:

  1. アニメーションするプロパティを所有するノードへの参照
  2. 文字列としてのプロパティの識別子
  3. 開始値
  4. 終了値
  5. アニメーションの継続時間(秒)
  6. トランジションのタイプ
  7. 方程式と組み合わせて使用するイージング。

最後の 2 つの引数を組み合わせると、イージング方程式に対応します。これにより、始点から終点まで間に値がどのように変化するかを制御します。

GUI ノードの横にあるスクリプト・アイコンをクリックして再度開きます。 Number ノード自体を更新するにはテキストが必要で、 Bar には浮動小数点または整数が必要です。 interpolate_property を使用して数値をアニメーションすることはできますが、テキストを直接アニメーションさせることはできません。これを使用して、 animated_health という名前の新しい GUI変数 をアニメーション化します。

スクリプトの先頭で、新しい変数を定義し、 animated_health という名前を付け、値を0に設定します。 update_health メソッドに戻り、その内容をクリアします。 animated_health 値をアニメートします。 Tween ノードの interpolate_property メソッドを呼び出します:

func update_health(new_value):
    tween.interpolate_property(self, "animated_health", animated_health, new_value, 0.6, Tween.TRANS_LINEAR, Tween.EASE_IN)
// Add this to the top of your class.
private float _animatedHealth = 0;

public void UpdateHealth(int health)
{
    _tween.InterpolateProperty(this, "_animatedHealth", _animatedHealth, health, 0.6f, Tween.TransitionType.Linear,
        Tween.EaseType.In);
}

呼出を中断しましょう:

tween.interpolate_property(self, "animated_health", ...

animated_healthself 、つまり GUI ノードをターゲットにします。 Tweeninterpolation_property は、プロパティの名前を文字列として取得します。 ですので "animated_health" とします。

... _health", animated_health, new_value, 0.6 ...

開始点は、バーの現在の値です。この部分はまだコーディングする必要がありますが、 animated_health になります。アニメーションの終了点は、 health_changed 後の Playerhealth 、つまり new_value です。 0.6 はアニメーションの秒単位の長さです。

...  0.6, tween.TRANS_LINEAR, Tween.EASE_IN)

最後の2つの引数は、 Tween クラスの定数です。 TRANS_LINEAR は、アニメーションがリニアでなければならないことを意味します。 EASE_IN は線形遷移では何も行いませんが、この最後の引数を指定しないとエラーが発生します。

tween.start()Tween ノードをアクティブにするまでアニメーションは再生されません。ノードがアクティブでない場合は、これを一度だけ実行する必要があります。 最後の行の後にこのコードを追加します:

if not tween.is_active():
    tween.start()
if (!_tween.IsActive())
{
    _tween.Start();
}

注釈

Playerhealth プロパティをアニメートすることはできますが、そうすべきではありません。キャラクターは命中するとすぐにライフを失います。これにより、いつ死亡したかを知りたいなど、状態を管理しやすくなります。アニメーションは常に別のデータ コンテナーまたはノードに格納する必要があります。 tween ノードは、コードで制御されたアニメーションに最適です。自作のアニメーションについては、 AnimationPlayer をご覧ください。

LifeBarにanimated_healthを割り当て

animated_health 変数はアニメーションされますが、実際の Bar ノードと``Number`` ノードは更新されません。これを修正しましょう。

これまでのところ、update_healthメソッドは次のようになります:

func update_health(new_value):
    tween.interpolate_property(self, "animated_health", animated_health, new_value, 0.6, Tween.TRANS_LINEAR, Tween.EASE_IN)
    if not tween.is_active():
        tween.start()
public void UpdateHealth(int health)
{
    _tween.InterpolateProperty(this, "_animatedHealth", _animatedHealth, health, 0.6f, Tween.TransitionType.Linear,
        Tween.EaseType.In);

    if(!_tween.IsActive())
    {
        _tween.Start();
    }
}

この例では、 number_label はテキストを取るため、 _process メソッドを使ってアニメーションする必要があります。前と同じように、 _process 内の Number ノードと TextureProgress ノードを更新します:

func _process(delta):
    number_label.text = str(animated_health)
    bar.value = animated_health
public override void _Process(float delta)
{
    _numberLabel.Text = _animatedHealth.ToString();
    _bar.Value = _animatedHealth;
}

注釈

number_labelbar は、 Number ノードと TextureProgress ノードへの参照を格納する変数です。

ゲームをプレイして、バーがスムーズにアニメーションされるのを確認します。しかし、テキストに小数点以下が表示され、混乱しているように見えます。また、ゲームのスタイルを考慮すると、ライフバーがより途切れやすい方法でアニメーションされるとよいでしょう。

../../_images/lifebar_tutorial_number_animation_messed_up.gif

アニメーションは滑らかですが、番号の表示が乱れています

animated_health を四捨五入することで両方の問題を解決できます。 round_value という名前のローカル変数を使用して、丸められた animated_health を格納します。 それを number_label.textbar.value に割り当てます:

func _process(delta):
    var round_value = round(animated_health)
    number_label.text = str(round_value)
    bar.value = round_value
public override void _Process(float delta)
{
    var roundValue = Mathf.Round(_animatedHealth);
    _numberLabel.Text = roundValue.ToString();
    _bar.Value = roundValue;
}

もう一度ゲームを実行すると、ブロックのようなアニメーションが表示されます。

../../_images/lifebar_tutorial_number_animation_working.gif

animated_healthの四捨五入と文字列へ変換を一緒に行えば、一石二鳥です

ちなみに

プレイヤーがヒットするたびに、 GUI_on_Player_health_changed を呼び出し、その _ on_Player_health_changedupdate_health を呼び出します。これにより、アニメーションが更新され、 _ processnumber_labelbar が更新されます。健康状態が徐々に低下する、アニメーションするライフバーは、単に見た目上のトリックですが、それによってGUIが生き生きと感じられます。もしも Player が3つのダメージを受けた場合、一瞬で発生します。

自機損失時にバーを消す

緑のキャラクタが消滅すると、消滅アニメーションが再生されて消えます。この時点では、インタフェースは表示されません。キャラクターが死んだら、バーも消去しましょう。複数のアニメーションを並行して管理するため、同じ Tween ノードを再利用します。

まず、 GUIPlayerdied シグナルに接続して、いつ死亡したかを知る必要があります。 F1 を押して2Dワークスペースに戻ります。シーンドックで Player ノードを選択し、インスペクタの隣にあるノードタブをクリックします。

died シグナルを見つけて選択し、接続ボタンをクリックします。

../../_images/lifebar_tutorial_player_died_signal_enemy_connected.png

シグナルにはすでに敵が接続しているはずです

シグナルの接続ウィンドウで、 GUI ノードにもう一度接続します。ノードへのパスは ../../GUI 、ノード内のメソッドは _on_Player_died と表示されます。関数作成オプションをオンのままにして、ウィンドウ下部の接続をクリックします。 これにより、スクリプトワークスペースの GUI.gd ファイルに移動します。

../../_images/lifebar_tutorial_player_died_connecting_signal_window.png

これらの値は、シグナルの接続ウィンドウに表示されます

注釈

GUIが新しい情報を必要とするたびに、新しいシグナルを発信します。より多くのコネクションを追加すればするほど、それらを追跡するのは難しくなります。上手く使いましょう。

UI要素でフェードをアニメーションするには、その modulate プロパティを使用する必要があります。 modulate はテクスチャの色を乗算する Color です。

注釈

modulateCanvasItem クラスから取得され、すべての2DノードとUIノードはこれを継承します。ノードの表示/非表示を切り替え、シェーダを割り当て、 modulate で色を使用して修正することができます。

modulate は、赤、緑、青、アルファの4つのチャンネルを持つ Color 値を取ります。最初の3つのチャネルのいずれかを暗くすると、インターフェイスが暗くなります。アルファチャンネルを下げると、インターフェイスがフェードアウトします。

2つのカラー値の間でTweenを行います。1つはアルファが 1 の白、つまり完全に不透明な状態、もう1つはアルファが 0 の完全に透明な白です。 _on_Player_die メソッドの先頭に2つの変数を追加し、それぞれに start_colorend_color という名前を付けます。 Color() コンストラクタを使用して、2つの Color 値を構築します。

func _on_Player_died():
    var start_color = Color(1.0, 1.0, 1.0, 1.0)
    var end_color = Color(1.0, 1.0, 1.0, 0.0)
public void OnPlayerDied()
{
    var startColor = new Color(1.0f, 1.0f, 1.0f);
    var endColor = new Color(1.0f, 1.0f, 1.0f, 0.0f);
}

Color(1.0、1.0、1.0) は白に対応します。 4番目の引数、 start_colorend_color のそれぞれ 1.00.0 は、アルファチャンネルです。

次に、 Tween ノードの interpolate_property メソッドをもう一度呼び出す必要があります:

tween.interpolate_property(self, "modulate", start_color, end_color, 1.0, Tween.TRANS_LINEAR, Tween.EASE_IN)
_tween.InterpolateProperty(this, "modulate", startColor, endColor, 1.0f, Tween.TransitionType.Linear,
  Tween.EaseType.In);

今回は、modulate プロパティを変更し、start_color から end_color にアニメートします。継続時間は1秒で、線形の遷移があります。ここでも、遷移は線形であるため、イージングは重要ではありません。完全な _on_Player_died メソッドは次のとおりです:

func _on_Player_died():
    var start_color = Color(1.0, 1.0, 1.0, 1.0)
    var end_color = Color(1.0, 1.0, 1.0, 0.0)
    tween.interpolate_property(self, "modulate", start_color, end_color, 1.0, Tween.TRANS_LINEAR, Tween.EASE_IN)
public void OnPlayerDied()
{
    var startColor = new Color(1.0f, 1.0f, 1.0f);
    var endColor = new Color(1.0f, 1.0f, 1.0f, 0.0f);

    _tween.InterpolateProperty(this, "modulate", startColor, endColor, 1.0f, Tween.TransitionType.Linear,
        Tween.EaseType.In);
}

以上です。これでゲームをプレイして最終結果を確認できます!

../../_images/lifebar_tutorial_final_result.gif

最終結果。上手くいきましたね!

注釈

まったく同じテクニックを使用して、プレイヤーが毒になったときにバーの色を変更し、体力が低下したときにバーを赤にし、彼らがクリティカルヒットしたときにUIを振動させることができます。 Player からの情報を GUI に転送し、 GUI に処理させます。