3

I've started to code a 2d JRPG engine in C#/XNA and i have some questions about class structure and game events.

In a 'game maker' type environment you have a game script which runs events and so on based on user input. This is usually not OO and has no reference to classes and so on.

Now in my own engine what is the best way to code game events?

Suppose you interact with an NPC on screen, how would that event be handled in an OO language? I assume I would have an event within the character class and I assume that event would be assigned to in the section which loads the map but where would that event be linked to? Which class would contain the event logic?

EDIT: I should note that I have no desire to turn this in a fully customisable engine for others to use and so a full scripting language implementation is not really what I want.

class Character {
...
public delegate void InteractionEventHandler(object sender, EventArgs e);
...
public event InteractionEventHandler Interact;

...

}

class Map {

public Map(){

...

//add a new character to the NPC collection
newchar.Interact += ???
...
}

}

Currently my class structure is fairly bare since I need to resolve this issue before I go much further but it looks something like this.

The Main class contains an instance of the Map class.

The Map class loads maps in xml via the Content Pipeline.

The map instance contains references to all the objects and NPCs that are contained in the map.

The Map class creates new instances of these objects which all inherit from the Drawable class, which contains the basic methods and properties needed to draw the object to the screen. These instances are all added to a collection within the Map class.

The Character class is one of the classes that inherits from the Drawable class and would contain the Interact event.

As I said, the project is based on the XNA framework on a fixed time step so each tick the engine runs the Update and Draw methods in the Main class.

The update method contains the logic to handle the player input. So the player can move to an NPC on the map and press the interact button. The logic checks for the NPC in front of the player and triggers its Interact event... then what happens?

Calin Leafshade
  • 1,195
  • 1
  • 12
  • 22

1 Answers1

1

Events should not have any logic attached to them; they are merely a message, a technique to tell the interested components of what happened, but how to deal with the event is the responsibility of said components (aka, listeners). In your case, that is your NPC(s).

But I don't understand your argument towards "events not being OO", what makes you believe that? What is it about events that can't be object-oriented?

Now on how to handle events and the process overall, I don't have experience with C# but I've done my share in C++, and here's an approach I repeatedly used, which was flexible enough for my needs:

I had an Event meta-class from which every specific event could subclass (ie, UI events, NPC events, etc). There was also an EventManager that creates and destroys all the events ("Emitters", components that need to trigger events, would call the manager for an instance, ie GameObjects) and most importantly, has the processing queue.

Emitter objects would "hook" the event to the queue, and the EventManager would dispatch them to the "Listeners". Now, a Listener is interested in events, and thus can register itself to certain Events or their types. Once the manager dispatches an event to these listeners, it's up to them to perform the logic related to that event from there on.

Eventually, the design of having an event meta-class from which I have to keep subclassing was not very flexible for me, and it was tedious work, so I went with another approach where I can attach properties arbitrarily to an event object, and the handling component would have to know how to deal with it. This has an impact on performance of course, but it was in a way necessary for me as I triggering and handling event logic in Lua, not C++.

If you are making an RPG game, events and scripting are pretty much the bulk of your game, and you will really need a clean design of these two aspects before you get into coding things. I suggest reading event-handling articles on Gamedev.net for a start.

Finally, I'm not sure if it will be helpful to you, but I posted once about events while I was making a networked game in C++/Lua, the design is probably more complex than you need given the nature of networked games, but you can check it out here anyway.

Update: I will show you an example of how I'd use my system, but I have to be clear first: you are using C# and XNA for a reason, and I can't be mistaken that XNA provides exactly what you need, so I would advise against using my event management system or anyone's for the matter, as mine is tightly coupled to C++ and its templating mechanisms, and might not be of use to you. The framework should give you what you need, so check that out first.

// singleton
class EventManager {
  public:
  Event* createEvt<EventType*>();
  void subscribe(Event*, Listener*);
  void hook(Event*);
  void update();
}

class Listener {
  // tells evt manager we want to listen to these events
  void register(Event* someEvtType, Handler* myMethod);

  // adds event to the queue (called by the EventManager)
  void enqueue(Event* someEvt); 

  // processes events in the queue
  void process();

  protected:
  // calls every subscribed handler to process the event
  // a handler is only a functor that is bound to an event
  // when calling "register()"
  void dispatch(Event*);

  map<Event*, list<Handler*>> myHandlers; // an event could have multiple handlers (methods)
}

class GameObject : public Listener {

}

class NPC : public GameObject {
  protected:
    void walkTo(NPCEvent_Walk* evt);
    void talk(NPCEvent_Talk* evt);
}

// inside wherever you're gonna trigger the event, i presumed on mouseclick here
void InputManager::mouseClicked(MouseEvent* evt) {
  // we want the NPC to move
  NPCEvent_Walk* evtWalk = EventManager->createEvt<NPCEvent_Walk>();
  evtWalk->setX(...);
  evtWalk->setY(...);
  // and talk
  NPCEvent_Talk* evtTalk = EventManager->createEvt<NPCEvent_Talk>();
  evtTalk->setText(...);

  // when the master queue is empty, these events will be
  // dispatched to their registered Listeners which will
  // process them on their own terms
  EventManager->hook(evtWalk);
  EventManager->hook(evtTalk);
}

// as an NPC, i'd like to be notified of NPCEvents
NPC::NPC() {
  register(NPCEvent_Walk*, &NPC::walkTo);
  register(NPCEvent_Talk*, &NPC::talk);
}

void NPC::walkTo(NPCEvent_Walk*) {
  // move it
  // ...

  // are we done?
  //  return true;
  // if we need more updates, return false and we will be called again
  //  return false;
}

void NPC::talk(NPCEvent_Talk*) {
  // update UI components or whatever
  // ...
  return true;
}

Clearly, this code will not work as it lacks all implementation details and isn't even syntactically correct, but it should give you an idea. However, as I said above, you shouldn't need to do this if you're using XNA.

amireh
  • 700
  • 4
  • 13
  • Ok I think I understand your solution but could you perhaps grace me with a short example? If we assume that the NPC class has a WalkTo and Say method and that when interacted with I want a particular instance of an NPC to walk to a specific location and then say something how would that work within your events 'pipeline' i guess you could call it? And when i said the events in a script were not OO all I really meant was that they were in a kind of amorphous 'global script' and not tied to any specific class. – Calin Leafshade Nov 03 '10 at 19:03
  • Can I add my 2 cents. The thing is the Script handler would itself be a class wouldnt it. You would need to impletement some methods in yur character base classe like "WalkTo" and "Say" and also to your camera to "Look" at certain places and what not. Then you can design a simple scrpit that runs (thats interpted) which your Script handler knows how to deal with. It would have to be global if you do it by interface too so thigns can be iWalkable, iTalkable and so on. – MrJoeBlow Nov 04 '10 at 09:03