Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

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, click the "Other Node" button 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에 의해 변경되는 점수(Score).

  • "Game Over"나 "Get Ready!"와 같은 메시지

  • 게임을 시작하기 위한 "Start" 버튼.

UI 요소의 기초가 되는 노드는 Control입니다. UI를 만들기 위해, 우리는 두 가지 타입의 Control 노드: LabelButton을 사용할 것입니다.

다음 노드들을 HUD 노드의 자식으로 추가하세요:

  • ScoreLabel로 이름지은 Label.

  • Message로 이름지은 Label.

  • StartButton으로 이름지은 Button.

  • MessageTimer로 이름지은 Timer.

ScoreLabel을 클릭하고 인스펙터(Inspecter)의 Text 필드에 숫자를 입력하세요. Control 노드의 기본 폰트는 작아서 크기 조정이 잘 되지 않습니다. 게임 애셋에는 "Xolonium-Regular.ttf"라는 폰트 파일이 있습니다. 이 폰트를 사용하려면, 각 Control 노드마다 다음과 같이 하세요:

Under "Theme Overrides > Fonts", choose "Load" and select the "Xolonium-Regular.ttf" file.

../../_images/custom_font_load_font.webp

The font size is still too small, increase it to 64 under "Theme Overrides > Font Sizes". Once you've done this with the ScoreLabel, repeat the changes for the Message and StartButton nodes.

../../_images/custom_font_size.webp

참고

Anchors: Control nodes have a position and size, but they also have anchors. Anchors define the origin - the reference point for the edges of the node.

Arrange the nodes as shown below. You can drag the nodes to place them manually, or for more precise placement, use "Anchor Presets".

../../_images/ui_anchor.webp

ScoreLabel

  1. Add the text 0.

  2. Set the "Horizontal Alignment" and "Vertical Alignment" to Center.

  3. Choose the "Anchor Preset" Center Top.

메시지

  1. Add the text Dodge the Creeps!.

  2. Set the "Horizontal Alignment" and "Vertical Alignment" to Center.

  3. Set the "Autowrap Mode" to Word, otherwise the label will stay on one line.

  4. Under "Control - Layout/Transform" set "Size X" to 480 to use the entire width of the screen.

  5. Choose the "Anchor Preset" Center.

StartButton

  1. Add the text Start.

  2. Under "Control - Layout/Transform", set "Size X" to 200 and "Size Y" to 100 to add a little bit more padding between the border and text.

  3. Choose the "Anchor Preset" Center Bottom.

  4. Under "Control - Layout/Transform", set "Position Y" to 580.

MessageTimer에서 Wait Time2로 설정하고 One Shot 속성을 "사용(On)"으로 설정합니다.

이제 HUD에 이 스크립트를 추가하세요:

extends CanvasLayer

# Notifies `Main` node that the button has been pressed
signal start_game

We now want to display a message temporarily, such as "Get Ready", so we add the following code

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

We also need to process what happens when the player loses. The code below will show "Game Over" for 2 seconds, then return to the title screen and, after a brief pause, show the "Start" button.

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

    $Message.text = "Dodge the Creeps!"
    $Message.show()
    # Make a one-shot timer and wait for it to finish.
    await get_tree().create_timer(1.0).timeout
    $StartButton.show()

이 함수는 플레이어가 패배했을 때 호출됩니다. 이 함수는 2초동안 "Game Over"를 보여주고, 타이틀 화면으로 돌아와서, 잠깐 일시정지한 후 "Start" 버튼을 보여줍니다.

참고

잠시 일시 정지를 해야 한다면 타이머 노드를 사용하는 대신 SceneTree의 create_timer() 함수를 사용하는 것이 좋습니다. 이 함수는 "Start" 버튼을 표시하기 전에 잠시 기다려야 하는 위의 코드와 같이 지연을 추가하는 데 매우 유용할 수 있습니다.

Add the code below to HUD to update the score

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

Connect the pressed() signal of StartButton and the timeout() signal of MessageTimer, and add the following code to the new functions:

func _on_start_button_pressed():
    $StartButton.hide()
    start_game.emit()

func _on_message_timer_timeout():
    $Message.hide()

메인에 HUD를 연결하기

이제 HUD 씬 만들기가 끝났으니 저장하고 다시 Main으로 돌아가세요. Player 씬에서 했듯이 HUD 씬을 Main에 인스턴스화하고, 트리의 맨 아래에 배치하세요. 모든 트리는 다음처럼 보여야 하므로, 놓친 것이 없는지 확인해보세요:

../../_images/completed_main_scene.webp

이제 HUD 기능을 Main 스크립트에 연결할 것입니다. 여기에는 Main 씬에 추가적인 것들이 요구됩니다:

In the Node tab, connect the HUD's start_game signal to the new_game() function of the Main node by clicking the "Pick" button in the "Connect a Signal" window and selecting the new_game() method or type "new_game" below "Receiver Method" in the window. Verify that the green connection icon now appears next to func new_game() in the script.

new_game()에서, 점수 화면을 업데이트하고 "Get Ready" 메시지를 보이게 합니다:

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

game_over()에서는, 해당 HUD 함수를 호출해야 합니다:

$HUD.show_game_over()

Finally, add this to _on_score_timer_timeout() to keep the display in sync with the changing score:

$HUD.update_score(score)

경고

Remember to remove the call to new_game() from _ready() if you haven't already, otherwise your game will start automatically.

Now you're ready to play! Click the "Play the Project" button. You will be asked to select a main scene, so choose main.tscn.

오래된 적들 제거하기

"Game Over"까지 플레이한 다음 바로 새 게임을 시작하면 이전 게임의 크립이 화면에 계속 표시될 수 있습니다. 새 게임이 시작될 때 모두 사라지면 더 좋을 것입니다. 우리는 모든 몹에게 스스로 제거하도록 지시할 방법이 필요합니다. "그룹(group)" 기능으로 이 작업을 수행할 수 있습니다.

Mob 씬에서 루트 노드를 선택하고 인스펙터 옆에 있는 "노드(Node)" 탭을 클릭하세요(노드의 시그널을 찾을 수 있는 동일한 위치). "시그널(Signals)" 옆에 있는 "그룹(Groups)"을 클릭하고 새 그룹 이름을 입력하고 "추가(Add)"를 클릭하세요.

../../_images/group_tab.webp

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.