Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

multiple classes with similar components?

Discussion in 'Scripting' started by mahdiii, Jan 29, 2018.

  1. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    Hi.Suppose you have some components (like 3 components). You have to use some of them in your classes (maybe you have to use all of them)
    See below:
    Code (CSharp):
    1.  
    2. public interface IClass{
    3.    void Func();
    4. }
    5. public class CClass:Monobehaviour,IClass{
    6.    public void Func(){
    7.       ComponentA.Func1();
    8.       ComponentB.Func2();
    9.       ComponentC.Func3();
    10.    }
    11. }
    12.  
    13. public class CClass1:Monobehaviour,IClass{
    14.    public void Func(){
    15.       ComponentA.Func1(parameters);
    16.       ComponentB.Func2(parameters);
    17.    }
    18. }
    19.  
    20. public class CClass2:Monobehaviour,IClass{
    21.    public void Func(){
    22.       ComponentA.Func1(parameters);
    23.       ComponentC.Func3(parameters);
    24.    }
    25. }
    26.  
    27. public class CClass3:Monobehaviour,IClass{
    28.    public void Func(){
    29.       if(Condition){
    30.          ComponentB.Func2(parameters);
    31.       }
    32.       else{
    33.           ComponentC.Func3(parameters);
    34.       }
    35.    }
    36. }
    How can we implement fewer classes and more generic? Can we use the command design pattern with an command array? or delegate?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    Your code references fields that are undefined.

    The context is also way to ambiguous.

    What is it you're attempting to accomplish?

    Are you trying to call some 'Func' on a group of components? What are CClass1/2/3 for? What is your end goal, what are you trying to accomplish?
     
    eisenpony and LaneFox like this.
  3. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    I have already faced it a lot.
    Suppose the classes 1,2,3 are about showing a panel
    I need components like effect component,sound component, animation component ,etc
    but in different classes (to show panels), I need different components. Sometimes it needs all of them sometimes not,..
    Do I need to define a different class for every panel?
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    Can you show a real world example?
     
    eisenpony likes this.
  5. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Have them all, use what you need, you can even have bools with ifs or an enum with a switch so they can use the components you want them to. Still it sounds like your logic is failing, I understand the question you want answered but it depends on the implementation.

    An idea might be to have the "components" inherit or have controler classes that inherit from one ComponentArrayItem with a public method Action(). Then have an array of ComponentArrayItem and call the Action(). Then have clases like ComponentAudio that in Action() they actually use audioSource.Play().

    Or something like that, hope i got my point across. If you have any questions i'll be here.
     
    mahdiii likes this.
  6. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    I said above. Sometimes I need to play an animation when a panel was shown or play a sound or effect but in all panels, I don't want it
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    I get that.

    And your code example is arbitrary, and that description is vague.

    I have no idea what sort of design pattern you're shooting for here. You want to discuss design... but are doing very little to demonstrate design.

    .......

    You know, never mind.

    This is what your threads often devolve into.

    I don't know why I even partake in your conversations.
     
  8. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Code (CSharp):
    1. if(iWantToPlayAnim){
    2.     animatotion.Play();
    3. }
    4. if(iWantToPlaySound){
    5.     sound.Play();
    6. }
     
    mahdiii likes this.
  9. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    you mean something like below?
    Code (CSharp):
    1. public interface ICommand{
    2.    void Run();
    3. }
    4. public class CPlayMusicCommand:Monobehaviour,ICommand{
    5.    [SerializeField]
    6.    AudioSource m_audioSource;
    7.    public void Run(){
    8.       m_audioSource.Play();
    9.    }
    10. }
    11. public class CPlayAnimationCommand:Monobehaviour,ICommand{
    12.    [SerializeField]
    13.    Animator m_animator;
    14.    public void Run(){
    15.       m_animator.Play("anim",0,0);
    16.    }
    17. }
    18. public class CShowPanelController{
    19.    ICommand[] commands;
    20.    void OnEnable(){// show a panel
    21.       for(int i=0;i<commands.Length;i++){
    22.          commands[i].Run();
    23.       }
    24.    }
    25. }
    26.  
    and use a controller that keeps an array of commands and call the commands? Run()
    when show a special panel?
    but if it was complex?!
     
    whileBreak likes this.
  10. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Exactly that, maybe turn ICommand into a class, since you can't assign interfaces on the editor.
     
    mahdiii likes this.
  11. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    you need to correct yourself at first. I don't like your conversation
    Do I force you to talk with me that you speak like this?
     
  12. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Vague description, indeed.

    My first recommendation are events or a listener-interface design, as it looks like a variable number of "components" are supposed to just "wait" for something to happen. That's a perfect situation for event-based designs.

    Perhaps I'm mistaken though.
     
    LaneFox, mahdiii and lordofduct like this.
  13. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    I'm not the only person who finds you vague, lacking in description of your problems, and often leaving out critical information and bringing it up later like it should have been known the entire time.

    I'm just not as sweet as everyone else. And instead insist that if you expect us to offer up our time/resources to assist/discuss with you... that maybe you should offer up a little more effort in describing your problems. I consider it both rude to me, and rude to my fellow forum members.

    By allowing shoddy descriptions of problems to persist, it fosters a notion that forum members can just vaguely meander through their problem until some kind soul comes in and sifts through the nonsense and magically pulls an answer out. Both wasting their time, and offering no true learning experience for the OP. Teach a man to fish, not give a man a fish.

    As my signature says:
     
    MadeFromPolygons likes this.
  14. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,383
    I'm really not sure what you're asking, your posts are unclear and vague and already suggested...

    But either way I would refrain from having an Interface of something extremely generic like ICommand with a Run() method in it. Not only would you have to loop through every component every time you want to use it but you have zero guarantee that it's going to be safe to use. Seems like a bad use of Interfaces to me.
     
    mahdiii likes this.
  15. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Not trying to argue, but i don't understand where you are coming from. Isn't the idea to loop through them? and what do you mean about not guaranteed to be safe?
     
  16. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,383
    From his examples it looks like he wants to put a Run() method on a bunch of unrelated components and 'fire and forget' on some object. If he has say, five components on that object that use ICommand then in order to use them all you have to get *all* of the components and target the ones that use ICommand. Then you are presented with the issue of whether or not you want to actually "Run()" all of those. What is Run() used by? Something so generic is dangerous to fire because it could be used by unrelated systems and have unexpected results.

    Whereas if you used something more specific like IUseAnimation { Animate() }, IUseParticles{ PopParticles() } and IHoverHighlight { Highlight() } then you can have your code target more explicitly and specifically what you want to occur, perhaps only firing animations and particles but not highlighting, rather than just hoping that there aren't components that are going to use the generic Run() method and say, Highlight, when you don't want them to.

    Overall it's a smelly approach when there are definitely more explicit and clearer approaches.
     
  17. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    are you ok? stop spam you are rude WTF
    I speak politely. I say again. Speak kindly or dont speak or discuss. I don't owe you. Understand? never answer to my questions if you think you waste time
    I helped to other developers a lot but you need to change yourself
    If you see others answered please finish and don't bother yourself
     
  18. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,383
    Just to be clear, we pretty much agree with his points. You'd benefit from trying to understand what he's saying and use that criticism to create better posts which will in turn yield better responses.
     
    MadeFromPolygons likes this.
  19. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    he doesn't need to speak 5 lines and insult me
    he can say politely, "Can you say an example and give more info"
    Even when I said an example clearly and some one answered, he didn't finish his discussion!
     
    Last edited: Jan 29, 2018
  20. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    So you prefer to create special classes like a class to show a panel with animation and not effect, other class uses playsound and animation and another one uses effect component etc?
    Thanks
     
  21. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    I have been for over a week.
     
    MadeFromPolygons likes this.
  22. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Oh yeah of course, nonetheless the idea was to have an array on ICommand on the component editor, so he would explicitly say what should be run. Thats why I recomended to use a monobehaviour as a class, sice like you said, you can only get interfaces with GetComponent<ICommand> and interfaces cannot be assigned on editor.
     
  23. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,383
    Pre-populating the interfaces in the editor? Why even have the interface, then?
     
  24. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Because if you don't, then you can't know beforehand how to use each component, since you don't know what components should be used, so you can't prepare for them either, hence an array to populate them by hand, plus the interface (that actually should be a base class) so you know how to talk to them. And the children classes that know how to talk to the components that they want to talk to.

    Another good idea would be to have just a single "resource/manager" class and instead of using an array of ICommand, use an array of UnityEvents and on the manager expose public methods like PlaySound(AudioClip), or something like that.

    Another idea would be just a simple !=null (for clips) or string notEmpty (for animation triggers), so if you have the resource you use it and if you don't, well, don't use it.
     
    mahdiii likes this.
  25. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,383
    It was a rhetorical question :p I don't see any upsides to doing this over more traditional design.
     
    whileBreak likes this.
  26. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    :eek:
     
  27. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    If your problem is that I can not assign interfaces to the inspector, you know that we can not use interfaces because of its nature. we implement them. So you can easily create gameobjects and assign arbitrary implemented interfaces for the gameobjects one by one like below and use getchild and GetComponent or other functions to access them
    -Root
    ---Gameobject1 (Command1 implemented ICommand)
    ---Gameobject2 (Command2 implemented ICommand)
    ---Gameobject3 (Command3 implemented ICommand)
    ---Gameobject4 (Command4 implemented ICommand)
    ...
    But dude LaneFox is right. It is not suitable to use interfaces like it. They are different and so general
     
    Last edited: Jan 29, 2018
  28. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
  29. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    It does actually depend on how you attempt to model the system. In my previous post, I mentioned a design that uses events or the listener-interface.

    First of all, yes: if you simply use GetComponents<TInterfaceOrComponent>, you might find some instances that are not meant to be addressed at all. This is surely not desired. But think about it: that's quite the opposite of what's happening in the case of populating the array/list through the inspector.

    The latter is some sort of dependency injection. The object that owns the array/list does not resolve the instances itself, instead they'll be set through the serialization system. And who does actually have the wise knowledge about how and where to set the dependencies? It's a third party, but who? It's you in this case (and later, the serialization system).
    None of the other both components know how to wire themselves up - and that's great!! (Keep this in mind)

    So basically, that's the drag&drop DI alternative for manual programmatic DI.
    However, it doesn't allow interfaces out of the box - so sad!
    But wait... Let's figure things out:

    You could now write small listener components and let them search and register for other components that they're interested in. They'd be aware of injecting themselves, whether or not the direction of dependency is desired and reasonable depends on various aspects, but that's also one approach to consider if these are very specific listeners (if they're components that are meant to be re-usable in various ways - not a great solution either.

    Third DI solution is to have some kind of controller/moderator/manager (terms vary alot). They wire things up, like a main method at the root of your program, they're more like the main hall where everything will be gathred and prepared for their specific sub-system. They do know more than those types that are about to be wired up/connected.

    Benefits?
    - EventReceiver/Listener (the callee) doesn't need know where to register - which is great, as it pushes software qualities.
    - "EventEmitter" (or simply the caller) does not need to care about getting the components to adress - which is great, for the same reasons above
    - you can use interfaces
    - you can re-use everything and only need to change that controller/moderator/manager component
    - some more...

    Anyway, built-in features for the rescue or long story short: UnityEvents.

    You can wire things up in the editor yourself - no additional code to control who knows whom - , which decouples your components, which in turn favours re-usability etc.... You don't even need interfaces, since you can just select any method that fullfills certain requirements. This is almost unavoidable in a fully programmatic approach, since base classes are often too restrictive.
    Last but not least - it can be done by designers.

    I gotta admin though, that I'm not a huge fan of UnityEvents. That irony kills me.
     
    Last edited: Jan 29, 2018
  30. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    Interfaces are supposed to sort of be general. They're supposed to abstract the interface (public members) of a class.

    But if you make it too general, they can be harmful. Especially in a component design model.

    Something like 'ICommand.Run' is a very general interface. What is this supposed to be used for?

    Lets take the unity events system... there are interfaces like IPointerEnterHandler. This is a very clear thing as to what the interface is intended for. If you're implementing it... you intend to receive this message in relation to the unity UI EventSystem.

    What is ICommand for though? If it's a specific type from a specific framework of code (like the unity EventSystem)... well then I'd say the naming is a bit vague. Where as if it is intended for anything that has a command, a parameterless void method... well, odds are that the majority of your classes have at least 1 public parameterless void method. So... what's the point of this contract?
     
    eisenpony likes this.
  31. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Oh yeah I agree with that, but I think that was just an example.
     
  32. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,383
    Well that's what he posted, so that's what we're discussing, literally, as he requested. Let me just quote this...

    As you can see, it's not as if there wasn't effort made to clarify the senseless and poorly defined example. So in light of that and his vigorous defense of his code, yes, we're taking it literally - as silly as it is.
     
  33. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    Yes it is perfect. You can assign functions for example to OnClick or other EventTriggers. They are called consecutively
    Code (CSharp):
    1. Animate() function --> Assign to EventTrigger or UnityEvent,...
    2. public class CAnimate:IAnimate{
    3.    public void Animate(){
    4.       //implement this
    5.    }
    6. }
    7.  
    8. Play() function --> Assign to EventTrigger or UnityEvent,...
    9. public class CPlaySound:ISound{
    10.    public void Play(){
    11.       //implement this
    12.    }
    13. }
    14.  
    Some developers prefer to use nullable design pattern like below:
    Code (CSharp):
    1. public class CAnimate:IAnimate{
    2.    public void Animate(){
    3.       //implement this
    4.    }
    5. }
    6. public class CNullAnimate:IAnimate{
    7.    public void Animate(){
    8.       //empty
    9.    }
    10. }
    11.  
    12. public class CPlaySound:ISound{
    13.    public void Play(){
    14.       //implement this
    15.    }
    16. public class CNullPlaySound:ISound{
    17.    public void Play(){
    18.       //empty
    19.    }
    20. }
    21.  
    And then use them in a special class (here showPanel)
    Code (CSharp):
    1. public class CShowPanel:Monobehaviour{
    2.    [SerializeField]
    3.    GameObject m_animateObj;
    4.    [SerializeField]
    5.    GameObject m_playSoundObj;
    6.  
    7.    IAnimate m_animate;// use GetComponent to initialize
    8.    IPlaySound m_playSound;// use GetComponent to initialize
    9.    public OnEnable(){
    10.       m_animate.Animate();
    11.       m_playSound.Play();
    12.    }
    13. }
    So you don't need to check null condition like traditional approach "if (m_animateObj!=null)"
     
  34. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Ok I'm sorry for trying, I'm out . This really doesn't make any sense, i thought it was just the language barrier.

    But if you are just going to use them like that what's the point on having any kind of wrapper/interface? Just use the damn component.
     
  35. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    You understand my frustrations now.

    lol
     
  36. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,383
    Glad we got that sorted.
     
  37. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    I cannot quite follow your thoughts here, and how this is an answer to my post.

    Anyway... I've only ever seen people doing that with delegates though. Some people like to add empty lambdas to it, but you're just loosing one valuable and important state (null).
     
  38. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    However it is a pattern that can be used to prevent null probelms
    In Game programming books:
    "Fortunately, there’s another design pattern called “Null Object” that we can use to address this. The basic idea is that in places where we would return NULL when we fail to find or create an object, we instead return a special object that implements the same interface as the desired object. Its implementation basically does nothing, but it allows code that receives the object to safely continue on as if it had received a “real” one.
    To use this, we’ll define another “null” service provider"
    Code (CSharp):
    1. class NullAudio: public Audio {
    2.    public:  virtual void playSound(int soundID) { /* Do nothing. */ }
    3.    virtual void stopSound(int soundID) { /* Do nothing. */ }
    4.    virtual void stopAllSounds()        { /* Do nothing. */ }
    5. }
     
  39. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Still going this thread.. :)
     
  40. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    MadeFromPolygons likes this.
  41. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    853
    Why do you spam?Why do you mock and jeer?
    It takes your memory? are you admin?!
     
  42. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
  43. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    971
    Your classes are doing different things with your components in different orders and under different conditions. This is exactly the kind of reasoning you want to encode into your classes. Don't try to abstract that away using design patterns for the sake of design patterns.

    Let's dig a little deeper.
    Your classes implement IClass. Great! You are coding to an abstraction. I hope your components code to an abstraction too! Also, it is totally okay for both of your classes to implement this abstraction differently. That is what makes them useful as concrete implementations of IClass.

    CClass1 appears to use ComponentA and ComponentB while CClass2 uses ComponentA and ComponentC. These two classes have different dependencies so they should be explicitly different:
    Code (csharp):
    1. CClass1 : IClass
    2. {
    3.   IComponentA A { get; }
    4.   IComponentB B { get; }
    5.   public CClass1(IComponentA a, IComponentB b)
    6.   {
    7.     A = a;
    8.     B = b;
    9.   }
    10. }
    11.  
    12. CClass2 : IClass
    13. {
    14.   IComponentA A { get; }
    15.   IComponentC C { get; }
    16.   public CClass1(IComponentA a, IComponentC c)
    17.   {
    18.     A = a;
    19.     C = c;
    20.   }
    21. }
    If you insist on making your classes derive from MonoBehaviour, you will need to inject your dependencies a different way, but the premise is the same.
     
    Last edited: Jan 30, 2018
    mahdiii likes this.
  44. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    971
    This, and the null reference problem are disadvantages of the service locator anti-pattern (which GetComponents<T> is)
    This sounds weird to me. Our registration will be all over the place instead of all in one spot.
    This is the proper way to do DI, though I understand that pattern doesn't fit into Unity very well, unfortunately.
    The Null Object design pattern is a nice fit with DI. It can be used to make sure a dependency always has an implementation so our code doesn't have to worry about defensive programming when using its dependencies. If my class says it needs an IFoo, then I don't want to litter my logic with if (MyFoo != null).. Instead, I should simply inject a null object which implements IFoo by doing "nothing".
     
    mahdiii likes this.
  45. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    @mahdiii
    I still don't understand that transition from "here's how you could wire up your components instead of writing very similar classes over and over again" to "instead of null check, we can just use the null object pattern".

    And yes, that's a pattern. But like any pattern, it has got pros and cons. It's useful in particular situations, not as a random or even ultimate replacement for null-checks. Do you really want to add a bunch of NullXYZ classes while you could just add a fast null-check, which is also straight-forward when you look at the code?

    I mean, at some point, you also have to implement some logic for the aquisition, replacement and removal of that NullObjectComponent. This adds complexity and raises questions about who's responsible for that. You're also introducing unnecessary "states" that you might need to consider at a later point. Why so complicated?
    They also have the potential to swallow important information about flaws in your program.

    Use them when there's an actual benefit, don't misuse it.


    I don't think it's weird, you can find that everywhere. Perhaps my wording was a bit bad. In fact, it's the one that's probably used most of the time: Components that subscribe themselves to events, or tell some other object about their existence. In other words, they're aware of some information that limits re-usability to a certain extent.
     
    mahdiii likes this.
  46. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    971
    In the context of events, I agree; interested parties might subscribe themselves. However, in the context of dependency injection, it's better to do all the "wire up" in one spot -- the so called "composition root". If class A is interested in the events of class B, it has a dependency on class B and should have it injected from the composition root.. Class A is then free to subscribe to the events of class B.

    Compare to Class A searching and registering to "interesting" components. This is the Service Locator approach which, arguably, provides no advantages and some disadvantages vs. pure dependency injection.
     
    Last edited: Jan 30, 2018
  47. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    If a component is able to subscribe itself to an event, it is also able to inject itself as a listener. It's basically the same principle with just a few different requirements, but in both cases, it has to know the emitter/target.

    Anyway, I totally agree that it's best to have a composition root which does the job, this includes subscription to events.

    Keep in mind though that (in Unity) we've got the built-in infrastructur for all the different ways of locating a service (component) that we're interested in.

    For instance, in a normal application, I would never implement a PointerClick class that attempts to resolve a dependency to a specific button on its own. That's not intuitive, because there's no underlying infrastructure (the service locator and such) available through base classes such as MonoBehaviour - unless we implement it.

    In Unity, we've got plenty of stuff that's just right there waiting to be used - if we want it or not. And that affects how we approach the implementation of components and systems that we need.
    It's a different way of thinking based on a different architecture, because any component has the ability to query an awful lot of information out of the box AND belongs to an entity in the game world.
    And in addition to that, we fill the gap by injecting the missing information when we attach it to an object.

    If you coded that without an entity + component-based architecture, this would be horrible.

    I'm not saying that the above is optimal. It's in fact still suboptimal from the perspective of various software qualities (I'm referring to the sample of the event listener finding the event emitter on its own).
     
    Last edited: Jan 31, 2018
  48. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    289
    Agree, don't think about injection when making a component with serialized attributes, look at it as making a component customizable. This hole talk about injection on Unity is out of focus, you can't just think about design patterns and code when programming here, the user experience with what you make is a lot more closer to what you write. So in fewer words, when you expose things to the editor, it's not injection its a field for the user to use.
     
  49. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    The serialization engine populates the fields with values/objects for you, using the values/objects that you've set. This is some sort of injection. You just don't need the composition root, because it can be done by dragging&dropping instead of using the programmatic approach.

    It's also not that much out of scope, because it's an essential part that can be used to simplify the problem at hand. The OP said he wants to avoid classes that are very similar, but have slightly different fields. And these varying fields were primarily components that need to be notified when something of interest happens.

    So we continued and started to suggest one solution that makes these components have a common "denominator", i.e. an interface or base class, so that we can collect them in an array/list or any other collection. Or as an alternative, subscribe to events, so that the type does no longer matter.
    The remaining question was, who's going to know whom to put everything together, and this can be the inspector if you don't need much of additional management logic.
     
  50. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,874
    This is really not the way to talk to people who are trying to help you, please dont lash out at developers who are taking their own time to help you with yours.

    @hippocoder or any other mod will tell you that this is a place for help, but the help is text based and therefore easy to be read in the wrong "voice" etc, so dont expect just because you were offended that someone meant offence.