1. Title screen제작
- User Interface(Control) 추가하고 이름을 MainScreen으로 변경합니다.
- Background 추가 후 TextureRectangle로 변경,
- Layout: Full Rect
- 인스펙터에서 Expand: on, Stretch Mode: Tile 로 설정
- MainScreen Node에 Label 노드 추가(Title)
○ My First Godot Game : Text 변환
○ Center Top: Layer 변경, Shift 누른채로 약간 아래로 변경
- VBoxContainer추가하여 이름을 Menu로 변경하고, 아래와 같이 버튼2개를 추가합니다.
○ Layout: Center
○ Button 2개 추가 및 텍스트 변경
○ Button을 VBoxContainer에 끌어다 놓음
○ Box 사이즈 조절
○ Button 2개 선택 후 size flags: expand vertically
- Title/Menu/PlayButton/QuitButton으로 각 요소의 이름을 변경하고, src/UserInterface폴더를 생성하여 별도 scene으로 각각 저장합니다.
- Scene저장(res://src/Screens/MainScreen.tscn으로 저장
- Project > Project Settings > Run 메뉴에서 Main Scene을 기존 Level1에서 MainScreen.tscn으로 변경해줍니다. 즉, 직접 레벨이 실행되던것을 UI화면이 뜨고, Play를 누르면 Level1으로 진입하도록 합니다.
2. 테마 설정
Title - font에 폰트 추가 대신 Theme기능을 이용하여 Scene 전체적으로 스타일을 적용하는 과정입니다. (제공되는 테마를 사용할 경우 skip 가능)
- Dynamic Font 추가
○ MainScreen노드에서 Add Resource Button을 클릭, Dynamic Font노드를 추가합니다.
- Font에 font file추가
- size: 24로 변경
- Assets 폴더에 new_dynamicfont.tres로 추가
- Add Resource Button을 한번 더 클릭합니다.
- Theme 노드 추가
- new_dynamicfont.tres를 Default Font에 추가
- Assets 폴더에 ui_theme.tres로 저장
- MainScreen에서 Theme에 ui_theme.tres를 추가
- Title.tscn을 열고 Text를 일반적으로 쓸 수 있도록 Title로 바꿔줍니다.
○ Align: center
○ Font: font_title.tres를 추가해줍니다.
- 다시 MainScreen으로 와서 top center: 위치 조정
3. Play / Quit Button에 Script추가
- PlayButton.tscn을 열고, PlayButton노드에서 새 스크립트 추가를 하여 PlayButton.gd로 이름을 변경합니다.
그리고 Signal: button_up 을 추가합니다.(_on_button_up() 함수 생성)
- Button이름을 ChangeSceneButton으로 변경합니다.(근데, 스크립트 이름은 안바꾸네요..^^;;)
tool #플러그인 사용
extends Button
export(String, FILE) var next_scene_path:="" #string형태로 scene을 받아들이고, 파일 다이얼로그를 보여줌
func _on_button_up():
get_tree().change_scene(next_scene_path)
func _get_configuration.warning() -> String:
return "next_screne_path must be set for the button to work" if next_scene_path=="" else ""
- QuitButton-Script추가
- Node탭-button_up시그널 추가(_on_button_up)
extends Button
func _on_button_up():
get_tree().quit()
4.EndScreen생성
- new scene-userinterface - EndScreen.tscn저장(screen폴더)
- Merge from scene - mainscreen.tscn에서 textureRect 선택으로 배경 불러오기
- Merge from scene - mainscreen.tscn에서 Menu 선택으로 메뉴/버튼 불러오기
○ Next scene에 mainscreen을 선택
○ Play버튼 텍스트를 Play Again으로 변경
- EndScreen선택 후 resource에서 title검색으로 title.tscn을 가져와서 화면으로 drag & drop
○ Title text변경: Congratulations, you finished the game
○ Layout: center top
○ 아래쪽으로 위치이동
- Label 노드 추가
○Layout: center top
○Text수정: 텍스트 오른쪽의 expand button
your final score is %s
you died times %s
- 헌번 더 layout 조정, 텍스트 얼라인 center조정
- Title, Label, Menu를 동시 선택 후 layout - center로 중앙 정렬 후 위치 조정
○ 화면 사이즈가 변하더라도 위치변화로 이미지가 겹치지 않는다.
5. Score 시스템
- new scene - Node추가 (Autoload폴더에 PlayerData.tscen으로 저장)
- Script 생성 - PlayerData.gd로 저장
extends Node
signal score_updated
signal player_died
var score: = 0 setget set_score #매 score변경시마다 setter함수 호출
var deaths: = 0 setget set_deaths
func reset() -> void:
score = 0
deaths = 0
# 다른 스크립트에서 score가 변경되는 이벤트가 발생하여 +1이 되면 setget으로 set_score함수가 실행되고,
score변수에 +1된 값을 설정함과 동시에 "score_update" 시그널을 보낸다.
func set_score(value: int) -> void:
score = value
emit_signal("score_updated")
func set_deaths(value: int) -> void:
deaths = value
emit_signal("player_died")
- Project Settings - autoload -PlayerData.tscn - ADD
- 스크립트 수정
func _on_EnemyDetector_body_entered(body: PhysicsBody2D)->void:
#queue_free() 수정/제거
die() #추가 함수 생성
func die()-> void: #신규함수
PlayerData.deaths += 1
queue_free()
<Enemy.gd script 수정>
export var score: = 100
func die() -> void:
queue_free()
PlayerData.score += score # 추가
<Coin.gd script 수정>
export var score: = 100
func picked() ->void:
PlayerData.score += score #추가
anim_player.play("picked")
6. UI생성
- User Interface 추가 - UserInterface로 변경 후 UserInterface폴더에 저장
- ui_theme.tres를 theme에 추가
- Label 추가(score용) - layout - top right - text align: right
Score %s
- Color Rect 노드 추가(PauseOverlay로 이름 변경)
○ 색상 black, alpha:63정도로 변경
- title.tscn을 끌어다 추가, text: Paused - VBoxContainer추가, layout center, alt키와 동시에 눌러 사이즈 조정, PauseMenu로 이름 조정 - QuitButton.tscen, SceneChangeButton.tscn을 선택하여 VBox안으로 가져옴(Ctrl+방향키로 버튼위치 변경 가능)
- SceneChangeButton의 Next Scene을 MainScreen.tscn으로 설정(우클릭-path copy기능으로)
- SceneChangeButton을 복제, RetryButton으로 변경후 더블클릭(Text: Retry로 변경)
- Script 제거 후 재 추가
<RetryButton.gd scrip 추가>
Extends Button
func _on_button_up() -> void:
PlayerData.score = 0
get_tree().paused = false
get_tree().get_root().get_node("/root/UserInterface/PauseOverlay").visible = false
get_tree().reload_current_scene()
- PauseOverlay visibility를 OFF
- UserInterface.gd script 작성
<UserInterface.gd script>
extends Control
onready var scene_tree: = get_tree() #_ready함수 전에 실행됨
onready var pause_overlay: ColorRect= get_node("PauseOverlay") #ColorRect type임을 명시해줌. 혼선의 여지가 없을 경우는 선언 안하더라도 상관 없음.
var paused: = false setget set_paused
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("pause"):
self.paused = !paused #(== "paused = not paused") #Self는 gdscript에서 기본이지만, setget함수를 위해서...
scene_tree.set_input_as_handled() #pause event가 끝날때까지 propagate하지 않고 기다린다.
func set_paused(value: bool) ->void:
paused = value
scene_tree.paused = value
- Project Settings - Input Map - pause생성 - Key 추가(+버튼) - Esc로 설정
- UserInterface.tscn을 Level01에 추가
○ Canvaslayer추가(UserInterface로 변경)
○ 상위 노드로 위치를 바꾸고 Layer를 +100정도로 앞쪽으로 한다.
○ 그 후 Canvaslayer에 UserInterface.tscn을 하위 자식으로 추가
- UserInterface노드 선택 후 Node-Pause-Process로 선택(Inherit(default)/Stop/Process 중)
○ 기본으로 되어있는 Inherit는 상위노드를 상속하고 상위노드는 Stop으로 되어있다.
○ Stop은 완전 정지로 아무것도 Process할 수 없는 상태임
- 추가로, UserInterface 씬에서 Label을 hide하고, 각 level에서 인스턴스된 UserInterface 노드에서는 Label을 show해야만 Label이 이중으로 나타나는 현상이 사라진다.
<UserInterface.gd script>
extends Control
onready var scene_tree: = get_tree() #_ready함수 전에 실행됨
onready var pause_overlay: ColorRect= get_node("PauseOverlay") #ColorRect type임을 명시해줌. 혼선의 여지가 없을 경우는 선언 안하더라도 상관 없음.
onready var score: Label = get_node("Label")
onready var pause_title: Label = get_node("PuaseOverlay/Title")
const DIED_MESSAGE: = "You died"
var paused: = false setget set_paused
func _ready() -> void: #46
PlayerData.connect("score_updated", self, "update_interface")
PlayerData.connect("player_died", self, "_on_PlayerData_player_died")
update_interface()
func _on_PlayerData_player_died() -> void:
self.paused = true
pause_title.text = DIED_MESSAGE
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("pause") and pause_title.text != DIED_MESSAGE: #죽었을 때 esc를 누르면 계속 진행되는 현상 방지
self.paused = !paused #(== "paused = not paused") #Self는 gdscript에서 기본이지만, setget함수를 위해서...
scene_tree.set_input_as_handled() #pause event가 끝날때까지 propagate하지 않고 기다린다.
func update_interface() -> void:
score.text = "Score: %s" % PlayerData.score
func set_paused(value: bool) ->void:
paused = value
scene_tree.paused = value
7. UI씬을 각 level에 복사
- level02 열기
○ Merge from scene
○ level01의 UserInterface(Canvaslayer) 선택
- Level template에도 적용
8. Endscreen 수정
- Endscreen 노드에 script 추가
extends Control
onready var label: Label = get_Node("Label")
func _ready() -> void:
label.text = label.text % [PlayerData.score, PlayerData.deaths]
- Level02의 nextscene에 Endscreen을 추가
- Project Settings - windows - Fullscreen으로 변경하고 Play
---- 끝 ---
'Programming > Godot' 카테고리의 다른 글
Godot 시작하기#2 - Mob Scene (0) | 2021.12.22 |
---|---|
Godot 시작하기#1 - 프로젝트 설정 및 Player Scene (0) | 2021.12.22 |
고도 엔진 횡스크롤 게임 예제 (Godot Platformer) - 2 (0) | 2020.01.29 |
고도 엔진 횡스크롤 게임 예제 (Godot Platformer) -1 (0) | 2020.01.29 |
고도 엔진 횡스크롤 게임 예제 시작하기 (Godot Platformer) (0) | 2020.01.29 |