ヘッドアップディスプレイ

このゲームに必要な最後の要素は、スコアや"ゲームオーバー"のメッセージ、リスタートボタンなどを表示するユーザーインターフェイス(UI)です。

新しいシーンを作成し、 HUDという名前のCanvasLayerノードを追加します。「HUD」は、ゲームビューの上にオーバーレイとして表示される情報表示である「ヘッドアップディスプレイ」("Heads-up display")の略です。

CanvasLayerノードを使用すると、ゲームの他の部分よりも上のレイヤにUI要素を描画することができるため、表示される情報がプレイヤーやモブなどのゲーム要素によって隠されることがなくなります。

HUDには、次の情報を表示する必要があります:

  • ScoreTimer によって変更されるスコア。

  • 「Game Over」や「Get Ready! (よーい!)」 などのメッセージ

  • ゲームを開始する「スタート」ボタン。

UI要素の基本ノードはコントロールです。UIを作成するには、ラベルボタンの2種類のコントロールノードを使用します。

HUD ノードの子として次を作成します:

  • ScoreLabel という名前のラベル

  • Message という名前のLabel

  • StartButton という名前のボタン

  • MessageTimer という名前のTimer

ScoreLabel をクリックし、インスペクタのTextフィールドに数字を入力します。 Control ノードのデフォルトのフォントは小さく、うまくスケールしません。そこで、ゲームアセットに含まれる 「Xolonium-Regular.ttf」というフォントファイルがあります。 このフォントを使用するには、次のようにしてください:

  1. Theme overrides > Fontsの下で、空欄をクリックして 「新規 DynamicFont」("New DynamicFont") を選択してください

../../_images/custom_font1.png
  1. 追加した "DynamicFont" をクリックし、Font > FontDataで 「読み込み」("Load") を選択して "Xolonium-Regular.ttf" を選択して下さい。

../../_images/custom_font2.png

Settingsの下の"Size"プロパティを64にセットするとうまくいきます。

../../_images/custom_font3.png

ScoreLabelでこれを行ったら、Fontプロパティの横の下矢印をクリックして「コピー」("Copy") を選び、他の二つのControlノードの同じ場所に 「貼り付け」("Paste") することができます。

注釈

**アンカーとマージン**: Controlノードには、位置とサイズがありますが、アンカーとマージンもあります。アンカーは原点 (ノードのエッジの参照点)を定義します。マージンはコントロールノードを移動またはサイズ変更すると自動的に更新されます。マージンはコントロールノードのエッジからアンカーまでの距離を表します。

以下に示すようにノードを配置します。「レイアウト」ボタンをクリックして、コントロールノードのレイアウトを設定します:

../../_images/ui_anchor.png

ノードをドラッグして手動で配置したり、より正確な配置を行うには、次の設定を使用します:

ScoreLabel

  • Layout : "Top Wide"

  • Text : 0

  • Align : "Center"

メッセージ

  • Layout : "HCenter Wide"

  • Text : Dodge the Creeps!

  • Align : "Center"

  • Autowrap : "On"

StartButton

  • Text : Start

  • Layout : "Center Bottom"

  • Margin :

    • Top: -200

    • Bottom: -100

MessageTimer 上で、Wait Time2 に設定し、One Shot プロパティを「On」に設定してください。

次に、このスクリプトを HUD に追加します:

extends CanvasLayer

signal start_game

start_game シグナルは、ボタンが押されたことを Main ノードに通知します。

func show_message(text):
    $Message.text = text
    $Message.show()
    $MessageTimer.start()

この関数は、「Get Ready」などのメッセージを一時的に表示させたい場合に呼び出されます。

func show_game_over():
    show_message("Game Over")
    # Wait until the MessageTimer has counted down.
    yield($MessageTimer, "timeout")

    $Message.text = "Dodge the\nCreeps!"
    $Message.show()
    # Make a one-shot timer and wait for it to finish.
    yield(get_tree().create_timer(1), "timeout")
    $StartButton.show()

この関数は、プレイヤーが負けたときに呼び出されます。 2秒間「Game Over」と表示され、タイトル画面に戻り、少し間を置いて「Start」ボタンが表示されます。

注釈

短い間、一時停止する必要がある場合は、Timerノードを使用する代わりに、SceneTreeの create_timer() 関数を使用します。 これは、上記のコードのように、"Start" ボタンを表示する前に少し時間を置きたい場合など、遅延させるのに非常に役立ちます。

func update_score(score):
    $ScoreLabel.text = str(score)

この関数はスコアが変わるたびに Main によって呼び出されます。

MessageTimertimeout() シグナルと StartButtonpressed() シグナルを接続してから、下記のコードを新しい関数に加えます:

func _on_StartButton_pressed():
    $StartButton.hide()
    emit_signal("start_game")

func _on_MessageTimer_timeout():
    $Message.hide()

HUDをメインに接続する

HUD シーンの作成が完了したら、 Main に戻ります。 Player のシーンと同じように HUD シーンを Main にインスタンス化し、ツリーの一番下に配置します。ツリー全体は次のようになるはずです。何も見落としていないか確認してください:

../../_images/completed_main_scene.png

次に、 HUD 機能を Main のスクリプトに接続します。これには、 Main シーンにいくつかの追加が必要です:

ノードタブで、「シグナルを接続」ウィンドウの 「受信側メソッド」に "new_game" と入力して、HUDの start_game のシグナルをメインノードの new_game() 関数に接続します。スクリプトの func new_game() の横に緑色の接続アイコンが表示されていることを確認してください。

new_game() で、スコア表示を更新し、「Get Ready」メッセージを表示します:

$HUD.update_score(score)
$HUD.show_message("Get Ready")

game_over() では、対応する HUD 関数を呼び出す必要があります:

$HUD.show_game_over()

最後に、これを _on_ScoreTimer_timeout() に追加して、変更されたスコアと同期して表示を維持します:

$HUD.update_score(score)

これでプレイの準備が整いました! [プロジェクトを実行] ボタンをクリックします。メインシーンを選択するように求められますので、 Main.tscn を選択します。

古い「クリープ」を削除する

「ゲームオーバー」までプレイしてから新しいゲームを開始すると、前のゲームの「クリープ」が画面に表示されたままになっています。 それらすべて、新しいゲームの開始時には消したほうがいいでしょう。それには、すべてのモブたちに自身の削除を指示する方法が必要です。これは「グループ」機能を使えば可能です。

Mob シーンでルートノードを選択し、インスペクタの隣にある「ノード」タブをクリックしてください (ノードのシグナルを見つけるのと同じ場所です)。「シグナル」の横にある「グループ」をクリックして、新しいグループ名を入力して「追加」をクリックします。

../../_images/group_tab.png

これですべてのモブが 「mobs」グループに入るようになります。あとは、 Main内の game_over()関数に次の行を追加します。

get_tree().call_group("mobs", "queue_free")

call_group() 関数はグループ内の全てのノードに対して名前付きの関数を呼び出します - この場合は全てのモブに自分自身を削除するように指示しています。

この時点で、ゲームはほぼ完成しています。次と最後のパートでは、背景、ループする音楽、キーボードショートカットを追加して、もう少し磨きをかけます。