Enhance save system functionality; improve game state management and session tracking

This commit is contained in:
2025-05-25 16:06:59 +02:00
parent 15c85a5aae
commit 250fb18e16
11 changed files with 92 additions and 25 deletions

View File

@@ -1,4 +1,3 @@
class_name SaveSystem
extends Node extends Node
@export var save_path: String = "user://savegame.save" @export var save_path: String = "user://savegame.save"
@@ -15,18 +14,32 @@ func save_game():
var file := FileAccess.open(save_path, FileAccess.WRITE) var file := FileAccess.open(save_path, FileAccess.WRITE)
file.store_var(save_data) file.store_var(save_data)
file.close() file.close()
print("Game saved to: ", save_path)
func load_game(): func load_game() -> bool:
if not FileAccess.file_exists(save_path): if not FileAccess.file_exists(save_path):
return return false
var file := FileAccess.open(save_path, FileAccess.READ) var file := FileAccess.open(save_path, FileAccess.READ)
var save_data: Dictionary = file.get_var() var save_data: Dictionary = file.get_var()
file.close() file.close()
if save_data.has("version") and save_data["version"] != version: if save_data.has("version") and save_data["version"] != version:
print("Save file version mismatch. Expected: ", version, ", Found: ", save_data["version"]) print("Save file version mismatch. Expected: ", version, ", Found: ", save_data["version"])
return return false
print("save data: ", save_data)
gm.player_state = save_data["player_state"] gm.player_state = save_data["player_state"]
gm.unlock_skills(gm.player_state["unlocked_skills"]) print("Player state loaded: ", gm.player_state)
var skills: Array[String] = []
for skill_name in gm.player_state["unlocked_skills"]:
skills.append(skill_name)
print("Newly unlocked skills: ", skills)
gm.unlock_skills(skills)
print("Game loaded from: ", save_path)
return true
func check_save_exists() -> bool:
return FileAccess.file_exists(save_path)

View File

@@ -36,6 +36,7 @@ Console="*res://addons/console/console.gd"
AchievementsManager="*res://objects/achievements.tscn" AchievementsManager="*res://objects/achievements.tscn"
ConfigFileHandler="*res://autoloads/config_file_handler.gd" ConfigFileHandler="*res://autoloads/config_file_handler.gd"
UiManager="*res://autoloads/ui_manager.gd" UiManager="*res://autoloads/ui_manager.gd"
SaveSystem="*res://autoloads/save_system.gd"
[debug] [debug]

View File

@@ -75,8 +75,9 @@ player_health = NodePath("../../Brick Player/HealthComponent")
current_level = SubResource("Resource_bqjcg") current_level = SubResource("Resource_bqjcg")
nodes_to_disable = [NodePath("../../Brick Player")] nodes_to_disable = [NodePath("../../Brick Player")]
[node name="Marketplace" parent="UI Layer" index="3" node_paths=PackedStringArray("skill_unlocker")] [node name="Marketplace" parent="UI Layer" index="3" node_paths=PackedStringArray("skill_unlocker", "components_to_disable")]
skill_unlocker = NodePath("../../Brick Player/SkillUnlockerComponent") skill_unlocker = NodePath("../../Brick Player/SkillUnlockerComponent")
components_to_disable = [NodePath("../../Brick Player")]
[node name="Global Light" parent="." instance=ExtResource("4_wykfl")] [node name="Global Light" parent="." instance=ExtResource("4_wykfl")]

View File

@@ -36,4 +36,4 @@ func on_exit_area_body_entered(_body: Node2D) -> void:
func go_to_next_level() -> void: func go_to_next_level() -> void:
gm.try_to_go_to_next_level() gm.on_level_complete()

View File

@@ -17,5 +17,5 @@ func _on_health_component_on_death() -> void:
effect.scale = Vector2(1.5, 1.5) effect.scale = Vector2(1.5, 1.5)
gm.remove_lives(1) gm.remove_lives(1)
gm.set_coins(0) gm.reset_current_session_state()

View File

@@ -6,10 +6,10 @@ extends Node
func _ready(): func _ready():
await get_tree().process_frame await get_tree().process_frame
var coins = get_tree().get_nodes_in_group("coins") var coins := get_tree().get_nodes_in_group("coins")
for coin in coins: for coin in coins:
coin.connect("collected", on_collected) coin.collected.connect(on_collected)
func on_collected(amount: int, type: CollectableResource.CollectableType) -> void: func on_collected(amount: int, type: CollectableResource.CollectableType) -> void:
@@ -17,4 +17,4 @@ func on_collected(amount: int, type: CollectableResource.CollectableType) -> voi
return return
if type != CollectableResource.CollectableType.COIN: if type != CollectableResource.CollectableType.COIN:
return return
game_manager.add_coins(amount) game_manager.current_session_state["coins_collected"] += amount

View File

@@ -6,6 +6,11 @@ extends Node
@onready var game_manager: GM = $"/root/GameManager" @onready var game_manager: GM = $"/root/GameManager"
func has_enough_coins(amount: int) -> bool:
return game_manager and game_manager.get_coins() >= amount
func try_unlock_skill(skill_data: SkillData) -> bool: func try_unlock_skill(skill_data: SkillData) -> bool:
if not game_manager: if not game_manager:
return false return false
@@ -13,11 +18,11 @@ func try_unlock_skill(skill_data: SkillData) -> bool:
if game_manager.is_skill_unlocked(skill_data.name): if game_manager.is_skill_unlocked(skill_data.name):
return false return false
if game_manager.get_coins() < skill_data.cost: if not has_enough_coins(skill_data.cost):
return false return false
game_manager.remove_coins(skill_data.cost) game_manager.remove_coins(skill_data.cost)
game_manager.unlock_skill(skill_data.name) game_manager.current_session_state["unlocked_skills"].append(skill_data.name)
skill_manager.add_skill(skill_data) skill_manager.add_skill(skill_data)
return true return true
@@ -31,8 +36,3 @@ func unlock_all_skills() -> void:
game_manager.unlock_skills(skills) game_manager.unlock_skills(skills)
skill_manager.apply_unlocked_skills() skill_manager.apply_unlocked_skills()
func _input(event: InputEvent) -> void:
if event.is_action_pressed("unlock_skills"):
unlock_all_skills()

View File

@@ -9,11 +9,18 @@ extends Node
"unlocked_skills": [], "unlocked_skills": [],
"current_level": 0, "current_level": 0,
"unlocked_levels": [], "unlocked_levels": [],
"completed_levels": [],
} }
var nodes_in_scene := [] var nodes_in_scene := []
var current_session_state := {
"coins_collected": 0,
"skills_unlocked": [],
}
func _enter_tree() -> void: func _enter_tree() -> void:
get_tree().node_added.connect(on_node_added) get_tree().node_added.connect(on_node_added)
get_tree().node_removed.connect(on_node_removed) get_tree().node_removed.connect(on_node_removed)
@@ -64,6 +71,7 @@ func get_kid_nodes() -> Array[CollectableComponent]:
func add_coins(amount: int) -> void: func add_coins(amount: int) -> void:
player_state["coins"] += amount player_state["coins"] += amount
player_state["coins"] = max(0, player_state["coins"])
func set_coins(amount: int) -> void: func set_coins(amount: int) -> void:
@@ -71,11 +79,20 @@ func set_coins(amount: int) -> void:
func get_coins() -> int: func get_coins() -> int:
return player_state["coins"] return player_state["coins"] + current_session_state["coins_collected"]
func remove_coins(amount: int) -> void: func remove_coins(amount: int) -> void:
player_state["coins"] -= amount var session_coins = current_session_state["coins_collected"]
if amount <= session_coins:
current_session_state["coins_collected"] -= amount
else:
var remaining_amount = amount - session_coins
current_session_state["coins_collected"] = 0
player_state["coins"] = max(0, player_state["coins"] - remaining_amount)
player_state["coins"] = max(0, player_state["coins"])
func add_lives(amount: int) -> void: func add_lives(amount: int) -> void:
@@ -95,7 +112,7 @@ func get_lives() -> int:
func is_skill_unlocked(skill_name: String) -> bool: func is_skill_unlocked(skill_name: String) -> bool:
return skill_name in player_state["unlocked_skills"] return skill_name in player_state["unlocked_skills"] or skill_name in current_session_state["skills_unlocked"]
func unlock_skill(skill_name: String) -> void: func unlock_skill(skill_name: String) -> void:
@@ -118,6 +135,7 @@ func reset_player_state() -> void:
"coins": 0, "coins": 0,
"lives": 3, "lives": 3,
"unlocked_skills": [], "unlocked_skills": [],
"completed_levels": [],
} }
@@ -132,6 +150,19 @@ func try_to_go_to_next_level() -> void:
get_tree().change_scene_to_packed(level_scenes[next_level]) get_tree().change_scene_to_packed(level_scenes[next_level])
func mark_level_complete(level_index: int) -> void:
unlock_level(level_index + 1)
if level_index not in player_state["completed_levels"]: player_state["completed_levels"].append(level_index)
func reset_current_session_state() -> void:
current_session_state = {
"coins_collected": 0,
"skills_unlocked": [],
}
func quit_game() -> void: func quit_game() -> void:
get_tree().quit() get_tree().quit()
@@ -152,9 +183,24 @@ func start_new_game() -> void:
func continue_game() -> void: func continue_game() -> void:
# todo: load player state from save file if not SaveSystem.load_game():
printerr("Failed to load game. Starting a new game instead.")
start_new_game()
return
if player_state["current_level"] < level_scenes.size(): if player_state["current_level"] < level_scenes.size():
get_tree().change_scene_to_packed(level_scenes[player_state["current_level"]]) get_tree().change_scene_to_packed(level_scenes[player_state["current_level"]])
else: else:
printerr("No levels unlocked to continue.") printerr("No levels unlocked to continue.")
func on_level_complete() -> void:
var level_index = player_state["current_level"]
mark_level_complete(level_index)
add_coins(current_session_state["coins_collected"])
for skill_name in current_session_state["skills_unlocked"]:
unlock_skill(skill_name)
reset_current_session_state()
try_to_go_to_next_level()
SaveSystem.save_game()

View File

@@ -23,6 +23,7 @@ func on_restart_button_pressed() -> void:
return return
gm.reset_player_state() gm.reset_player_state()
gm.reset_current_session_state()
get_tree().reload_current_scene() get_tree().reload_current_scene()

View File

@@ -27,6 +27,11 @@ func _ready() -> void:
if version_label: if version_label:
version_label.text = "v. " + ProjectSettings.get_setting("application/config/version") version_label.text = "v. " + ProjectSettings.get_setting("application/config/version")
if not SaveSystem.check_save_exists() and continue_button:
continue_button.disabled = true
else:
continue_button.disabled = false
func _on_new_game_button_pressed() -> void: func _on_new_game_button_pressed() -> void:
if gm: if gm: