Thursday, 17 February 2011

How to communicate between game objects.

Over on Richard “PhotonStorm” Davey’s blog he proposed a simple way to communicate between objects in your game using a “Registry” a class with static variables storing all the major systems of your game. So, for example if you wanted to create a spray of blood when an enemy is hit, in the enemy’s hit() function you would include the line Registry.fx.sprayBlood(x, y) and the FX object stored in the Registry.fx variable would create the blood spray and handle updating etc.

In the comments on Richard’s post, I pointed out that this isn’t a very object-oriented approach: these are basically global variables by a different name. I have used a similar approach myself on quite a few games projects, and overall it works well and is a quick way of getting things done. I have, however, encountered two problems with it.

Firstly, you can end up with all you code in one huge blob or “god class”. For example, if the FX class is responsible for handling any possible visual effect you would want to create, it could end up getting very big. But, other than academic notions of “good” and “bad” code, there’s nothing especially wrong with having big classes. They may be a bit harder to maintain and reuse, but nothing to worry about too much.

Secondly, using static/global variables as a communication method means you can be limited to having only one “game” in a single project. Now in most scenarios this wouldn’t be a problem, but it’s normally best not to assume you will only ever have one of a particular class of object. I’ve worked on several Flash projects that were collections of minigames in a single swf. Where I was relying on static variables in some of my base-classes and utility classes, I started to see clashes between the different games.

Ok so how do I handle the same problems? Well, say an enemy needs a reference to the player in order to chase after them. Rather than looking up Registry.player, I would just have a “player” variable in my enemy class and I would pass in the value of player when I create the enemy, or once I know the player exists. Or if the enemy needed more than a couple of different references from game in order to work, I would just pass in a reference to the game itself, and let the object access whatever information it needs. As Richard points out, the downside to this approach is that you end up with a lot of references in different places. This isn’t really a problem if you null your references when destroying objects, but it is more work, and you can leak memory if you’re sloppy with it.

Secondly, pretty much everything in my game extends a base Entity class. I have a main Game class that manages all these entities. Game has a method called addEntity(entity:Entity) which adds any new entities I create to the array of entities. Every frame I loop through all my entities and call their public update() function (to pause the game, I just don’t run this loop).

So say I have a SpaceShip object that creates a Bullet object every time it fires. How would I let the game know? I wouldn’t call Game.instance.addEntity() because I may have more than one mini-game that extends my base Game class in a single project. Instead, the base Entity class has a function addEntity(entity:Entity) which dispatches an AS3Signal with the entity value. My game is listening for this signal, and directs the entity to its own addEntity function. You could also use an event to achieve the same effect. Now any Entity can itself create more entities and add them to the game.

How would I use this to solve the problem of creating a spray of blood? I would create two Entity classes. One class is BloodDrop which is a single particle of blood. Every update() it moves based on its speed and falls with gravity, and after 30 frames it fades out and destroys itself. The other class is BloodSpray, which lives for a single frame, and in that frame just runs a loop creating 100 instances of BloodDrop, setting their initial position and speed, and calling addEntity(bloodDrop). Now to add my spray of blood in the enemy’s hit() function, I simply create a new BloodSpray, set its position to match the enemies position and call addEntity(bloodSpray). All the entities know how to update and destroy themselves and are pooled for reuse.

This won’t solve all the communication problems in your game, but it will solve a big chunk of them, and now your code is neatly organised into distinct Entity classes which each perform a single purpose.

Happy coding! I think my next conference/user group talk might have to be one about organising game code :)

25 comments:

With regard to you not using the Registry option, surely what you are doing in this case is increasing the coupling and interdependencies between all the various objects in your game. This cannot be a good thing, if something goes wrong then you are going to have a crash (via a null pointer or whatever), if the registry entry isn't there you can continue without a crash

That said I don't think the registry system works especially well, have a look at a blackboard approach instead. Or even better you could have a map of key->value which is type independent and so you wouldn't need a whole bunch of variables to get and set them. This is possible in C++ but I'm not sure if it is in what you are using.

I used to work in a similar way, passing variables to what I thought classes *would* need, ie the player into the enemy class. But *what* and enemy needs may change in the course of development. This tight coupling that is created then needs to be reworked and all related classes re factored which can be a mayor headache.

Using a *lookup* although it is slower and sometimes feels a bit messy (in terms of OOP) allows much more flexibility which to me is becoming most important when writing the code of games.

Great comments guys. I really like the Registry approach in a lot of ways, but a reference to the game itself is even more useful, surely? Just make your useful info - player, map, enemies etc public vars.

Anyway, I think the main take-away from this post should be the Entity stuff :)

So basically you use dependency injection, without a DI container to maintain control and do the injecting :)

Two things:

1) My article was written for flixel specifically. Flixel objects don't (and can't) dispatch events. Which is just fine given the hit you take with events in AS3. With regard to the update / render calls you mention, that's exactly how flixel works. The FlxObject base type being the equivalent of your Entity.

2) To say that using a service wrapper / Registry isn't a very OO way of coding (with added irony given who devised the pattern), yet passing in a reference to an entire games is, is a bit strange imho. It's like DI gone wild.

When the games get large enough, or for multi-game suites especially, it's easily extended out into CommonRegistry, ActorRegistry, FxRegistry, etc. Very little code (if any) resides in them. There is no single "God class". The FX class in my example had just 3 methods in it. Had I needed lots more I would have looked at an FxManager instead, rather than triggering them directly. For that game however it was sufficient.

A true Registry is a list of pointers, nothing more. The classes themselves are responsible for house-keeping, access permissions, etc (just like they are in the DI/local reference approach).

We've used the multi-Registry approach on large game suites quite happily. We could easily have used a single well constructed DI container too.

That's the beauty of coding isn't it. There's never just one "true" way to skin the cat.

Communication between entities is one of the main issues with the traditional flash game development. Your better off using a true entity system that side steps a lot of these issues. Here my post on the subjecthttp://www.tomseysdavies.com/2011/01/23/entity-systems/

I fully agree with you that there's no right and wrong way to do things. If you find a method you're happy with you should use it - you'll notice that I haven't actually told anyone not to use your approach - I actually like it.

You can call my approach dependency injection if you want, but I would just call it passing references to resources. Dependency injection to me implies using containers, mxml tags, etc.

Re. your point (1) - a Flixel object could still dispatch an AS3Signal. Anything can dispatch them without having to extend EventDispatcher, which is their beauty. But yes, all good frameworks should have a single base GameObject/Entity class.

Re. your point (2) It doesn't matter who came up with the name your approach (appeal to authority?), it's still just some static vars in a class. Passing reference to a game instance rather than using a static class - to me - feels more OOP - you could have any number of games running simultaneously and they wouldn't clash. Obviously people might say it's not good practice to expose so many public properties, etc etc, but I think we're both agreed that this is about what works rather than what is "correct".

Anyway Rich, we both know what we're doing - it's new developers who I think will find this discussion most useful.

@tom - yeah I've read up on that kind of system, but for me it's just too counter-intuitive to use on a Flash game. I like working with game object classes with methods, properties etc, rather than "data".

@Ian agree if your used to flash where everything extends everything then its a very different way of working. Your post nicely hi-lights the issues with that form of game architecture in all but the simplest of projects. It comes down to what your familiar with but remember if your only tool is a hammer then the whole world looks like a nail.

Hmm... interesting to read the different views on this. I've used both these systems to varying degrees in the past, and really they're quite similar in a lot of ways. Iain's way is essentially making a registry out of the main Game class, and making sure everything that needs to has a reference to it. In which case, why not just give the Game class a static reference to itself which anything can just refer to? Game.instance.addBaddie()

My own feeling is that it's easy to get too hung up on this stuff in Flash game dev stuff. In our search for acceptance as 'proper' programmers, we worry about what's 'right' and 'wrong' a bit too much. Or maybe that's just me... ;o)

@tom I have gone down some bad roads of deep inheritance trees in the past, but now I limit myself to 2 levels of inheritance. There is a base Entity class, and there are the objects that extends it - Player, Enemy, FireBall etc. Rather than adding intermediate levels of object like MovableEntity etc, I do use composition of components instead. So an Entity has components for Body, Physics, View etc. What I can't get into is the data-driven approach of putting all your entities definitions into XML etc.

@Ian good that's much better than lots of inheritance but here are two main issue with that approach. First is dependencies between components say a physics and view components where they need to share data or communicate. Quite often things end up being tightly coupled and not as reusable as they should be. Second is inter entity communications. As for defining your entities in XML well that's your choice but its good to know you can. Generally flash games are small project worked on by a single developer and the real pay off of making everything data driven come into play with large teams. One of the main advantages of making everything data driven is you can share the data between clients easily or store it and load it automatically.

I read the original registry post over at Photon Storm and enjoy seeing this alternate post regarding the reference passing.

I've been using the reference passing method for a few years now and while it works well enough I agree the main problem I've run into with it is what another commenter above mentions and that is that during development I find I have to refactor quite often and then I'm left to crawl through a lot of my class files changing or altering all the places I'm passing my references around.

What appeals to me about the Registry idea is how it would (hopefully) greatly reduce this refactoring during rapid development. A lot of the games I work on are less than 100 hour projects to create small scope games and development speed is crucial to being able to support myself. I enjoy any design patterns that help me more or less get the code down fast enough to understand the game and keep it flexible enough to alter as I get new ideas and feedback after reaching the first playable prototype.

I think I'm going to try the Registry on my next few games and see how it goes because that is obviously the only way I'll know if it works out for me.

I too agree that a developer should work with the methods they are comfortable with and that there are many solutions with nothing being really "wrong" or "right." That doesn't mean I don't want to hear these kind of interesting discussions though! I learn something new every time.

I remember ages ago posting how I do this kind of thing on the blog.I also remember being jumped on by a lot of people for not being oop "enough" ( Iain, think you were in there mate :) ).

Any post like this is going to be abused, as we all have our own variations of "What's right" ( It's like Monopoly, has anyone ever played that with the proper rules ? ).

Coding has so many variations, and a really strict oop approach doesn't really have a place in Flash game dev.For me the key is to steal the bits you like from other people so you're in a happy place, be that a registry singleton or public vars.

Yeah I change my mind about this stuff all the time as I learn and try out new things. A couple of years ago I was sure MVC was the way to go for games! Wrong!! Anyway, yeah, each to their own I guess. I might even come back round to the Registry approach eventually. Making everything an Entity always seems to be a good idea though.

Ian, you wrote:Instead, the base Entity class has a function addEntity(entity:Entity) which dispatches an AS3Signal with the entity value. My game is listening for this signal, and directs the entity to its own addEntity function.If I understand that right: Bullet extends Entity,Then Game has to know Bullet before if can listen to the signal dispatch from the addEntity function inherited from Entity. Then Game might as well addEntity(bullet) immediately.Or is addEntity from Entity a static function?

I didn't go digging through the comments much, but I see that signals have already been mentioned. As far as refactoring an enemy who targets a player goes, I generally use a variable named TARGET, which uses my BaseEntity class. That way, any entity I create can be the enemy's target.

I do my entity updates in an almost identical way, and I'd be curious to see what sort of setup you have for your base engine. Right now I have an Engine class, which handles all of the set up. I have the BaseEntity class, which I can extend for any object I want to add to my game, a World class which handles level/map loading, and some utility classes.

It's still a WIP, and I think it would be cool to see the way you have it set up. I had initially gone with a more Source Engine feel to things, but then adopted FlashPunk naming conventions because of a recent experiment.

Essentially I'm trying to make my engine easier for newer users, as I plan to do a few collaborations.

I really would like to see an article about code organization, communication and probably a simple game in a whole. I still can't make up my mind and not sure how to organize things. Till now I haven't used inheritence but only a bit of composition and you said that you have generic class Entity. What you put in that class and what is the purpose of it? Sorry, for the noobish questions.

Thanks for this article, there's lots of interesting points made here, and it's helping me to work on my own framework. I personally find events as a method of inter-object communication a little bit complicated for my coding style, and prefer to pass information between objects including references to object pools etc, from within my main game class, and I also make extensive use of static variables in a Globals class much like Flixel's FlxG. There really is more than one way to boil an egg, and I truly believe the only right way of doing things is the way you believe is the easiest or most becoming. We don't drive the same cars, listen to the same music or paint in the same way, so why should we all make games in one definitive pattern? Patterns can help, but only if you find them natural, and this is key. I think that we all think differently on a psychological level. We code machines, but we are human and for genetic and physiological reasons we tackle problem solving in different ways. This to me is a shortcoming of design patterns, particularly in so creative a programming outlet as games dev.