Jump to content
  • Advertisement

Christin Kalina

Member
  • Content Count

    4
  • Joined

  • Last visited

Community Reputation

8 Neutral

2 Followers

About Christin Kalina

  • Rank
    Newbie

Personal Information

  • Role
    Programmer
  • Interests
    Education
    Programming

Social

  • Github
    Pixelrella

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. As the player moves along in a game and interacts with different objects in the world, the aim is to reflect his actions in the game by changing the state of objects permanently. For example, a door is opened or some first experience guidance does not need to be displayed anymore. Objectives Save and restore states of objects in the scene according to the progress of the player. These objects may be are interconnected. (A door opens when pulling a level/ defeating an enemy) Let level design decide and modify which objects need to have their state changed when. Used programming concepts Enum https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum MonoBehavior https://docs.unity3d.com/ScriptReference/MonoBehaviour.html UnityEvent https://docs.unity3d.com/ScriptReference/Events.UnityEvent.html JSON serialization https://unity3d.com/learn/tutorials/topics/scripting/loading-game-data-json Checkpoints Step 1 - Checkpoints First, we need something that defines what a state change in the game is and when it happens. Let's call this a Checkpoint. When the player does an action to activate the checkpoint let's call that reached the checkpoint. This checkpoint needs an ID to be identifiable for saving and restoring. This checkpoint also needs something that can be fired off when the checkpoint was reached. In my case, for the ID, I created an enum because its nicely readable in the inspector. On top of being readable by humans it also is robust against typos and other string mischief. For firing off the state changes, I picked UnityEvents which have the advantage that your level designer can put anything in there and debug and modify it by himself. Step 2 - Reaching Checkpoints So, we have a MonoBehavior called Checkpoint, that has an ID and a UnityEvent. Now, you can attach this to any gameObject in your scene. What will happen? Nothing, because we are not reaching the Checkpoint yet. To reach the Checkpoint, we add a public method that calls the UnityEvent. Now we can call this function from anywhere in the code or from another UnityEvent. Step 3 - CheckpointController Great! But wait, when I restart the scene it does not remember that I reached the Checkpoint. To save and restore the state of the Checkpoint I created a CheckpointController that knows all the checkpoints in the scene and who to talk to make the state persistent on the disk. For the first part, I created a function that registers the Checkpoint in the CheckpointController. This can be called in Awake() for example. Now this controller can store all the Checkpoint gameObjects in the current scene. For the second part, I let the Checkpoint inform the CheckpointController when a it was reached. The controller that is hooked up to any kind of saving like a JSON file reader/writer can then write the ID of the Checkpoint that was reached to the disk. On top of saving, I also inform all the Checkpoints with the ID that was just reached to fire off their UnityEvent. This way, I do not need to fire off the UnityEvent on the individual Checkpoint anymore but let it backfire through the CheckpointController . Great success! Now, when Unity starts a new game, the CheckpointController needs to receive the persisted list of Checkpoint IDs that where reached before. When the scene has loaded successfully, it will notify all Checkpoints that have the IDs that were saved before. (Remember that the Checkpoints register themselves to the CheckpointController on their Awake()). So that the Checkpoints that were reached before now also fire off their UnityEvent when the level was loaded. Thank you for your interest, let me know what you thought or if you have any questions
  2. Building a save system for level objects in Unity Pt. 2 - Usable Objects This builds on https://www.gamedev.net/blogs/entry/2266638-building-a-save-system-for-level-objects-in-unity-pt1-checkpoints/ and I would highly recommend to read through part 1 before continuing with this second part. (You still will understand what is going on, I hope, but I am skipping the underlying save and loading logic here because I went into these details in part 1 already.) As the player moves along in a game and interacts with different objects in the world, we want to reflect his actions in the game by changing the state of objects permanently. For example, an item that was picked up should not appear again. Objectives: Save and restore states of objects in the scene according to the progress of the player. These objects are not interconnected. Just remember that this object was used Used programming concepts: System.Guid https://docs.microsoft.com/en-us/dotnet/api/system.guid Monobehavior https://docs.unity3d.com/ScriptReference/MonoBehaviour.html UnityEvent https://docs.unity3d.com/ScriptReference/Events.UnityEvent.html JSON serialization https://unity3d.com/learn/tutorials/topics/scripting/loading-game-data-json Interface AssetModificationProcessor.OnWillSaveAssets https://docs.unity3d.com/ScriptReference/AssetModificationProcessor.OnWillSaveAssets.html Link to first part: https://www.gamedev.net/blogs/entry/2266638-building-a-save-system-for-level-objects-in-unity-pt1-checkpoints/ Unique IDs 1. Finding a persistent unique ID for GameObjects This is very similar to the checkpoint but instead of using enums to identify the saved state, this approach works with a unique ID per GameObject. So that you do not need to create hundreds of enum entries just because you want your game to remember that token ABC was picked up. GameObjects do not come with a unique ID out of the box. There is Object.GetInstanceID() https://docs.unity3d.com/ScriptReference/Object.GetInstanceID.html but this is exactly only that - an instance id. This ID gets regenerated every time a unity scene is loaded. As we seek for consistent behavior, this will not do. 2. UUID So, after researching some time in the internet on how to give GameObjects a unique ID, I found Bunny83's UUID: https://github.com/Bunny83/UUID/. It is a component that will create and serialize a System.Guid for a GameObject - Perfect! The way it creates and remembers the Guid across scenes is an interesting process, definitely worth debugging through it to see how it works. IPersistentObject Great, now we have a unique ID that will not change when we load scenes. Next question is how to distribute this on the GameObjects that we want to remember. One way would be to just attach it. But is there an automatic way? Yes, there definitely is! We could work with [RequireComponent] but this only works on objects that have not been added to the scene yet. Let's build our own system for that then. The method I went for uses an Interface and the OnWillSafeAssets method in Unity. The later is called when a scene is saved. I basically search for all the objects in the scene that implement this interface and add the UUID component if it does not exist yet. In my case all objects that are interacted with came with a component that handles the logic of interacting with the object like adding stuff to the inventory or some currency counter. I extended this component with implementing my persistence interface. So that I can "mark" all types of components with the IPersistentObject interface that need a unique ID for saving. PersistableObject Now, similar to the checkpoint system, I created a component that handles the saving of the object. It also comes with a unity event and will register itself in a controller that has access to a save object that will be serialized to JSON. Instead of saving the enum though, this will save the UUID of the object. The OnWillSafeAssets method not only attaches the UUID but also the PeristableObject component. So that this does not need to be done manually either. The saving is then hooked up into the logic when the object is picked up, so that it will not appear again after being picked up once. (Have a look at the first part of this series for how approach the saving and loading. ) Great success! Now with both the enum based and UUID based saving of objects in the scene we have great tools that let the player feel that he is impacting the world with his/her actions. In the next part I will introduce you to how to integrate this into Unity's editor system for easy debug.
  3. Christin Kalina

    [BETA] Spell Slingers - Battle Cards

    Only watched the trailer so far but love the character art, clear design and sounds.
  4. Building a save system for level objects in Unity Pt1 - Checkpoints As the player moves along in a game and interacts with different objects in the world, the aim is to reflect his actions in the game by changing the state of objects permanently. For example, a door is opened or some first experience guidance does not need to be displayed anymore. Objectives Save and restore states of objects in the scene according to the progress of the player. These objects may bE interconnected. (A door opens when pulling a level/ defeating an enemy) Let level design decide and modify which objects need to have their state changed when. Used programming concepts Enum https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum Monobehavior https://docs.unity3d.com/ScriptReference/MonoBehaviour.html UnityEvent https://docs.unity3d.com/ScriptReference/Events.UnityEvent.html JSON serialization https://unity3d.com/learn/tutorials/topics/scripting/loading-game-data-json Checkpoints Step 1 - Checkpoints First, we need something that defines what a state change in the game is and when it happens. Let's call this a Checkpoint. When the player does an action to activate the checkpoint let's call that reached the checkpoint. This checkpoint needs an ID to be identifiable for saving and restoring. This checkpoint also needs something that can be fired off when the checkpoint was reached. In my case, for the ID, I created an enum because its nicely readable in the inspector. On top of being readable by humans it also is robust against typos and other string mischief. For firing off the state changes, I picked UnityEvents which have the advantage that your level designer can put anything in there by himself (fe changing the activation status of a GameObject, changing a material or calling a public method in a MonoBehavior) . Step 2 - Reaching Checkpoints So, we have a MonoBehavior called Checkpoint, that has an ID and a UnityEvent. Now, you can attach this to any gameObject in your scene. What will happen? Nothing, because we are not reaching the Checkpoint yet. To reach the Checkpoint, we add a public method that calls the UnityEvent. Now we can call this function from anywhere in the code or from another UnityEvent. Step 3 - CheckpointController Great! But wait, when I restart the scene it does not remember that I reached the Checkpoint. To save and restore the state of the Checkpoint I created a CheckpointController that knows all the checkpoints in the scene and who to talk to make the state persistent. For the first part, I created a function that registers the Checkpoint in the CheckpointController. This can be called in Awake(), for example. Now this controller can store all the Checkpoint GameObjects in the current scene. For the second part, I let the Checkpoint inform the CheckpointController when a it was reached. The controller that is hooked up to any kind of saving like a JSON file reader/writer can then write the ID of the Checkpoint that was reached to the disk. On top of saving, I also inform all the Checkpoints with the ID that was just reached to fire off their UnityEvent. This way, I do not need to fire off the UnityEvent on the individual Checkpoint anymore but let it backfire through the CheckpointController . Great success! Now, when Unity starts a new game, the CheckpointController needs to receive the persisted list of Checkpoint IDs that where reached before. When the scene has loaded successfully, it will notify all Checkpoints that have the IDs that were saved before. (Remember that the Checkpoints register themselves to the CheckpointController on their Awake()). So that the Checkpoints that were reached before now also fire off their UnityEvent when the level was loaded.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!