9
\$\begingroup\$

I'm starting out on my first 'proper' game project, and I've inevitably hit a block trying to decide how game components in XNA should communicate.

From previous (Java) GUI programming events, handlers and listeners seemed like the way forward. So I'd have some kind of event bus which accepts event registrations and classes subscribed to those events, with handlers to deal with them. For example (pseudocode):

class SpriteManager
    Update(){
        if(player.collidesWith(enemy)
             // create new 'PlayerCollisionEvent'
    }

class HUDManager
    onPlayerCollisionEvent(){
        // Update the HUD (reduce lives etc)
    }

However, I'm not sure of the code setup (in C#) that would be required to fully accomplish this. What keeps track of events (some kind of bus?), and how is it structured?

There also seems to be a lot mentioned about on Game Services, whereby you can register a GameComponent in your main Game.cs class, then fetch it from anywhere in your code that has a reference to the main 'Game' object. I've tried this with my SpriteBatch object and it seems very easy.. however, I can't see this being as flexible as an event model.

Take for example when an enemy dies. We want to update the game score. Using services I can get a reference to my StateManager object created in Game1 and added as a service, then set 'score' to the new value. I would of thought a 'onEnemyDeath' event, which can be handled differently by a multitude of classes, but initiated by 1 line of code in the relevant 'enemy death detection' section, would be better than individually casting each required GameComponent then calling whatever methods are required.

Or are these inferior strategies to something else?

I realise this is partly my poor C# knowledge as much as game communication paradigms, but I'd really like to get this fundamental thing right.

Update

Having looked at Services is more detail I'm less convinced - it's basically passing a global variable around (from what I understand).

Update 2

Having had a look at this basic tutorial on event handling and testing the sample code it seems events would be a logical choice for what I'm discussing. But I can't much of it in use in the samples I've seen. Is there some obvious reason why one shouldn't?

\$\endgroup\$
4
  • \$\begingroup\$ I would recommend you try FlatRedBall first. It sits on top of XNA and makes life really easy. \$\endgroup\$
    – ashes999
    Oct 16, 2011 at 15:14
  • 3
    \$\begingroup\$ I'd like to really understand the basics of what's going on before jumping to an engine. \$\endgroup\$ Oct 16, 2011 at 18:23
  • \$\begingroup\$ I think your failing here is really a lack of information about C#. C# uses events to facilitate communication between classes usually. It's really up to you how to do it -- XNA provides a SpriteBatch class, and most of the work is up to you to write. An engine will give you a solid idea of how things work at a higher level before diving into details. \$\endgroup\$
    – ashes999
    Oct 16, 2011 at 20:37
  • 1
    \$\begingroup\$ I agree to an extent, but from I've read most interclass communication between GameComponents can be done using Services. I'm used to using events. I'm not sure which is best, or if there are valid alternatives (singletons, static classes masquerading as globals as 2 other methods I've omitted) \$\endgroup\$ Oct 16, 2011 at 20:44

4 Answers 4

4
\$\begingroup\$

From previous (Java) GUI programming events, handlers and listeners seemed like the way forward. So I'd have some kind of event bus which accepts event registrations and classes subscribed to those events, with handlers to deal with them.

The reason you won't find much about event buses in C# is because I don't think anybody outside of Java calls such a thing a 'bus', in my experience. More common terms might be message queue, event manager, signals/slots, publish/subscribe, etc.

You don't need any of those to make a working game, but if that is the kind of system you are comfortable with, it will serve you well here too. Unfortunately nobody can tell you exactly how to make one because everybody rolls them a bit differently, if they even use them at all. (I don't, for example.) You might start with a simple System.Collections.Generic.List<Event> for the queue, with your various events being subclasses of Event, and a list of subscribers for each event type. For each event in the queue, get the list of subscribers, and for each subscriber, call handle(this_event) on it. Then remove it from the queue. Repeat.

There also seems to be a lot mentioned about on Game Services, whereby you can register a GameComponent in your main Game.cs class, then fetch it from anywhere in your code that has a reference to the main 'Game' object. I've tried this with my SpriteBatch object and it seems very easy.. however, I can't see this being as flexible as an event model.

It's probably not as flexible, but it's easier to debug. Events and messages are tricky because they decouple the calling function from the called function, which means that your call stacks aren't terribly helpful when debugging, intermediate actions can cause something to break which normally works, things can fail silently when not hooked up properly, and so on. The explicit method of "grab a component, and call what you need on it" works well when it comes to catching errors early on and having clear and explicit code. It just tends to lead to tightly coupled code and lots of complex dependencies.

I realise this is partly my poor C# knowledge as much as game communication paradigms, but I'd really like to get this fundamental thing right.

C# is pretty much an identical language to Java. Whatever you did in Java can be done in C#, just with different syntax. If you have trouble translating a concept, it's probably just because you only know a Java-specific name for it.

\$\endgroup\$
11
  • \$\begingroup\$ Thank you @Kylotan. Out of curiosity, what system do you yourself use for interclass communication - the Services approach or something else? \$\endgroup\$ Oct 16, 2011 at 21:14
  • \$\begingroup\$ AFAIK, event buses are similar to messaging queue stuff, but for events. \$\endgroup\$
    – ashes999
    Oct 16, 2011 at 22:15
  • 2
    \$\begingroup\$ @codinghands, I don't normally use any formalised interclass communication method. I just keep things simple - if one class needs to call another, it usually either already has a reference to the second class as a member, or had the second class passed in as an argument. Sometimes however when I'm working with the Unity engine, that has an approach similar to what you're calling the 'services' approach, in that I would look up an object by name that has the component I require, look up the component on the object, then call methods on that component. \$\endgroup\$
    – Kylotan
    Oct 16, 2011 at 23:35
  • \$\begingroup\$ @ashes999 - Messages and events are pretty much the same thing in this context. If you put an event onto a queue, or a bus, or whatever, what you're really storing is a message that denotes that an event has taken place. Similarly putting a message on a queue implies that an event occurred to generate that message. Just different ways of looking at an asynchronous function call. \$\endgroup\$
    – Kylotan
    Oct 16, 2011 at 23:38
  • \$\begingroup\$ Sorry I haven't marked this as 'answered' yet, but I thought there would be more points of view given that every game needs to communicate between components somehow, regardless of language... Have we covered the main possibilities? \$\endgroup\$ Oct 18, 2011 at 14:49
1
\$\begingroup\$

Have you tried just using simple static events? For example, if you wanted your score class to know about when an enemy died, you would do something like this:

Score.cs

class Score
{
    public int PlayerScore { get; set; }

    public Score()
    {
        EnemySpaceship.Death += new EventHandler<SpaceshipDeathEventArgs>(Spaceship_Death);
    }

    private void Spaceship_Death(object sender, SpaceshipDeathEventArgs e)
    {
        PlayerScore += e.Points;
    }
}

EnemySpaceship.cs

class EnemySpaceship
{
    public static event EventHandler<SpaceshipDeathEventArgs> Death;

    public void Kill()
    {
        OnDeath();
    }

    protected virtual void OnDeath()
    {
        if (Death != null)
        {
            Death(this, new SpaceshipDeathEventArgs(50));
        }
    }
}

SpaceshipDeathEventArgs.cs

class SpaceshipDeathEventArgs : EventArgs
{
    public int Points { get; private set; }

    internal SpaceshipDeathEventArgs(int points)
    {
        Points = points;
    }
}
\$\endgroup\$
1
\$\begingroup\$

If you feel uneasy with the event-based approach, give Artemis C# a try, it is an Entity System framework based on http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/

Source: https://github.com/thelinuxlich/artemis_CSharp Example game: https://github.com/thelinuxlich/starwarrior_CSharp

\$\endgroup\$
0
\$\begingroup\$

try to use event aggregator like this one

\$\endgroup\$
1
  • 4
    \$\begingroup\$ This answer would be better if you elaborated more about your suggestion, instead of just providing the link. \$\endgroup\$
    – House
    Apr 17, 2012 at 21:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .