Event Driven FSMs

Posted in Code on October 11th, 2009 by Pyroka

In AI this week we had to implement our own Finite State Machine, in the seminar before hand we talked about it and decided that the best approch, is a buffered event driven FSM, where FSMs listen for events that are generated, this gives us the advantages of event driven FSMs (Any class can interact, by the event, with any other class without even knowing if that other class exists etc) without the draw-backs (code being executed at a non-determinate time and order)

I decided to have a crack at implementing one myself, I’m not saying this is the best method for doing so, but it is a method.

What do we need? Well, we need an Event class, I’ll also use an EventType class to distinguish between instances of Events and types of Events, since FSMs will listen for events of a certain type, I’ll use an EventFactory to create the Events and EventTypes and an EventOccurance class to hold event occurrences. That’s good enough to be getting on with, so if you’re sitting comfortably, I’ll begin.

Firstly, registering a FSM (or sub-class) to listen for an EventType, for this, we’ll need to store a pointer to the FSM and a pointer to a member function on the said FSM, the first is easy, the second, not so.

Pointers to member functions can be problematic, we either can make the function static (which is a restraint I didn’t want to push on myself) or we need to know the type of class the function is a member on, the problem being we can’t cast, so a pointer to a function of the FSM class, has a different syntax to one on a DoorFSM class.

So how to store a list of these? Well for that we turn to Functors (anyone who knows functors or is afraid of templates, look away now)

I created a TemplateFunctor class, which has a ctor that takes a pointer to a class, and a function pointer to a function that’s a member of said class, the code looks like this:


template<class T, class U>
class TemplateFunctor
: public Functor
{
public:
TemplateFunctor(T* pObject, void(T::*pFunction)(U*))
{
m_pObject = pObject;
m_pFunction = pFunction;
}

virtual void operator()(void* pArg)
{
(*m_pObject.*m_pFunction)((U*)pArg);
}

private:
T*    m_pObject;
void (T::*m_pFunction)(U*);
};

As you can see, this templated class has two arguments, T is the type of class the member function belongs to, U is the type of the object passed as a parameter to the callback function, the overloaded function call operator just calls the function. The eagle-eyed of you will spot that it inherits from a bass class called Functor, this is so we can store a list of them, since every instance of this class could potentially have a different T value and thus, in reality be a different class type, we need a common parent so we can store pointers to them.

Ok, now we can store the information we need to register listeners, where will we keep this list? Well for me that’s on the EventType class, which is basically a black-magic way of doing RTTI (Runtime type identification), for this, we’ll need an EventFactory class, which you can see here:

class Empty{};
template<typename T, class P = Empty>
class EventFactory :
public P {
public:

virtual EventType* Type()
{
return TYPE;
}

EventFactory() : P()
{
}

~EventFactory()
{
}

static EventType* TYPE;

};
template </typename><typename T, class P> EventType* EventFactory<t , P>::TYPE = new EventType();

Ok, this template class also takes two parameters, T is the type of Event, P is that event types parent, which for most new classes will be Event, but defaults to the aptly named Empty.

The black magic here is the TYPE variable, which is public for good reason, it allows you to do DoorOpenEvent::TYPE to return a pointer to that classes type, the Type() method is virtual to allow an instance of a subclass of Event (DoorOpenEvent) to get a pointer to the right EventType (if you have an instance of DoorOpenEvent called pEvent, calling pEvent::TYPE would return the EventType for Event)

So why are we even creating an Event class to subclass from? I use it for the Dispatch method, which calls the Dispatch method on the EventType (By calling Type()->Dispatch()) but saves on some typing, you may also want to add other methods and state for all events to contain.

The function to register a listener is a templated function, and just creates a new TemplateFunctor with a pointer to a class and member function.

The Dispatch() method, this is pretty simple, all FSMs have an AddEventOccurance() method that takes an EventOccurance object, this is just a storage class that holds a pointer to the EventType of the event that occurred (so you can have a callback method that handles more than one type of event, and check which type of event it was by comparing that pointer to pointers returned by the TYPE variable of an Event subclass) a priority variable (just an int) and a void pointer for any other data (It’s assumed that the callback function will know what to cast that to to be useful). So all we need to do is iterate over all registered listeners, and add a new EventOccurence to them.

EventOccurances overload the less-than operator, this is used by the priority queue to sort it so that the highest priority event will be at the top.

Uni progress, week two

Posted in Uni on October 11th, 2009 by Pyroka

On the third week of uni now, final year is where it all kicks off, year 2 was hard but was about getting you ready for placement, which it did wonderfully, final year is where you’re let off the leash with some really interesting projects to work with, so far these are:

Network Programming

Along-side ARP this is one of the modules that’s not CGP exclusive the assignment brief; implement a multi-player game over TCP/IP featuring a lobby with chat where players can challenge others to a game, minimum of 2 players per game however that’ll cap your grade at a C+ so the more the merrier. Add to that a dev-diary to chart your progress and a 1500 word report that’s given equal weight to the code (to help the non-coders get a leg in).

My game will be blackjack, a player can either start or join a server, servers broadcast to all possible clients, allowing a joining player to select which server they want to connect to, once they connect to the lobby they can chat to others connected to the same lobby and start a game (challenging others if they like) any player connected to a server can join any of the games available (provided the game isn’t full on players) and be dealt in next hand, when the game is over (after a set number of rounds) all players are returned to the lobby.

So far, progress is good, we can use any language we like as-long as it uses ports, so I’m using C# (mainly so I can use XNA to cut-down on time spend actually developing the game) I’ve chosen to go with UDP, since one you can get bonus marks for it and two to me it makes more sense for games (more up-to-date data is better than reliable data) I made the actual networking code as a library, so I could start testing it in a console app then move it over to the actual game without any fuss, I have a client and server done, a packet class with various read/write methods for shipping data back and fourth and a class to uniquely identify players. The plan is to have the server run a client as-well, so no extra code needs to be done for that to happen.

AI

A topic close to my heart, this module promised to be really interesting and so far, it’s not disappointed. Assignment is not out yet but if it’s the same as last year, we all pick an area to focus on and implement that to a high standard, this year we’re using the LightSpeed engine, the third incharnation of the Gamebryo engine from Emergent, which is focused on rapid development and promises to be awesome (one we get the bugs out of running it). So far we’ve  looked at finite state machines, and implemented our own. This module has a seminar rather than a lecture, where we all throw ideas around about the different ways to achieve certain things.

Implementing an FSM is something I’ve done before, so I decided to go one step further this time and go for a more sophisticated design, it’s main point is that it’s event-based, but events are dumped in a priority queue ordered by a priority value set when the event is dispatched (although it can be overridden for fixed priority events, before the state is updated, the one at the top of the queue is run, invoking the callback function associated with it, this avoids the special hell that usually plagues event-based code of code being ran at bad times and in a non-determinable order.

I’ve implemented this in a static-library, which I hope to build-up each week into something nice for the portfolio (a year of working at Strawdog has taught me to love static libraries).

Advanced 3D Graphics (A3D)

One of the ‘hardcore’ modules this year (the other being AI) this year it’s different from last year; teams of two will complete 3 mini-projects on one of a list of subjects (one per group) thankfully it was pre-arranged that me and Chris (who happens to know a fair bit about shaders) would team up. Our first project is NPR (non photo-realistic rendering) and progress goes well, Chris found a paper on a really cool water-colour shader to make everything look painted and is busy implementing that, I’m doing a cell-shader and then working on getting it running in a DirectX framework (since we’re working in Render Monkey at the moment)

This looks like it’ll be a challenging module for me, having done no previous shader work, but a good partner helps a lot and it’s something that I’m developing more and more interesting in as I work on it.

ARP (aka ‘The Dissertation’)

That should really do with some dramatic music, this year-long module is the cornerstone of our final year grade (and since the final year is worth 80% of the mark for the degree, it’s the main component for that too).

For this module you have to have a mentor to guide you through, a tutor can take a minimum of 5 students, and given the extra work involved for each one, that’s about all most of them take, and whilst we’ve got access to any tutor on the School of buisiness and computing (the area of the uni our course falls under) having one of the specialist CGP tutors is a plus, but there’s only three of them and twenty-two students this year (more than expected) so 7 will have to look else-where for a mentor.

Originally I had chosen Dynamic Difficulty in Games, a topic suggested by the course leader, John Sear. However places for him were filling up fast, and he didn’t seem to enthused by the idea, so I decided to look else where, I handed that proposal to Adam Thornett, our A3D tutor, but then e-mailed him saying that I was willing to change the topic to one more in his area of expertise if that helped, he said it would so I wrote a proposal for a study on Art-pipelines, after a talk on this subject, we decided that coming up with a decent project on it would be hard, and not very interesting to boot.

Adam mentioned that you can get marks for a code-implementation along side a report for this year, so it’s not a waste to pick a code-heavy project he also listed a few ideas he would consider fun and I tended to agree with him on most of them.

After all that, my chosen topic is ‘Alternative Input Methods for Games’ looking at all the different ways we can get the player to interact with a game, for the first part, I will take an open-source game and change it’s input method to a variety of different ones, and see how they play, currently the list of input methods include a dance-mat, webcam, 3D mice and Wiimote. I will then make my own game, and look to combine several of them to make a challenging and immersive game. It seems a fun project (not-least the fun I’ll have watching people run around on a dance-mat) but still mostly half-formed ideas at the moment.

So that’s a run-down of what this year holds, work is tough but manageable, the years placement has benefited me no-end making me a much better coder and worker, but mostly this year should be fun, all the modules hold the possibility to be really interesting and I’m really looking forward to getting stuck in with my ARP. Hopefully I’ll still be this enthusiastic come Christmas time.