How could I save player's current level, stats, position?

Just trying to expand Character controller project from GameDev.tv to save some parameters from player position, current level .

I have manage to save general settings → How to keep those GlobalScene Data persistent? - #2 by artemisia but wonder if I should now build on top of this script or make new autoload saver with export variables for each of those variables and logic.

currently level is managed by : Project Settings → Applications → Run → Main Scene

  • there is possible transition via Portal.

Player position is managed by Player itself.

FileSystem architecture :

Started working on it :

It looks like easy task, but main culprit for me is portal() and access to data at right time.

class_name GeneralSaveSystemClass
extends Node

@export var levels : Array[String] = []
@onready var player_spawner: Node3D = $PlayerSpawner

var player
var level_node
var current_level_index: int = 0
var level
var player_position
func _ready() -> void:
	player = get_tree().get_first_node_in_group("Player")
	level_node = get_tree().get_first_node_in_group("Level")

		
func update_data() -> void:
	player_position = player.global_position
	level = level_node.scene_file_path

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("debug_key"):
		update_data()
		print(level)
		print(player_position)

I have tested this, it’s all nice and works in one level. But as soon as you enter another level via portal

func _on_area_3d_body_entered(body: Node3D) -> void:
	if body is Player:
		UserInterface.change_scene(next_level, player_spawner.global_transform)

it complains :

Invalid access to property or key 'global_position' on a base object of type 'previously freed'.

Small change fixed this behavior, instead of _ready and storing old values now it’s updated on request, so maybe some signal to UI or manual save/load buttons to make it work?

edit : added exact data type, check for index

class_name GeneralSaveSystemClass
extends Node

@export var levels : Array[String] = []
@onready var player_spawner: Node3D = $PlayerSpawner

var player : CharacterBody3D
var level_node : Node3D
var current_level_index: int = 0
var level : String
var player_position : Vector3


func find_level_in_array() -> void:
	for level_index in range(levels.size()):
		if levels[level_index] == level:
			current_level_index = level_index
			break

func get_tree_reference() -> void:
	player = get_tree().get_first_node_in_group("Player")
	level_node = get_tree().get_first_node_in_group("Level")
		
func update_data() -> void:
	get_tree_reference()
	player_position = player.global_position
	level = level_node.scene_file_path
	find_level_in_array()

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("debug_key"):
		update_data()
		print(current_level_index, " ", level, " ", player_position)



0 res://Levels/DebugLevel.tscn (10.54292, 0.925232, 17.60353)
1 res://Levels/TestLevel.tscn (10.00271, 0.925785, 12.79769)


1 Like