Saving/loading inherited class scripts (C#)
Hello, I'm having some issues with the saving and loading of inherited class scripts. I hope that makes sense but if not i'll try my best to explain it.
so I have an abstract class, lets say its called "Boo" and boo has a few variables:
using system;
public abstract class Boo : monobehavior
{
int x,y,z;
//and a abstract method too:
Private abstract bool ExampleMethod(int i);
}
now we have the classes that inherit from Boo lets say 1, 2 and 3
using system;
Public class 1 : Boo
{
//and an override for our abstract method
public override bool ExampleMethod (int i)
{
//do some stuff
}
}
so my problem is that I want to be able to store all of my inherited classes for saving and loading into a container object and have the correct class (1,2 or 3) chosen when its loaded so that its method overrides and values are the correct ones.
I should probably note that I do know how to do serialization of variables but i just cant figure out how to get the class to save and load.
Hopefully that explains my problem properly, I often seem to have difficulty with explaining and asking appropriate questions so sorry about that. (don't really have good people skills)
Okay, so after some research i have come up with this:
IEnumerable temp = AppDomain.CurrentDomain.GetAssemblies().Select$$anonymous$$any(assembly => assembly.GetTypes()).Where(type => type.IsSubclassOf(typeof(Boo)) && !type.IsAbstract);
Which allows me to get the correct classes (1,2,3) and ignore any abstract classes along the way. The only problem is that now I don't know how to create the gameobject from Ienumerable . I have tried the following:
foreach (Type t in temp)
{
Boo tmp = (Boo)Activator.CreateInstance(Boo);
}
however its giving an error because Boo itself inherrits from monobehavior. Is there a way to add a component to a game object based on a Ienurable?
Got the same problem, did you ever figure it out @LightShadow ??
Answer by streeetwalker · Apr 15, 2020 at 05:56 AM
@LightShadow & @AsclepiiusUnknown, Here is one way to think about it:
Save the state of objects, not classes. Classes are just definition templates for objects. You don't need to save them because those definitions exist from one game session to the next.
[edit for clarification] In the context of saving the state of a running game, saving a Class doesn't make sense if you think about it because MonoBehavior classes don't have any existence outside of the GameObjects they are attached to as Script Components. And a GameObject can have multiple scripts attached to them. The GameObject is not defined by the script class objects you attach to it. It is the GameObject that owns the scripts, not the other way around.
[end edit]
Therefore, you need to come up with a scheme for serializing objects and their state, and that includes a "type" identifier of object (e.g. which prefab is used to instantiate it) and all of the variables values that are not part of the object script component's initialization code (e.g. you want to save an enemy's location mid-game, which has changed from a location defined in the Start function a script attached to the object).
You could use a integer or string that is assigned in the derived class definition when the object is instanced as the "type" identifier. Integers are efficient because they are small. Strings are nice if you want to be able to read the type as a string. Each type identifies a different prefab object, with their associated derived classes in script components.
For example, you have 3 different types of enemies and several instances of each at the time you save. Those instances are created from 3 different prefabs, with names Ghost, Goblin, Troll. So we associate 0,1 and 2 with each, respectively. When we go to Instantiate them, we assign 0, 1, or 2 to the type variable depending on which of the enemies prefabs we are using. (It is also a good idea to assign each instance a unique ID of some kind, and the gameobject.name can be used for that, but that is another discussion)
When you go to save, assuming you have kept a reference to each enemy instance in a list, array, or collection of some kind, you loop through all the enemy instances and for each instance read and save its type identifier, name, location, and any other variables that have been changed after the object was instantiated.
When you then load a session, you loop through all the saved elements (e.g. read from a json file) and get the saved object type identifier to use in a switch statement (or a bunch of if else) to Instantiate the object from the correct prefab, and then set up all of the values you have saved. This is really the same Instantiation code as when you first ran the game, only here you are reading from a file to determine which objects to instantiate and what their "restarting" values are.
Use the same strategy for non-MonoBehvior class instances.
Remember that derived classes inherit any values defined in their parent class, so there is no need to worry about parent Class values, unless you have declared static variables or something - in which case all Instances will have the same value for those
Does that make sense - address your question?