Don't use Interfaces in Unity? - c#

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;
}
}

Related

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!)

Unity - Struggling with Dependency Injection and Monobehaviour

So I'm experimenting with DI and am trying to create a GameObject Generator.
That GameObject Generator generates GameObjects inside the scene based on some internal logic.
There is variation to what kinds of GameObjects are generated and the logic can vary.
I thought that I could create a Interface and be able to create a class per "unique logic" (i.e. for every generator behaviour i create a class and can switch between generating a lot of small objects and a couple of big objects without having to use if statements, but instead the power of polymorphism).
So I've got something like
GameObjectGenerator : Monobehaviour
IGeneratorType
SmallGenerator : Monobehaviour, IGeneratorType
BigGenerator : Monobehaviour, IGeneratorType
from a logical standpoint this seems to be making sense.
The issue arrises, when transitioning from those generators.
I want to have some sort of condition, where i call a method "TransitionGenerator" from IGeneratorType
that returns a new IGeneratorType. Logically this is working aswell.
However, i want to keep track of my generated Objects (in a list for instance), because they need to be Destroyed later.
When transitioning, the List of generated Objects need to be passed to the new IGeneratorType.
This is where I find myself struggling.
The classes that implement from IGeneratorType need to extend Monobehaviour aswell because i need to make calls to Instantiate and Destroy.
But because they extend from Monobehaviour, I can't seem to create a constructor.
After a bit of research i found a lot of people pointing to either Awake/Start or to creating a Init method.
The problem is, with Awake/Start i cant pass anything and with Init, i would need to put that into the interface aswell, which doesnt make a lot of to me sense from a design standpoint.
Example code:
public class GameObjectGenerator : Monobehaviour{
private IGeneratorType generator;
public void Start(){
generator = new SmallGenerator();
}
public void Update(){
generator.Generate();
if(somecondition){
generator = generator.Transition();
}
}
}
public interface IGeneratorType{
void Generate();
IGeneratorType Transition();
}
public class SmallGenerator : Monobehaviour, IGeneratorType{
private List<GameObject> generatedObjects;
public SmallGenerator(/*List<GameObject> previousObjects*/){
//generatedObjects = previousObjects;
}
public void Generate(){
//...
if(somespecificcond){
generatedObjects.Add(Instantiate(...));
}
if(somecondition){
Destroy(generatedObjects[0])
}
}
public IGeneratorType Transition(){
return new BigGenerator(/*generatedObjects*/);
}
}
public class BigGenerator : Monobehaviour, IGeneratorType{
private List<GameObject> generatedObjects;
public BigGenerator(/*List<GameObject> previousObjects*/){
//generatedObjects = previousObjects;
}
public void Generate(){
//...
if(somespecificothercond){
generatedObjects.Add(Instantiate(...));
}
if(somecondition){
Destroy(generatedObjects[0])
}
}
public IGeneratorType Transition(){
return new SmallGenerator(/*generatedObjects*/);
}
}
I just found the simplest workaround to this specific case:
public class BigGenerator : IGeneratorType{
private List<GameObject> generatedObjects;
public BigGenerator(/*List<GameObject> previousObjects*/){
//generatedObjects = previousObjects;
}
public void Generate(){
//...
if(somespecificothercond){
generatedObjects.Add(Object.Instantiate(...));
}
if(somecondition){
Object.Destroy(generatedObjects[0])
}
}
public IGeneratorType Transition(){
return new SmallGenerator(/*generatedObjects*/);
}
}
This works because Instantiate and Destroy are static methods from "Object", of which "GameObject" inherits.
However this doesn't solve the problem in case one really HAS TO inherit from monobehaviour

(Unity) How to prevent MonoBehavior Awake() function overriding in children

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.

Proper way to create a static virtual factory method in C#

I'm implementing classes for Effects (something with a duration that applies a behavior in the FixedUpdate loop while it is active) in Unity3D.
I have a base abstract Effect class which has the behavior for keeping track of the duration, removing itself when the duration is up, and calling a protected abstract _doEffect function while its duration is up. In my derived classes, I override _doEffect to create Effects with different behaviors.
public abstract class Effect : MonoBehaviour
{
public virtual float kDuration { get { return 1.0f; }}
public static bool IsStackable { get { return false; }}
private float _elapsed = 0.0f;
protected virtual void Start()
{
_elapsed = kDuration;
}
protected virtual void FixedUpdate()
{
_elapsed -= Time.fixedDeltaTime;
if(_elapsed <= 0) {
Destroy(this);
}
_doEffect();
}
protected abstract void _doEffect();
}
Now, because you can't use constructors with Unity3D, I need a way to do the following for each derived Effect class when I'm applying a new Effect of that type to a game object:
1) If this type of effect is not stackable, then remove all other instances of this monobehaviour from the game object.
2) Create a new component of the effect type to the game object.
3) Do some initialization specific to that effect type.
For these requirements, I was imagining doing something like
public class DerivedEffect : Effect
{
public override float kDuration { get {return 1.0f; }}
public static bool IsStackable { get { return true; }}
private int _derivedData;
public static void Create(GameObject obj, int data)
{
DerivedEffect effect = DerivedEffect.CreateEffect(obj);
effect._data = data;
}
protected override void _doEffect()
{
//Do some stuff
}
}
and then in the base class putting
public static virtual Effect CreateEffect(GameObject obj)
{
//T is somehow magically the type of the class you called this function on
if(!T.IsStackable()) {
//delete all components of type T on obj
}
T effect = obj.AddComponent<T>();
return effect;
}
Obviously this isn't possible unless I do some weird stuff with generics and reflection that seems a bit extreme and probably not that right way to do things.
The crux is that I want a static function that does 1), 2), 3), and I want to share the code that does 1) and 2), and 1) depends on a bool which is different for every derived class.
What is a proper, working design for these desiderata?
What is a proper, working design for these desiderata?
Unity is component based and gets things complicated when you want to use it the way you in a normal C# application.
The simplest way is to use Composition. Make the Effect class it's own class that is not abstract. Just a normal class that inherits from MonoBehaviour. You can easily create new instance of it with AddComponent and get it with GetComponent. This script can also destroy itself directly after the timer is done counting without any problems.
Create a global variable in the DerivedEffect class to hold the instance of the Effect script that is created and this can be re-used over and over again until it becomes null which means that the script is destroyed. Note that there is no inheritance involved here and DerivedEffect script is only used as an example of the script that manages the Effect script.

Better alternative to static events

I'm writing a simple game in Unity, and learning C# on my own. Currently I'm doing first pass on the scoring system. I decided to do this with native c# events. So my first idea was to have the Score class responsible for counting/keeping player score. This class would receive events from objects implementing the IScoreable interface.
It would look something like this (example code):
public interface IScoreable {
event Action<IScoreable> Scored;
int Value { get; set; }
}
public class Score {
public void addScore(IScoreable scoreable) {
//do something with scoreable.Value
}
}
In theory, it's decent enough, but I had a problem with coupling:
With just the above code, Score needs to know about all possible objects that implement IScoreable, so it can subscribe to the Scored event. Considering there will be a lot of various objects implementing this interface - it may get instantiated from different parts of code, I don't see any "clean" way of doing this.
Another option would be, to have every IScoreable object register itself with Score object, but this again would create strong coupling. For example adding another player, and subsequently another Score instance, would require rewriting all classes implementing IScoreable)
Which leaves me with two alternatives (that I see). Create some kind of event manager/ aggregator. This option is now for me (subjectively speaking, I like how in c# events are strongly connected to class that defines them).
Another option, the one I'm leaning towards, is to use a static event for this. This would require a switch from interface to abstract class for IScoreable. Which could be a big deal with c# single inheritance, but in this case it isn't (Unity component based approach, discourages deep inheritance trees) I think it would fit this use case quite well.
public abstract class Scorable {
public static event Action<Scorable> Scored;
protected virtual void onScored() { if (Scored != null) Scored(this); }
public int Value { get; set; }
}
Score object would simply subscribe to Scored, and be done. Every class inheriting from Scoreable would call base.onScore when needed, and be done. No additional classes would be needed. Other than possibility of memory leak - if not careful I don't see downsides to this.
But since the use of static events seems to be discouraged, I have my doubts, maybe because of my inexperience I don't see a simple solution.
So the question... Is there a better (cleaner, simpler) solution to my problem? Would you advise against the use of static event in this case?
I think you have this backwards. Rather than have a Score object that knows about everything that can change the score, you should have all of your objects that might update the Score know about a single instance (a singleton) Score object.
Really simple case might be something like:
public class Score
{
public int TheScore { get; private set; }
public static _instance;
public static Instance // I'm using a static property, but you could also create a static "getInstance" method if you prefer
{
get
{
if (_instance == null)
{
// Note: if you are multithreading, you might need some locking here to avoid ending up with more than one instance
_instance = new Score();
}
return _instance;
}
}
private Score()
{
// Note: it's important to have a private constructor so there is no way to make another instance of this object
}
public int AddToScore(int score)
{
// again - if you have multiple threads here you might need to be careful
TheScore += score;
}
}
Now in your object that might update the score, you just:
Score.Instance.AddToScore(100); // adds 100 to the score
Now if you want to get really fancy here, you could abstract the Score class into an interface IScore and then use an inversion of control (IoC) container to manage it for you. That way you can decouple the implementation of the class that holds the score from the classes that will consume it.
And of course to get the current score:
int currentScore = Score.Instance.TheScore;
If you want to use events, then you could look at the publisher/subscriber pattern where you'd basically have a singleton that acts as the manager for your events and everybody that need to publish an event (i.e. your Player class) will publish to it and your Score class will subscribe to it.
Here are a few changes that will give you much smoother coupling
public interface IScoreable {
event EventHandler<IScoreable> Scored;
int Value { get; set; }
}
Create a new ScoreEventArgs class to handle your event args in a more flexible way
public class ScoreEventArgs: EventArgs
{
public int Score {get;set;}
// Can put more properties here to include when the event is raised
public ScoreEventArgs(int value)
{
this.Score=value;
}
}
Changes to your abstract class to ensure that event is handled according to your needs
public abstract class Scorable {
event EventHandler<ScoreEventArgs> scored;
public event EventHandler<ScoreEventArgs> Scored;
{
add { this.scored += value; }
remove { this.Scored -= value; }
}
// onScored method now handles the object (could be player in your case) where its called from and the score
protected virtual void onScored(IScorable sender,int score)
{
if (Scored != null)
{
var e = new ScoreEventArgs(score)
Scored(sender,e);
// Could set optional this.Value += score; // to get the current score or something like that
}
}
public int Value { get; set; }
}
Your calling class which will implement the event and will have a score
public class Player : Scorable
{
public Player()
{
// Also can register a scored event callback
Scored+= new EventHandler<ScoreEventArgs>(PlayerScored);
}
private void PlayerScored(object sender, ScoreEventArgs args)
{
// Other logic can go here as well, this method will be called after the onScored(this, e) is called from the PlayerScored method.. You can update your UI or do other stuff here
}
public event EventHandler<ScoreEventArgs> Scored
{
add {this.Scored+=value;}
remove {this.Scored += value;}
}
private void PlayerScored()
{
// Raise the on scored event
onScored(this, new ScoreEventArgs(10));
}
}
Hope this clears some ambiguities..

Categories

Resources