diff --git a/index.tscn b/index.tscn index eff4230..75882ae 100644 --- a/index.tscn +++ b/index.tscn @@ -45,14 +45,15 @@ func set_main_menu(): main_menu.connect(\"request_play_level\", start_level) add_child(main_menu) -func start_level(level_scene: PackedScene) -> void: +func start_level(level: Level) -> void: if is_instance_valid(current_level): current_level.queue_free() if is_instance_valid(main_menu): main_menu.queue_free() - current_level = level_scene.instantiate() + current_level = level add_child(current_level) + current_level.connect(\"completed\", finish_current_level) current_level.connect(\"ring_collected\", func(): gui_rings.remaining_rings = len(current_level.rings) - current_level.finished_rings_count diff --git a/levels/forest/level.tscn b/levels/forest/level.tscn index e12a221..e9763f3 100644 --- a/levels/forest/level.tscn +++ b/levels/forest/level.tscn @@ -10,8 +10,18 @@ [sub_resource type="GDScript" id="GDScript_mqwxc"] script/source = "extends Level +var cycle := 0 + func _init() -> void: self.id = \"forest\" + self.thumbnail = load(\"res://levels/forest/thumbnail.png\") + +func _process(_delta: float) -> void: + var moving_ring: Ring = $Rings/Ring18 + if !moving_ring.collected: + if moving_ring.position.y < 55 or moving_ring.position.y > 65: + cycle += 1 + moving_ring.position.y += 0.5 if cycle % 2 else -0.5 func _on_player_velocity_change(new_velocity: float) -> void: self.velocity = new_velocity diff --git a/levels/forest/thumbnail.png b/levels/forest/thumbnail.png new file mode 100644 index 0000000..07c40d6 Binary files /dev/null and b/levels/forest/thumbnail.png differ diff --git a/levels/forest/thumbnail.png.import b/levels/forest/thumbnail.png.import new file mode 100644 index 0000000..01c5a71 --- /dev/null +++ b/levels/forest/thumbnail.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhyxogc13hnbe" +path="res://.godot/imported/thumbnail.png-6909560b6205778a3cb325a584af7ca5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://levels/forest/thumbnail.png" +dest_files=["res://.godot/imported/thumbnail.png-6909560b6205778a3cb325a584af7ca5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/levels/level.gd b/levels/level.gd index 2d386b7..36bd750 100644 --- a/levels/level.gd +++ b/levels/level.gd @@ -6,13 +6,16 @@ signal completed ## Lowercase, spaceless name of the level var id: String +var thumbnail: CompressedTexture2D var music: Music -var velocity: float = 0.0 var rings: Array[Ring] = [] var finished_rings_count: int = 0 +var velocity: float = 0.0 + +func _init() -> void: + assert(len(id) > 0, self.name + " has no id!") func _ready() -> void: - assert(len(id) > 0, self.name + " has no id!") var children = get_children() for child in children: if is_instance_of(child, Music): diff --git a/menus/main/level_selection_menu.tscn b/menus/main/level_selection_menu.tscn index 45b6a11..152645d 100644 --- a/menus/main/level_selection_menu.tscn +++ b/menus/main/level_selection_menu.tscn @@ -5,19 +5,56 @@ script/source = "extends Control signal request_play_level +@onready var carousel := $VBoxContainer/Selection/Carousel +@onready var label_time := $VBoxContainer/Presentation/MarginContainer/VBoxContainer/BestTime const levels = [ - preload(\"res://levels/base/level.tscn\"), - preload(\"res://levels/forest/level.tscn\"), - preload(\"res://levels/night/level.tscn\"), + \"res://levels/base/level.tscn\", + \"res://levels/forest/level.tscn\", + \"res://levels/night/level.tscn\", ] -var selected_level := -1 +var loaded_level: Level func _ready() -> void: + var placeholders := carousel.get_children() + for placeholder in placeholders: + placeholder.queue_free() + for i in len(levels): var btn := Button.new() btn.text = \"Level \" + str(i + 1) - btn.connect(\"pressed\", func(): request_play_level.emit(levels[i])) - $VBoxContainer/Carousel.add_child(btn) + btn.connect(\"pressed\", func(): prepare_level(levels[i])) + carousel.add_child(btn) + +func prepare_level(level_scene_path: String): + if is_instance_valid(loaded_level): + loaded_level.queue_free() + + ResourceLoader.load_threaded_request(level_scene_path) + var level_scene = ResourceLoader.load_threaded_get(level_scene_path) + loaded_level = level_scene.instantiate() + $VBoxContainer/Presentation/Thumbnail.texture = loaded_level.thumbnail + $VBoxContainer/Presentation/MarginContainer/VBoxContainer/LevelName.text = \"The \" + loaded_level.id.capitalize() + $VBoxContainer/Presentation.show() + $VBoxContainer/MarginContainer/PlayButton.show() + display_file_data(SaveFiles.read(SaveFiles.selected_file)) + +func display_file_data(data: Variant) -> void: + label_time.text = \"Best time: \" + var property_name := loaded_level.id + \"_best_time\" + if data.has(property_name) and data[property_name] is float: + var seconds: float = data[property_name] + var minutes: int = floor(seconds / 60) + label_time.text += (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)]) + else: + label_time.text += \"00:00.000\" + +func _on_play_button_pressed() -> void: + if is_instance_valid(loaded_level): + request_play_level.emit(loaded_level) + +func seconds_to_readable(seconds: float) -> String: + var minutes: int = floor(seconds / 60) + return (\"%0*d\" % [2, minutes]) + \":\" + (\"%0*.3f\" % [6, seconds - (minutes * 60)]) " [node name="LevelSelectionMenu" type="Control"] @@ -37,6 +74,62 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="Carousel" type="HBoxContainer" parent="VBoxContainer"] +[node name="Selection" type="ScrollContainer" parent="VBoxContainer"] +custom_minimum_size = Vector2(0, 50) +layout_mode = 2 + +[node name="Carousel" type="HBoxContainer" parent="VBoxContainer/Selection"] +layout_mode = 2 +size_flags_horizontal = 3 +theme_override_constants/separation = 10 +alignment = 1 + +[node name="Placeholder1" type="Button" parent="VBoxContainer/Selection/Carousel"] +layout_mode = 2 +theme_override_constants/icon_max_width = 150 +text = "Placeholder" + +[node name="Placeholder2" type="Button" parent="VBoxContainer/Selection/Carousel"] +layout_mode = 2 +text = "Placeholder" + +[node name="Placeholder3" type="Button" parent="VBoxContainer/Selection/Carousel"] +layout_mode = 2 +text = "Placeholder" + +[node name="Presentation" type="HBoxContainer" parent="VBoxContainer"] +visible = false +layout_mode = 2 + +[node name="Thumbnail" type="TextureRect" parent="VBoxContainer/Presentation"] +custom_minimum_size = Vector2(150, 150) +layout_mode = 2 +expand_mode = 1 +stretch_mode = 4 + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/Presentation"] +layout_mode = 2 +theme_override_constants/margin_left = 5 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/Presentation/MarginContainer"] layout_mode = 2 alignment = 1 + +[node name="LevelName" type="Label" parent="VBoxContainer/Presentation/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Placeholder" + +[node name="BestTime" type="Label" parent="VBoxContainer/Presentation/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Best time: 00:00.000" + +[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"] +layout_mode = 2 +theme_override_constants/margin_top = 15 + +[node name="PlayButton" type="Button" parent="VBoxContainer/MarginContainer"] +visible = false +layout_mode = 2 +text = "Play!" + +[connection signal="pressed" from="VBoxContainer/MarginContainer/PlayButton" to="." method="_on_play_button_pressed"] diff --git a/menus/main/main_menu.tscn b/menus/main/main_menu.tscn index 87a94da..7437b53 100644 --- a/menus/main/main_menu.tscn +++ b/menus/main/main_menu.tscn @@ -38,7 +38,7 @@ func start() -> void: const res_level_selection_menu = preload(\"res://menus/main/level_selection_menu.tscn\") func level_selection() -> void: var level_selection_menu := res_level_selection_menu.instantiate() - level_selection_menu.connect(\"request_play_level\", func(level: PackedScene): request_play_level.emit(level)) + level_selection_menu.connect(\"request_play_level\", func(level: Level): request_play_level.emit(level)) $Menus/Panel3.change_menu(level_selection_menu) rotate_cube_to(180)