Virtual method getting called instead of the override - c#

I have four classes, Event and Action which are both base classes, and then I have two child classes Create : Event and MoveTo : Action.
Event contains a list of Action instances, and when Trigger() is called in the child Create it calls Event.Trigger(), which loops over the list of actions, and calls Action.Run() on each action which calls Called().
The Issue I am having is the virtual method is getting called and not the override method inside of MoveTo.
[Serializable]
public abstract class Event : MonoBehaviour {
[SerializeField] public List<Action> actions = new List<Action>();
protected void Trigger() {
foreach (Action action in actions) {
action.Run();
}
}
}
Event
public class Create : Event {
void Start() {
Trigger();
}
}
Action
[Serializable]
public class Action {
public virtual void Called() {
Debug.Log("Virtual");
}
public void Run() {
Called();
}
}
MoveTo
public class MoveTo : Action {
public override void Called() {
Debug.Log("Called");
}
}
I am adding the MoveTo action to the event list from the Unity Editor onto a prefab. I am not sure how unity handles these at runtime, does in initialize them or do I? That I am not sure about. That is what might be causing my issue...
private Event GetCurrentEvent(){}
void AddActionCallback(Type actionType) {
// actionType is MoveTo
var prefab = GetCurrentPrefabItem().Value;
var evt = GetCurrentEvent();
evt.actions.Add((Action)Activator.CreateInstance(actionType));
Undo.RecordObject(prefab.gameObject, "Added actions");
PrefabUtility.RecordPrefabInstancePropertyModifications(prefab.gameObject);
}
Here is what it looks like before I run the game. It shows MoveTo, the button in the red column shows the action using action.GetType().Name. This is the name before I run the game:
After I run the game the button now looks like this:
When running:
evt.actions.Add((Action)Activator.CreateInstance(actionType));
The editor displays Type mismatch even when the output of actionType and Activator.CreateInstance(actionType) is MoveTo:

Unity does not support built-in polymorphic serialization.
When you save the prefab, it serializes the List as a list of pure Actions, and erases any information that only the child class MoveTo has.
From the Unity docs on serialization:
No support for polymorphism
If you have a public Animal[] animals and
you put in an instance of aDog, a Cat and a Giraffe, after
serialization, you have three instances of Animal.
One way to deal with this limitation is to realize that it only
applies to custom classes, which get serialized inline. References to
other UnityEngine.Objects get serialized as actual references, and for
those, polymorphism does actually work. You would make a
ScriptableObject derived class or another MonoBehaviour derived class,
and reference that. The downside of this is that you need to store
that Monobehaviour or scriptable object somewhere, and that you cannot
serialize it inline efficiently.
The reason for these limitations is that one of the core foundations
of the serialization system is that the layout of the datastream for
an object is known ahead of time; it depends on the types of the
fields of the class, rather than what happens to be stored inside the
fields.
This is why its class shows up as an Action.
However, it can't serialize as an Action because:
How to ensure a custom class can be serialized
Ensure it:
Has the Serializable attribute
Is not abstract
Is not static
Is not generic, though it may inherit from a generic class
Action is an abstract class, so it won't even serialize partially properly. I assume this is the root cause of the Type Mismatch problem, as Unity is struggling to deserialize something that is unsupported.
In short, if you want to serialize data in MoveTo, you'll need to have a [SerializeField] List<MoveTo> in order to not lose the information, or you can have Action inherit from ScriptableObject, which brings its own problems.

Related

How can I do a simple effect system with inheritance?

I'm trying to practice with inheritance and just in general having scripts interact with each other and I thought doing a simple effect system could be fun, but I'm a bit stuck on how to structure things.
I keep wanting to do this
public abstract class BaseEffect : ScriptableObject
{
//not sure if this is a good use of enum
public enum EffectType
{
harm, //can be applied to enemies
help, //can be applied to allies
self //can be applied to yourself
}
public string name;
public string description;
public float duration;
public bool canStack; //can the effect be applied multiple times
public EffectType type;
//I'd probably also write my apply and remove effect methods here
}
And then a bunch of derived classes like this
public class TestEffect : BaseEffect
{
//maybe include some variables specific to this effect
//when the effect gets applied have this run every frame to od whatever the effect does
public void DoEffect()
{
}
}
I have a feeling though that this isn't a good way to go about doing this or at least the way I've written it isn't good so looking for some advice to get on the right track
This arrangement may benefit from an abstract method or usage of an Interface consumed by an abstract class to enforce derived classes to respond to events. Speaking of events, you could also wire the derived calls up through events. In simple terms, introduce an abstract method in the base class, which must be implemented in derived classes. Then call the method in the base classes "plumbing" when everything special about the event is ready.
public abstract class BaseEffect : ScriptableObject
{
protected abstract void DoEffect();
private SomeMethod()
{
if(canDoEffect)
DoEffect();
}
}

Serializing nested polymorphical objects in Unity

Hi fellow game developers, I'm working on a Unity project that allows level designer to edit instructions to scene elements of how they should act to events.
screenshot of command editor in unity inspector
I've managed to express all executable instruction units--expressions, statements, control blocks--with a common abstract base class Command. It comes like this:
[Serializable]
abstract class Command {
public abstract object Execute();
public abstract void Inspect(/* ... */);
}
class CommandCarrier : MonoBehaviour {
public Command command;
}
/*
There are several carrier classes in the real project,
this one is only for illustrating the problem.
Command.Inspect() would be called by a CustomEditor of CommandCarrier.
*/
Where Execute() is to perform the command at runtime, and Inspect() is to draw the inspector GUIs.
Every solid type of command would be a derived class of Command, e.g. an if-else block would be like:
[Serializable]
class Conditional : Command {
public Command condition, trueBranch, falseBranch;
public override object Execute() {
if((bool)condition.Execute()) trueBranch.Execute();
else falseBranch.Execute();
return null;
}
public override void Inspect(/* ... */) { /* ... */ }
}
A constant expression would contain no sub-commands:
[Serializable]
class Constant<T> : Command {
public T value = default(T);
public override object Execute() => value;
public override void Inspect(/* ... */) { /* ... */ }
}
Here comes the problem: all the commands I've written in the inspector panel would be lost as long as a reserialization is triggered (like when the code changed and therefore is recompiled).
This is probably because Unity failed to serialize a subclass instance stored in a field of base class; all the type information and the contained data are lost during reserialization.
What's worse is that these polymorphical instances are even nested.
I've tried to solve the case and failed: given a field of base class, it's apparently impossible to "upgrade" an instance to a subclass by calling whatever methods belonging to that instance; it must be done externally by assigning the field with a subclass instance created elsewhere.
But again, every subclasses have their own fields, and these data I haven't figure out where to recover from.
Could anybody help?
Now that you corrected your code here I would point you to Script Serialization and in particular the section
No support for polymorphism
If you have a public Animal[] animals and you put in an instance of a Dog, a Cat and a Giraffe, after serialization, you have three instances of Animal.
One way to deal with this limitation is to realize that it only applies to custom classes, which get serialized inline. References to other UnityEngine.Objects get serialized as actual references, and for those, polymorphism does actually work. You would make a ScriptableObject derived class or another MonoBehaviour derived class, and reference that. The downside of this is that you need to store that Monobehaviour or scriptable object somewhere, and that you cannot serialize it inline efficiently.
The reason for these limitations is that one of the core foundations of the serialization system is that the layout of the datastream for an object is known ahead of time; it depends on the types of the fields of the class, rather than what happens to be stored inside the fields.
So in your case I would simply use ScriptableObject and do
abstract class Command : ScriptableObject
{
public abstract object Execute();
public abstract void Inspect(/* ... */);
}
and
[CreateAssetMenu]
public class Conditional : Command
{
public Command condition, trueBranch, falseBranch;
public override object Execute() {
if((bool)condition.Execute()) trueBranch.Execute();
else falseBranch.Execute();
return null;
}
public override void Inspect(/* ... */) { /* ... */ }
}
and
public abstract class Constant<T> : Command
{
public T value = default(T);
public override object Execute() => value;
public override void Inspect(/* ... */) { /* ... */ }
}
and e.g.
[CreateAssetMenu]
public class IntConstant : Constant<int>
{
}
each in their own script files with matching name (that part is very important for the serializer).
And then you would create instance of these via the Assets -> right click -> Create -> "Conditional" for example and reference it into the according slots.
Also note that these are now re-usable and you can simply reference the same item in various places, something that wasn't possible if you use a normal serializable class due to
When might the serializer behave unexpectedly?
Custom classes behave like structs
With custom classes that are not derived from UnityEngine.Object Unity serializes them inline by value, similar to the way it serializes structs. If you store a reference to an instance of a custom class in several different fields, they become separate objects when serialized. Then, when Unity deserializes the fields, they contain different distinct objects with identical data.
When you need to serialize a complex object graph with references, do not let Unity automatically serialize the objects. Instead, use ISerializationCallbackReceiver to serialize them manually. This prevents Unity from creating multiple objects from object references. For more information, see documentation on ISerializationCallbackReceiver.
This is only true for custom classes. Unity serializes custom classes “inline” because their data becomes part of the complete serialization data for the MonoBehaviour or ScriptableObject they are used in. When fields reference something that is a UnityEngine.Object-derived class, such as public Camera myCamera, Unity serializes an actual reference to the camera UnityEngine.Object. The same occurs in instances of scripts if they are derived from MonoBehaviour or ScriptableObject, which are both derived from UnityEngine.Object.

Better way to have static class / method access a gameObject variable from several scripts away?

TLDR: How can I have a script that inherits from a public abstract class have access to an often changing Enemy gameObject variable (so it can't be static) without passing it through several other scripts first?
In my game, I have a battle system where a different "Battle Event" gets loaded for each battle. Each "Battle Event" gets its own script, and each of those events inherits from the same BattleEvent parent (which is public abstract).
The code structure basically goes:
BattleSystem (main brain of battles which holds the Enemy
gameObject) ->
BattleEventsManager (handles both which BattleEvent to load, and which methods to run on that BattleEvent) ->
a random BattleEvent (BattleEventOne or BattleEventTwo etc)
public class BattleSystem : MonoBehaviour
{
BattleEventsManager battleEventsManager;
public Enemy currentEnemy;
// the Enemy data is passed when the battle starts
public void Start(Enemy enemyToLoad)
{
battleEventsManager = GetComponent<BattleEventsManager>();
currentEnemy = enemyToLoad;
}
public void BeginPlayerTurn()
{
battleEventsManager.SetupEvent(currentEnemy);
}
}
public class BattleEventsManager : MonoBehaviour
{
BattleEvent currentBattleEvent;
private void Awake()
{
// define this battleEvent
currentBattleEvent = GetComponent<BattleEventOne>();
}
public void SetupEvent(Enemy currentEnemy)
{
// start the battleEvent with its Setup function
currentBattleEvent.Setup(currentEnemy);
}
}
// inherits from `BattleEvent` parent class, shown below
public class BattleEventOne : BattleEvent
{
// override the method from the parent
public override void Setup(Enemy currentEnemy) {
// we can now use the data we need in `currentEnemy`
// all I wanted was to get access to `BattleSystem.currentEnemy`
// but i had to pass it down all the way here. Is there a better way?
}
}
// parent of all `BattleEvents`
public abstract class BattleEvent : MonoBehaviour
{
public abstract void Setup(Enemy currentEnemy);
} // end BattleEvent class
As you can see, the the currentEnemy variable needs to be passed down through 2 classes in order to get to where it needs to be: BattleEventOne.Setup().
Furthermore, I needed to add the Enemy currentEnemy param to the parent BattleEvent, which is problematic because not all BattleEvents will need this information.
I originally wanted to just call BattleSystem.currentEnemy from BattleEventOne (using a property or something), but because the BattleSystem is abstract/static, it can't access it. And because currentEnemy contains new data each battle, I can't make that a static variable.
So, how can I have BattleEventOne here access BattleSystem.currentEnemy without having to pass it down as I've done above?
(I still struggle a lot with passing information between scripts, so any help here is really appreciated!)

How to use a child class method when the Dictionary has the abstract class as value?

I am making a chess game and I have an abstract class named cls_ChessPieces and a class for every chess piece (cls_Pawn, cls_Knight, ...).
class cls_ChessPieces
{
}
class cls_Pawn : cls_ChessPieces
{
public bool CheckLegalMove()
{
// this is the method I want to call
}
}
I made this abstract class because I want to store every chess piece in a dictionary with the location on the chess board as Key (string).
private Dictionary<string, cls_ChessPieces> _dicPieces;
_dicPieces.Add((Column + Row), _pawn);
After making a move I want to know the type of the piece that has moved.
_chessLogic.DicPieces.TryGetValue(key, out piece1);
When I put a breakpoint and inspect the piece1 object, I can see which type it has (cls_Pawn). But this type is only given to that object at runtime. This makes it impossible to call the CheckLegalMove() method.
This is the way I solve this issue, but I don't think this is the proper way of doing it. It takes a lot of code do to this for every chess piece class and every time that I want to pass the object I need to do this again.
if (piece1 is cls_Pawn)
{
cls_Pawn pawn= (cls_Pawn)piece1;
pawn.CheckLegalMove();
}
Is there an easy way to get the cls_pawn class out of the dictionary an call the CheckLegalMove() method? I tried to get the type :
Type t = piece1.GetType();
But I don't know if it is possible to cast with this type
(t)piece1;
Thanks!
Edit:
CheckLegalMove() is maybe not a good example
public bool Promote()
{
// this is a method only this child class should have
}
I guess every type of chess item needs to check moves, so declare method in base class:
public abstract class cls_ChessPieces
{
public abstract bool CheckLegalMove();
}
class cls_Pawn : cls_ChessPieces
{
public override bool CheckLegalMove()
{
// this is the method I want to call
}
}
you will be able to call CheckLegalMove() for every class, derived from cls_Pawn:
bool ok = piece1.CheckLegalMove();
For this answer I suppose you don't want to have an abstract CheckLegalMove method in the cls_ChessPieces base class. If this is not a problem don't choose this approach.
Approach 1 (not recommended)
You could get the type of the object with
var type = piece1.GetType();
and then inspect per reflection if the type defines the method CheckLegalMove() by doing
var type = piece1.GetType();
var checkLegalMoveMethod = type.GetMethod("CheckLegalMove");
if(checkLegalMoveMethod != null)
{
var result = (bool)checkLegalMoveMethod.Invoke(piece1);
}
This works but only as long as your CheckLegalMove method doesn't contain any parameters.
Approach 2 (the recommended way)
One thing you could also do is introduce another base class (again only do this if you don't want to have a CheckLegalMove method directly inside cls_ChessPieces) <SubBaseClassName> which is defined as the following:
class <SubBaseClassName> : cls_ChessPieces
{
public abstract bool CheckLegalMove();
}
The your cls_Pawn would inherit from <SubBaseClassName> and you could just check if piece1 is of type <SubBaseClassName> and if it is call the CheckLegalMove method on it.

How to approach an Entity class with inheritance?

SO, my concern is not being completely aware if this is the best approach for my situation.
Lets, say I got a base class "Entity". Assuming the purpose is to construct a class hierarchy system.
public class Entity
{
public int _hp;
private int _max_hp;
public Entity(int hp)
{
_max_hp = hp;
_hp = _max_hp;
}
}
And we got other derived classes
public class d_class1: Entity
{
public d_class1(int hp):
base(hp)
{
}
}
public class d_class1_Mono: MonoBehaviour
{
public d_class1 d1;
}
public class d_class2: Entity
{
public d_class2(int hp):
base(hp)
{
}
}
public class d_class2_Mono: MonoBehaviour
{
public d_class2 d2;
}
(Excuse the bad naming conventions, was done on purpose)
Assume the scripts that are inheriting from Mono are attached to different objects in the scene.
I want to be able to distinguish which "class" I currently have when "click" on the unit.
Is there anyway I can avoid having to check between all possible classes I may have.
ex.
obj = gameObject containg the component d_class2_Mono
if(obj contains d_class1)
do something with d1
else if(obj contains d_class2)
do something with d2
else
error("Unknown class derivation");
I feel myself having to do this sometimes to do something like get the hp, just because I need someway of accessing the component. Maybe this is not the best approach. Currently, this is all simple, but each of these class will be in their own way different from the other (i.e. different abilities, etc)
So, hoping someone could shed some knowledge in my understanding.
The GameObject that you attach the MonoBehaviour you can have a handler specifically for that object. For example you could implement "void OnUpdate()" on the d_class1_Mono and a different update function for d_class2_Mono.
If you assume that you don't know which object you have clicked on (because this is being routed through some other class/function) -
You can do:
obj.GetComponent<d_class1_Mono>()
and
obj.GetComponent<d_class2_Mono>()
Whichever one returns a non-null reference has that script attached to it. Hope this makes sense.
I would probably define a virtual or abstract method in the Entity class which each inherited classes would implement. For example, if you have both mobile and immobile entities, and you have a void MoveToPosition(Position pos) method defined in Entity:
// Mobile entity
public class d_class1: Entity
{
// ...stuff...
public void MoveToPosition(Position pos)
{
TweenPosition(_currPosition, pos, movementSpeed);
}
}
// Immobile entity
public class d_class2: Entity
{
// ...stuff...
public void MoveToPosition(Position pos)
{
// Do nothing
}
}
Then within your logic/update loop, you can simply tell ALL entities to MoveToPosition(...) and those that shouldn't respond will simply do nothing.
I find that coding is cleaner when I've got a common interface or class with a common "do something" method, and let each derived class handle the "how" of that method call in its own ways.

Categories

Resources