Search Unity

Inheritance vs Optimization ?

Discussion in 'Scripting' started by winterfive, Oct 3, 2018.

  1. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    I want to create good OOP code by using inheritance but I am going around in circles on this issue.

    Method1(a Lerp method) is in a script placed on my prefab. Method1 needs two values. It gets them using a reference to a manager script that's located on an empty game object in the scene (so I can use the editor to fill in those values). Method1 needs to be called in Update().

    The prefab is an enemy in my app. I have three types of enemies, each using Method1 in its prefab script and creating a reference to its manager class. I'm repeating code. Feels bad man.

    GenericSingleton
    ^
    EnemyManager
    ^
    Enemy1Manager / Enemy2Manager / Enemy3Manager


    Enemy (prefab script parent)
    ^
    Enemy1 / Enemy2 / Enemy3


    Should Method1 be on each prefab so it is close to what it affects? Should I have it in the manager class for each prefab type (closer to the values it needs but a step away from the object it affects)? Should Method1 be in the manager parent class? Thoughts? Thanks!
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I'm not sure I followed the structure of how you currently have things organized, but as a general rule, if you find yourself writing the same function in every subclass, that function should probably be moved to the parent class.
     
    winterfive likes this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Here's your first problem.

    Good OOP does not have an over reliance on inheritance. But rather a minor reliance on it.

    The big part of OOP is polymorphism and encapsulation. Polymorphism being the idea that 2 similar objects of similar types can be treated similarly. And encapsulation is the general idea of having a boundary to your data/implementation which generalizes it as an 'object'.

    Inheritance and composition facilitate the polymorphism. You can get a polymorphic behaviour through inheritance and composition. Inheritance has declined in popularity over the years since it has a lot of gotchas to it that are hard to resolve, and as a result composition has rised in favor.

    Unity facilitates composition via the 'component model'. By adding components to a GameObject you extend its capabilities. It is compositing its own behaviour as a sum of the components attached to it.

    A lerp method is usually a arithmetic formula. Like Vector3.Lerp, for Mathf.Lerp. They're usually value oriented, and not object oriented. In that it's a function which takes in some values and spits out some resulting value.

    As a result they tend to be implemented as a 'static' method. This way they're independent of any given object. Hence Mathf.Lerp and Vector3.Lerp are static methods.

    ...

    That is unless you meant something completely else by a "A Lerp method". Such as if you meant a function which animates an object across screen which may use a 'Lerp' internally.


    Give us a more concrete example.

    These abstract layout is mostly arbitrary and just looks like "inheritance chain with arbitrary methods". It's not enough to reliably go off of.
     
    Gametyme, Joe-Censored and winterfive like this.
  4. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    Yea, I try to follow that rule but here it got complicated in design and difficult to explain here. Hmm.
     
  5. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    I was trying to keep my post generic and simple. I definitely failed there.

    Let me try again.

    I have a prefab object (ADrone) that holds a script (AttackDrone). That script creates a reference to another script (AttackDroneManager) at runtime. AttackDroneManager is placed on an empty game object in my scene. It has public fields that show up in the editor so I can fill them in. Two of those values are needed by a method, called in Update(), in AttackDrone. They are assigned into private fields in AttackDrone and then used in LerpColor()...

    Code (CSharp):
    1.     private void LerpColor()
    2.     {
    3.         if (_glowRenderer)
    4.         {
    5.             float pingpong = Mathf.PingPong(Time.time * _glowSpeed, 1.0f);
    6.             _glowRenderer.material.color = Color.Lerp(_defaultGlowColor, _otherGlowColor, pingpong);
    7.         }
    8.     }
    Every drone in my game will need this method which normally would point towards placing it in a parent class or using interfaces. But this method is called in Update() for every frame by every drone in the game. I don't want to add extra steps/make it more expensive to run by requiring the code to go up and down my hierarchy for every drone for every frame. That's why I've placed the method in the AttackDrone script (which will place it on every attack drone instance). And this is repeating code, which I do not like.

    That's my issue. Placing the script directly on the prefab has the code "close" to the object it affects (this is faster) but this is not OOP.
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    How is this repeating code?

    The code exists in one place, inside the 'AttackDrone' class.

    You just have multiple instances of 'AttackDrone' attached do various ADrone instances. The code was not copy/pasted around... it's been reused.

    This IS OOP. You've encapsulated the functionality of "lerping one's color in a pingpong fashion" inside a class named 'AttackDrone'.

    I would argue that it breaks the KISS mentality. In that AttackDrone doesn't really describe that it pingpong's its own color, but instead that it defines the behaviour of a drone attacking. Which implies either that your class is doing more than one thing (defining a drone that attacks AND a pingpong color effect)... or that the class is misnamed if all it does is PingPong.

    If it's the ladder (misnamed), you should probably renamed 'AttackDrone' to something like 'PingPongColorOverTime' or something.

    If it's the former (too much in one class), abstract out the pingpong effect into its own component/script indpendent of 'AttackDrone' so it can be attached to not only AttackDrones, but other objects as well (composition).

    ...

    But that's just technicality stuff.

    As is, that's perfectly fine the way you're doing it.

    I'm not fully understanding your judgement calls of what is "fast" or what is "oop".
     
    winterfive likes this.
  7. winterfive

    winterfive

    Joined:
    May 21, 2018
    Posts:
    31
    Ahhhh! Thanks, I see it now!

    I named the class AttackDrone because it handles all the actions that each individual drone does independently. And this is the kind of bad naming that happens when you work on a project alone. I'll change it. Thanks again!