I’m stuck with an architectural problem: In my game I want a central way of managing levels. More concretely: I want to organize my levels into chapters and store some additional information per chapter and per level (which I need to be able to persist on disk later on, since the information will change when the player completes a level). The structure would look something like this:
- Chaptername (FString)
- points needed to unlock the chapter (int32)
- array of levels belonging to the chapter (TArray)
- Time taken to solve the level (float)
- primary score (int32)
- secondary score (int32)
- Level name (FName, corresponds to the name of an existing levelasset)
Now I need to store an array of chapters somewhere and the place that appeared best for that in my opinion was the gamemode, but I’m not bound to that decision. It needs to be, however, in a globally accessible place (across levels). I want to be able to edit the array of chapters in the editor (so it’s easy for artists to add new levels without the need to go and change code) which means the array needs to be a UProperty.
Do you have a recommendation on how I could/should implement this? I have tried creating FStructs but I wasn’t able to use them as properties (the property didn’t get persisted and was reset whenever I reloaded the project; I’m quite confused about this behavior because I used the BlueprintType specifier in the FStruct macro). Then I created UObjects but I can’t really use something which needs to be instanced, since I’m not able to create an instance of an object in the editor (at least not of a UObject; and actor types need to be placed in a specific level wich doesn’t work either).
I’m very interested in your thoughts about this problem and would be enormously glad if you could share your experience, in case you implemented similar logic! Thank you in advance!
Just FYI: when I tried to use FStructs, I placed the definition inside the gamemode header. Could that be the problem for it not being persisted? Where else should one generally place struct definitions?
For persistent data while the game is running, check out the Game Instance. You can access this from anywhere with GetGameInstance() call and this persists through level loads.
You may then also want to check out the USaveGame class - Which allows you to easily save data in a binary file to disk.
Thanks a lot for the remark! I will definitely look into those things!
Hey it looks like I’ve had derped once again. I got it working with the struct now! But I moved everything to the game instance so please change your comment into an answer so I can give you credit for solving this problem.
For constant level information, you can store that in a
Table of custom
Struct. Then for dynamic save information, you must create a
SaveGame object, inside you can store any structs or primitive data. You cannot save a whole object, like your
Player. So instead, you should pull the important information you want to save from any object, and store it in a struct or list of structs.
For example, if you want to save the progress of all your levels. Maintain an array of structs that hold that data in you
GameMode, then send that to your
SaveGame data before you save. Or just maintain it in your save object, just be sure to update it when things change, so it can be saved!
Below I’ll show how I store my linear game’s data:
- My constant level data struct
LevelStruct. In this, I store information that is shown on the main menu.
- My Levels table
Levels. Holds a list of my
LevelStruct with different values for each level.
- My dynamic save data
FinishedLevels. In my game, I only need to store whether or not the player reached/completed a level. So it stores two
maps of Level-ID’s paired with with whether or not they were reached or completed. This object is what is saved, and loaded.
- I call this save function any time the values change, and I only ever have one persistent save. You could save multiple files in different slots.
- Here’s how I load my save data. And if the location doesn’t exist, in my game I just make a new blank one. But your needs may be different. You may only want to create a new save data object, when a player starts a new game.
Thanks a lot for your detailed explanation! I didn’t know about tables so that’s definitely a plus for your answer. I guess i will, however go with the fully fledged GameInstance version that @Dune mentioned, since all of my data that i store - appart from the names - is dynamic (in comparison to your solution wich has static and dynamic properties separated)
Happy to help.
I suggest you still make a table of constant level information for devs to specify. Stuff like
Number of Required Shards to Complete,
Next Level ID.
This way when you create a new
SaveGame from scratch, you can pull this data from the table.
And your artists can add entries or edit entries of the table when they design levels.
the table cannot be edited dynamically though right?