From aaea76d6d48b6758be0dea1701489b18a00ca1f5 Mon Sep 17 00:00:00 2001 From: theludovyc Date: Sun, 29 Sep 2024 13:50:18 +0200 Subject: [PATCH] fix #17 Create class SaveHelper to helps saving data in a JSON file Handle save in PauseMenu - Create a save button - Handle SaveButton press - Take a screenshot and make a save when press the button - Show a confirm popup when saved Make the LoadSaveMenu - load saves from this menu Update the LoadSaveMenu, add it to the MainMenu - Create the SaveContainer, with a screenshot, a name, buttons to load and delete the save - Update the SaveHelper to get the save_file_names In the LoadSaveMenu, handle the load button from the SavePanelContainer - when click on the load button open a confirmation popup If yes, save the save_file_name to load and change scene Handle save/load properly - PauseMenu ask Game to save - Game save the PauseChecker sprite rotation - Decrease speed of the PauseChecker to see more if the load works or not - In Game, if SaveHelper.save_file_name_to_load is not empty load the PauseChecker rotation and assign it - In MainMenu, when press the play button reset save_file_name_to_load In SaveHelper, replace get_save_file_names by update_save_file_names - Avoid multiples disc access - Permit to know if saves exist - Show/Hide LoadButton in MainMenu in consequences In MainMenu, add ContinueButton In LoadSaveMenu, handle the deletion - Handle the deletion of the save file and the save screenshot - Update SaveHelper to defete a save file and get needed paths In MainMenu, handle delete last save in LoadMenu - When delete last available save in LoadMenu close LoadMenu and hide ContinueButton and LoadButton --- .../scripts/SaveHelper.gd | 187 ++++++++++++++++++ scenes/Game/Sprite2D.gd | 2 +- scenes/Game/game.gd | 17 ++ scenes/Game/game.tscn | 1 + scenes/LoadSaveMenu/loadSaveMenu.tscn | 21 ++ scenes/LoadSaveMenu/load_save_menu.gd | 85 ++++++++ scenes/LoadSaveMenu/savePanelContainer.tscn | 49 +++++ scenes/LoadSaveMenu/save_panel_container.gd | 22 +++ scenes/MainMenu/MainMenu.gd | 36 +++- scenes/MainMenu/MainMenu.tscn | 24 ++- scenes/PauseMenu/PauseMenu.gd | 42 ++++ scenes/PauseMenu/PauseMenu.tscn | 11 ++ 12 files changed, 493 insertions(+), 4 deletions(-) create mode 100644 addons/rakugo_game_template/scripts/SaveHelper.gd create mode 100644 scenes/LoadSaveMenu/loadSaveMenu.tscn create mode 100644 scenes/LoadSaveMenu/load_save_menu.gd create mode 100644 scenes/LoadSaveMenu/savePanelContainer.tscn create mode 100644 scenes/LoadSaveMenu/save_panel_container.gd diff --git a/addons/rakugo_game_template/scripts/SaveHelper.gd b/addons/rakugo_game_template/scripts/SaveHelper.gd new file mode 100644 index 0000000..869f379 --- /dev/null +++ b/addons/rakugo_game_template/scripts/SaveHelper.gd @@ -0,0 +1,187 @@ +extends Object +class_name SaveHelper +## Helps to save data in [JSON] format +## +## Here is a sample on how to save data: +## [codeblock] +## var data_to_save := {"something":"Something"} +## if SaveHelper.save(data_to_save) != OK: +## push_error("Cannot save data") +## [/codeblock] +## And how to load and use them: +## [codeblock] +## SaveHelper.update_save_file_names() +## +## if SaveHelper.load_last_save() != OK: +## push_error("Cannot load data") +## var something := SaveHelper.last_saved_data["something"] +## [/codeblock] + + +## where the data will be saved +const save_dir_path = "user://saves" + +## to avoid errors +const json_extension = "json" + +## updated with SaveHelper.update_save_files_names [br] +## saved here to avoid multiples disk access [br] +## after update it, can be used to check if save(s) exist or not [br] +## should be clear with SaveHelper.clear_save_files_names to avoid +## memory consumption +static var save_file_names:PackedStringArray + +## the last saved file name without extension .json +static var last_saved_file_name := "" + +## use it to save the file_name to load between scenes +static var save_file_name_to_load := "" + +## last loaded data [br] +## empty [Dictionary] by default +static var last_loaded_data:Dictionary = {} + +## save data in a file [br] +## the file will be created in save_dir_path [br] +## the file_name will be generated from the systemTime in local time [br] +## the file_name name will look like YYYY-MM-DDTHH:MM:SS.json [br] +## yes, the user can modify his system time, so you can use this feature and/or create easter-eggs [br] +## if cannot create saves directory return ERR_CANT_CREATE [br] +## if cannot create and write in the save file return ERR_FILE_CANT_WRITE [br] +## return OK in other cases +static func save(data:Dictionary) -> Error: + if not DirAccess.dir_exists_absolute(save_dir_path): + if DirAccess.make_dir_absolute(save_dir_path) != OK: + push_error("Cannot create saves directory in user://") + return ERR_CANT_CREATE + + var file_name := Time.get_datetime_string_from_system() + + var file := FileAccess.open(save_dir_path + "/" + file_name + "." + json_extension, FileAccess.WRITE) + if file == null: + push_error("Cannot create the save file in " + save_dir_path) + return ERR_FILE_CANT_WRITE + + var json_data = JSON.stringify(data) + + file.store_string(json_data) + + last_saved_file_name = file_name + + return OK + +## return a file_path into the save directory from the file_name [br] +## if file_name is empty return empty String [br] +## if the extension .json is missing it will be added +static func get_save_file_path(file_name:String) -> String: + if file_name.is_empty(): + return "" + + if not file_name.get_extension() == json_extension: + file_name += "." + json_extension + + return save_dir_path + "/" + file_name + +## return a file_path into the save directory from the file_name [br] +## if the extension .json is present it will be removed +## if file_name is empty return empty String +static func get_save_file_path_without_extension(file_name:String) -> String: + if file_name.is_empty(): + return "" + + return save_dir_path + "/" + file_name.trim_suffix("." + json_extension) + +## load data from file [br] +## file_name should looks like YYYY-MM-DDTHH:MM:SS.json [br] +## if file_name is empty return ERR_INVALID_PARAMETER [br] +## if the extension .json is missing it will be added [br] +## if the file cannot be opened and read return ERR_FILE_CANT_READ [br] +## if the file cannot be parsed to [JSON] return ERR_INVALID_DATA [br] +## return OK in other cases and save the parsed result in last_loaded_data +static func load(file_name:String) -> Error: + if file_name.is_empty(): + push_warning("file_name is empty !") + return ERR_INVALID_PARAMETER + + var file_path := get_save_file_path(file_name) + + var file := FileAccess.open(file_path, FileAccess.READ) + if file == null: + push_error("Cannot open the save file: " + file_path) + return ERR_FILE_CANT_READ + + var json_data := file.get_as_text(true) + + var parsed_json = JSON.parse_string(json_data) + + if parsed_json == null: + last_loaded_data = {} + + push_error("Cannot parse to json the save file") + return ERR_INVALID_DATA + + last_loaded_data = parsed_json + + return OK + +## Call SaveHelper.load(save_file_name_to_load) [br] +## if save_file_name_to_load is empty return ERR_INVALID_PARAMETER +static func load_saved_file_name() -> Error: + return SaveHelper.load(save_file_name_to_load) + +## warning, make disk access, avoid multiples use [br] +## set SaveHelper.save_file_names +static func update_save_file_names() -> Error: + var dirAccess := DirAccess.open(save_dir_path) + if dirAccess == null: + push_warning("Cannot open the save directory") + return FAILED + + save_file_names.clear() + + dirAccess.list_dir_begin() + + var file_name = dirAccess.get_next() + + while not file_name.is_empty(): + if not dirAccess.current_is_dir() \ + and file_name.get_extension() == json_extension: + save_file_names.push_back(file_name.left(file_name.rfind("."))) + + file_name = dirAccess.get_next() + + if not save_file_names.is_empty(): + save_file_names.sort() + + return OK + +## set SaveHelper.save_file_name_to_load with last saved name [br] +## if save_files_names is empty return ERR_DOES_NOT_EXIST [br] +## return OK in other cases +static func update_with_last_saved_name() -> Error: + if save_file_names.is_empty(): + push_warning("No save to load") + return ERR_DOES_NOT_EXIST + + save_file_name_to_load = save_file_names[-1] + + return OK + +## move to trash the save file [br] +## file_name should looks like YYYY-MM-DDTHH:MM:SS.json [br] +## if file_name is empty return ERR_INVALID_PARAMETER [br] +## if the extension .json is missing it will be added [br] +## if the file cannot be found return ERR_FILE_NOT_FOUND [br] +## return OS.move_to_trash(...) in other cases +static func delete(file_name:String) -> Error: + if file_name.is_empty(): + push_warning("file_name is empty !") + return ERR_INVALID_PARAMETER + + var file_path := get_save_file_path(file_name) + + if not FileAccess.file_exists(file_path): + push_error("Cannot found the save file: " + file_path) + return ERR_FILE_NOT_FOUND + + return OS.move_to_trash(ProjectSettings.globalize_path(file_path)) diff --git a/scenes/Game/Sprite2D.gd b/scenes/Game/Sprite2D.gd index 60235ee..65c24d5 100644 --- a/scenes/Game/Sprite2D.gd +++ b/scenes/Game/Sprite2D.gd @@ -4,5 +4,5 @@ extends Sprite2D #I permit to see if the pause is effective func _process(delta): - rotate(delta) + rotate(delta / 2.0) pass diff --git a/scenes/Game/game.gd b/scenes/Game/game.gd index 3e56b66..49b202c 100644 --- a/scenes/Game/game.gd +++ b/scenes/Game/game.gd @@ -4,6 +4,18 @@ class_name Game @onready var pause_menu = %PauseMenu @onready var end_menu = %EndMenu +@onready var pause_checker_sprite = $PauseChecker + +func _ready() -> void: + if SaveHelper.save_file_name_to_load.is_empty(): + return + + if not SaveHelper.load_saved_file_name() == OK: + return + + pause_checker_sprite.rotation = \ + SaveHelper.last_loaded_data.get("pause_checker_sprite_rot", 0) + func _process(_delta): if pause_menu.visible == false and Input.is_action_just_pressed("ui_cancel"): pause_menu.show() @@ -19,3 +31,8 @@ func _on_gameover(): end_menu.set_gameover() end_menu.show() get_tree().paused = true + +func _on_pause_menu_ask_to_save() -> void: + pause_menu.save_this_please({ + "pause_checker_sprite_rot":pause_checker_sprite.rotation + }) diff --git a/scenes/Game/game.tscn b/scenes/Game/game.tscn index 77e76f5..d2c35df 100644 --- a/scenes/Game/game.tscn +++ b/scenes/Game/game.tscn @@ -56,5 +56,6 @@ position = Vector2(637, 143) texture = ExtResource("3_6luik") script = ExtResource("4_lltyx") +[connection signal="ask_to_save" from="GUI/PauseMenu" to="." method="_on_pause_menu_ask_to_save"] [connection signal="pressed" from="RemoveMe/HBoxContainer/WinButton" to="." method="_on_win"] [connection signal="pressed" from="RemoveMe/HBoxContainer/LooseButton" to="." method="_on_gameover"] diff --git a/scenes/LoadSaveMenu/loadSaveMenu.tscn b/scenes/LoadSaveMenu/loadSaveMenu.tscn new file mode 100644 index 0000000..aa28ac2 --- /dev/null +++ b/scenes/LoadSaveMenu/loadSaveMenu.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=2 format=3 uid="uid://choevp6ilq78t"] + +[ext_resource type="Script" path="res://scenes/LoadSaveMenu/load_save_menu.gd" id="1_nyk5l"] + +[node name="LoadSaveMenu" type="ScrollContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +horizontal_scroll_mode = 0 +script = ExtResource("1_nyk5l") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] +unique_name_in_owner = true + +[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_confirmation_dialog_confirmed"] diff --git a/scenes/LoadSaveMenu/load_save_menu.gd b/scenes/LoadSaveMenu/load_save_menu.gd new file mode 100644 index 0000000..46aa67a --- /dev/null +++ b/scenes/LoadSaveMenu/load_save_menu.gd @@ -0,0 +1,85 @@ +extends ScrollContainer + +signal no_save_to_load + +const confirm_load = "Are you sure you want to load this save?\n" +const confirm_delete = "Are you sure you want to delete this save ?\n" + +var SavePanel = preload("res://scenes/LoadSaveMenu/savePanelContainer.tscn") + +@onready var vbox_container = $VBoxContainer + +@onready var confirm_dialog = %ConfirmationDialog + +enum Modes{ + Loading, + Deleting +} + +var popup_mode = Modes.Loading +var current_save_file_name:String = "" +var current_save_panel:Node = null + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + if SaveHelper.save_file_names.is_empty(): + SaveHelper.update_save_file_names() + + if SaveHelper.save_file_names.is_empty(): + push_warning("No save to load") + pass + + for save_file_name in SaveHelper.save_file_names: + var save_panel = SavePanel.instantiate() + + vbox_container.add_child(save_panel) + + save_panel.init(save_file_name) + + save_panel.load_button.pressed.connect(_on_load_button_pressed.bind(save_file_name)) + save_panel.delete_button.pressed.connect( + _on_delete_button_pressed.bind(save_panel, save_file_name)) + +func _on_load_button_pressed(save_file_name:String): + popup_mode = Modes.Loading + + current_save_file_name = save_file_name + + confirm_dialog.dialog_text = confirm_load + save_file_name + + confirm_dialog.popup_centered() + +func _on_delete_button_pressed(save_panel:Node, save_file_name:String): + popup_mode = Modes.Deleting + + current_save_file_name = save_file_name + + current_save_panel = save_panel + + confirm_dialog.dialog_text = confirm_delete + save_file_name + + confirm_dialog.popup_centered() + +func _on_confirmation_dialog_confirmed() -> void: + match(popup_mode): + Modes.Loading: + SaveHelper.save_file_name_to_load = current_save_file_name + + SceneLoader.change_scene(RGT_Globals.first_game_scene_setting) + + Modes.Deleting: + SaveHelper.delete(current_save_file_name) + + # move to trash the screenshot + OS.move_to_trash( + ProjectSettings.globalize_path( + SaveHelper.get_save_file_path_without_extension(current_save_file_name) + ".png" + )) + + SaveHelper.update_save_file_names() + + if SaveHelper.save_file_names.is_empty(): + no_save_to_load.emit() + + current_save_panel.queue_free() + diff --git a/scenes/LoadSaveMenu/savePanelContainer.tscn b/scenes/LoadSaveMenu/savePanelContainer.tscn new file mode 100644 index 0000000..bb418d8 --- /dev/null +++ b/scenes/LoadSaveMenu/savePanelContainer.tscn @@ -0,0 +1,49 @@ +[gd_scene load_steps=2 format=3 uid="uid://wal8k0gos06y"] + +[ext_resource type="Script" path="res://scenes/LoadSaveMenu/save_panel_container.gd" id="1_np60c"] + +[node name="SavePanelContainer" type="PanelContainer"] +script = ExtResource("1_np60c") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 2 +theme_override_constants/margin_left = 12 +theme_override_constants/margin_top = 12 +theme_override_constants/margin_right = 12 +theme_override_constants/margin_bottom = 12 + +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"] +layout_mode = 2 +theme_override_constants/separation = 8 + +[node name="SaveTextureRect" type="TextureRect" parent="MarginContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 4 +expand_mode = 5 +stretch_mode = 5 + +[node name="NameLabel" type="Label" parent="MarginContainer/HBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(8, 8) +layout_mode = 2 +size_flags_horizontal = 3 +horizontal_alignment = 1 +vertical_alignment = 1 +autowrap_mode = 1 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HBoxContainer"] +layout_mode = 2 +size_flags_vertical = 4 +alignment = 1 + +[node name="LoadButton" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Load" + +[node name="DeleteButton" type="Button" parent="MarginContainer/HBoxContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Delete" diff --git a/scenes/LoadSaveMenu/save_panel_container.gd b/scenes/LoadSaveMenu/save_panel_container.gd new file mode 100644 index 0000000..4dc6ae5 --- /dev/null +++ b/scenes/LoadSaveMenu/save_panel_container.gd @@ -0,0 +1,22 @@ +extends PanelContainer + +@onready var name_label = %NameLabel +@onready var save_texture = %SaveTextureRect +@onready var load_button = %LoadButton +@onready var delete_button = %DeleteButton + +func init(save_name:String): + name_label.text = save_name + + var image_path := SaveHelper.save_dir_path + "/" + save_name + ".png" + + if not FileAccess.file_exists(image_path): + return + + var image := Image.load_from_file(image_path) + + if image == null: + return + + save_texture.texture = ImageTexture.create_from_image(image) + diff --git a/scenes/MainMenu/MainMenu.gd b/scenes/MainMenu/MainMenu.gd index 33e092b..f70d197 100644 --- a/scenes/MainMenu/MainMenu.gd +++ b/scenes/MainMenu/MainMenu.gd @@ -8,12 +8,22 @@ var sub_menu @onready var header_margin = $VBoxContainer/HeaderMargin +@onready var continue_button = %ContinueButton @onready var play_button = %PlayButton +@onready var load_button = %LoadButton @onready var option_button = %OptionsButton @onready var credit_button = %CreditsButton @onready var exit_button = %ExitButton -@onready var menu_button_list = [play_button,option_button,credit_button,exit_button] - +@onready var menu_button_list = [ + continue_button, + play_button, + load_button, + option_button, + credit_button, + exit_button +] + +@onready var load_save_menu = %LoadSaveMenu @onready var option_menu = %OptionsMenu @onready var credit_menu = %CreditsContainer @@ -64,10 +74,26 @@ func _ready(): if RGT_Globals.loading_scene_setting.is_empty(): play_button.hide() + + SaveHelper.update_save_file_names() + + if SaveHelper.save_file_names.is_empty(): + continue_button.hide() + load_button.hide() + +func _on_continue_button_pressed() -> void: + SaveHelper.update_with_last_saved_name() + + SceneLoader.change_scene(RGT_Globals.first_game_scene_setting) func _on_play_button_pressed(): + SaveHelper.save_file_name_to_load = "" + SceneLoader.change_scene(RGT_Globals.first_game_scene_setting) +func _on_load_button_pressed() -> void: + _open_sub_menu(load_save_menu) + func _on_options_button_pressed(): _open_sub_menu(option_menu) @@ -82,3 +108,9 @@ func _on_exit_confirmed(): func _on_back_button_pressed(): _close_sub_menu() + +func _on_load_save_menu_no_save_to_load() -> void: + continue_button.hide() + load_button.hide() + + _close_sub_menu() diff --git a/scenes/MainMenu/MainMenu.tscn b/scenes/MainMenu/MainMenu.tscn index 2816aa8..7b92584 100644 --- a/scenes/MainMenu/MainMenu.tscn +++ b/scenes/MainMenu/MainMenu.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=5 format=3 uid="uid://c6k5nnpbypshi"] +[gd_scene load_steps=6 format=3 uid="uid://c6k5nnpbypshi"] [ext_resource type="Script" path="res://scenes/MainMenu/MainMenu.gd" id="1"] [ext_resource type="PackedScene" uid="uid://t2dui8ppm3a4" path="res://scenes/Credits/Credits.tscn" id="3_5dhvp"] [ext_resource type="PackedScene" uid="uid://bkcsjsk2ciff" path="res://addons/rakugo_game_template/MusicPlayers/BackgroundMusicPlayer.tscn" id="4_w8sbm"] +[ext_resource type="PackedScene" uid="uid://choevp6ilq78t" path="res://scenes/LoadSaveMenu/loadSaveMenu.tscn" id="5_mfpq2"] [ext_resource type="PackedScene" uid="uid://djnvp4x64ukay" path="res://scenes/OptionsMenu/OptionsContainer.tscn" id="6_ky335"] [node name="MainMenu" type="Control"] @@ -96,12 +97,24 @@ size_flags_horizontal = 4 theme_override_constants/separation = 16 alignment = 1 +[node name="ContinueButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons"] +unique_name_in_owner = true +layout_mode = 2 +text = "Continue" +alignment = 0 + [node name="PlayButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons"] unique_name_in_owner = true layout_mode = 2 text = "Play" alignment = 0 +[node name="LoadButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons"] +unique_name_in_owner = true +layout_mode = 2 +text = "Load" +alignment = 0 + [node name="OptionsButton" type="Button" parent="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons"] unique_name_in_owner = true layout_mode = 2 @@ -150,11 +163,20 @@ theme_override_constants/margin_bottom = 8 [node name="OptionsContainer" parent="VBoxContainer/MarginContainer/HBoxContainer/OptionsMenu/MarginContainer" instance=ExtResource("6_ky335")] layout_mode = 2 +[node name="LoadSaveMenu" parent="VBoxContainer/MarginContainer/HBoxContainer" instance=ExtResource("5_mfpq2")] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 3 + [node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] unique_name_in_owner = true dialog_text = "Quit the Game ?" +[connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons/ContinueButton" to="." method="_on_continue_button_pressed"] [connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons/PlayButton" to="." method="_on_play_button_pressed"] +[connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons/LoadButton" to="." method="_on_load_button_pressed"] [connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons/OptionsButton" to="." method="_on_options_button_pressed"] [connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons/CreditsButton" to="." method="_on_credits_button_pressed"] [connection signal="pressed" from="VBoxContainer/MarginContainer/HBoxContainer/MenuButtons/ExitButton" to="." method="_on_exit_button_pressed"] +[connection signal="no_save_to_load" from="VBoxContainer/MarginContainer/HBoxContainer/LoadSaveMenu" to="." method="_on_load_save_menu_no_save_to_load"] diff --git a/scenes/PauseMenu/PauseMenu.gd b/scenes/PauseMenu/PauseMenu.gd index 3d9194f..562bcfb 100644 --- a/scenes/PauseMenu/PauseMenu.gd +++ b/scenes/PauseMenu/PauseMenu.gd @@ -1,5 +1,7 @@ extends Control +signal ask_to_save + const confirm_menu = "Go back to Main Menu ?" const confirm_restart = "Restart the Game ?" const confirm_quit = "Quit the Game ?" @@ -7,6 +9,10 @@ const confirm_quit = "Quit the Game ?" @onready var confirm_dialog = %ConfirmDialog @onready var sub_menu_container = %SubMenuContainer @onready var resume_button = %ResumeButton +@onready var save_button = %SaveButton + +@onready var accept_dialog = %AcceptDialog +@onready var accept_dialog_ok_button = accept_dialog.get_ok_button() func _process(_delta): if visible and Input.is_action_just_pressed("ui_cancel"): @@ -51,3 +57,39 @@ func _on_confirm_exit_confirmed(): func _on_back_button_pressed(): sub_menu_container.hide() + +func _on_save_button_pressed() -> void: + save_button.disabled = true + + accept_dialog.dialog_text = "Saving..." + + accept_dialog_ok_button.disabled = true + + accept_dialog.popup_centered() + + ask_to_save.emit() + +func save_this_please(data:Dictionary): + if SaveHelper.save(data) == OK: + accept_dialog.hide() + hide() + + #Take screenshot and save it + await RenderingServer.frame_post_draw + get_viewport().get_texture().get_image().save_png( + SaveHelper.get_save_file_path_without_extension( + SaveHelper.last_saved_file_name + ) + ".png" + ) + + show() + accept_dialog.popup_centered() + + accept_dialog.dialog_text = "The game is saved !" + else: + accept_dialog.dialog_text = "Cannot save the game !" + + accept_dialog_ok_button.disabled = false + +func _on_accept_dialog_confirmed() -> void: + save_button.disabled = false diff --git a/scenes/PauseMenu/PauseMenu.tscn b/scenes/PauseMenu/PauseMenu.tscn index 901756f..d5b3c0f 100644 --- a/scenes/PauseMenu/PauseMenu.tscn +++ b/scenes/PauseMenu/PauseMenu.tscn @@ -57,6 +57,12 @@ custom_minimum_size = Vector2(128, 40) layout_mode = 2 text = "Resume" +[node name="SaveButton" type="Button" parent="MenuContainer/VBoxContainer/MenuButtons"] +unique_name_in_owner = true +custom_minimum_size = Vector2(128, 40) +layout_mode = 2 +text = "Save" + [node name="RestartButton" type="Button" parent="MenuContainer/VBoxContainer/MenuButtons"] custom_minimum_size = Vector2(128, 40) layout_mode = 2 @@ -128,10 +134,15 @@ custom_minimum_size = Vector2(62, 40) layout_mode = 2 text = "Back" +[node name="AcceptDialog" type="AcceptDialog" parent="."] +unique_name_in_owner = true + [connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"] [connection signal="pressed" from="MenuContainer/VBoxContainer/MenuButtons/ResumeButton" to="." method="_on_resume_button_pressed"] +[connection signal="pressed" from="MenuContainer/VBoxContainer/MenuButtons/SaveButton" to="." method="_on_save_button_pressed"] [connection signal="pressed" from="MenuContainer/VBoxContainer/MenuButtons/RestartButton" to="." method="_on_restart_button_pressed"] [connection signal="pressed" from="MenuContainer/VBoxContainer/MenuButtons/OptionsButton" to="." method="_on_options_button_pressed"] [connection signal="pressed" from="MenuContainer/VBoxContainer/MenuButtons/MainMenuButton" to="." method="_on_main_menu_button_pressed"] [connection signal="pressed" from="MenuContainer/VBoxContainer/MenuButtons/ExitButton" to="." method="_on_exit_button_pressed"] [connection signal="pressed" from="SubMenuContainer/VBoxContainer/MarginContainer2/BackButton" to="." method="_on_back_button_pressed"] +[connection signal="confirmed" from="AcceptDialog" to="." method="_on_accept_dialog_confirmed"]