From 0c905be6fc58f5b6118a6fd810e26466ca8e3e35 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Wed, 20 May 2020 18:06:35 +0200 Subject: [PATCH] save/load current game --- src/Main.gd | 48 ++++++++++++++++++++++++ src/Main.tscn | 4 +- src/Taquin.gd | 101 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 131 insertions(+), 22 deletions(-) diff --git a/src/Main.gd b/src/Main.gd index c9c9013..4bb0893 100644 --- a/src/Main.gd +++ b/src/Main.gd @@ -3,8 +3,56 @@ extends Control onready var taquin = $HSplitContainer/Taquin func _ready(): + load_game() print("Starting state: ", taquin.current_state_name()) +func _notification(what): + if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST: + save_game() + get_tree().quit() # default behavior + +# https://docs.godotengine.org/en/3.2/tutorials/io/saving_games.html +func save_game(): + var save_game = File.new() + save_game.open("user://savegame.save", File.WRITE) + var save_nodes = get_tree().get_nodes_in_group("Persist") + for node in save_nodes: + # Check the node has a save function + if !node.has_method("save"): + print("persistent node '%s' is missing a save() function, skipped" % node.name) + continue + + # Call the node's save function + var node_data = node.call("save") + + # Augment data with origin + node_data["path"] = node.get_path() + + # Store the save dictionary as a new line in the save file + save_game.store_line(to_json(node_data)) + save_game.close() + +func load_game(): + var save_game = File.new() + if not save_game.file_exists("user://savegame.save"): + return # Error! We don't have a save to load. + + # Load the file line by line and process that dictionary to restore + # the object it represents. + save_game.open("user://savegame.save", File.READ) + while save_game.get_position() < save_game.get_len(): + # Get the saved dictionary from the next line in the save file + var node_data = parse_json(save_game.get_line()) + + # Call the node's save function + var node = get_node(node_data["path"]) + node.call("load", node_data) + + save_game.close() + +# +# Signals +# func _on_Taquin_state_changed(previous, new): print("Taquin state: ", Taquin.State.keys()[previous], " -> ", Taquin.State.keys()[new]) match new: diff --git a/src/Main.tscn b/src/Main.tscn index b1a90bd..f780321 100644 --- a/src/Main.tscn +++ b/src/Main.tscn @@ -34,7 +34,9 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="Taquin" parent="HSplitContainer" instance=ExtResource( 2 )] +[node name="Taquin" parent="HSplitContainer" groups=[ +"Persist", +] instance=ExtResource( 2 )] margin_right = 540.0 margin_bottom = 560.0 rows = 4 diff --git a/src/Taquin.gd b/src/Taquin.gd index fd9cf1e..13d9adb 100644 --- a/src/Taquin.gd +++ b/src/Taquin.gd @@ -75,27 +75,12 @@ func _ready() -> void: padding = compute_padding(piece_size) print("piece size: ", piece_size) print("padding: ", padding) - - for c in range(columns): - var pieces_row: Array = [] - for r in range(rows): - var piece = Piece.instance() - - piece.size = piece_size - piece.position = position_for_index(Vector2(c, r), piece.size) - piece.order = 1 + c + r * columns - piece.taquin_index = Vector2(c, r) - piece.piece_scale = Vector2((float(piece_size) / width), (float(piece_size) / height)) - piece.taquin_position = Vector2(float(piece.position.x) / width, float(piece.position.y) / height) - - if r == rows - 1 && c == columns - 1: - piece.visible = false - missing_piece = piece - - $Background.add_child(piece) - pieces_row.append(piece) - - pieces.append(pieces_row) + var pieces_order: Array = [] + for order in range(1, rows * columns + 1): + pieces_order.append(order) + var hidden_piece = rows * columns # Last piece is hidden + + init(pieces_order, hidden_piece) shuffle(difficulty) @@ -326,6 +311,80 @@ func transition_to(state): $Timer.stop() emit_signal("state_changed", previous_state, current_state) +func save() -> Dictionary: + var serialized_pieces = [] + for c in range(columns): + for r in range(rows): + var piece: Piece = pieces[c][r] + serialized_pieces.append(piece.order) + return { + "rows": rows, + "columns": columns, + "pieces": serialized_pieces, + "hidden_piece": serialized_pieces.size(), + } + +func load(saved_state) -> void: + if not saved_state.has_all(["rows", "columns", "pieces", "hidden_piece"]): + return + rows = saved_state["rows"] + columns = saved_state["columns"] + init(saved_state["pieces"], saved_state["hidden_piece"]) + +func init(pieces_order: Array, hidden_piece: int) -> void: + var piece_size: int = compute_piece_size() + padding = compute_padding(piece_size) + print("piece size: ", piece_size) + print("padding: ", padding) + + if pieces.size() > 0: + for c in range(columns): + for r in range(rows): + var piece: Piece = pieces[c][r] + $Background.remove_child(piece) + piece.queue_free() + pieces.clear() + + for c in range(columns): + var pieces_row: Array = [] + for r in range(rows): + var piece = Piece.instance() + # Uniforms + piece.size = piece_size + piece.piece_scale = Vector2((float(piece_size) / width), (float(piece_size) / height)) + + # order start from top-left (1) and iterate over every row + # eg. 1 2 3 + # 4 5 6 + # 7 8 9 + piece.order = pieces_order[r + c * rows] + print("piece at ", c, ", ", r, " -> order: ", piece.order) + + # place inside the taquin as indices (i, j) + piece.taquin_index = Vector2(c, r) + # place inside the taquin as coordinates (x, y) + piece.position = position_for_index(piece.taquin_index, piece.size) + + # position inside the original taquin as normalized coordinates (x, y) (domain: [0, 1]) + # used for offsetting the texture on pieces + var original_index = Vector2((piece.order - 1) % columns, (piece.order - 1) / columns) + var original_position = position_for_index(original_index, piece.size) + piece.taquin_position = Vector2(float(original_position.x) / width, float(original_position.y) / height) + + if piece.order == hidden_piece: + piece.visible = false + missing_piece = piece + + $Background.add_child(piece) + pieces_row.append(piece) + + pieces.append(pieces_row) + + shuffle(difficulty) + +# +# Signals +# func _on_Timer_timeout(): transition_to(State.GAME_OVER)