I was trying to implement a checkpoint system. In the game you can kill enemies and when you respawn in a checkpoint the enemies that you have already killed before getting to the checkpoint should not reappear but the ones you killed after getting to it should. I don’t know how to do this since reloading the scene and placing the player on the checkpoint would make all the enemies appear again but just placing the player on the checkpoint without reloading the scene would not respawn the enemies which are supposed to.
I would also like the checkpoint system to do the same with any other interactable things in the game like collectables or breakable objects.
You have to persist data to reload the scene and then remove enemies you killed before reaching the checkpoint.
To persist data you can write to a file (savegame - which then can be reloaded after closing and re-opening the game), you can write to a ScriptableObject or Prefab-Asset (any kind of Asset is not inside a scene, so it won’t be affected when the scene is reloaded … btw. Scenes are Assets as well, atleast in the Editor), or you can write to an object that is in another scene that doesn’t get unloaded, such as the DontDestroyOnLoad-Scene (there is a method to move objects into this scene).
Probably the easiest way would be to give each enemy in your scene a unique ID.
Then have a temporary list of killed enemies, containing the ID and a “bool isDead”.
Also you have a permenant list of killed enemies, also containing the ID and a “bool isDead” (as mentioned above, this can be a SaveGame-File, ScriptableObject/PrefabAsset or a Component in another Scene).
Once you reach a checkpoint, write the temporary list to the permanent list.
If the player dies, reload the scene, then read the permanent list and remove all enemies that were already killed (according to the permanent list).
Checkpoints are just in the domain of save-game stuff most of the time. Ergo, record the state of objects you care about at certain points in the game, and rewind everything back to that point when needed (such as the player dying). Normally you’d do this for games where you can resume the level at any point, or at the last checkpoint the player was at.
Alternatively, you can ‘tag’ objects (not literal Unity tags but a component of some kind) that assign them to a certain checkpoint. Then when you ‘go back’ to a checkpoint, you reset everything beyond the current checkpoint. I’ve done this in a game where there was no mid-level saving (puzzle platformer with small levels).
Yep, as Spiney notes, just good old loading and saving, very well-traveled ground.
Load/Save steps:
An excellent discussion of loading/saving in Unity3D by Xarbrough:
Loading/Saving ScriptableObjects by a proxy identifier such as name:
When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. The reason is they are hybrid C# and native engine objects, and when the JSON package calls new to make one, it cannot make the native engine portion of the object.
Instead you must first create the MonoBehaviour using AddComponent() on a GameObject instance, or use ScriptableObject.CreateInstance() to make your SO, then use the appropriate JSON “populate object” call to fill in its public fields.
If you want to use PlayerPrefs to save your game, it’s always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:
Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.