Added level selection screen
This commit is contained in:
@@ -2,6 +2,10 @@ class_name AbstractLevel
|
|||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
|
const NEXT_LEVEL_META = "next_level"
|
||||||
|
const CURRENT_LEVEL_INDEX = "current_level"
|
||||||
|
|
||||||
|
|
||||||
@onready var pause_menu : PauseMenu = $%PauseMenu
|
@onready var pause_menu : PauseMenu = $%PauseMenu
|
||||||
@onready var game_over_menu : GameOverMenu = $%GameOverMenu
|
@onready var game_over_menu : GameOverMenu = $%GameOverMenu
|
||||||
@onready var completion_menu : CompletionMenu = $%CompletionMenu
|
@onready var completion_menu : CompletionMenu = $%CompletionMenu
|
||||||
@@ -27,3 +31,10 @@ func _on_level_end_entered(body: Node2D) -> void:
|
|||||||
if body is Player:
|
if body is Player:
|
||||||
get_tree().paused = true
|
get_tree().paused = true
|
||||||
completion_menu.show()
|
completion_menu.show()
|
||||||
|
|
||||||
|
var level_index : int = get_tree().get_meta(AbstractLevel.CURRENT_LEVEL_INDEX, 0)
|
||||||
|
get_tree().remove_meta(AbstractLevel.CURRENT_LEVEL_INDEX)
|
||||||
|
|
||||||
|
if SaveManager.completed_levels <= level_index:
|
||||||
|
SaveManager.completed_levels = level_index + 1
|
||||||
|
SaveManager.save()
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
class_name Level1
|
class_name TestLevel
|
||||||
extends AbstractLevel
|
extends AbstractLevel
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[gd_scene load_steps=21 format=4 uid="uid://bmn74wc2vophn"]
|
[gd_scene load_steps=21 format=4 uid="uid://bmn74wc2vophn"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://mpsu4g2b5h3a" path="res://game/levels/abstract_level.tscn" id="1_15okj"]
|
[ext_resource type="PackedScene" uid="uid://mpsu4g2b5h3a" path="res://game/levels/abstract_level.tscn" id="1_15okj"]
|
||||||
[ext_resource type="Script" uid="uid://b04km0lbc108u" path="res://game/levels/level_1.gd" id="2_hj65a"]
|
[ext_resource type="Script" uid="uid://b04km0lbc108u" path="res://game/levels/test_level.gd" id="2_hj65a"]
|
||||||
[ext_resource type="PackedScene" uid="uid://b3kyqvuxmfn8f" path="res://game/objects/fireplace.tscn" id="3_tuvkr"]
|
[ext_resource type="PackedScene" uid="uid://b3kyqvuxmfn8f" path="res://game/objects/fireplace.tscn" id="3_tuvkr"]
|
||||||
[ext_resource type="PackedScene" uid="uid://pw8xqtpauy57" path="res://game/objects/tutorial/jump_kbd.tscn" id="4_crrvt"]
|
[ext_resource type="PackedScene" uid="uid://pw8xqtpauy57" path="res://game/objects/tutorial/jump_kbd.tscn" id="4_crrvt"]
|
||||||
[ext_resource type="PackedScene" uid="uid://g0n5npbt3hb2" path="res://game/doors/circle_door.tscn" id="4_yrqjd"]
|
[ext_resource type="PackedScene" uid="uid://g0n5npbt3hb2" path="res://game/doors/circle_door.tscn" id="4_yrqjd"]
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://cutjutvd8dqqc" path="res://game/characters/black_enemy.tscn" id="19_ohfy3"]
|
[ext_resource type="PackedScene" uid="uid://cutjutvd8dqqc" path="res://game/characters/black_enemy.tscn" id="19_ohfy3"]
|
||||||
[ext_resource type="PackedScene" uid="uid://bv2gahb4wxgb1" path="res://game/characters/white_enemy.tscn" id="20_rt0xo"]
|
[ext_resource type="PackedScene" uid="uid://bv2gahb4wxgb1" path="res://game/characters/white_enemy.tscn" id="20_rt0xo"]
|
||||||
|
|
||||||
[node name="Level1" instance=ExtResource("1_15okj")]
|
[node name="TestLevel" instance=ExtResource("1_15okj")]
|
||||||
script = ExtResource("2_hj65a")
|
script = ExtResource("2_hj65a")
|
||||||
|
|
||||||
[node name="Door" parent="Doors" index="0" instance=ExtResource("11_g1txn")]
|
[node name="Door" parent="Doors" index="0" instance=ExtResource("11_g1txn")]
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
class_name CSaveManager
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
|
||||||
|
@export var save_file_path := "user://save.bin"
|
||||||
|
@export var save_file_pass := "save_file_data"
|
||||||
|
|
||||||
|
|
||||||
|
const CATEGORY_GAME = "game"
|
||||||
|
const GAME_COMPLETED_LEVELS = "completed_levels"
|
||||||
|
|
||||||
|
|
||||||
|
var completed_levels := 0
|
||||||
|
|
||||||
|
var _save_file: ConfigFile
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_save_file = ConfigFile.new()
|
||||||
|
_load()
|
||||||
|
|
||||||
|
|
||||||
|
func save() -> void:
|
||||||
|
_save_file.set_value(CATEGORY_GAME, GAME_COMPLETED_LEVELS, completed_levels)
|
||||||
|
_save_file.save_encrypted_pass(save_file_path, save_file_pass)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _load() -> void:
|
||||||
|
if _save_file.load_encrypted_pass(save_file_path, save_file_pass) == OK:
|
||||||
|
_process_save_file()
|
||||||
|
|
||||||
|
save()
|
||||||
|
|
||||||
|
|
||||||
|
func _process_save_file() -> void:
|
||||||
|
completed_levels = _save_file.get_value(
|
||||||
|
CATEGORY_GAME, GAME_COMPLETED_LEVELS, completed_levels
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d2vtovrykiwd
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://cuqxyst3qlvmw"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://d2vtovrykiwd" path="res://game/managers/save_manager.gd" id="1_c6jim"]
|
||||||
|
|
||||||
|
[node name="SaveManager" type="Node"]
|
||||||
|
script = ExtResource("1_c6jim")
|
||||||
@@ -2,28 +2,39 @@ class_name CompletionMenu
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
|
||||||
@export var next_level : PackedScene
|
|
||||||
|
|
||||||
|
|
||||||
@onready var next_level_button : Button = $%NextLevelButton
|
@onready var next_level_button : Button = $%NextLevelButton
|
||||||
|
@onready var main_menu_button : Button = $%MainMenuButton
|
||||||
@onready var focus_timer : Timer = $FocusTimer
|
@onready var focus_timer : Timer = $FocusTimer
|
||||||
|
|
||||||
|
|
||||||
|
func _get_next_level(remove := false) -> PackedScene:
|
||||||
|
var next_level : PackedScene = get_tree().get_meta(AbstractLevel.NEXT_LEVEL_META, null)
|
||||||
|
|
||||||
|
if remove:
|
||||||
|
get_tree().remove_meta(AbstractLevel.NEXT_LEVEL_META)
|
||||||
|
|
||||||
|
return next_level
|
||||||
|
|
||||||
|
|
||||||
func _on_next_level_button_pressed() -> void:
|
func _on_next_level_button_pressed() -> void:
|
||||||
get_tree().paused = false
|
get_tree().paused = false
|
||||||
|
get_tree().change_scene_to_packed(_get_next_level(true))
|
||||||
if next_level != null:
|
|
||||||
get_tree().change_scene_to_packed(next_level)
|
|
||||||
else:
|
func _on_main_menu_button_pressed() -> void:
|
||||||
get_tree().change_scene_to_file("res://game/menu/main_menu.tscn")
|
get_tree().paused = false
|
||||||
|
get_tree().change_scene_to_file("res://game/menu/main_menu.tscn")
|
||||||
|
|
||||||
|
|
||||||
func _on_visibility_changed() -> void:
|
func _on_visibility_changed() -> void:
|
||||||
if visible:
|
if visible:
|
||||||
|
next_level_button.visible = _get_next_level() != null
|
||||||
if focus_timer != null:
|
if focus_timer != null:
|
||||||
focus_timer.start()
|
focus_timer.start()
|
||||||
|
|
||||||
|
|
||||||
func _on_focus_timer_timeout() -> void:
|
func _on_focus_timer_timeout() -> void:
|
||||||
if next_level_button != null:
|
if next_level_button != null and next_level_button.visible:
|
||||||
next_level_button.grab_focus()
|
next_level_button.grab_focus()
|
||||||
|
elif main_menu_button != null:
|
||||||
|
main_menu_button.grab_focus()
|
||||||
|
|||||||
@@ -48,9 +48,15 @@ unique_name_in_owner = true
|
|||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Next level"
|
text = "Next level"
|
||||||
|
|
||||||
|
[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Main menu"
|
||||||
|
|
||||||
[node name="FocusTimer" type="Timer" parent="."]
|
[node name="FocusTimer" type="Timer" parent="."]
|
||||||
one_shot = true
|
one_shot = true
|
||||||
|
|
||||||
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
|
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
|
||||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/NextLevelButton" to="." method="_on_next_level_button_pressed"]
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/NextLevelButton" to="." method="_on_next_level_button_pressed"]
|
||||||
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/MainMenuButton" to="." method="_on_main_menu_button_pressed"]
|
||||||
[connection signal="timeout" from="FocusTimer" to="." method="_on_focus_timer_timeout"]
|
[connection signal="timeout" from="FocusTimer" to="." method="_on_focus_timer_timeout"]
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ class_name GameOverMenu
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
|
||||||
|
@onready var retry_button : Button = $%RetryButton
|
||||||
@onready var main_menu_button : Button = $%MainMenuButton
|
@onready var main_menu_button : Button = $%MainMenuButton
|
||||||
@onready var focus_timer : Timer = $FocusTimer
|
@onready var focus_timer : Timer = $FocusTimer
|
||||||
|
|
||||||
|
|
||||||
|
func _on_retry_button_pressed() -> void:
|
||||||
|
get_tree().paused = false
|
||||||
|
get_tree().change_scene_to_file(get_tree().current_scene.scene_file_path)
|
||||||
|
|
||||||
|
|
||||||
func _on_main_menu_button_pressed() -> void:
|
func _on_main_menu_button_pressed() -> void:
|
||||||
get_tree().paused = false
|
get_tree().paused = false
|
||||||
get_tree().change_scene_to_file("res://game/menu/main_menu.tscn")
|
get_tree().change_scene_to_file("res://game/menu/main_menu.tscn")
|
||||||
@@ -19,4 +25,4 @@ func _on_visibility_changed() -> void:
|
|||||||
|
|
||||||
func _on_focus_timer_timeout() -> void:
|
func _on_focus_timer_timeout() -> void:
|
||||||
if main_menu_button != null:
|
if main_menu_button != null:
|
||||||
main_menu_button.grab_focus()
|
retry_button.grab_focus()
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ layout_mode = 2
|
|||||||
text = "Game over!"
|
text = "Game over!"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="RetryButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Retry"
|
||||||
|
|
||||||
[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
@@ -52,5 +57,6 @@ text = "Main menu"
|
|||||||
one_shot = true
|
one_shot = true
|
||||||
|
|
||||||
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
|
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
|
||||||
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/RetryButton" to="." method="_on_retry_button_pressed"]
|
||||||
[connection signal="pressed" from="MarginContainer/VBoxContainer/MainMenuButton" to="." method="_on_main_menu_button_pressed"]
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/MainMenuButton" to="." method="_on_main_menu_button_pressed"]
|
||||||
[connection signal="timeout" from="FocusTimer" to="." method="_on_focus_timer_timeout"]
|
[connection signal="timeout" from="FocusTimer" to="." method="_on_focus_timer_timeout"]
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
class_name LevelSelection
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
|
||||||
|
@export var levels : Array[PackedScene] = []
|
||||||
|
|
||||||
|
|
||||||
|
@onready var grid : GridContainer = $%GridContainer
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
levels = levels.filter(func(item: PackedScene) -> bool: return item != null)
|
||||||
|
|
||||||
|
for i in range(levels.size()):
|
||||||
|
var level := levels[i]
|
||||||
|
var next_level := levels[i+1] if i+1 < levels.size() else null
|
||||||
|
var disable := SaveManager.completed_levels < i
|
||||||
|
|
||||||
|
var button : Button = Button.new()
|
||||||
|
button.text = "Level %d" % (i + 1)
|
||||||
|
button.disabled = disable
|
||||||
|
button.focus_mode = Control.FOCUS_NONE if disable else Control.FOCUS_ALL
|
||||||
|
grid.add_child(button)
|
||||||
|
button.pressed.connect(_on_level_selected.bind(i, level, next_level))
|
||||||
|
|
||||||
|
if i == 0:
|
||||||
|
button.grab_focus()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_level_selected(index: int, level: PackedScene, next_level: PackedScene) -> void:
|
||||||
|
get_tree().set_meta(AbstractLevel.CURRENT_LEVEL_INDEX, index)
|
||||||
|
get_tree().set_meta(AbstractLevel.NEXT_LEVEL_META, next_level)
|
||||||
|
get_tree().change_scene_to_packed(level)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_main_menu_button_pressed() -> void:
|
||||||
|
get_tree().change_scene_to_file("res://game/menu/main_menu.tscn")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://47impoi24o7g
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://cdw72hewwmypn"]
|
||||||
|
|
||||||
|
[ext_resource type="Theme" uid="uid://bh56my8b2htnr" path="res://themes/menu.tres" id="1_5cn0b"]
|
||||||
|
[ext_resource type="Script" uid="uid://47impoi24o7g" path="res://game/menu/level_selection.gd" id="1_fb5q3"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bmn74wc2vophn" path="res://game/levels/test_level.tscn" id="3_3oqjo"]
|
||||||
|
|
||||||
|
[node name="LevelSelection" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme = ExtResource("1_5cn0b")
|
||||||
|
script = ExtResource("1_fb5q3")
|
||||||
|
levels = Array[PackedScene]([ExtResource("3_3oqjo"), ExtResource("3_3oqjo")])
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="GridContainer" type="GridContainer" parent="MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 4
|
||||||
|
size_flags_vertical = 6
|
||||||
|
columns = 4
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Main menu"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/MainMenuButton" to="." method="_on_main_menu_button_pressed"]
|
||||||
@@ -22,7 +22,7 @@ func _setup_neighbors() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _on_start_button_pressed() -> void:
|
func _on_start_button_pressed() -> void:
|
||||||
get_tree().change_scene_to_file("res://game/levels/level_1.tscn")
|
get_tree().change_scene_to_file("res://game/menu/level_selection.tscn")
|
||||||
|
|
||||||
|
|
||||||
func _on_options_button_pressed() -> void:
|
func _on_options_button_pressed() -> void:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ config/icon="res://icon.svg"
|
|||||||
|
|
||||||
SettingsManager="*res://game/managers/settings_manager.tscn"
|
SettingsManager="*res://game/managers/settings_manager.tscn"
|
||||||
SoundManager="*res://game/managers/sound_manager.tscn"
|
SoundManager="*res://game/managers/sound_manager.tscn"
|
||||||
|
SaveManager="*res://game/managers/save_manager.tscn"
|
||||||
|
|
||||||
[debug]
|
[debug]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user