해당 내용 출처 :) https://docs.godotengine.org/en/stable/getting_started/first_2d_game/index.html
이전 내용:) https://twd0622.tistory.com/90
저번 포스팅에서 메인 화면을 만들어 게임을 할 수 있게 되었다.
하지만 게임이 완성되려면 사용자 인터페이스도 중요하기 때문에 이번 포스팅에서는 HUD(Heads up display)를 만들어 점수, 게임 오버 메시지, 게임 시작 버튼 등을 표시할 것 이다.
HUD란?
예전 전투기 조종사들이 전투기를 조종할 때 계기판을 보기위해 고개를 숙였다 들었다 하면서 조종했는데, 이를 편하게 하기 위해 고개를 숙이지 않고 고개를 든채로 볼수있게 해주는 디스플레이라는 뜻에서 'heads up display'란 명칭이 붙었다.
요즘은 항공 부분 뿐아니라, 자동차, 게임 등 다양한 분야에서도 이와 같은 명칭을 사용하는데, 게임을 하면서 게임 화면 위에 다양한 정보를 표시해주는 화면을 의미한다.
6장 Heads up display
6-1 HUD 씬 생성
먼저 새로운 씬을 생성해 다른 노드를 눌러 루트 노드를 만들어 보자.
HUD의 루트노드는 'CanvasLayer'노드 이다. 생성 후 이름을 'HUD'로 변경해 주자.
- CanvasLayer: 2D 작업 내에서 객체를 독립적으로 랜더링 하는 데 사용되는 노드, 해당 노드에 표시되는 정보가 플레이어나 몹에 가려지지 않음
루트 노드를 생성했다면 이제 자식 노드를 생성해보자.
Label 노드 2개, Button 노드, Timer 노드를 생성하자.
- Label1 → 'ScoreLabel' : 점수를 알려주는 라벨
- Label2 → 'Message' : 메시지를 표시해주는 라벨
- Button → 'StartButton' : 게임 시작 버튼
- Timer → 'MessageTimer' : 메세지를 표시해주는 시간 타이머
아래 사진처럼 노드를 생성하면 된다.
6-2 노드 세팅
'ScoreLabel'을 클릭한 후 인스펙터 메뉴에서 Text에 '0'을 입력해 준다.
기본 폰트는 크기가 작고 조절이 어렵기 때문에 폰트를 변경해 줄것이다.
인스펙터 메뉴에 Control 영역에서 Theme Overrides > Fonts 를 열어 폰트를 불러온다.
fonts 폴더 안에 'Xolonium-Regular.ttf'를 불러온다.
글자 크기가 여전히 작기 때문에 Theme Overrides > Fonts Size에서 글자 크기를 64px로 변경해준다.
폰트 변경과 크기 설정을 'Message'노드와 'StartButton'노드에도 동일하게 적용해주다.
'Mesage'노드에 Text는 임시로 아무 글자를 입력해주고 'StartButton'은 'Start'를 입력해주면 된다.
노드를 드래그 해서 위치를 설정해줄수도 있지만, 'Anchor Presets'을 통해 더 정확하게 배치해줄 수 있다.
- Anchors: 배치를 설정해주는 속성으로 원점 즉, 노드의 구석을 기준으로 지정해준다.
이제 각 노드를 아래의 내용대로 설정해주자.
ScoreLabel
- Text: 0
- Horizontal Alignment & Vertical Alignment : Center
- Anchor Preset : 위쪽 중앙
Message
- Text: Dodge the Creeps!
- Horizontal Alignment & Vertical Alignment : Center
- Autowrap Mode: Word (라벨 줄 바꿈 설정)
- Control > Layout > Transform > Size X : 480
- Anchor Preset : 중앙
StartButton
- Text: Start
- Control > Layout> Transform > Size : (200, 100)
- Anchor Preset : 아래쪽 중앙
- Control > Layout > Transform > Position Y : 580
MessageTimer
- WaitTime: 2
- OneShot: 사용
설정을 모두 마친 화면 모습이다.
6-3 HUD 스크립트 작성
노드 설정을 모두 했다면 이제 스크립트를 작성할 차례이다.
HUD 노드에서 스크립트를 생성하자.
스크립트 상단 extends CanvasLayer 밑에 signal 하나 추가해주자.
extends CanvasLayer
# Main씬에 StartButton이 눌린걸 알려주기 위한 signal
signal start_game
메시지를 표시해주는 함수를 만들어 보자.
func show_message(text):
$Message.text = text
$Message.show()
$MessageTimer.start()
다음은 게임 오버가 됬을 때 실행될 함수를 만들어 볼것이다.
플레이어가 몹에 닿으면 "Game Over" 이라는 글자를 2초간 띄워주고 다시 원래의 타이틀과 시작 버튼을 띄어줄것이다.
func show_game_over():
show_message("Game Over")
await $MessageTimer.timeout # MessageTimer가 끝날때 까지 기다림
$Message.text = "Dodge the Creeps!"
$Message.show()
await get_tree().create_timer(1.0).timeout # 일회용 1초 타이머 생성 후 종료까지 기다림
$StartButton.show()
- get_tree().create_timer()를 통해 굳이 노드를 생성하지 않고 일회용으로 사용할 timer를 만들어 사용할 수 있다.
다음은 HUD에 점수가 업데이트 되는 함수이다.
func update_score(score):
$ScoreLabel.text = str(score)
이제 'StartButton'의 'pressed()' 시그널과 'MessageTimer'의 'timeout()' 시그널을 연결해주자.
func _on_start_button_pressed() -> void:
$StartButton.hide()
start_game.emit() # start_game 시그널 호출
func _on_message_timer_timeout() -> void:
$Message.hide()
여기까지 HUD 스크립트 작성이 완료되었다.
extends CanvasLayer
# Main씬에 StartButton이 눌린걸 알려주기 위한 signal
signal start_game
func show_message(text):
$Message.text = text
$Message.show()
$MessageTimer.start()
func show_game_over():
show_message("Game Over")
await $MessageTimer.timeout # MessageTimer가 끝날때 까지 기다림
$Message.text = "Dodge the Creeps!"
$Message.show()
await get_tree().create_timer(1.0).timeout # 일회용 1초 타이머 생성 후 종료까지 기다림
$StartButton.show()
func update_score(score):
$ScoreLabel.text = str(score)
func _ready() -> void:
pass # Replace with function body.
func _process(delta: float) -> void:
pass
func _on_start_button_pressed() -> void:
$StartButton.hide()
start_game.emit() # start_game 시그널 호출
func _on_message_timer_timeout() -> void:
$Message.hide()
6-3 Main 씬과 HUD 씬 연결
Main씬으로 넘어가 저번 Main씬을 만들때 Player씬을 연결해줄때 처럼 체인 버튼을 눌러 HUD씬을 연결해주자.
이제 Main 스크립트에 HUD씬 기능을 추가하기 위해 코드를 추가해보자.
HUD씬 인스턴스 노드를 누르고 노드 메뉴에서 start_game()을 더블 클릭하면 위의 사진과 같은 창이 나온다.
여기서 선택 버튼을 눌러준다.
메인 노드를 클릭하고 선택 버튼을 누르면 메서드를 선택할 수 있는 창이 나오는데 'new_game()' 함수와 연결해준다.
연결이되면 노드 메뉴에서 start_game() 시그널 밑에 'new_game()'함수가 연결된것을 확인할 수 있다.
연결을 했다면 'new_game()'함수에 아래 코드를 추가하면 점수를 초기화하고 "Get Ready" 메시지를 띄워준다.
$HUD.update_score(score)
$HUD.show_message("Get Ready")
'game_over()' 함수엔 아래 코드를 추가하면 게임 오버 메시지를 띄워준다.
$HUD.show_game_over()
마지막으로 '_on_score_timer_timeout()'에 아래의 코드를 추가하면 점수가 올라갈때 마다 화면에 변화된 점수를 보여준다.
$HUD.update_score(score)
_ready() 함수에 new_game()을 지우는 것을 까먹지 말자!!
이제 게임을 플레이 해보면 된다.
시작 버튼을 누르면 게임이 시작되고, 죽으면 게임이 띄워지는지 등 HUD가 추가된것을 확인해보자.
6-4 몹 삭제하기
게임을 플레이하다 플레이어가 몹에 닿아 죽고나서 바로 게임을 다시 시작했을때, 전에 게임하면서 나왔던 몹이 아직 사라지지않고 남아있는 경우가 있을 수 있다. 이를 방지하기위해 몹들을 그룹으로 묶어 새로 게임을 시작하면 몹들을 전부 지워줄것이다.
Mob씬에서 노드 메뉴에 그룹으로 들어가서 + 버튼을 눌러 그룹을 생성 창을 띄우자.
그룹이름을 'Mobs'로 지정하고 그룹을 생성해주면 된다.
Mobs 그룹이 생긴것을 확인할 수 있다.
다음 Main씬에서 'new_game()'함수에 아래의 코드를 추가해 새로 게임이 시작될 때 몹 그룹을 삭제 시켜주자.
get_tree().call_group("Mobs", "queue_free")
이제 게임을 플레이해보면 기존에 있던 몹들이 삭제되는 것을 볼 수 있다.
Main 스크립트 전체
extends Node
@export var mob_scene : PackedScene
var score
func _ready() -> void:
# new_game()
pass
func _process(delta: float) -> void:
pass
# Player씬에서 hit() 신호를 보낼 경우
func game_over() -> void:
$ScoreTimer.stop()
$MobTimer.stop()
$HUD.show_game_over()
func new_game():
score = 0; # 점수 초기화
$Player.start($StartPosition.position) # 플레이어 위치 설정
$StartTimer.start() # 2초 대기
$HUD.update_score(score)
$HUD.show_message("Get Ready")
get_tree().call_group("Mobs", "queue_free")
func _on_start_timer_timeout() -> void:
$MobTimer.start()
$ScoreTimer.start()
func _on_score_timer_timeout() -> void:
score += 1
$HUD.update_score(score)
func _on_mob_timer_timeout() -> void:
var mob = mob_scene.instantiate() # 몹 인스턴스 생성
# 몹 위치
var mob_spawn_location = $MobPath/MobSpawnLocation
mob_spawn_location.progress_ratio = randf() # MobPath에서 랜덤으로 지정
# 몹 방향
var direction = mob_spawn_location.rotation + PI / 2 # 몹의 방향을 경로의 수직으로 설정
direction += randf_range(-PI / 4, PI / 4) # 방향을 랜덤으로 살짝 병경해준다.
# 몹 속도
var velocity = Vector2(randf_range(150.0, 250.0), 0.0) # 몹의 속도 랜덤 지정
# 몹 인스턴스에 설정한 값들 부여
mob.position = mob_spawn_location.position
mob.rotation = direction
mob.linear_velocity = velocity.rotated(direction)
# 메인 화면에 몹 생성
add_child(mob)
HUD씬을 만들어 점수와 타이틀 및 메시지, 버튼을 띄워주었다.
게임으로서 필요한 부분은 대부분 들어갔다. 다음 포스팅에서 배경, 음악, 몇가지 키보드 단축키를 만들어 게임의 완성도를 올려보겠다.
다음 포스팅 :) https://twd0622.tistory.com/92
'Godot Engine > 게임 제작' 카테고리의 다른 글
[GodotEngine] Tutorial 2D Game - 7 [完] (3) | 2025.01.02 |
---|---|
[GodotEngine] Tutorial 2D Game - 5 (0) | 2024.12.27 |
[GodotEngine] Tutorial 2D Game - 4 (0) | 2024.12.19 |
[GodotEngine] Tutorial 2D Game - 3 (2) | 2024.12.16 |
[GodotEngine] Tutorial 2D Game - 2 (0) | 2024.12.11 |