Search Unity

The Interface Component Pattern

Discussion in 'General Discussion' started by jeango, May 17, 2019.

  1. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    It's not an absolute number, nor an absolute rule (hence the "probably"). What it means is rather "as your class becomes bigger, the need to reconsider your design becomes bigger".

    I don't know about your country, but in mine, University is about theory, where College is about practice. Programming was a very minor part of my cursus for example, instead we learned about compilers theory, design theory, patterns theory etc. Often using pseudo-code instead of an actual language (though, Java was used to illustrate OO concepts).

    But I also had that same feeling about some teachers not knowing what they were talking about, and not being in touch with the actual practical side of things.

    It depends, a pattern is a practical solution to a problem. Here the problem is to serialize an interface in the unity editor, my solution is to use a component as an interface with other components. It may look too simple to be called a pattern, but no one ever said that something needs to be elaborate to be called that. Just look at the Template pattern, it's probably the most simple pattern in the world. Yet they call it that and no one has complained about it in the last 20 years.

    MonoBehaviours have a lot of issues. Just because they implement the composite pattern doesn't mean you shouldn't be looking for ways to make it better.



    you're absolutely right, it's not the end of the world. Does it mean one should not talk about how they could be using them better in the first place?


    I would disagree with this. Games are different, but mechanics are similar.
    You shoot stuff, deal damage, gain points, display feedback, ...

    You shouldn't re-invent the wheel every time you make a game, but if your design is plagued by dependencies, you'll eventually indeed have to do that.

    Sure that's not the case with ALL the mechanics in your game, but the less time you spend on re-doing stuff you've done 1000 times before, the more time you spend on doing the new stuff
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    What I've meant by this:
    Is that interfaces are basic design blocks of the application.
    You could've replaced the whole article with a single "Use interfaces kids, they're good".
    And that would've saved you a bunch of time to make an actual useful blogs / articles / tutorials.

    Yeah, data / behaviour should be a separate thing. Might be worth mentioning that.
    Problem is that Components in classic approach is not that good for containing data.
    ScriptableObjects are.

    Making components like [Health] [Damage] makes little to zero sense, when you actually should have ScriptableObject data containing all immutable data required per entity.

    Making them atomic also makes it pain in the ass to modify for designers.
    Because their data would get inevitably attached to the prefab.
    Which leads to data duplication and waste of memory.

    (Nested prefabs are kinda ammended that, its still there)

    Putting the behaviour inside of component instead of data, might be the right thing to do.

    From what I see you're really into making C stand out. Maybe you should switch to ECS instead?
    It would fit all your article / tutorial needs as well as filling that void in the information on the ECS topic.
     
    Last edited: May 22, 2019
  3. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Also, a bunch of things that will backfire on those who will follow your article:
    1. Using classes instead of structs for data. (.TakeDamage(new Damage(...) alloc);
    2. .GetComponent<T>. Slow. Using in conjunction with lots of calls will drain your performance.
    Using it inside inherited class is even more evil since its hidden and not a nice move.
    3. Using caching will ruin your "no-dependency" mojo.
    3.1. Unity is all about Service Location not Dependency Injection.
    4. Not using ScriptableObjects as an immutable data object container.
    5. Null checks. They're not free, because they're overriden by Unity's Object.
    6. OnCollisionEnter callbacks (slow and unreliable);
    7. Splitting behaviours into atomic parts will make your inspector and designers wanna cry in the corner.
     
    RecursiveFrog likes this.
  4. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    I think you missed the point of my article. While I do spend some time explaining why interfaces are good, it is not the main subject. The subject is about the limitations of using interfaces with Unity's serialisation (and more specifically, the inspector). A few days ago, I even read a comment on a GDC vid, with a guy complaining about "When do we get interfaces in the inspector". Maybe the problem you have is with the name I give to my pattern. Perhaps "Interface Serializer Pattern" would make things clearer.

    Anyways, I don't find this article useless, because at least it leads to this discussion we're having, and anything that provoques debates, exchanges of opinion, and constructive criticism is in my opinion worth writing.

    I know ScriptableObjects were initially made to serve as Data Containers, however I don't like the school of thought that they should never be used to implement behaviour. One use case for ScriptableObjects I find wonderful is to implement State-driven behaviour, or a Strategy. I even use scriptable objects that contain absolutely no data, and only implement one method, as a means to inject code into a MonoBehaviour directly through the inspector.

    Example: I made a "Boss" game where bosses have phases in combat. At one point I was happy with one of the phases but thought it didn't sit right with how that boss fight was going. I eventually re-targeted that phase on another boss without having to change a single line of code, all through the inspector.

    My objective, when I program for Unity is twofold
    - Empower other devs (be it someone else or my future self) by writing code with scale and reuse in mind
    - Empower the editor users (who may be devs, but may not be devs) to be able to tweak or even implement mechanics without resorting to code.

    I fully agree, but that was just an example to illustrate something. My article is not about how to best implement health, it's about how to serialize an interface.


    Oh yeah, ECS is something I've been wanting to look into for a while. I've been discouraged by some people who told me it's only meant for AAA games, but I'll get to it no matter what, because I'm too curious a person to just accept to keep that door locked.
     
    xVergilx likes this.
  5. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Naming it "How to serialize an interface in Unity" might be a better alternative.
    Nothing prevents you from making a custom interface serializer and overriding default editor by the way.
    (I think Odin Serializer does that?)

    Behavior Trees exist for those things. Swapping one sequence for another is probably a single click & drag action (depending on the implementation).
     
    RecursiveFrog likes this.
  6. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    I agree with most of that, but I wanted to keep things "simple". I see what you're trying to say but really you can't jam every single bit of code optimisation in what is just a practical example used as a means to explain something else.

    When you explain to your kids how rainbows are made, you don't start talking about the cycle of water and the effect of astrophysics on the weather.

    However I'm curious about your comment on "OnCollisionEnter" callbacks. It seems like a very bold statement, that pretty much invalidates the entire purpose of Unity's physics layer.

    Also I don't know much about the Service Locator Pattern, I'll look into it.

    Edit: I guess you're talking about the way Unity handles Event Functions (Update, Start, ... and SendMessage).

    While it's (kinda) fine to work in that way for unity's framework (which, thank god, was made much less error-prone since they added auto-complete), I would definitely want to stay away from that pattern for my own code. I abhor SendMessage with all of my soul.
     
    Last edited: May 22, 2019
  7. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Depending on the Unity version and method overload you're using, those callbacks (their contacts) may not have recycling, leading to alloc.
    Make sure you've got Physics -> Re-use callbacks enabled.

    Any message passed from native side to managed is slow (all of them, .Awake, .Start, .Update, .OnCollisionX, .OnTriggerX etc, even empty methods have overhead, due to them being registered internally and called anyway).

    This is more visible when using lots of behaviours. .Update() is the most common case that is tossed away and replaced by a single managed side manager.

    From my experience OnCollisionX / OnTriggerX is not reliable as it might seems.
    As they tend to not fire at all sometimes (probably some legacy bug that nobody really cares to fix, because its really hard to pin down).

    Also, collision ones called too often (on collision, duh).
    And may be called on things that you do not want, leading to extra null-checks and wasting cpu usage.

    Also, they're prone to velocity issues the same way as rigidbodies are. (They ignore intercollision at high velocities)

    Also, they're almost always slower than simple physics query.

    Rolling a custom trigger solution that doesn't perform checks constantly is most-likely best solution in these cases. Depending on the design requirements, it may be even better to replace those with a simple physics queries instead.

    SendMessage shouldn't even exist in the first place. It just an abomination.
     
    RecursiveFrog and jeango like this.
  8. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    At least we can fully agree on that :D

    Very interesting that part about Collisions. I'm honestly really not versed at all in optimisation considerations, imho it's a specialty on its own that is very precious indeed. Yet another string missing on my Unity guitar.

    I'm curious though, how do you get away without constant checks for collisions? Do you use an inference engine to anticipate (or posticipate if that's even a word) collisions?
     
  9. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Simple timer + rng frame split + disabling when not needed + managed update system (for slow moving objects).
    Physics for rigidbodies are still handled by the physics engine.

    For things that move too fast for physics to react I use physics queries that can envelope whole delta distance traveled (without any rigidbody).
    As a bonus, when query hits something you've already got your callback.
     
  10. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    In first sentence you have it right - things depend on how the game is going to work. If something takes you into semantics, you've gone off-track. For example, stopping to consider the Responsibility of Health, and whether that includes taking damage. I'm saying the Single Responsibility Principle tends to pull you away from your design and into semantics. IMHO, it's not useful.
     
  11. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    If you dont carefully design health or any other system you end up with a spagetti project which is impossible to maintain, atleast if you are more than one dev. Single responsibility is part of that
     
  12. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    Yes. That was the last bullet in my comments.

    Yikes! That mess of a wikipedia article proves my point. They even changed the name from Dependency to Coupling (in the Talk section) and list a dozen contradictory rules. In C-like languages, a formal dependency is something you need in order to compile. If Health declares "DamageTakerA DTA;", that's a dependency. It you replace it with "IDamageable ID;" which is aimed an a DamageTakerA, you're eliminated the dependency, and now formally depend only on the smaller IDamageable interface.

    Most people seem to use it as the English meaning "something you use". If feels that way when jeango wrote Health could turn into a huge mass of dependencies. If "fire heals me" is a checkbox in Health, there's no formal dependency. If Health reaches over and checks CreatureType, then there is. But I think the intent is to say Health will be hand-checking too many special cases.
     
  13. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    Coupling is what happens when you have a dependency. The change in name for the Wikipedia article doesn’t mean «dependency» is a bad term and shouldn’t be used.

    Dependency is to coupling what intercourse is to mating.

    As for what a dependency is, it's really not complicated:

    Do your refer to another concrete class in your class? Then that's a dependency

    There's really not much more to it than that.

    The more your class relies on how your dependencies are implemented, the more coupled your class becomes.

    Let's say your class A declares a variable of type B. B is said to be a dependency.

    Then you call the method B.DoStuff().

    If you start caring about what "DoStuff()" actually does, then you are coupled to B's implementation of DoStuff. If the guy who rote class B suddenly changes his code, it may have an effect on your code.

    When you code to an interface instead of coding to a concrete implementation, you can't possibly care about what "DoStuff" does, because you have no way to know what's going to be implemented. That's what happens in my OnCollisionEnter call. I don't care what it means for the collider to TakeDamage() whatever the implementation is, I just tell it to do it.

    As to my phrase "Your class has become a dependency monster" I was extrapolating on the future of the Health class if you keep pushing every new damage-related feature into the Health class. Sure you can find some example that will add code without adding dependencies/coupling, but it's a slippery road.

    In the end, there's always going to be dependencies at some point, they're not bad per se. But if you can get away with not having one, it's better.
     
    Last edited: May 22, 2019
  14. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    The beauty of event aggregation, two completly separated components can communicate without knowing anything about each other. Coupled with scoping (for example in our game items have an internal event aggregator that only lives within the scope of a single item) it's a very powerful tool
     
    angrypenguin, jeango and xVergilx like this.
  15. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    Beautiful
     
  16. RecursiveFrog

    RecursiveFrog

    Joined:
    Mar 7, 2011
    Posts:
    350
    I understand that point. However, it’s quite dangerous to try to teach a person how to shoot a gun without ensuring that they know the rules of gun safety. Similarly, teaching people how to program in Unity as though they were an enterprise developer, without recognition of the problems they are going to encounter and the trade offs they are making will place them into a situation where they have created an intricate system completely dependent on code practices that will grind their gameplay to a slideshow.

    You can’t afford to remain ignorant of the considerations required to develop a game on a resource constrained device, so it’s absolutely worth calling out in your work when a choice is made with a trade off. Alternatively, it may be worth starting with a lesson on the trade offs, since they are such an important consideration.
     
    xVergilx, Ryiah and jeango like this.
  17. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    Point taken. Boy I never imagined I would learn so much from posting this :)

    Keep them coming ;-)
     
  18. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Your site looses responsiveness if you shrink the page horizontally. Which is a pain for those of us who like to have forums and blogs on one half of the screen and do the day job on the other half. The code sections don't scale well with page size either.

    Is that what you were going for?
     
  19. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,619
    I'm glad you're getting something useful out of it.

    Perhaps explicitly breaking the article into two parts would help? First part is a problem definition, second part is your pattern as a proposed solution to the problem.

    Maybe also linking to your own definitions of some of the academic terms used would be useful, for those who aren't already familiar with them?

    The point is that this is a well researched concept, with published articles since the late 70s, which has become standard terminology since, and which even has resulted in other, also well-recognised areas of work such as Dependency Injection. Some of the other stuff discussed in this thread is similarly recognised and valuable.

    I'm not one for blind adherence to these things, but I certainly acknowledge that they exist and are useful in discussions like these.
     
  20. jeango

    jeango

    Joined:
    Dec 19, 2012
    Posts:
    109
    It’s just the layout of the default Overblog presentation. I still have to look up how to customise it but it looks like it’s a mess. Probably can touch upon the CSS though.

    The code snippet I’m definitely unhappy about but I couldn’t find any option to fix it. If you know of a nice way to embed code on a blog page I’m all ears
     
  21. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,997
    The few professional game developers I've know are pragmatic. Most of their skills are about game play - level design, flow, balance. They have just enough coding to be able to tweak old code. Their top 10 list of things to get better at doesn't include coding. I'm thinking of, say, Clash Royale, which was only a few people from the studio, wildly successful, but really pretty simple. I wouldn't be surprised if every ability was built-in to the monster class, or added using IF's. Or my current favorite, Idle Apocalypse. It does clever things with numbers, but otherwise could have been written in Basic - none of the monsters or items have special abilities.

    It's hard to get a real sample. Way back, Forums and UA was all unityscripters who kept things as simple as possible. Now Forums is more the dedicated C# crowd, but it's only, what, a dozen or two at most? The best way might be to go to, or find people who attend the GDC's. You used to meet lots of people from all over that way.
     
  22. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Gameplay and maintainability goes somewhat hand in hand. Atleast I you have a complex domain for example VR game with physics based interaction.

    Down the line you need to refactor alot to account for new ideas, tweaks, etc. Not staying it can't be done on a messy code but it will take longer time and the code will become a bigger mess. Better put that time on polishing the mechanics.

    Though you might be right, no idea, have only played my own game that I know is made by a (c# crowd guy). But I don't give much for anecdotal evidence