Game Event Handler in c#?

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

    • Game Event Handler in c#?

      If possible, this should be moved to the Programming forum, didnt realize there was one, oops.

      Im working on a current game in c#. Right now I dont really have game events or a game event handler, but thought it would probably be a good idea. Any ideas how I could do this? Possibly using the c# type EventHandler and delegates or something along those lines. . .

      Right now to do movement, for example, I have a function which polls the keyboard every gameloop iteration and sets the characters direction/speed based on the keys pressed, then I have another function which animates/moves him based on that, which is also called every loop iteration.

      I guess if this were traslated to events, then the keypress/setspeed would be an event that was then handled by some sortof event handler, but how would this event handler have access to information about the player? If the eventhandler was a class, then would all other game information/ class objects have to be instanciated inside it?

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

    • I've learned a little more about scripting languages since my last post and have actually started embedding lua into my game. Right now my goal is to have all game "events" run their own script file, then I just need to give lua access to the functions it needs to do whatever that event should do. Seems pretty straightforward really, but I'm still not using an "event manager". Any tips?
    • We use Lua in Ratrace as well, it's a great little scripting language. One thing is that Lua is rather slow, so keep that in mind when developing systems around it. Event handlers are fine because those are rarely fired in the grand scheme of things, but you probably wouldn't want anything render-bound there.

      In Game Coding Complete, Mike shows you his implementation of a very good event manager system. It's in C++, but it shouldn't be too difficult to translate that into C#. You can download the source code from the nav links on the right and see how it plugs into everything.

      In Ratrace, we have two message systems. One is called Note, which is very lightweight and used as a glue between systems. It has two classes, Note and Note Receiver. NoteReceiver's register for messages by ID. Whenever a Note sends its message, it iterates through a vector of all NoteReceiver's that are registered for it and calls the virtual ReceiveNote() function. Very simple, very lightweight. It's not very versatile though. For example, the ReceiveNote() function has a void* parameter for the payload. It can be anything, but it's up to the NoteReceiver. One place we use the Note is in AI when somebody tries to complete a path. Right before they go to the last node, they check to see if it's obstructed by some other entity (like another character using the snack machine). If it is, the pathing system fires a message which the UtilEcon system (high-level planning AI) catches and forces a replan.

      The second system we have is called the Action System. It's the exact opposite of the Note system. It's robust, there are multiple user-defined parameters, you can run actions across multiple frames (our main game script is actually one big compound action that runs forever), etc. However, it's not lightweight at all. Actions are comparatively very expensive. Most of our Logic tick is taken up by processing Actions in the effects phase.

      I'm curious, why did you choose C#?

      -Rez
    • I actually have the book and source code and was trying to make sense of the event manager, but since it is covered with pointers and function pointers I really am having trouble converting it to c#. I was hoping to maybe get some help in that area, I'll look at it again and try to come up with a more specific question.

      Basically we are using c# is because the project leader wanted to. I think he just really likes c# a lot more than c/c++. As for specific reasons why that is I'm not sure, but I can say that making a windows form application in c# (even if its really fullscreen) looks a hell of a lot cleaner than making a win32 app in c++, and I am enjoying all the c#/.net syntax and predefined types/classes a lot.
    • I can't really help with specifics since I don't know C# well enough. C# is the king of Win32 GUI stuff (we use it for our backend tools), but it's still pretty slow when compared to unmanaged C++. Every professional game I know of is written primarily in C++. The Sims 3 (and probably most modern EA games based on that engine) is the only game I know of that uses C# in the engine. They use it as a scripting language.

      Let me know how the project shapes up, I'm curious to see how well C# performs.

      -Rez
    • Perhaps looking at a particular scenario would clarify things for me. Lets say, when the player walks up to a particular NPC and presses the spacebar I want him to say something, wait for keypress, walk away, then explode. Thats probably 3 events, and each one of them will need access to different game systems. To talk I need to tell my MenuManager class object to make a conversation-menu /dialog. The NPC (which is stored in an AnimatedImageMgr class object) needs to wait until the menu is closed before it starts walking away, then it waits until it reaches a particular destination before exploding (which would be deleting it and then creating a new object for the explosion, which lasts for a certain duration until deleted).

      I'm imagining each of these events could be an Event Class object that contains the following information: 1: functioncalls that actually do the event, 2: the condition which signifies the event is over, 3: any event(s) which this event should wait to finish before beginning

      Then I can imagine an EventManager Class object which would contain the list of events and each loop would look for any events that are ready to execute (arent waiting for another to finish and arent waiting to finish themselves) and delete any that have finished.

      Now here for my actual question(s):

      1. is my idea of an event and an event manager sound?
      2. how does an Event object, which is stored in an Event Manager have access to the other game systems?
      3. when an event is excecuted, is it really executing a script file? If this is the case, I do know how to register functions with lua.
    • 1) Your design concept does sound fine, though Mr. Mike does it a bit differently. The core concept of an event system, in my mind, is that it is meant to abstract separate systems. For instance, the explosion logic and the dialog logic are separate, and they can reside with complete abstraction from each other, because they don't need to know about the other system. Keep this in mind when you design the event system, is that it is simply relaying messages between systems so that they may be abstracted from each other.
      With this in mind, I would design an Event class to simply contain the information about the occurrence of the event, and I give an example below. This Event class would only contain this information. The EventManager class would contain a map of event types to function pointers. Once an event is fired, the type of the event is determined, the appropriate list of function pointers retrieved, and then the event is passed to all the function as an argument, with the optional argument for the event data (if you store it in a void*, perhaps).
      GCC takes this approach, with the EventManager knowing only about a list of function pointers (which could be from any system in your game) and a type of event that they want to receive.

      2) The Event object, in it of itself, should not know about the other game systems. It is simply a packet with enough self-contained information to let one system tell any other system who wants to know that something happened. For instance, walking up to an NPC would involve a system (maybe physics) figuring out that your played has stepped within the conversation trigger area (a collision with some bounding area) and it would send an event that notified which NPC the player walked up to, and when.
      Then, your system that governs conversations would listen to this, request the UIManager to open up a conversation dialog with the specific conversation text, and it would then wait for a spacebar pressed event to tell the UIManager to progress to the next page.
      All of these systems determine what state your game is in, and they can relay messages specific to that state to each other. In the above cases, the event doesn't need to know about the other game systems, the EventManager simply hands the event to the system that wants it. Each event, such as the conversation event, has enough information to tell the listening system what it needs to know, such as what NPC you walked up to and when. It is a self-contained packet of information, which shouldn't have any knowledge of the world outside it.

      3) When an event is received, you do some action. This could be running the code in a specific function, or calling a Lua script. You don't have to run a Lua script, though for commercial games it affords a good amount of flexibility (Rez can tell you more than I on this), but you could just as well hook it into some delegate that executes C# code that you wrote.

      Hope this helps.
      Feel you safe and secure in the protection of your pants . . . but one day, one day there shall be a No Pants Day and that shall be the harbinger of your undoing . . .

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

    • Lua can be quite quick if you spend the time to fine-tune it. A solid script manager that caches script files will save tons of time since the interpreter doesn't have to load the file every time it is called. There are other tweaks as well, but I'm not really an expert. Some of the guys on the mailing list have gotten remarkable performance out of Lua.

      C# is starting to look like a cool scripting language, too - I was a little amazed that someone actually embedded it in a C++ project when I first heard it. The more I thought about it the more I think it would be pretty nice because the syntax is very similar to C++ (though that sort of defeats part of the purpose of scripting - letting designers write script).
      "Your job is not to die for your country. Your job is to make some other poor sod die for his."
    • What about events that have durations.. How does an event know it is finished without accessing other systems?

      Such as an event that sends an NPC walking to a screen position, but it isnt finished until the NPC reaches the position, then the event can be declared finished and any other events that were dependent on it (waiting for it to finish) can begin.

      If that was a message sent to the GameObject System, then would it be up to the gameobject system to monitor the progress and then inform the eventmanager when it is finished? The only problem I see then is, every game system would essentially have to have its own list of ongoing events. Lets say the GameObjectManager class object recieves an event, it performs whatever action the event says, then it checks the events finished conditions and sees if it is yet, if not, it would need to save the event and check again in future iterations.

      Another example could be you want a conversation bubble to appear, then a 5 second pause before it is destroyed (which could be a second event). Ok sure you could have the duration of the conversation bubble as a paramater when you create it, but you still want to do something ELSE after that and you need to wait 5 seconds. So I imagine you could create one event to make the text box and a timer (that is the event has two separate recievers), the game will probably need to be able to dynamically make timers for various things, so this could be done in its own game system... like a GameUtilities Class or something... but whenever the timer elapses it could send a message back to the eventmanager sayings so (or not really a message just a function call like eventIsDone(eventID) )... and this could be the finished-signifier for the textbox event, which would allow dependent events to begin, etc...

      Is this a good way to do things? Or am I overly complicating things? I havent started actually coding an event manager system like this, i'm trying to understand how it will work first.
    • Ok i just checked back on the chapter about processes, and it seems like I seem to be getting events and processes confused, or maybe inadvertently combining the two. Any sort of ongoing activity should be a process (i think?). Then events arent dependent on one another, PROCESSES are, this is starting to make sense...

      Could anyone help clarify the diference between events and processes, and how the two interact in a game?
    • I am now integrating process(es) into my game.

      It seems to me that everything that happens every iteration should be a process. Therefore I imagine the first step would be to create a CDrawProcess, which draws everything to the screen. However, right now all my graphics methods are in CGraphics... so, should I make CGraphics a friend of CDrawProcess, or should CGraphics actually BE CDrawProcess? Also, does anyone have an opinion on if it would be better to have lots of smaller processes for drawing, like CDrawTilesProcess / CDrawObjectsProcess... etc, Right now I'm thinking that wouldnt help anything.

      Actually there are no "friend functions" in c#, so I guess I'll look up what else is possible.

      Ok, I "could" give the CDrawProcess access to the CGraphics Class by making the whole CGraphics class static... this is the c# equivalent of making it global. Since the only goal of CGraphics is to encapsulate directdraw's drawing functions and provide them to the rest of my program this solution seems to work very well, although I'm not yet sure if any processes onther than CDrawProcess would ever actually need access... in which case I'm just allowing wierd things to happen, like drawing in a CKeyboardProcess ...

      Any alternative solutions people can think of?

      I'm starting to think that both CInput (directinput) and CGraphics (directdraw) should really both be processes, rather than having a dummy process that just calles a static Draw or DoInput methods.

      The real problem is still my original question (of my first post even), except now all the game systems are "processes", so how does one process know about the others? If you only have messages/events to work with, then, imagine CKeyboardProcess, it generates a list of keys that are pressed, but without knowing anything else it cannot set the players speed/direction, it cannot open a menu, so then the CKeyboardProcess is really just a message generator... if a menu should open when escape is pressed, then the Menu must subscribe to recieve that particular keypress message, and so on with all keypresses. But what about the CDrawProcess... How can it know what tiles/characters/objects/menus are onscreen right now?! This is why I thought perhaps each of these should have their own drawProcess, since it wouldnt make sense to store them all in one huge process but they could each have their own. If each is simply drawing everything it contains then that is simple enough but if you have a screen that scrolls about then you would need to their pass in some of that information or have it stored statically somewhere.

      Ok this has turned into more of a thinking while typing post, but I dont mind if you dont '-)

      The post was edited 3 times, last by JamesFord ().

    • Ok I finally thought of a simple and elegant solution... each process contains a pointer to any game systems that it needs access to! Wow that is simple but I didnt think of it at first because C# doesnt actually have "pointers", but really everything is a reference unless you exclicity create a new instance.
      So if I want a CDrawGameObjectsProcess... It needs an internal CGameObjectManager reference/pointer. This way there is really only one instance of each of my game systems, but any processes that need access to one or more just get initialized with pointers.

      Does this make sense? I'm still thinking this is not quite how things are done in GameCodeComplete because it seems to eliminate the need for events! In the CKeyboardProcess from my previous post... no it just needs pointers to the other game systems and then it doesnt have to generate messages/events it can just do what needs to be done. . .

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

    • I'm slightly confused on your earlier post. Would the CKeyboardProcess directly modify the player's position, speed, etc? If so, this seems slightly backwards to me. The structure that events work with the best (in my little experience) is by passing messages between say the CKeyboardProcess and the CPlayerActionProcess. You would be correct in assuming, in my mind, that CKeyboardProcess would be just a message generator, but it would (perhaps) be the process that holds the player's configurable key set. If the player presses W, for instance, the CKeyboardProcess would recognize that this is forward and generate a MoveForwardEvent. Later, the CPlayerActionProcess would receive this and then (because it holds the player information) move the player accordingly.

      However, I could be misunderstanding what you're saying. The other method, as you said, would be to give all the processes access to the things that they need. Depending on your class hierarchy, this can sometimes get messy, depending on how deep some classes may be nestled inside your game. My current game just makes a global singleton of the GameManager, which holds instances of all the core systems, sound, graphics, game timer, input, etc. Then, everything has access and we trust that no one will just out right abuse that.
      Feel you safe and secure in the protection of your pants . . . but one day, one day there shall be a No Pants Day and that shall be the harbinger of your undoing . . .
    • Thanks for the post, lots of good info.

      So yeah, right now my KeyboardProcess has a pointer to the menuManager and the gameObjectManager, and makes any changes to the player (inside the gObjMgr) or the currently open menu, if their is one. This in particular looks like it would make sense to instead have it generate events and just change the listener between the gameObjMgr and the MenuMgr.

      In your project you said everything is in a big Singletron class? Yes, why cant we all just do it that way and save all the time worrying about what the most OOP is... What are the real reasons for using events? I think the book says it allows you to use scripting, but how exactly does it do that?

      Although i notice that the keyboard/input process does lend itself more to message/event(s), what about the drawing process? I guess using the message/event method rather than the pointer/singletron method your drawing process would be sending each of your systems a message to draw themselves, is that correct? If that is the case, then the order your events are sent in is very important, since you need your gameobjects drawn infrontof your background, and your menus on top, etc..

      A question about Singletrons: Its suppose to be a class that "manages its own pointer". What the hell does that mean? lol. In c# for your entire game to have access to it anyway it would need to be static.. is that right?
    • Queueing Events?

      Ok I have all my processes now sending events to the eventmanager which passes them on to any subscribed game systems, rather than having my prcesses containing pointers/references to the sgame systems themselves. This seem to be working great, One question about the EventManager though..

      In the book the eventmanager seems to contain a queue/list of events then they are only processed once per loop iteration... but right now when I generate an event (and send it to the event manager) I am just having the event manager send out that event immediately, what is the benefit of having a queue and sending them out later?

      Is this to deal with events that generate new events? Then the new event is added to a temporary queue, which is copied over to the real event queue after all events have been processed?

      Is there any problem with just doing them as soon as they go out?