save/load current game
This commit is contained in:
		
							parent
							
								
									a44ec0a41b
								
							
						
					
					
						commit
						0c905be6fc
					
				
					 3 changed files with 131 additions and 22 deletions
				
			
		
							
								
								
									
										48
									
								
								src/Main.gd
									
										
									
									
									
								
							
							
						
						
									
										48
									
								
								src/Main.gd
									
										
									
									
									
								
							| 
						 | 
					@ -3,8 +3,56 @@ extends Control
 | 
				
			||||||
onready var taquin = $HSplitContainer/Taquin
 | 
					onready var taquin = $HSplitContainer/Taquin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func _ready():
 | 
					func _ready():
 | 
				
			||||||
 | 
						load_game()
 | 
				
			||||||
	print("Starting state: ", taquin.current_state_name())
 | 
						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):
 | 
					func _on_Taquin_state_changed(previous, new):
 | 
				
			||||||
	print("Taquin state: ", Taquin.State.keys()[previous], " -> ", Taquin.State.keys()[new])
 | 
						print("Taquin state: ", Taquin.State.keys()[previous], " -> ", Taquin.State.keys()[new])
 | 
				
			||||||
	match new:
 | 
						match new:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,7 +34,9 @@ __meta__ = {
 | 
				
			||||||
"_edit_use_anchors_": false
 | 
					"_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_right = 540.0
 | 
				
			||||||
margin_bottom = 560.0
 | 
					margin_bottom = 560.0
 | 
				
			||||||
rows = 4
 | 
					rows = 4
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,27 +75,12 @@ func _ready() -> void:
 | 
				
			||||||
	padding = compute_padding(piece_size)
 | 
						padding = compute_padding(piece_size)
 | 
				
			||||||
	print("piece size: ", piece_size)
 | 
						print("piece size: ", piece_size)
 | 
				
			||||||
	print("padding: ", padding)
 | 
						print("padding: ", padding)
 | 
				
			||||||
 | 
						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
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	for c in range(columns):
 | 
						init(pieces_order, hidden_piece)
 | 
				
			||||||
		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)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	shuffle(difficulty)
 | 
						shuffle(difficulty)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -326,6 +311,80 @@ func transition_to(state):
 | 
				
			||||||
			$Timer.stop()
 | 
								$Timer.stop()
 | 
				
			||||||
	emit_signal("state_changed", previous_state, current_state)
 | 
						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():
 | 
					func _on_Timer_timeout():
 | 
				
			||||||
	transition_to(State.GAME_OVER)
 | 
						transition_to(State.GAME_OVER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue