Godot Version
v4.6.1.stable.official [14d19694e]
Question
I am trying to make a system to save a series of pieces to build a spaceship in part of my game. Each piece is an individually instanced scene and moved around so you can arrange them however you want. The issue comes with saving.
I’ve tried saving a node that parents all the pieces as a scene that is overwritten when you save, but that bugged out in a way that’s far beyond my skill level. I’m now trying to save each piece individually in a Global Dictionary called “spaceship”, but an error appears the second time it tries loading.
ALL the children in each node is no longer able to be referenced. I think it may have something to do with repeatedly instantiating, but I don’t know how to get around it, and I’m having trouble finding other solutions that work with loading multiple times.
Here’s the code for the loader and saver:
func _ready() -> void:
if Global.spaceship != {}:
for packed_scene in Global.spaceship.values():
var jeremiah = packed_scene.instantiate()
pieces.add_child(jeremiah)
func save() -> void:
Global.spaceship = {}
for child in pieces.get_children():
var instance = child.duplicate()
var save_build = PackedScene.new()
save_build.pack(instance)
Global.spaceship[child.name] = save_build
I want to save the position and some variables of each node, so I’m pretty set on the individuals nodes. Does anyone have any ideas to solve or alternate strategies?
EDIT: I don’t need ways to store the information. I need ways to save and load the information. Repeatedly copying instantiated nodes somehow lost their children, and another strategy I tried didn’t allow me to delete parts. My problem is that I don’t know how to save and load, NOT with knowing where to store the data.
I’d simplify it.
On your Player make a Dictionary structure that stores all its parts. Then make a Resource to hold all the details of each part.
class_name ShipPart extends Resource
@export var scene: PackedScene
# Position relative to the Player object
@export var position: Vector2 # Or Vector3 if this is a 3D game
Then just use ResourceSaver to save them.
Or go really simple, and store a reference to the UID in each part, and store the UID in the Resource.
class_name ShipPart extends Resource
@export var scene_uid: String
# Position relative to the Player object
@export var position: Vector2 # Or Vector3 if this is a 3D game
Then use that to load each one:
for ship_part: ShipPart in ship_parts:
var part = load("uid://" + ship_part.scene_uid)
add_child(part)
part.position = ship_part.position
I’m not familiar with a Resources or UIDs, but I don’t think this would work.
I only have four types of parts, but each one can have multiple instances of itself in the building area. With what I understand of your solution, it would change the original scene of each part rather than saving every instanced part in the build, making them all have the same data and stack on top of one another.
I still feel that Dictionary is the way to go, but I’m specifically having trouble switching between the nodes in the scene and said Dictionary.
To be blunt, you do not understand my solution.
I’m saying use a Dictionary.
Then I’m saying use ResourceSaver and ResourceLoader and save the resources.
There is no part of that which would limit you to one object per ship.
I still don’t understand where the Resource comes from or how to connect the part to the Resource. You’re being quite vague with your instructions.
Can you list all information that you need to save per piece?
I need to save a Vector2 position, a Dictionary with 4 elements, and one of four part types. The position is used for where the part is in the building, the Dictionary represents directional orientation and is used with a bunch of functions to dictate the behavior of the part, and the part types are already made with separate scenes because of their functional and visual differences. The part type doesn’t need to be specified in the scene, because each part type is made from it’s own scene. I have four scenes, one for each part type, that are instantiated when I need to place them in the scene.
As I have said before (in less detail oops), I need help transferring the parts from being instances to being saved, and then from being saved back into instances while retaining the information.
You can make a resource class called e.g. SpaceshipPartPlacement that contains all that data. Then another resource class called SpaceshipDesign that contains an array of part placement objects. Those data structures can be built before saving from the actual situation in your scene and then saved to a tres file. When you need to reconstruct, load the tres file, look what’s in there and rebuild the scene accordingly.
1 Like
I cannot read your mind. I’m not sure how you expect me to be more specific when I do not know the information you are trying to save.
class_name SpaceShipPartPlacement extends Resource
Enum Type {
WING,
ENGINE,
BODY,
NOSE,
}
@export var position: Vector2
@export var elements: Dictionary
@export var part_type: Type
Actually, this reminded me I can store just the basic values in the Dictionary and have a script to re-instantiate the things based on the simple values. This will probably work, because I’m not re-reading packedscenes that have been packed and instantiated multiple times. Gonna see if it works, then come back.
Yeah, the thing worked. Here’s my code for anyone wondering:
func _ready() -> void:
if Global.spaceship != {}:
for part in Global.spaceship.values():
var instance : Node
match part[0].left(part[0].length() - 2):
"Engine":
instance = ENGINE.instantiate()
"Quarter":
instance = QUARTERS.instantiate()
"Pipe":
instance = PIPE.instantiate()
instance.directions = part[2]
"Power sour":
instance = POWER_SOURCE.instantiate()
instance.name = part[0]
instance.position = part[1]
pieces.add_child(instance)
else:
sucks to suck ig
func save() -> void:
Global.engine_count = 0
Global.quarters_count = 0
Global.spaceship = {}
for child in pieces.get_children():
var vars_to_save : Array = []
vars_to_save.append(child.name)
vars_to_save.append(child.position)
match child.name.left(child.name.length() - 2):
"Engine":
Global.engine_count += 1
"Quarter":
Global.quarters_count += 1
"Pipe":
vars_to_save.append(child.directions)
Global.spaceship[child.name] = vars_to_save
I want to apologize to you, dragonforge-dev. I’ve been struggling with this for a couple of days and have been getting increasingly frustrated with everything, but my anger (and ignorance) shouldn’t have been directed towards you. I hope the rest of your day is better than today, and I thank you for guiding me to the right path. Even if I asked poor questions
1 Like
No worries. I appreciate the apology.
Glad you found a solution.