Events, one more time

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Events, one more time

      Hi guys,

      It's been a long time since I posted last time. By fate last half a year I worked on one non-game project (3d editor actually). Despite non-game character of the program, I tried to apply maximum of the architecture solutions described in the book.

      I must tell that logic-view-screen approach is simply awesome (despite that in the program I had only single view, obviously no bots will 'play' the editor :D). Sending input in the form of messages down from the function which catches the input is great as well (although I didn't have controllers and just handles the input in the screens, probably I didn't understood the purpose of the controllers...). Used processes in several places, but yet again seems likes (at least in Unity) ticked updates is fairly simpler way to make simple animations.

      All good so far, but the event system raised more questions than everything else. At the first glance, it's perfect for solving many questions, but on practice I faced the fact that I simply can't construct the set of rules when the system should be applied. Detailed description below.

      Look at the image. It shows pretty standard workflow in the program. Although the scenario is non-game related, but you can easily change it to the example with throwing a grenade..
      [IMG:http://s17.postimg.org/m19j4ujpb/Workflow.png]

      Clearly there are two places where we need some form of communication (marked with blue number 1 and 2). If we make more generic conclusion, these two numbers can be called: request and notification.

      So, where should one use the events? At first phases of my program I've used events in both cases, e.g.

      Source Code

      1. // Button handle
      2. EventManager.Queue(new OpenFileData())
      3. // Open file method
      4. EventManager.Queue(new FileOpenedData())
      5. // In camera, scene, etc I had subscription for the FileOpened event


      Using this method I quickly realized that this bring more complications that profit... While number '2' from the scheme still should be implemented as an event so I don't need to call every system manually when the file is opened, but number '1' probably shouldn't... In the practice '1' has been addressed to the one and only one method in the whole program (e.g. ProjectManager.Open() method). Now I can of course call that method indirectly by using the event, but I can't see any pluses to just calling the method directly!

      Trying to derive some meaningful thoughts from the situation I came to the conclusion that '1' rarely need an event at all (while '2' still should be an event). And this applied to almost any scenario in the program. Request is always aimed at single object and/or method. While the effect may disturb many sub-systems. What do you think about this? Am I missing something here?

      I also found that changing the object via events bring complications as well. If we forget for a minute that I was working on the editor then the objects in my scene could be treated as game actors and many properties they have could be just 'health', 'mana' etc.. But writing an event for changing every single property quickly added a bunch of events even in the beginning, so I dropped this idea and just changed the properties via instance of the object (actor) directly. Probably this is not applicable to the editors, and only work for game scenarios with scripting systems.. I couldn't figure out this myself. Speaking generally, this question could be summarized as - should one change object properties via events or directly? And this touch both cases - GUI screens and 'game' screens.

      One of the ideas I got is - sometimes it's hard to get the object which should handle the event (e.g. it's deep down the 'has-a' hierarchy, in this casecalling via events simplifies things, but these cases are rare). Second thought is that probably request event can solve the problem of changing the symantics? E.g. if for example I need to change the name or parameter order of the actual method, all the events will stay the same! But if I add some data to the event I will still need to revisit every single place in the program where the event is constructed and modern refactoring features of the VisualStudio solves renaming as well... So I could count second thought as a plus...

      Another thing that I found is while events are aimed to decouple systems, some systems are still tightly coupled by their data. Simple example from my program (yeah it's bad style from architectural point of view, but I didn't had much time to fix it alas..) - tooltip system should know if the mouse if over the scene window to handle things properly. If I call SceneManager from the TooltipManager I make solid connection which I don't really want to have.. Rephrasing this case - how do I solve the problem of coupling between systems when I need to GET information from one system in the other? Events, as I understand, are designed to SET information rather than GET. Of course, we can do something like this:

      Source Code

      1. MouseOverSceneData evt = new ...
      2. EventManger.Trigger(evt)
      3. // the event is then filled with data in the system which has the data
      4. if (evt.OverTheScene)
      5. {
      6. ...
      7. }


      Yet again this is more complex, and slower than just calling and bring EVEN MORE events to the program..

      Thanks for reading this long posts, share your thoughts on this!
      Looking for a job!
      My LinkedIn Profile
    • RE: Events, one more time

      Hi,

      so I thought I was going to share my thoughts about this.
      Everything I'm about to say is of course my own opinion (so I might be completely wrong) and there might not necessarily a clear one-size-fits all general solution/approach to this. But then again, I love discussions about such things, as I think they are highly valuable and instructive, so here I go:


      I tried to apply maximum of the architecture solutions described in the book.

      I think that's a great idea. There's certainly a lot to be gained from using this very nice architecture.


      I must tell that logic-view-screen approach is simply awesome

      I completely agree. It's also very similar to the MVC-approach (which has been promoted by some software engineering lectures I've attended ;) ).


      Now I can of course call that method indirectly by using the event, but I can't see any pluses to just calling the method directly!

      Trying to derive some meaningful thoughts from the situation I came to the conclusion that '1' rarely need an event at all (while '2' still should be an event). And this applied to almost any scenario in the program. Request is always aimed at single object and/or method. While the effect may disturb many sub-systems. What do you think about this?


      Personally, I think that approach would be perfectly fine.
      It makes a lot of sense to do things immediately, if possible.
      (Concerning that, here's a
      link to a talk from John Carmack where I think he also talks a little bit about such architecture stuff. I (re-)watched this video series a little while ago, but I'm not completely sure if it's the right one (but it's worth watching anyway ;) ))
      I mean, if no one else could possibly be interested in that event (or rather in that method being called, since you don't need an event in this case), then why even bother sending it to an Event-processing system? If you can do it right ther without any trouble, I think it's perfectly reasonable to do so. You also save a lot of indirection this way, which makes the code easier to understand and probably also a tad faster.


      Am I missing something here?


      I don't think so. But then again, I might of course be wrong ;)



      I also found that changing the object via events bring complications as well.


      IMHO that's true for every subsystem you include-
      instead of doing things immediately, you send information to some other subsystem so that the information can be processed later on, somewhere else. And if your information is not immutable, who knows whether it might be changed somewhere on its way? (This may, of course, be intended, but it certainly makes reasoning about your code harder if you have a function and have to be aware of some (potentially large portion of) code somewhere completely different. Compare that with a pure function ;)).
      But then again, I don't want to promote spaghetti-code; Subsystems should simply be as modular as possible. And it might in some cases not possible (or good) to just change things in place (which is probably even the majority of cases). That's of course the advantage of splitting your code. Anyway, maybe I went of on a tangent somewhere, so btt :)



      But writing an event for changing every single property quickly added a bunch of events even in the beginning, so I dropped this idea and just changed the properties via instance of the object (actor) directly.


      Why do you have to? Wouldn't it be possibly to just write one ChangePropertyEvent which you can e.g. parametrize with the property you want to change (and the value to which it should be set, or the amount of change, whatever).



      should one change object properties via events or directly? And this touch both cases - GUI screens and 'game' screens.

      That's a tough question and might depend on the specific case.
      Just one hypothetical case:
      Assume we have a character and she drinks a potion.
      Assume furthermore that this potion is poisoned.
      You could know set some parameter of the character,
      e.g.

      Source Code

      1. character.poisoned = true;
      , but that might not necessarily be the best option. Maybe the character is immune to that kind of poison (e.g. because she has already taken some kind of antidote).
      Maybe you could check whether this person has taken this kind of antidote. Like in:

      Source Code

      1. if (character.hasTaken (my_specific_antidote)){
      2. ...} else{
      3. character.poisoned = true;
      4. }

      But maybe there are different reasons why your character might not be affected by that poison.
      (Maybe poison wasn' the best example)
      Maybe there are more possibilities, so you decide to write an Event,
      which tells you that the character has taken this specific poison.
      Maybe some component in the character reacts to this event,
      thus changing some property of the event in order to make sure that the character will not be poisoned.
      Like in:

      Source Code

      1. class SpecificComponent ...{
      2. /* should implement component and event handling stuff. Depends on how your stuff is structured and doesn't matter for this example, I guess */
      3. ...
      4. public:
      5. handleEvent (CharacterPoinsonedEvent & e) {
      6. e.setActive(false);
      7. }
      8. };

      This might of course apply to multiple cases. So I would say in general, if no one else might be interested in a certain event, and you only need code to handle that event in one place, then you might as well drop the event and simply call the respective function (which would otherwise handle the event).
      On the other hand, if there might be many things that affect the outcome of the function, then you might consider using an event.





      One of the ideas I got is - sometimes it's hard to get the object which should handle the event



      I'm not exactly sure whether or not I understood what you meant. Doesn't the object which handles the event simply register for some specific kind(s) of event? If so, there shouldn't be a problem, right?




      E.g. if for example I need to change the name or parameter order of the actual method, all the events will stay the same

      This is confusing me a little bit, to be honest. But it should mean the same as I wrote above (parametrizing the event), doesn't it?



      But if I add some data to the event I will still need to revisit every single place in the program where the event is constructed and modern refactoring features of the VisualStudio solves renaming as well... So I could count second thought as a plus...


      That's definitely a plus. I needed to change something in the game I'm working on in my spare time a while ago (when I decided to pool some kind(s) of object, which was absolutely necessary, as I was/am still working in Java...), and I had then replaced all constructors with a single standard constructor and an init(...)-method. That way, the compiler (or rather, the IDE) immediately showed me all places that I thus had to change. It's a huge win when you can simply change the API and the compiler helps you find all places you have to check. Otherwise, you might create some really evil, subtle bugs.


      tooltip system should know if the mouse if over the scene window to handle things properly.


      Depends on what information you need. If you simply need to know when the mouse is over the scene window, then maybe sending an event like MouseEntersSceneWindow when your mouse enters the window might be sufficient.
      If the mouse leaves this window again, you might send an MouseLeftSceneWindow. This way, the tooltip system would always know whether or not the mouse is currently over the scene window or not.


      Rephrasing this case - how do I solve the problem of coupling between systems when I need to GET information from one system in the other? Events, as I understand, are designed to SET information rather than GET.


      Not necessarily (see example above).
      It is perfectly valid to send events when something happens (simply as notifications). It's kind of similar to Message passing in this case, I think.


      Concerning the number of events:
      I'm not sure whether or not it is necessarily bad if you have lots of events. I must admit I don't have much experience with systems that use lots of events, but maybe you don't have to avoid this at all.

      And one more option that crossed my mind:
      Considering the above case with the two events (one for request, etc.). If there would be more than one place/system that might be interested in the request event, you could also just send that event (and only that one). It is then handled and you could send the second event in one of the handlers (which is probably the place where you would otherwise (i.e. if you would have to do without an event) call the function). This way, you could also make sure that the first event is handled before the second one.
      Although that should probably be the case anyway (Unless you do some concurrent Event Handling, I guess). But I think this
      (i.e. sending an event from an event handler) is also an option to consider in general.


      So, that's it for now. I hope this was helpful (even if just a bit).
      I'm looking forward to the other comments :)
    • You should use events where they make sense. I know that sounds like a cop-out, but hear me out.

      When you get to this level of architecture, it really just depends on what you're doing. First and foremost, events are an architectural construct that allow you to keep two systems completely decoupled and still allow them to communicate. The two systems don't even have to know that the other one exists, you simply send an event with one system and catch it with the other. That's the real power of an event and what it's true architectural purpose is.

      Events also have a number of other benefits, such as notifying multiple systems in one call (though you can do that with direct function calls too) and being able to easily delay something (though again, you can do that in other ways). In the end, as with most architectural concepts, the core benefit is decoupling. (Seriously, look at all the design patterns. They're mostly about decoupling systems).

      Events have a major disadvantage too, which is that they decouple two systems. Yes, this is a hindrance as well as a benefit. Decoupling systems tends to obfuscate the code and makes it harder to debug. I can't even count the number of times that I've set a break point somewhere only to realize the code came from an event, so the callstack was useless for determining where it came from. This is especially bad for common events. Events can be really hard to debug. They're also a bit slower as they add architecural overhead. It is always faster to just call the function rather than going through an event.

      So when should you use an event? When the benefits of using an event outweigh the hindrances. In the end, it's a judgement call. Sometimes that call is obvious. For example, separating the game logic, application, and game views has some very big wins that greatly outweigh any pain it might bring. The actor component system is the same. But there are other times when it's very clearly on the other side. I could hide every single thing behind an interface with an observer that is only allowed to throw and respond to events, but it would end up getting insane.

      Unfortunately, most of the time it's just a judgement call. For example, my World class has a pointer to the Scene interface. It doesn't know or care what type of scene it is, which is a useful kind of decoupling. I don't want outside systems to know or care whether this is a multi-threaded scene. To further decouple those systems, I could have the world know nothing about the Scene class at all and just throw events, but I didn't see a big win there. It was far easier (and faster) to just call the functions I needed directly on the Scene interface. Now, if I had the concept of scenes that constantly changed or multiple scenes or even completely different interfaces based on the type of scene, it would probably become worth it to use events.

      Hopefully that makes sense.

      -Rez
    • an interesting read.

      I have not nearly the experience of anyone on here, but i thought i would add some of my amateur thoughts...

      I find i always need to remember what it is that i am building and that the purpose of software architecture is for programmers, whether its yourself or someone down the line extending your code.
      Also, that decoupling is a 'best practice' but it's intention so that things are modular, swappable etc. if you as a developer are writing a system, module or component where never going to happen then why decouple systems at all?

      and maybe none of this is relevant...

      cheers

      The post was edited 1 time, last by quin ().

    • Yup, exactly. When I write little automation scripts that are only a few hundred lines, I frequently use global variables, simple classes, and almost no architecture whatsoever. Who cares? It's just a throw-away script.

      Games are very different. The code is constantly changing over the development cycle and it's critical that it's able to scale and accept that change. If making one change required me to touch half the code-base, nothing would ever get done.

      There are certain best practices that you should ALWAYS do though. Things like using meaningful identifier names, commenting, etc. I do that no matter what and have never regretted it.

      -Rez

    • Games are very different. The code is constantly changing over the development cycle and it's critical that it's able to scale and accept that change. If making one change required me to touch half the code-base, nothing would ever get done.

      I completely agree. Although I think this has a bigger impact if your application (read: game) is more complex. For the Shoot-'Em-Up I'm working on right now, which is one of my own hobby side-projects, where the code base will not become that large and no one else will probably ever have to work on the code, it's not that big of an issue. I'm just iterating over and over again every time I want to add a new feature. After I'm done with adding a new feature, I usually do a bit of refactoring. In the beginning, the architecture was very clear, but since I didn't really plan all the features in advance, there are some more or less ad-hoc hacks in the code. I'm trying to refactor these as good as possible, but I don't have the time to redesign everything from ground (and if I did, I would never be able to actually complete anything!). So at a few places, you actually have to know what happens elsewhere, which is not a sign of a good, decoupled architecture, but it's fine for me, since I exactly know what happens where and which places I have to change if I want to add another feature.
      In the end, I'll learn a lot and will be able to do it better next time (especially when I have planned the game more thoroughly in advance), where I can apply more patterns and use a better decoupled system.
      But of course this is completely insane if you are working with even just a small team.
      What I'm trying to say is that you shouldn't force some kind of architecture upon you; you should simply use what you're most comfortable with (while of course trying to decouple things in a clean and sensible way) and take the experience you gain this way into the next project, where you can try to take architecture to a higher level.
    • We just finished having this argument at work, my argument was that given a full tool-belt of utilities to use ie. Events, Processes, Delegates, etc, you can have a case for almost every situation (this also includes straight up function calls). Each one has its ups and downs and needs to be used only when it is appropriate for the type, (don't use an event to tick something every frame, processes may be better here).
      PC - Custom Built
      CPU: 3rd Gen. Intel i7 3770 3.4Ghz
      GPU: ATI Radeon HD 7959 3GB
      RAM: 16GB

      Laptop - Alienware M17x
      CPU: 3rd Gen. Intel i7 - Ivy Bridge
      GPU: NVIDIA GeForce GTX 660M - 2GB GDDR5
      RAM: 8GB Dual Channel DDR3 @ 1600mhz