From d9629a09213a5dc575083bc447047e07268c627b Mon Sep 17 00:00:00 2001 From: Ruslan Ignatov Date: Wed, 1 Jul 2026 13:35:27 +0300 Subject: [PATCH] Added level selection --- game/levels/abstract_level.gd | 18 +++++++ game/levels/abstract_level.tscn | 17 +++++++ game/levels/test_level.tscn | 6 ++- game/managers/level_manager.gd | 12 +++++ game/managers/level_manager.gd.uid | 1 + game/managers/level_manager.tscn | 8 ++++ game/managers/save_manager.gd | 40 ++++++++++++++++ game/managers/save_manager.gd.uid | 1 + game/managers/save_manager.tscn | 6 +++ game/managers/sound_manager.gd | 1 + game/managers/sound_manager.tscn | 2 + game/menu/completion_menu.gd | 45 ++++++++++++++++++ game/menu/completion_menu.gd.uid | 1 + game/menu/completion_menu.tscn | 70 ++++++++++++++++++++++++++++ game/menu/level_selection.gd | 38 +++++++++++++++ game/menu/level_selection.gd.uid | 1 + game/menu/level_selection.tscn | 40 ++++++++++++++++ game/menu/main_menu.gd | 2 +- project.godot | 2 + sound/sfx/level_completed.wav | 3 ++ sound/sfx/level_completed.wav.import | 24 ++++++++++ 21 files changed, 336 insertions(+), 2 deletions(-) create mode 100644 game/managers/level_manager.gd create mode 100644 game/managers/level_manager.gd.uid create mode 100644 game/managers/level_manager.tscn create mode 100644 game/managers/save_manager.gd create mode 100644 game/managers/save_manager.gd.uid create mode 100644 game/managers/save_manager.tscn create mode 100644 game/menu/completion_menu.gd create mode 100644 game/menu/completion_menu.gd.uid create mode 100644 game/menu/completion_menu.tscn create mode 100644 game/menu/level_selection.gd create mode 100644 game/menu/level_selection.gd.uid create mode 100644 game/menu/level_selection.tscn create mode 100644 sound/sfx/level_completed.wav create mode 100644 sound/sfx/level_completed.wav.import diff --git a/game/levels/abstract_level.gd b/game/levels/abstract_level.gd index 0e75a8d..6b36d82 100644 --- a/game/levels/abstract_level.gd +++ b/game/levels/abstract_level.gd @@ -16,6 +16,7 @@ var _corruption_x: float @onready var player : Player = $Player @onready var pause_menu : PauseMenu = $%PauseMenu @onready var game_over_menu : GameOverMenu = $%GameOverMenu +@onready var completion_menu : CompletionMenu = $%CompletionMenu @onready var health_bar : HealthBar = $%HealthBar @onready var corruption_timer : Timer = $CorruptionTimer @@ -33,6 +34,7 @@ func _ready() -> void: _corruption_x = initial_corruption_x pause_menu.hide() game_over_menu.hide() + completion_menu.hide() health_bar.initialize(player.MAX_HEALTH, player.MAX_HEALTH) player.health_changed.connect(health_bar.set_current_value) @@ -94,6 +96,17 @@ func _show_game_over() -> void: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE +func _complete_level(player_position: Vector2) -> void: + SoundManager.play_sfx_stream(SoundManager.sfx_stream_level_completed, player_position) + get_tree().paused = true + completion_menu.show() + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + + if SaveManager.completed_levels <= LevelManager.current_level_index: + SaveManager.completed_levels = LevelManager.current_level_index + 1 + SaveManager.save() + + func _on_corruption_timer_timeout() -> void: if not player: corruption_timer.stop() @@ -114,3 +127,8 @@ func _on_death_fall_timer_timeout() -> void: func _on_destruction_timer_timeout() -> void: _show_game_over() + + +func _on_level_end_body_entered(body: Node2D) -> void: + if body is Player: + _complete_level(player.global_position) diff --git a/game/levels/abstract_level.tscn b/game/levels/abstract_level.tscn index a17e4e5..e03bc11 100644 --- a/game/levels/abstract_level.tscn +++ b/game/levels/abstract_level.tscn @@ -9,6 +9,7 @@ [ext_resource type="PackedScene" uid="uid://b1x0tmnf7hx7h" path="res://game/hud/health_bar.tscn" id="6_x8k35"] [ext_resource type="PackedScene" uid="uid://cl7vqh8j2f5py" path="res://game/menu/game_over_menu.tscn" id="7_l0xih"] [ext_resource type="PackedScene" uid="uid://bafplnd2un011" path="res://game/effects/code.tscn" id="8_b7vts"] +[ext_resource type="PackedScene" uid="uid://dbnpcpwbw7f8q" path="res://game/menu/completion_menu.tscn" id="10_8xgvj"] [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6b8cu"] resource_name = "Beams" @@ -1199,8 +1200,13 @@ glow_intensity = 4.0 glow_hdr_threshold = 0.5 glow_hdr_scale = 4.0 +[sub_resource type="RectangleShape2D" id="RectangleShape2D_bhunq"] + [node name="AbstractLevel" type="Node2D" unique_id=1001045799] script = ExtResource("1_o2mui") +initial_corruption_x = null +corruption_speed = null +desctruction_offset = null [node name="Player" parent="." unique_id=763780926 instance=ExtResource("2_r0ht6")] @@ -1242,6 +1248,9 @@ process_mode = 2 unique_name_in_owner = true process_mode = 2 +[node name="CompletionMenu" parent="CanvasLayer" unique_id=1435656270 instance=ExtResource("10_8xgvj")] +unique_name_in_owner = true + [node name="CorruptionTimer" type="Timer" parent="." unique_id=783383429] wait_time = 0.5 @@ -1254,7 +1263,15 @@ one_shot = true [node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=310371888] environment = SubResource("Environment_bhunq") +[node name="LevelEnd" type="Area2D" parent="." unique_id=1444951079] +collision_layer = 0 +collision_mask = 2 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="LevelEnd" unique_id=1314456096] +shape = SubResource("RectangleShape2D_bhunq") + [connection signal="dead" from="Player" to="." method="_on_player_dead"] [connection signal="timeout" from="CorruptionTimer" to="." method="_on_corruption_timer_timeout"] [connection signal="timeout" from="DestructionTimer" to="." method="_on_destruction_timer_timeout"] [connection signal="timeout" from="DeathFallTimer" to="." method="_on_death_fall_timer_timeout"] +[connection signal="body_entered" from="LevelEnd" to="." method="_on_level_end_body_entered"] diff --git a/game/levels/test_level.tscn b/game/levels/test_level.tscn index ad58d4c..76fa294 100644 --- a/game/levels/test_level.tscn +++ b/game/levels/test_level.tscn @@ -10,12 +10,13 @@ viewport_path = NodePath("CanvasLayer/CodeViewport") [node name="TestLevel" unique_id=1001045799 instance=ExtResource("1_46m3m")] initial_corruption_x = -500.0 corruption_speed = 10.0 +desctruction_offset = 100.0 [node name="Player" parent="." index="0" unique_id=763780926] position = Vector2(0, -38) [node name="TileMapLayer" parent="." index="1" unique_id=502099522] -tile_map_data = PackedByteArray("AAAMAP//AAAFAAoAAAAMAP7/AAALAAYAAAAMAP3/AAAIAAYAAAAMAPz/AAAKAAYAAAAMAPv/AAADAAYAAAAMAPr/AAAGAAYAAAAMAPn/AAABAAYAAAAMAPj/AAAIAAYAAAAMAPf/AAAFAAYAAAAMAPb/AAAIAAYAAAAMAPX/AAALAAYAAAAMAPT/AAALAAYAAAAMAPP/AAADAAYAAAAMAPL/AAACAAYAAAAMAPH/AAAFAAYAAAAMAPD/AAABAAYAAAAAAPn/AAADAAQAAAAAAPj/AAAKAAYAAAAAAPf/AAACAAYAAAAAAPb/AAADAAYAAAAAAPX/AAAJAAYAAAAAAPT/AAADAAYAAAAAAPP/AAAIAAYAAAAAAPL/AAAKAAYAAAAAAPH/AAAGAAYAAAAAAPD/AAAJAAYAAAAAAO//AAAJAAYAAAD0////AAAGAAcAAAD0//7/AAAGAAYAAAD0//3/AAABAAYAAAD0//z/AAAGAAYAAAD0//v/AAAFAAYAAAD0//r/AAAHAAYAAAD0//n/AAAHAAYAAAD0//j/AAACAAYAAAD0//f/AAAEAAYAAAD0//b/AAABAAYAAAD0//X/AAABAAYAAAD0//T/AAAIAAYAAAD0//P/AAALAAYAAAD0//L/AAAFAAYAAAD0//H/AAAGAAYAAAD0//D/AAAKAAYAAAD0/+//AAAGAAYAAAD0/+7/AAAKAAYAAAD0/+3/AAAJAAYAAAD0/+z/AAALAAYAAAD0/+v/AAAAAAYAAAD0/+r/AAAIAAYAAAD0/+n/AAAFAAYAAAD0/+j/AAAIAAYAAAD0/+b/AAAEAAYAAAD0/+f/AAADAAYAAAAMAO//AAAIAAYAAAAMAO7/AAACAAYAAAAMAO3/AAAHAAYAAAAMAOz/AAAJAAYAAAAMAOv/AAAFAAYAAAAMAOr/AAALAAYAAAAMAOn/AAADAAYAAAAMAOj/AAAGAAYAAAAMAOf/AAAFAAYAAAAAAO7/AAABAAYAAAAAAO3/AAALAAYAAAAAAOz/AAAKAAYAAAAAAOv/AAAIAAYAAAAAAOr/AAADAAYAAAAAAOn/AAAEAAYAAAAAAOj/AAACAAYAAAAAAOf/AAAAAAYAAAAAAOb/AAAEAAYAAAAMAOb/AAAFAAYAAAAMAOX/AAAJAAgAAAANAOX/AAAIAAUAAAAOAOX/AAAAAAUAAAAPAOX/AAACAAUAAAAQAOX/AAAAAAUAAAARAOX/AAAHAAUAAAASAOX/AAAHAAUAAAATAOX/AAACAAUAAAAUAOX/AAAKAAUAAAAVAOX/AAAKAAUAAAAWAOX/AAAGAAUAAAAXAOX/AAALAAUAAAAYAOX/AAAKAAUAAAAZAOX/AAAAAAUAAAAaAOX/AAADAAUAAAAbAOX/AAAFAAUAAAD0/+X/AAAKAAkAAADz/+X/AAAFAAUAAADy/+X/AAAGAAUAAADx/+X/AAAJAAUAAADw/+X/AAAHAAUAAADv/+X/AAABAAUAAADu/+X/AAAIAAUAAADt/+X/AAAKAAUAAADs/+X/AAAHAAUAAADr/+X/AAAHAAUAAADq/+X/AAABAAUAAADp/+X/AAAKAAUAAADo/+X/AAAIAAUAAADn/+X/AAABAAUAAADm/+X/AAALAAUAAADl/+X/AAAHAAUAAAAAAOX/AAAAAAYAAAAAAOT/AAALAAYAAAAAAOP/AAACAAYAAAAAAOL/AAAEAAYAAAAAAOH/AAAHAAYAAAAAAOD/AAADAAYAAAAAAN//AAAGAAYAAAAAAN7/AAAEAAYAAAAAAN3/AAABAAYAAAAAANz/AAAKAAYAAAAAANv/AAADAAYAAAAAANr/AAACAAMAAAALAP//AAAHAAUAAAAKAP//AAAFAAUAAAAJAP//AAACAAUAAAAIAP//AAAIAAUAAAAHAP//AAAAAAUAAAAGAP//AAABAAUAAAAFAP//AAAJAAUAAAAEAP//AAALAAUAAAADAP//AAAEAAUAAAACAP//AAADAAUAAAABAP//AAAJAAUAAAAAAP//AAAJAAUAAAD/////AAAJAAUAAAD+////AAACAAUAAAD9////AAADAAUAAAD8////AAAGAAUAAAD7////AAACAAUAAAD6////AAAIAAUAAAD5////AAACAAUAAAD4////AAAHAAUAAAD3////AAACAAUAAAD2////AAAKAAUAAAD1////AAAEAAUAAADk/+X/AAAGAAUAAADj/+X/AAAKAAUAAADi/+X/AAACAAUAAADh/+X/AAAFAAUAAADg/+X/AAAGAAUAAADf/+X/AAAKAAUAAADe/+X/AAAIAAUAAADd/+X/AAAKAAUAAADc/+X/AAAIAAUAAADb/+X/AAAEAAUAAADa/+X/AAABAAUAAADZ/+X/AAAKAAUAAADY/+X/AAAAAAUAAADX/+X/AAAGAAUAAADW/+X/AAAKAAUAAADV/+X/AAAJAAUAAADU/+X/AAABAAUAAADT/+X/AAAEAAUAAADS/+X/AAALAAUAAADR/+X/AAACAAUAAADQ/+X/AAAJAAUAAADP/+X/AAAAAAUAAADO/+X/AAAJAAUAAADN/+X/AAAAAAUAAADM/+X/AAAKAAUAAADL/+X/AAACAAUAAADK/+X/AAABAAUAAADJ/+X/AAAJAAUAAADI/+X/AAAFAAUAAADH/+X/AAAAAAEAAAAcAOX/AAAFAAUAAAAdAOX/AAACAAUAAAAeAOX/AAAEAAUAAAAfAOX/AAACAAUAAAAgAOX/AAACAAUAAAAhAOX/AAACAAUAAAAiAOX/AAAJAAUAAAAjAOX/AAAGAAUAAAAkAOX/AAAAAAUAAAAlAOX/AAAEAAUAAAAmAOX/AAAKAAUAAAAnAOX/AAAKAAUAAAAoAOX/AAAEAAUAAAApAOX/AAADAAIAAAA=") +tile_map_data = PackedByteArray("AAAMAP//AAAFAAoAAAAMAP7/AAALAAYAAAAMAP3/AAAIAAYAAAAMAPz/AAAKAAYAAAAMAPv/AAADAAYAAAAMAPr/AAAGAAYAAAAMAPn/AAABAAYAAAAMAPj/AAAIAAYAAAAMAPf/AAAFAAYAAAAMAPb/AAAIAAYAAAAMAPX/AAALAAYAAAAMAPT/AAALAAYAAAAMAPP/AAADAAYAAAAMAPL/AAACAAYAAAAMAPH/AAAFAAYAAAAMAPD/AAABAAYAAAAAAPn/AAADAAQAAAAAAPj/AAAKAAYAAAAAAPf/AAACAAYAAAAAAPb/AAADAAYAAAAAAPX/AAAJAAYAAAAAAPT/AAADAAYAAAAAAPP/AAAIAAYAAAAAAPL/AAAKAAYAAAAAAPH/AAAGAAYAAAAAAPD/AAAJAAYAAAAAAO//AAAJAAYAAAD0////AAAGAAcAAAD0//7/AAAGAAYAAAD0//3/AAABAAYAAAD0//z/AAAGAAYAAAD0//v/AAAFAAYAAAD0//r/AAAHAAYAAAD0//n/AAAHAAYAAAD0//j/AAACAAYAAAD0//f/AAAEAAYAAAD0//b/AAABAAYAAAD0//X/AAABAAYAAAD0//T/AAAIAAYAAAD0//P/AAALAAYAAAD0//L/AAAFAAYAAAD0//H/AAAGAAYAAAD0//D/AAAKAAYAAAD0/+//AAAGAAYAAAD0/+7/AAAKAAYAAAD0/+3/AAAJAAYAAAD0/+z/AAALAAYAAAD0/+v/AAAAAAYAAAD0/+r/AAAIAAYAAAD0/+n/AAAFAAYAAAD0/+j/AAAIAAYAAAD0/+b/AAAEAAYAAAD0/+f/AAADAAYAAAAMAO//AAAIAAYAAAAMAO7/AAACAAYAAAAMAO3/AAAHAAYAAAAMAOz/AAAJAAYAAAAMAOv/AAAFAAYAAAAMAOr/AAALAAYAAAAMAOn/AAADAAYAAAAMAOj/AAAGAAYAAAAMAOf/AAAFAAYAAAAAAO7/AAABAAYAAAAAAO3/AAALAAYAAAAAAOz/AAAKAAYAAAAAAOv/AAAIAAYAAAAAAOr/AAADAAYAAAAAAOn/AAAEAAYAAAAAAOj/AAACAAYAAAAAAOf/AAAAAAYAAAAAAOb/AAAEAAYAAAAMAOb/AAAFAAYAAAAMAOX/AAAJAAgAAAANAOX/AAAIAAUAAAAOAOX/AAAAAAUAAAAPAOX/AAACAAUAAAAQAOX/AAAAAAUAAAARAOX/AAAHAAUAAAASAOX/AAAHAAUAAAATAOX/AAACAAUAAAAUAOX/AAAKAAUAAAAVAOX/AAAKAAUAAAAWAOX/AAAGAAUAAAAXAOX/AAALAAUAAAAYAOX/AAAKAAUAAAAZAOX/AAAAAAUAAAAaAOX/AAADAAUAAAAbAOX/AAAFAAUAAAD0/+X/AAAKAAkAAADz/+X/AAAFAAUAAADy/+X/AAAGAAUAAADx/+X/AAAJAAUAAADw/+X/AAAHAAUAAADv/+X/AAABAAUAAADu/+X/AAAIAAUAAADt/+X/AAAKAAUAAADs/+X/AAAHAAUAAADr/+X/AAAHAAUAAADq/+X/AAABAAUAAADp/+X/AAAKAAUAAADo/+X/AAAIAAUAAADn/+X/AAABAAUAAADm/+X/AAALAAUAAADl/+X/AAAHAAUAAAAAAOX/AAAAAAYAAAAAAOT/AAALAAYAAAAAAOP/AAACAAYAAAAAAOL/AAAEAAYAAAAAAOH/AAAHAAYAAAAAAOD/AAADAAYAAAAAAN//AAAGAAYAAAAAAN7/AAAEAAYAAAAAAN3/AAABAAYAAAAAANz/AAAKAAYAAAAAANv/AAADAAYAAAAAANr/AAACAAMAAAALAP//AAAHAAUAAAAKAP//AAAFAAUAAAAJAP//AAACAAUAAAAIAP//AAAIAAUAAAAHAP//AAAAAAUAAAAGAP//AAABAAUAAAAFAP//AAAJAAUAAAAEAP//AAALAAUAAAADAP//AAAEAAUAAAACAP//AAADAAUAAAABAP//AAAJAAUAAAAAAP//AAAJAAUAAAD/////AAAJAAUAAAD+////AAACAAUAAAD9////AAADAAUAAAD8////AAAGAAUAAAD7////AAACAAUAAAD6////AAAIAAUAAAD5////AAACAAUAAAD4////AAAHAAUAAAD3////AAACAAUAAAD2////AAAKAAUAAAD1////AAAEAAUAAADk/+X/AAAGAAUAAADj/+X/AAAKAAUAAADi/+X/AAACAAUAAADh/+X/AAAFAAUAAADg/+X/AAAGAAUAAADf/+X/AAAKAAUAAADe/+X/AAAIAAUAAADd/+X/AAAKAAUAAADc/+X/AAAIAAUAAADb/+X/AAAEAAUAAADa/+X/AAABAAUAAADZ/+X/AAAKAAUAAADY/+X/AAAAAAUAAADX/+X/AAAGAAUAAADW/+X/AAAKAAUAAADV/+X/AAAJAAUAAADU/+X/AAABAAUAAADT/+X/AAAEAAUAAADS/+X/AAALAAUAAADR/+X/AAACAAUAAADQ/+X/AAAJAAUAAADP/+X/AAAAAAUAAADO/+X/AAAJAAUAAADN/+X/AAAAAAUAAADM/+X/AAAKAAUAAADL/+X/AAACAAUAAADK/+X/AAABAAUAAADJ/+X/AAAJAAUAAADI/+X/AAAFAAUAAADH/+X/AAAAAAEAAAAcAOX/AAAFAAUAAAAdAOX/AAACAAUAAAAeAOX/AAAEAAUAAAAfAOX/AAACAAUAAAAgAOX/AAACAAUAAAAhAOX/AAACAAUAAAAiAOX/AAAJAAUAAAAjAOX/AAAGAAUAAAAkAOX/AAAAAAUAAAAlAOX/AAAEAAUAAAAmAOX/AAAKAAUAAAAnAOX/AAAKAAUAAAAoAOX/AAAEAAUAAAApAOX/AAADAAIAAAAsAOX/AAAAAAQAAAAsAOT/AAAJAAYAAAAsAOP/AAALAAYAAAAsAOL/AAAKAAYAAAAsAOH/AAAJAAYAAAAsAOD/AAAGAAYAAAAsAN//AAAJAAYAAAAsAN7/AAADAAYAAAAsAN3/AAALAAYAAAAsANz/AAACAAYAAAAsANv/AAAGAAMAAAA=") [node name="Turret" parent="Turrets" parent_id_path=PackedInt32Array(491073452) index="0" unique_id=328367237 instance=ExtResource("2_giiqr")] position = Vector2(606, -432) @@ -29,3 +30,6 @@ offset_bottom = -55.0 [node name="CodeSprite" parent="CanvasLayer" parent_id_path=PackedInt32Array(1125559156) index="1" unique_id=1152584149] texture = SubResource("ViewportTexture_giiqr") + +[node name="LevelEnd" parent="." index="9" unique_id=1444951079] +position = Vector2(688, -419) diff --git a/game/managers/level_manager.gd b/game/managers/level_manager.gd new file mode 100644 index 0000000..8bc3e2c --- /dev/null +++ b/game/managers/level_manager.gd @@ -0,0 +1,12 @@ +class_name CLevelManager +extends Node + + +@export var levels : Array[PackedScene] = [] + + +var current_level_index := 0 + + +func _ready() -> void: + levels = levels.filter(func(item: PackedScene) -> bool: return item != null) diff --git a/game/managers/level_manager.gd.uid b/game/managers/level_manager.gd.uid new file mode 100644 index 0000000..806ab23 --- /dev/null +++ b/game/managers/level_manager.gd.uid @@ -0,0 +1 @@ +uid://cm1lme51ido64 diff --git a/game/managers/level_manager.tscn b/game/managers/level_manager.tscn new file mode 100644 index 0000000..6ef145f --- /dev/null +++ b/game/managers/level_manager.tscn @@ -0,0 +1,8 @@ +[gd_scene format=3 uid="uid://bk2pkmgxsgars"] + +[ext_resource type="Script" uid="uid://cm1lme51ido64" path="res://game/managers/level_manager.gd" id="1_te7jw"] +[ext_resource type="PackedScene" uid="uid://cuig5x5fd47hs" path="res://game/levels/test_level.tscn" id="2_ow2rn"] + +[node name="LevelManager" type="Node" unique_id=1657502743] +script = ExtResource("1_te7jw") +levels = Array[PackedScene]([ExtResource("2_ow2rn")]) diff --git a/game/managers/save_manager.gd b/game/managers/save_manager.gd new file mode 100644 index 0000000..913e98b --- /dev/null +++ b/game/managers/save_manager.gd @@ -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 + ) diff --git a/game/managers/save_manager.gd.uid b/game/managers/save_manager.gd.uid new file mode 100644 index 0000000..ad21462 --- /dev/null +++ b/game/managers/save_manager.gd.uid @@ -0,0 +1 @@ +uid://o5dv431ncjlu diff --git a/game/managers/save_manager.tscn b/game/managers/save_manager.tscn new file mode 100644 index 0000000..5b583a5 --- /dev/null +++ b/game/managers/save_manager.tscn @@ -0,0 +1,6 @@ +[gd_scene format=3 uid="uid://2pbgcr5yk7iy"] + +[ext_resource type="Script" uid="uid://o5dv431ncjlu" path="res://game/managers/save_manager.gd" id="1_c6jim"] + +[node name="SaveManager" type="Node" unique_id=352412412] +script = ExtResource("1_c6jim") diff --git a/game/managers/sound_manager.gd b/game/managers/sound_manager.gd index 56c5341..21224d6 100644 --- a/game/managers/sound_manager.gd +++ b/game/managers/sound_manager.gd @@ -31,6 +31,7 @@ const MUSIC_BUS = "Music" @export var sfx_stream_game_over : AudioStream @export var sfx_stream_jump : AudioStream @export var sfx_stream_land : AudioStream +@export var sfx_stream_level_completed : AudioStream @export var sfx_stream_swing : AudioStream @export var sfx_stream_turret_hit : AudioStream @export var sfx_stream_turret_shot : AudioStream diff --git a/game/managers/sound_manager.tscn b/game/managers/sound_manager.tscn index 6c5d297..26d1cbe 100644 --- a/game/managers/sound_manager.tscn +++ b/game/managers/sound_manager.tscn @@ -13,6 +13,7 @@ [ext_resource type="AudioStream" uid="uid://byn27t4ualxmi" path="res://sound/sfx/danger.wav" id="6_wyfta"] [ext_resource type="AudioStream" uid="uid://bj6ausg5hyuyg" path="res://sound/sfx/swing.wav" id="7_ab171"] [ext_resource type="AudioStream" uid="uid://33unutlwsika" path="res://sound/sfx/wall_jump.wav" id="8_22ptj"] +[ext_resource type="AudioStream" uid="uid://mwornwi1s000" path="res://sound/sfx/level_completed.wav" id="12_lqyhh"] [ext_resource type="AudioStream" uid="uid://bnrvkm5wy8wda" path="res://sound/sfx/turret_shot.wav" id="13_814q3"] [ext_resource type="AudioStream" uid="uid://8nag1oaly0by" path="res://sound/sfx/turret_hit.wav" id="13_ounmg"] @@ -35,6 +36,7 @@ sfx_stream_fall = ExtResource("6_q7cyi") sfx_stream_game_over = ExtResource("6_6ll5c") sfx_stream_jump = ExtResource("5_fpnh3") sfx_stream_land = ExtResource("6_22ptj") +sfx_stream_level_completed = ExtResource("12_lqyhh") sfx_stream_swing = ExtResource("7_ab171") sfx_stream_turret_hit = ExtResource("13_ounmg") sfx_stream_turret_shot = ExtResource("13_814q3") diff --git a/game/menu/completion_menu.gd b/game/menu/completion_menu.gd new file mode 100644 index 0000000..0eb711d --- /dev/null +++ b/game/menu/completion_menu.gd @@ -0,0 +1,45 @@ +class_name CompletionMenu +extends Control + + +@onready var next_level_button : Button = $%NextLevelButton +@onready var main_menu_button : Button = $%MainMenuButton +@onready var focus_timer : Timer = $FocusTimer + + +func _is_last_level() -> bool: + return LevelManager.current_level_index >= (LevelManager.levels.size() - 1) + + +func _on_gui_focus_changed(_node: Control) -> void: + SoundManager.play_ui_stream(SoundManager.ui_stream_select) + + +func _on_next_level_button_pressed() -> void: + SoundManager.play_ui_stream(SoundManager.ui_stream_accept) + get_tree().paused = false + LevelManager.current_level_index += 1 + get_tree().change_scene_to_packed(LevelManager.levels[LevelManager.current_level_index]) + + +func _on_main_menu_button_pressed() -> void: + SoundManager.play_ui_stream(SoundManager.ui_stream_accept) + get_tree().paused = false + get_tree().change_scene_to_file("res://game/menu/main_menu.tscn") + + +func _on_visibility_changed() -> void: + if not is_node_ready(): return + if visible: + next_level_button.visible = not _is_last_level() + focus_timer.start() + get_viewport().gui_focus_changed.connect(_on_gui_focus_changed) + elif get_viewport().gui_focus_changed.is_connected(_on_gui_focus_changed): + get_viewport().gui_focus_changed.disconnect(_on_gui_focus_changed) + + +func _on_focus_timer_timeout() -> void: + if next_level_button != null and next_level_button.visible: + next_level_button.grab_focus() + elif main_menu_button != null: + main_menu_button.grab_focus() diff --git a/game/menu/completion_menu.gd.uid b/game/menu/completion_menu.gd.uid new file mode 100644 index 0000000..5a11070 --- /dev/null +++ b/game/menu/completion_menu.gd.uid @@ -0,0 +1 @@ +uid://xoischtv2dir diff --git a/game/menu/completion_menu.tscn b/game/menu/completion_menu.tscn new file mode 100644 index 0000000..c439298 --- /dev/null +++ b/game/menu/completion_menu.tscn @@ -0,0 +1,70 @@ +[gd_scene format=3 uid="uid://dbnpcpwbw7f8q"] + +[ext_resource type="Theme" uid="uid://bqj884yfvhhft" path="res://game/themes/main_menu.tres" id="1_xuusr"] +[ext_resource type="Script" uid="uid://xoischtv2dir" path="res://game/menu/completion_menu.gd" id="2_0iv8v"] + +[sub_resource type="Environment" id="Environment_0iv8v"] +background_mode = 3 +tonemap_mode = 3 +glow_enabled = true +glow_intensity = 4.0 +glow_hdr_threshold = 0.5 +glow_hdr_scale = 4.0 + +[node name="CompletionMenu" type="Control" unique_id=1435656270] +process_mode = 2 +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme = ExtResource("1_xuusr") +script = ExtResource("2_0iv8v") + +[node name="ColorRect" type="ColorRect" parent="." unique_id=1975928285] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.19607843, 0.19215687, 0.23137255, 1) + +[node name="MarginContainer" type="MarginContainer" parent="." unique_id=14906773] +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" unique_id=736609031] +layout_mode = 2 +alignment = 1 + +[node name="Label" type="Label" parent="MarginContainer/VBoxContainer" unique_id=74970990] +layout_mode = 2 +text = "COMPLETED!" +horizontal_alignment = 1 + +[node name="NextLevelButton" type="Button" parent="MarginContainer/VBoxContainer" unique_id=240104273] +unique_name_in_owner = true +layout_mode = 2 +text = "NEXT LEVEL" + +[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer" unique_id=585564250] +unique_name_in_owner = true +layout_mode = 2 +text = "MAIN MENU" + +[node name="FocusTimer" type="Timer" parent="." unique_id=416713934] +one_shot = true + +[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=885590829] +environment = SubResource("Environment_0iv8v") + +[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/MainMenuButton" to="." method="_on_main_menu_button_pressed"] +[connection signal="timeout" from="FocusTimer" to="." method="_on_focus_timer_timeout"] diff --git a/game/menu/level_selection.gd b/game/menu/level_selection.gd new file mode 100644 index 0000000..2e003f0 --- /dev/null +++ b/game/menu/level_selection.gd @@ -0,0 +1,38 @@ +class_name LevelSelection +extends Control + + +@onready var grid : GridContainer = $%GridContainer + + +func _ready() -> void: + for i in range(LevelManager.levels.size()): + var level := LevelManager.levels[i] + 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)) + + if i == 0: + button.grab_focus() + + get_viewport().gui_focus_changed.connect(_on_gui_focus_changed) + + +func _on_gui_focus_changed(_node: Control) -> void: + SoundManager.play_ui_stream(SoundManager.ui_stream_select) + + +func _on_level_selected(index: int, level: PackedScene) -> void: + SoundManager.play_ui_stream(SoundManager.ui_stream_accept) + LevelManager.current_level_index = index + get_tree().change_scene_to_packed(level) + + +func _on_main_menu_button_pressed() -> void: + SoundManager.play_ui_stream(SoundManager.ui_stream_decline) + get_tree().change_scene_to_file("res://game/menu/main_menu.tscn") diff --git a/game/menu/level_selection.gd.uid b/game/menu/level_selection.gd.uid new file mode 100644 index 0000000..d706d75 --- /dev/null +++ b/game/menu/level_selection.gd.uid @@ -0,0 +1 @@ +uid://cjakr7gskefp4 diff --git a/game/menu/level_selection.tscn b/game/menu/level_selection.tscn new file mode 100644 index 0000000..1c64fbb --- /dev/null +++ b/game/menu/level_selection.tscn @@ -0,0 +1,40 @@ +[gd_scene format=3 uid="uid://br21ln0ol0745"] + +[ext_resource type="Theme" uid="uid://bqj884yfvhhft" path="res://game/themes/main_menu.tres" id="1_5cn0b"] +[ext_resource type="Script" uid="uid://cjakr7gskefp4" path="res://game/menu/level_selection.gd" id="2_3oqjo"] + +[node name="LevelSelection" type="Control" unique_id=1026459282] +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("2_3oqjo") + +[node name="MarginContainer" type="MarginContainer" parent="." unique_id=598516023] +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" unique_id=1523206303] +layout_mode = 2 +alignment = 1 + +[node name="GridContainer" type="GridContainer" parent="MarginContainer/VBoxContainer" unique_id=2020347789] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 4 + +[node name="Control" type="Control" parent="MarginContainer/VBoxContainer" unique_id=741081620] +layout_mode = 2 + +[node name="MainMenuButton" type="Button" parent="MarginContainer/VBoxContainer" unique_id=1148321937] +layout_mode = 2 +text = "MAIN MENU" + +[connection signal="pressed" from="MarginContainer/VBoxContainer/MainMenuButton" to="." method="_on_main_menu_button_pressed"] diff --git a/game/menu/main_menu.gd b/game/menu/main_menu.gd index 96810d8..a2f3c69 100644 --- a/game/menu/main_menu.gd +++ b/game/menu/main_menu.gd @@ -31,7 +31,7 @@ func _on_gui_focus_changed(_node: Control) -> void: func _on_start_button_pressed() -> void: SoundManager.play_ui_stream(SoundManager.ui_stream_accept) - get_tree().change_scene_to_file("res://game/levels/test_level.tscn") + get_tree().change_scene_to_file("res://game/menu/level_selection.tscn") func _on_options_button_pressed() -> void: diff --git a/project.godot b/project.godot index e244079..a832acd 100644 --- a/project.godot +++ b/project.godot @@ -25,6 +25,8 @@ buses/default_bus_layout="uid://c2chib4gm7ni4" SoundManager="*uid://b5wqc1hgwcdm4" SettingsManager="*uid://cuyv26utj07j4" HitstopManager="*uid://ba262w3ebkyo1" +LevelManager="*uid://bk2pkmgxsgars" +SaveManager="*uid://2pbgcr5yk7iy" [debug] diff --git a/sound/sfx/level_completed.wav b/sound/sfx/level_completed.wav new file mode 100644 index 0000000..fcd085c --- /dev/null +++ b/sound/sfx/level_completed.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:454a918f718216f1194322708b4498aa3a7bd2627d5103dd43e1776751f96aa4 +size 81796 diff --git a/sound/sfx/level_completed.wav.import b/sound/sfx/level_completed.wav.import new file mode 100644 index 0000000..14226b8 --- /dev/null +++ b/sound/sfx/level_completed.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://mwornwi1s000" +path="res://.godot/imported/level_completed.wav-07dcc83a0c57c107eb67698e1bebcccb.sample" + +[deps] + +source_file="res://sound/sfx/level_completed.wav" +dest_files=["res://.godot/imported/level_completed.wav-07dcc83a0c57c107eb67698e1bebcccb.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=0 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=2