Search Unity

Embracing Component based design. What are best practices?

Discussion in 'General Discussion' started by Slyder, Jul 27, 2015.

  1. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    I'm finding it really hard to embrace component-based design. I can see the benefits, but some things feel foreign or wrong to me coming from an oldschool OOD background.

    The thing that bugs me the most is communication between the various components internal to different GameObjects. In this case, I'll lay out some diagrams of the different ways GameObject#1 can interact with GameObject#2:

    Note: The Components internal to each GameObject are unaware of Components in the other GameObject. The task is to get each Component to interact with the corresponding Component in the other GameObject.

    Direct Approach
    upload_2015-7-27_14-27-34.png

    Opposite of Indirect Approach. Controller#1 tells each Component to interact with Object#2 Components. Controller#1 interacts directly with Controller#2.

    Hybrid Approach
    upload_2015-7-27_14-10-11.png

    Controller#1 calls some function to handle an event on Controller#2. Controller#2 calls functions on Object#2 to interact directly with Object#1 components.

    Indirect Approach
    upload_2015-7-27_14-14-13.png


    The most elegant communication pattern. I'm not even sure how you would program this communication pattern as everything would have to be routed through the Object Controllers.
     
  2. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    Just as a note, the Component Pattern is OOD. By oldschool I'm assuming that you are talking about pure inheritance strategy.

    In my projects, I use a mix of both strategies, driven by a simple design question on entities relationship: is a or has a.

    On communication between objects, I tend to prefer anonymous dispatcher / observer pattern, centered on events instead of entities.

    Along many projects, this is the combination of strategies with best results for me.
     
  3. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    yes, I am fairly familiar with pure inheritance strategy, and it can become a nightmare lol.

    I'm planning on an approach where GameObject#1 tries to do everything to GameObject#2 and controllers either succeed or fail independently. In this case, I can group Controllers using interfaces, such as IConsumeItem and iterate them through from some other Controller.

    Could you elaborate on your Event approach? I have heard this thrown around a bit and I am curious to how it works.
     
  4. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    Sure. The simplest approach would be to have a basic (non-monobehaviour) Message class. It is then inherited by specialized messages (like entities taking damage, some construction finished and so on), for example DamageMessage:Message.

    Then, build a centralized (static) message dispatcher visible through the entire project. It is responsible for both dispatching messages on request and for registering watchers to specific messages classes. Leverage from C# event Action<> to have easily attachable message handlers with the += operator (do not forget to use -= on destruction as it is a common source of memory waste on GC environments).

    This way, arbitrary objects can listen to the said damage messages for wherever it came, totally decoupled.
     
    GarBenjamin likes this.
  5. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    I use essentially this. I don't represent it like an event, I represent it like a pub/sub system (events I generally think of as hooking to the event's originator, pub/sub is totally disconnected and centralized). But any which way, this kind of thing is super useful.

    As a side note - I would also be cautious about using a static instance for this, since you need to take a care in managing object lifespan and it's subscriptions and potentially garbage collection.
     
    NomarPimentel likes this.
  6. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    So let me try to understand this...You could have Player Pick and Item up and have the Item subscribe to Player waiting for a ConsumeItem message?

    Player then ConsumesItem.
    HungerController may try to process Food Component on item. If successful, it sends Message "ConsumeItem". When received by the Item, the Item knows to handle item removal?
     
  7. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    Could you provide a simpler example... on something that u need in your project? I will try to answer with a simple code implementing it using dispatch/obs pattern as I use.
     
  8. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    ItemGameObject
    Item
    Food (contains calories)
    Drink (contains hydration)

    Player
    CalorieController (can consume Items with Food component to increase calories)
    HydrationController (can consume Items with Drink component to increase hydration)
    NeedsController(references CalorieController and HydrationController)

    When NeedsController is told to consume some item,
    1. CalorieController tries to Consume Food component
    2. HydrationController tries to Consume Drink component
    3. NeedsController tells the Item that it was consumed if 1 or 2 is successful.

    I know it isn't "simple". I chose this use-case to build because it will teach me most of what I need to know about inter-object communications. I have many ideas on how I can process the above using GetComponent(). I wonder if this entire process could be simplified by raising some "ConsumeItem" event and listening for it on the Item.
     
  9. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    Nice. I will post a basic example code later, when I reach home.
     
  10. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    I actually simplified this from Food/Drink components into a single "Consumable" component. Each component will just pull the appropriate value out of the Consumable component. Much simpler
     
    frosted likes this.
  11. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    If you can get away with less engineering, always pick that! For reference, here's basically what my pub/sub system looks like and how you might use it.

    Code (csharp):
    1.  
    2. // this interface is entirely optional, I like it because it enforces certain conventions
    3. // but it really doesn't do anything
    4. public interface ISubscriber<T> : ISubscriber{
    5. void HandleMessage( T msg );
    6. }
    7.  
    8. // this is what message pump actually uses, it keeps lists of ISubscribers and notifies them using the type passed into Publish<T>
    9. public interface ISubscriber{
    10.   void HandleMessage<T>( T msg );
    11. }
    12.  
    13. // obviously you can get rid of this, but I like it just to be explicit.
    14. public interface IMessage{}
    15.  
    16. public class MessagePump{
    17.   // This class is just a simple wrapper on this dictionary.
    18.   private Dictionary<T, List<ISubscriber>> m_IDoAllTheWork;
    19.  
    20.   public void Publish<T>( T msg ){ ... }
    21.   public void Subscribe<T>( ISubscriber subscriber ){  ... }
    22. }
    23.  
    That's pretty much the entire thing.

    You could dump a 'messagepump' into a static object if you want, although I'd suggest against it. The code for this class can be stupidly simple, the only real catch is that if a subscriber publishes a new message in it's handler, you should really assure that all of the original messages subscribers receive notice before you broadcast the next message (you can do this by queueing messages that come in while you're 'publishing').

    Here's an example of how you use it.
    Code (csharp):
    1.  
    2.  
    3. public class ThingThatNeedsToKnowAllActiveCharacters: ISubscriber< CharacterCreatedMessage >, ISubscriber<CharacterKilledMessage>{
    4.   // subscribe to CharacterCreatedMessage and CharacterKilledMessage whenever is appropriate (perhaps in constructor, or if this guys a monobehaviour on awake or whatever)
    5.  
    6.   public void HandleMessage( CharacterCreatedMessage msg ){
    7.     // this guy keeps track of all the characters that are active, so he can update his state here
    8.   }
    9.   public void HandleMessage( CharacterKilledMessage msg ){
    10.   }
    11.  
    12.   // this just routes the messages to its handler. A poor man's dynamic dispatch or late binding without reflection.
    13.   public void HandleMessage<T>( T msg ){
    14.     ((ISubscriber<T>)this).HandleMessage( msg );
    15.   }
    16. }
    17.  
    18. // the messages can either be highly specific, or they can have more fields that provide more
    19. // detail. So for instance instead of separate Created/Killed, you could do
    20. // CharactersChanged and include a flag for if it's a killed or created. Either way works.
    21. public class CharacterCreated : IMessage{
    22.   public Character Character;
    23. }
    24.  
    You can elaborate as much as needed. I prefer it to be fast and clean rather than feature rich, but to each their own.

    It should be noted that this implementation is about the simplest implementation that's possible in c#.
     
    Last edited: Jul 28, 2015
  12. L-Tyrosine

    L-Tyrosine

    Joined:
    Apr 27, 2011
    Posts:
    305
    Very nice.
     
  13. Master-Frog

    Master-Frog

    Joined:
    Jun 22, 2015
    Posts:
    2,302
    Well... I'm kind of weird in that I'm not a professional programmer, and I do everything wrong, but it works great without issues and it's easy.

    So what I've been doing is I have events and effects, and events are things like "on click" or "on collision" and they're just components I add to gameobjects, then I use public enumeration representing different kinds of things in the scene, like Fireball or Player, and then I add a component that has essentially one method... trigger... and it does something, like change the scene or request a sound effect to play. And I link them up and customize them right in the editor. And setting it all up is a pain, but toward the final stretch when its just content adding/tweaking and its a mad dash for the finish, it is so easy to add new stuff and change things... so using components that way it's almost like visual scripting or drag and drop game making, but you can customize your drag and drop components.

    And if you don't add any of your specific game logic to these components, but make sure they're highly generalized, they become completely reusable for the next game.

    I can't be bothered with diagrams. Too busy writing code.

    However, Graphs are fun, kids:

    windowsopen.png
     
    Last edited: Jul 28, 2015
    Ony and GarBenjamin like this.
  14. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I tend to think of my components in terms if a system level, rather then at an entity level.

    In most cases you are designing and building systems, rather then entities. An entity is just something that occurs when a various systems interact.

    Components within a system are allowed to be reasonably closely coupled. The class Eater probably knows about Eatable. This kind of dependency is often not a huge deal. When replacing code you normally have to consider the whole system anyway.

    What is not allowed is random components from different systems to be dependent. Shooting and Eating are fundamentally different systems, and should not interact except through a very narrowly defined pathway.

    These systems might end up spread across dozens of disparate GameObjects. But as long as data flow through systems and between systems is understood and controlled then you've got a maintainable structure.

    Under this system building an entity is simply a case of gathering the requisite components onto a single GameObject.
     
    chadfranklin47 likes this.
  15. Master-Frog

    Master-Frog

    Joined:
    Jun 22, 2015
    Posts:
    2,302
    Well, for example, let's say I want my character to shoot a fireball.

    Does the object responsible for spawning the fireball have to be a part of my character, since the fireballs come from my character?

    If you say yes... I would say, then how many objects are going to be running around with identical spawners? And how are you going to keep track of all the spawned items?

    If you say no... I would say, then how are you going to make the fireballs spawn? The most efficient way is a single object responsible for spawning and managing a pool of fireballs. But then that raises the question of how do you talk to it from your character object? An explicit reference is no bueno...

    One school of thought says no dependencies... decouple...
    Makes sense, too. What if you start a new level and that reference you thought you had gets broken. How far are you willing to go to maintain coupled, but unrelated, objects?

    I like a central static class dispatching stuff out to everybody. Not necessarily doing anything, just letting objects know what they ought to do through method calls, then the objects can run their own logic and figure out their business.

    I'm also a big fan of sending messages and letting objects interpret them (or not) depending on what kind of handlers they have. Fast and loose is my motto. Components just fit that mentality. Drop 'em in, take 'em out... switch them around, copy and paste. Multi-edit, done done done.
     
  16. Deep Azure

    Deep Azure

    Joined:
    May 21, 2015
    Posts:
    8
    I wouldn't make something highly generalized unless I need it. Sure you may be tempted into doing so, but if your game is made only of squares, don't make your collision engine support triangles.
    https://en.wikipedia.org/wiki/You_aren't_gonna_need_it
     
    Kiwasi likes this.
  17. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I would say yes. A weapon would be responsible for instantiating and initialising it's own projectile. This could be done with a prefab reference. Or it could be done through a more sophisticated factory.

    The projectile itself would take care of it's own lifecycle. So in general there would be no need to 'keep track' of it.

    And who cares how many identical spawners you have in the game. The memory foot print of a component is fairly light. Reusing code this way is the entire point of OOP.
     
  18. Master-Frog

    Master-Frog

    Joined:
    Jun 22, 2015
    Posts:
    2,302
    There is no "entire point" of anything, right off the bat... there's so many ways of using a screwdriver it would make your head spin, infinitely more so when it comes to programming computers and the complexity of these languages we write in.

    The projectile should manage itself. Everything should manage itself. The trouble comes when two of these self-managing things come into contact with one another. The trouble doubles when thing A calls a method on thing B, because now thing A is partially responsible for thing B working correctly. So if you change thing A, you might break thing B without even thinking about it, and vice versa. What I find untenable is that these inter-dependencies actually have the effect of multiplying as the complexity of the game increases. It seems virtually unavoidable that things require lots of references to lots of other things in order to gain information about their states or, as is probably very often the case, to call a method on the other object that affects its state.

    To me, this is a giant spider web.

    Another thing, there being no need to keep track of your projectiles... this is absolutely baseless.

    Imagine a scenario where you want to create a chain lightning spell, like I am going to have in my next game. How do you do that if you have no idea where the other objects in the scene are? Do I have to iterate through each scene object, each frame? Checking if they are valid targets, checking to see if they are not already currently being affected by the chain lightning, seeing if they are a certain distance from the other nearest object being affected? Think about that for a moment... that's a lot of processing. If you already knew where all the valid targets were, you could just iterate that collection. You could build methods to find the nearest member of group x to point x,y,z, etc.

    Or, take another scenario where you wish to build a simple heatseaking missile. How do you know which object is the hottest and nearest if you have no clue where everything in the scene is?

    Truthfully, if you're making pong or space invaders, it doesn't matter. But, if you're trying to start doing things more complex, involving lots of decisions or data, it gets really messed up. You need the MVC model to keep your head straight. So to me, step one is creating a model of all the objects in the scene that can be queried. The view part in Unity is already handled. What's left is that tricky issue of control...

    And that's where I think components come in for the win. It's a lot easier to control everything in the scene if controls don't have to be hard-wired for every single thing you create. I can't even think of a single real-world thing that isn't designed to be modular, at this point. All appliances, every piece of plumbing in your house, your furniture, entertainment devices... everything is designed to be modular and has repair and replacement parts. Things can be modified and upgraded.

    I think at its core component design IS modular design, is inherently decoupled, works great, is easy to understand and just generally rocks. Writing long classes for each individual object to get the behavior you desire, just doesn't make much sense when you consider the alternative.

    Ultimately, every thing that happens in a game has what, a "cause" right? And every thing that happens is an "effect" of that "cause". And the vast majority of all your in-game operations involve activating/deactivating things, or modifying a single property of some other object's state... and this isn't new. Microsoft already broke down application development into events and the design of applications into reusable components. HTML and the DOM already have this as well. Unity actually has a Heirarchy which is very much like the DOM, except it's a lot more flexible, the drawback being you have to figure it out on your own. To me, this concept... event-based programming utilizing reusable, generalized components... this is not even really up for debate, it's just the way things are now. Unity allows you to not do it that way, though, which is really interesting.

    And if I could write every piece of code to be 100% general, I would. I'm a game designer and developer. I have to write code to do what I want, but my goal is less code, more functionality.
     
    Last edited: Jul 28, 2015
    chadfranklin47 likes this.
  19. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    It's true, my games are pretty simple, so I can get away with simpler structures. @zombiegorilla is the one that you want I talk to if you want big, complex structures for large games. And that basically amounts to using Unity only for visualisation, and running the entire game in your own code.

    Down to specific examples, you can always use the physics system to find local targets for chain lightening. You can also roll your own global list of all targets if you liked. I just get nervous anytime someone uses the terms static or global. Except for a few services and stateless helper methods, nothing should be global.

    As to the messaging system I normally find Unity's built in EventSystem sufficient.
     
  20. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,529
    I think its easy to get bogged down in all these diagrams and stuff... Like @BoredMormon eludes, you don't really need insane structures on simple/small scale games so a great deal of this could be a moot point unless you're actually applying these principles on projects with larger teams and scale and I don't think that applies as much as we think around here.

    So with that being said, I usually just try to think about how communication needs to work with the minimal amount of work. For instance in my case (right now) I use a Subject class which is basically anything I can interact with. In the Subject class you'll define what this thing is as an enum and this basic structure serves as a good gateway for communication.

    It works good for communicating between objects because you only need one GetComponent() call. All of the sub components on that GameObject will be using the Subject as a bottleneck that can hold information or direct something how to get to the component that it might need. I can usually just do a switch case on the type if what I'm trying to access isn't part of the fundamental Subject and figure out where and how to access a more specific component pretty easily.

    Basically, the data is always there and the idea is to use one component to answer questions rather than cross communicating between other components and dealing with unique situations on the fly. I do want to experiment with more abstract structure, but for now this is incredibly simple to scale up and works great for a lot of typical game styles.
     
    Master-Frog likes this.
  21. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    This is a really interesting thread. I've seen several systems written by programmers much better than myself that use a decoupled event router technique. I've tried to work that way myself, but I tend to get frustrated tracing the events. This applies both at runtime and during design.

    At runtime, I want to be able to easily identify originating behavior. Using an event router, I sometimes found it hard to tell who called an event, and when and why the receiver subscribed to that event.

    When coding, explicit references help me see where one component connects to another. I find this easier to read and visualize than publishing events that go off to... where does this one end up again? The other nice thing is that collecting a class's dependencies at the top of a script in the form of public fields makes it easy to control-F through code to refamiliarize myself with how something works and to refactor.

    I would like to give it a more sincere try one day, though!
     
    Last edited: Jul 29, 2015
  22. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Tag events with their origin for run time debugging.

    The more layers of abstraction and misdirection you add the less obvious data flow through your program becomes. It's an unfortunate side effect.

    That said it can be managed.
     
  23. Master-Frog

    Master-Frog

    Joined:
    Jun 22, 2015
    Posts:
    2,302
    And by nature, they're rigid. Rigid things don't bend, they break. And if any one of your referenced objects goes MIA, it's like a frag grenade, ripping everything to pieces from within. Now you get to figure out which one of that object's explicit references betrayed it by calling Destroy on it, or some such madness. The more dynamic your game becomes, the more these problems pop up.

    Question: Why do we make explicit references?
    Answer: To access another object's properties directly without any kind of interface or protocol.

    Ouch.

    I advocate laziness. I'm a believer. If you're making a simple game with one scene and no dynamic elements, just use explicit references. Game done fast, happy developer!

    Oddly enough, past a certain point the lazy way makes it 10x more work, so that's when I switch up my approach.
     
    GarBenjamin and Kiwasi like this.
  24. delinx32

    delinx32

    Joined:
    Apr 20, 2012
    Posts:
    417
    The actual answer is "because I don't want to put the time into doing it correctly".

    Whether the base reason is deadlines, or anti-feature-creep or laziness, the end result is the same. Code that is a bear to maintain. I personally believe in structure first, but others just want to get it done quickly, and that's fine too. If you're not going to have to aggressively maintain the code then the cost savings over lifetime isn't that great. If its something that you need to maintain aggressively then you will save 10x the cost if you put the time in up front to structure it well. Also, a project that is 1000 lines of code is a heck of a lot easier to maintain than a project with 50000 lines of code.

    When you start getting into the tens of thousands of lines of code, you learn very quickly how important structure is. I've been maintaining an app with about 40k lines of code for the last 10 years. I wrote it, and I wrote it poorly because I didn't know any better at the time. I used to break sh*t all the time when modifying it because of the poor structure. A few years ago I rewrote many of the core components using design patterns and I can't even quantify how many hours of my life have been saved. Its still not perfect because I effed it up so bad to begin with, but its much much better.

    Every time you have to fix a bug, poorly designed code will take orders of magnitude longer to fix than well designed code.

    If you take the time to make an IProjectile interface, and then implement that for bullets, lasers, flame throwers, etc, and your flamethrower starts acting funny, you know exactly what code to look at to fix it, and because the flame thrower is isolated from the laser, you have a very minimal risk of adversely affecting lasers when changing flame throwers. It also makes it easy to implement new projectiles. You just create a new class that implements the interface. If you have a very large "If" block that handles all weapon types, then you are running a very high risk of breaking things that you aren't actually working on.


    All programmers (newb, pro, expert, casual) should read up on design patterns and try to implement them whenever possible. I believe this strongly, and I think design patterns should be a college course that anyone studying programming should have to take VERY early in their education.
     
    Kiwasi likes this.
  25. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,268
    You know what would be a good idea for an asset store package? A project that demonstrates use cases for the different design patterns in Unity. I'd gladly spend a tenner on a collection of functioning templates to study. I know there are free internet resources and several books, but I lack for sparse working code, not dubious videos for beginners or an abstract manifesto of abstract principles.

    I'm sure I'll never be a great coder, but I do like the sound of shaving time off project maintenance, decreasing fragility, and reducing long term workload. I'm worried I have a coding style that only seems to work fine (I've published a fairly complex game) because I don't know any better.
     
    Last edited: Jul 29, 2015
    Kiwasi likes this.
  26. Master-Frog

    Master-Frog

    Joined:
    Jun 22, 2015
    Posts:
    2,302
    To me, means exactly the same thing as:

    "To access another object's properties directly without any kind of interface or protocol."

    Honestly... you have to care, just a little, to do it well enough that it actually works and keeps working. That's what a lot of people lack. They don't care. Code is an obstacle, an annoyance. It's just a means to an end, the code is just a roadblock to where they see themselves. So it has always been, so it shall always be.
     
    Last edited: Jul 29, 2015
  27. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    I make most of my code focused to specific aspect and self working, it is ok 99% of the time.
    Most of the time it doesn't require to communicate more than unity built in events and when it does I create some manager script to handle everything on a higher level, so I don't have to bother communicating.

    Then in some rare cases I need custom events, so I just create them and attach from outside whenever required.
    For the things used very commonly, like game state I use a singleton which is never destroyed.

    Haven't encountered a single issue so far and since the code is very task specific i reuse them all around and I can keep my code to the minimum without going crazy.
     
    Master-Frog likes this.
  28. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    I try to make each component as self-sustaining as possible. Most things will fail silently if they are unable to occur (desired component doesn't exist). I am using interfaces to tell my components how they can interact and with whom they can interact with.

    I am also trying to communicate to as few components on another gameobject as possible.

    For example:
    Food prefab has two components:
    Item (can be picked up, handles stacking)
    Consumable (can be consumed, holds values, RequiresComponent Item)

    If I had Player consume Item, I would only want to communicate with "Consumable" and have "Consumable" tell Item to handle the stack adjustment. I would then want my InventoryController to clean itself of items that no longer exist.
     
    Master-Frog likes this.
  29. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Just be careful if you still have inventorycontroller polling itself to maintain state. If the current state of the inventory isn't 100% reliable or borders on non deterministic (as in: you don't know when exactly the inventory will clean itself up) then you can run into some very esoteric and confusing bugs. "Why is this item still here? I just consumed it!"
     
  30. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    Right now it is cleaned at the start of Update. I can probably clean it only while the UI is active if there are any performance issues. I have not ran into any issues yet, even if I manually delete the gameobject from the scene during play.

    Items kill themselves when stackQty < 1.
    Inventory runs itemList.RemoveAll(p => p == null); in update to remove null items.
    UI Itembutton List also removes ItemButtons with references to null Items.

    This was the easiest way i could think of to handle the interaction between the 4.6 UI, InventoryController, and Items without having to talk to many components whenever anything is done to an Item.

    Cases like (below) are all handled just by calling DepleteStack() on Item.
    Shooting bullets (Gun is empty when ammoRef == null)
    Reloading from an inventory stack
    Consuming items

    It actually scares me how simple the code is...like I'm assuming something unexpected is going to break, but so far nothing has. This component system is also extremely easy to modify and build on.

    A more elegant way of doing it would be to send an event or message out whenever an item stack is depleted...
     
    Last edited: Jul 29, 2015
  31. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    Obviously, I'm a huge advocate of "the easiest way I could think of". Just keep in mind that you may run into wonky problems due to things not happening when you might expect them to. The way you work with the rest of your project, it might really never be an issue, or once you get a bit deeper in, it might be a nightmare. Just something to keep in mind.

    Keeping data synchronized and up to date without having tons of dependencies everywhere is one of the main challenges of software engineering. C#'s events are in almost all cases just used to keep other, dependent objects synchronized properly, pub/sub systems are as well. So much of what we do as programmers really revolves around just making sure that Thingie.X updates properly when OtherThingie.Y changes.

    If you really want to be a better programmer, I'd suggest doing some homework/playing with this stuff in depth.

    Here's a few wiki links that are relevant and possibly useful:
    https://en.wikipedia.org/wiki/Observer_pattern
    https://en.wikipedia.org/wiki/Publish–subscribe_pattern
    https://en.wikipedia.org/wiki/Mediator_pattern

    Even if your project right now doesn't need to use any of these tools. Learning how to sort of use some of these techniques will make your code, way, way better.
     
    Last edited: Jul 29, 2015
  32. Slyder

    Slyder

    Joined:
    Oct 17, 2013
    Posts:
    270
    I am definitely going to look into Event systems at some point. I am trying to get in a state of "base functionality" so that I can move on to where most of my time is planned to be spent.....AI

    My main focus is enemy AI. I developed a barebones Behaviour Tree system end editor extension that I want to build on. At this time, the player just needs to be able to pick up items, equip items, consume items, and shoot things. Once I am at that point, I can build my AI around interacting with the player. I've rebuilt my systems 3 or 4 times and I think they are finally at a point where I can move forward.

    Thanks for the links...i will check them out.
     
    Last edited: Jul 29, 2015
  33. darkhog

    darkhog

    Joined:
    Dec 4, 2012
    Posts:
    2,218
    For my game, Computer Virus Simulator (First technical demo released!), I'm using what I call "Task Components". Each script (aside of asset store ones of which I don't have control over) is doing one specific task ONLY. So you have movement script, script that handles pressing button in the UI, etc. Often there's need to affect other components to achieve specific task (e.g. affecting rigidbody to do movement), but overall it is very clear and intuitive as you always know what script does what and when movement is bad, you know you need to change movement script.