Heads up display

The final piece our game needs is a User Interface (UI) to display things like score, a "game over" message, and a restart button.

Create a new scene, and add a CanvasLayer node named HUD. "HUD" stands for "heads-up display", an informational display that appears as an overlay on top of the game view.

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. Under Theme overrides > Fonts click on the empty box and select "New DynamicFont"

../../_images/custom_font1.png
  1. Click on the "DynamicFont" you added, and under Font > FontData, choose "Load" and select the "Xolonium-Regular.ttf" file.

../../_images/custom_font2.png

Set the "Size" property under Settings, 64 works well.

../../_images/custom_font3.png

Once you've done this on the ScoreLabel, you can click the down arrow next to the Font property and choose "Copy", then "Paste" it in the same place on the other two Control nodes.

注釈

Anchors and Margins: Control nodes have a position and size, but they also have anchors and margins. Anchors define the origin - the reference point for the edges of the node. Margins update automatically when you move or resize a control node. They represent the distance from the control node's edges to its anchor.

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

../../_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

Now all mobs will be in the "mobs" group. We can then add the following line to the new_game() function in Main:

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

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

The game's mostly done at this point. In the next and last part, we'll polish it a bit by adding a background, looping music, and some keyboard shortcuts.