Is it possible to disable the option to override MonoBehavior functions like Start(), Awake(), Update(), etc... in children class?
The reason behind this is, that when multiple people work on Unity project, someone unaware of this problem could disable important initialization that is defined in parent which could cause unwanted behavior that is hard to debug.
It seems to me that this goes against principles of OOP since you can mess a lot of things on other places. You wont even see a warning in Visual Studio, when trying to do this.
public class A: MonoBehavior
{
void Awake()
{
// Do some stuff
}
}
public class B: A
{
void Awake()
{
// This actually overrides stuff that Awake() does in parent class
}
}
Solution is simple and adheres to the principles of OOP.
Any class you think could have children in the future, define in it stubs
protected virtual void Awake() {}
protected virtual void Start() {}
protected virtual void OnEnable() {}
...list goes on.
Now if someone to use any of the callbacks in a child without 'overriding' the IDE will certainly notify them that there is a base implmentation of the callback.
I think sealing the Awake() method from your class A should be what you are looking for:
public class A: MonoBehavior
{
public sealed override void Awake()
{
// Do some stuff
}
}
Now when you try to override this method in your class B it will not only give an IDE warning but it will not compile.
Related
Is it possible to use virtual void OnDisable() ? Its a built in Unity method, just like Start() or OnEnable(). I couldnt find any resources online where its explained if we can use virtual on these built in methods.
public abstract class ShipComponent : MonoBehaviour
{
[HideInInspector] public ShipControl shipControl;
public virtual void Init(ShipControl control)
{
this.shipControl = control;
StartCommonCoroutines();
}
public virtual void IsPlayer()
{
SetListeners();
StartPlayerOnlyCoroutines();
}
public virtual void OnEnable()
{
StartCommonCoroutines();
if (!shipControl.shipWrapper.ship.IsPlayer) return;
SetListeners();
StartPlayerOnlyCoroutines();
}
public virtual void OnDisable()
{
RemoveListeners();
StopAllCoroutines();
}
public abstract void SetListeners();
public abstract void RemoveListeners();
public abstract void StartCommonCoroutines();
public abstract void StartPlayerOnlyCoroutines();
public abstract void StopPlayerOnlyCoroutines();
}
I want to Inherit from ShipComponent in subclasses and whenever a subclass that inherits from ShipComponent calls OnDisable() (Unity built in version) then I want it to call the baseClass' ShipComponent.OnDisable() as initialized above.
I realize OnDisable() is a built in method, so should I instead be doing:
public override void OnDisable()
{
base.OnDisable();
RemoveListeners();
StopAllCoroutines();
}
Because we are overidding the original built in Unity method this way?
Thanks.
Unity does a little bit of reflection magic on user scripts, and it creates internal list of MonoBehaviours that have OnEnable/OnDisable methods - it calls them even if they are private, and you don't need to explicitly implement any interface for this to work.
This also means that it does not care if the method is virtual or not, it will call a correct override if you override it in your inheriting classes.
Do not mark it as override in your base class as there is no base implementation in MonoBehaviour itself. I would assume this decision was made for performance reasons - if all objects had those methods, even if they were empty, they would have to be called. If there are no methods, its a few calls less.
I need to initiate my GameManager with data, which is provieded by the LevelLoader. The problem is that some Behaviours need to access some of this data themself on Initation and there are already present, when the scene loads, meaning I'll get a NullReference because the GameManager isn't initiated yet.
class LevelLoader
{
void LoadLevel()
{
// ...
// Initiate Game Manager
GameManager.Instance.Initiate(data);
}
}
class GameManager : MonoBehaviour
{
// ...
public int someNum;
public void Initiate(data)
{
// ...
// This action may take a cuple of frames
// ...
someNum = data.someNum;
}
}
class SomeSceneObject : MonoBehaviour
{
void Awake()
{
// Initiate SomeSceneObject
DoSomething(GameManager.Instance.someNum);
}
}
Option 1:
I was thinking about adding an Interface for any script that requires the GameManager on Setup, which will replace the default Awake and Start methods:
interface IStartable
{
void Awake2();
void Start2();
}
But than I would also have to override the Update method, because it needs to be suppressed until Awake2 and Start2 are called. Which would make this solution even more ugly.
interface IStartable
{
void Awake2();
void Start2();
void Update2();
void LateUpdate();
void FixedUpdate();
}
Option 2:
I was also thinking about moving my initiation code to the Start method and disabling all scripts before there are called and reactivating them when ready.
But than I would have to keep track on all objects I need to disable on my GameManager/LevelLoader Script, which would be even more ugly and difficult to maintain.
Option 2b:
I could also add an Initiate() method to SomeSceneObject and call it when the GameManager is done instead of using Awake() but same problem: I need to keep track of all MonoBehaviours how need to be called on the GameManager which isn't ideal.
Question:
How do I delay the iniation and keep it maintainalbe?
I'm working on a Unity project which uses a good amount of inheritance. I have an abstract base class whose methods I want its children to always call (e.g. Awake).
I haven't worked with attributes much - is there a way to add an attribute to my ABC's Awake method which causes the child-class to log an error if they override Awake() without calling base.Awake() in its implementation?
Thanks!
You could something like this:
public class A
{
public void Awake()
{
Console.WriteLine("Everybody does X on awake");
AwakeExtra();
}
public virtual void AwakeExtra() => Console.WriteLine("'A' also does A on awake");
}
public class B : A
{
public override void AwakeExtra() => Console.WriteLine("'B' also does B on awake");
}
in Unity I make use of interfaces. I set a logic for components which are totally different to each other.
Examples:
A car, a dog and a aircraft would implement IMovable. I can call Move() from each component but these components execute different code.
Same for ISavable, each component, that has to save data to the database could save the stuff when looping through all savables.
The problem:
Some people in forums say that interfaces are bad for Unity.
When destroying a gameobject and call its interface method this still gets executed.
No error would come up because Destroy() does not destroy objects. Unity as a C++ driven Engine would setup a C# wrapper for the objects. These objects just get a flag destroyed which is a bool.
Destroyed gameobjects will not get destroyed immediately, they will be destroyed later on at the end of the frame.
Until this end of the frame is not reached the method can still get called from the destroyed object.
The best way would be using abstract classes only and never use interfaces because of the bad behaviour coming up when destroying objects.
I tested this with a small example, I created the following scripts:
public interface IIntfacable
{
void DoSomething();
void DestroyComponent();
}
public class bar : MonoBehaviour
{
private IIntfacable i;
private void Start()
{
i = FindObjectOfType<foo>().GetComponent<IIntfacable>();
}
private void Update()
{
i.DoSomething();
i.DestroyComponent();
i.DoSomething();
}
}
public class foo : MonoBehaviour, IIntfacable
{
public void DoSomething()
{
Debug.Log("=> DoSomething");
}
public void DestroyComponent()
{
Debug.Log("=> DestroyComponent");
Destroy(gameObject);
}
}
When executing this code I get the following result
Workaround:
I could create an abstract base class and choose between
public abstract void Foo();
and
public virtual void Bar()
{
return;
}
but this might lead to overengineering. Because all Scripts would need this base class whether they need this method or not.
Conclusion:
Should I prevent using interfaces?
I am confident in saying there is no harm in using interfaces.
The underlying fear is about keeping track of unmanaged references, a problem which will still be there weather you are using interfaces, abstract classes or whatever. You simply have to make sure that your game code will not try to access any objects which have been Destroy()ed.
Basically, I just construct a collection of objects that I know are not destroyed in my scene, and remove them after destruction.
With risk of answering an xy-problem, If you are scared to miss out on your reference count anyway or there is something in particular which wont allow creating such a list, there is not really any magic wand here, but there are a few precedent patterns in the .net framework with the IDisposable interface/pattern that may lead the way.
Many implementations of these patterns checks a flag in a few public-facing methods of the object. IDisposable.Dispose() would set the flag to true and throw an ObjectDisposedException on some public method if this is set to true, analog to MissingReferenceException in this case. Some patterns will then expose the flag IsDisposed, so that other objects that use the implementation can check instead of doing a try-catch on any access to the object. Your analog could be IsDestroyed, and you should set it in the override of OnDestroy.
You could change your method update like this (well it's not really a use case, why would you try to use it after destroying it, but to show my point):
private void Update()
{
i.DoSomething();
i.DestroyComponent();
if (!i.IsDestroyed) {
// This will not be called
i.DoSomething();
}
}
and implementation could be
public interface IIntfacable : IDestroyable
{
void DoSomething();
}
public interface IDestroyable
{
void DestroyComponent();
bool IsDestroyed { get; }
}
public class foo : MonoBehaviour, IIntfacable
{
bool IsDestroyed { get; private set; }
public void DoSomething()
{
Debug.Log("=> DoSomething");
}
public void DestroyComponent()
{
Debug.Log("=> DestroyComponent");
Destroy(gameObject);
}
public override OnDestroy() {
base.OnDestroy();
IsDestroyed = true;
}
}
I want to ask this question because of some safety mechanism for my code.
This may seem like useless, but it already made me lose much time debugging.
public class AnimalClass
{
virtual void Mod{}
virtual void UpdateSomeValues{}
}
public class CatClass : AnimalClass
{
override void Mod{}
override void UpdateSomeValues{}
}
Is there a way in C# to automatically fire up Cat's UpdateSomeValues function whenever Cat's Mod function is called (without having to call it manually from Cat's Mod function)?
And if possible, make it the same for all derived classes?
No. You could solve that issue by introducing another, protected method that derived classes can override, and make the public one call into it once all the necessary processing is done:
public class AnimalClass
{
public void Mod()
{
// do stuff
ModImpl();
}
protected virtual ModImpl() {}
}
With that derived classes would implement ModImpl() if they want to do some extra processing, and you're sure that // do stuff still happens when Mod is called.