Flash Game Dev Tip #1 – Creating a cross-game communications structure
Tip #1 – Flixel – Creating a cross-game communications structure
As moderator of the flixel forums there is one question I see time and time again. It starts something like this: “how can I make X talk to Y, especially when the State changes?”. The problem is a classic OOP one, and thankfully there is a classic OOP approach to solving it. Have a look at the following diagram:
Here we have part of a mock-up Game State structure for an RPG game. As part of the state you can see the Player, an Enemy Manager, an Inventory (which both Player and Enemy can share) and a Map consisting of several important locations.
Of course this is just a rough-example, so don’t get bogged down in the semantics or structure of it. Instead think about how inter-dependant all of these objects are on each other.
- For example perhaps the Temple won’t allow the Player to enter if he is carrying a weapon.
- What if when fighting the Thief you win, but he steals a Potion from your Inventory before running away.
- Perhaps the enemy wouldn’t even attack you if he realised what Sword you were carrying?
- A Wizard casts a fireball at you. How much of the damage does your Armour repel?
In all but the most simple of games it’s vital that your game objects can communicate with each other. And communicate effectively.
When you create your Game State you could first make the Player object, and then pass a reference of that into say the Enemy Manager, so the baddies it creates can check out your vital stats prior to attack. But passing references around like this gets messy, and it’s all too easy to leave “open ends” that don’t get cleared up as needed. In a worse-case scenario they could leak memory and crash Flash Player. And in a “best case” they just confuse you during development.
One Ring to Rule Them All
My suggestion is to use a Registry. A Registry is “A well-known object that other objects can use to find common objects and services.” (Martin Fowler, P of EAA) – sounds ideal, right?
They are extremely easy to create too. In your Project create a file called Registry.as – Here is an example file based on the structure above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package { import flash.display.Stage; import org.flixel.*; public class Registry { public static var stage:Stage; public static var player:Player; public static var enemies:EnemyManager; public static var inventory:Inventory; public static var map:Map; public static var weapons:Weapons; public static var potions:Potions; public static var spells:Spells; public static var previousLevel:int; public static var enemiesKilledThisLevel:int; public static var enemiesKilledThisGame:int; public static var arrowsFiredThisGame:int; public function Registry() { } } } |
It consists of a bunch of static variables that map to the main objects required in our game. Not everything has to go in here, just the objects that you need to either retain their content when you change state, or objects that you know you’ll need to reference from elsewhere in your code, no matter how deep you get.
You can also see a few stats (previousLevel, etc) that are just holding details about the number of baddies killed in the whole time they played the game. Perhaps they can be used for achievements.
So how do you use them?
Quite simply by referencing them in your code. For example say we’ve got a Soldier. Our class file Soldier.as contains all the functions he can perform. One of them is attack, but before he attacks he checks out the player to see how much health he has. We do this via the Registry:
1 2 3 4 |
if (Registry.player.health < 50) { attack(); } |
So our wimpy Soldier will only attack if he thinks he has a chance of defeating you! “health” is just an integer in our Player.as file that holds the current health of the player. You use the Registry as a conduit between the objects in your game. It’s a means for any object to gain access to another object or service, regardless of its depth in your structure. Once you start planning and thinking in this way, designing your game starts to become a lot easier. Your game objects can “share” knowledge of the game without the need for passing references or instances. Another example. Here we have a CharacterDialogue class. It’s responsible for the speech and interactions between characters in the game. It too has access to the Registry, which means you can do things like:
1 2 3 4 |
if (Registry.map.castle.getNumberOfSoldiers() >= 20 && Registry.player.potions.hasStealth == false) { speech = "The castle is heavily guarded. A stealth potion should help"; } |
On a more “arcade” level enemies can use the Registry to get player x/y coordinates, or to find out if he’s colliding with something. I often have a class called SpecialFX in my games, which is referenced in my Registry as fx. The class contains various particle effects such as “spurting blood” and “sparks”. This means that when an enemy dies, in their kill() function I can call:
1 |
Registry.fx.bloodSpurt(this.x, this.y); |
As long as the “bloodSpurt” function is public then a shower of blood will erupt forth, based on the x/y location of the enemy that just died.
I prefer this approach to the opposite. Which would be that the enemy creates a “blood spurt” particle when it dies and is responsible for displaying and running that. I just find the above neater. It ensures that the classes deal with their specific tasks and don’t “cross breed”.
Populating your Registry
If you use the example Registry above then it’s just full of empty (null) objects. You need to instantiate each object before it can be used.
When you do this is up to what fits best for your game, and it will vary from game to game. But there are two common methods:
1) When the game first starts (after the pre-loader has completed)
2) Every time your main Game State begins
If you do not need to maintain objects once your game has ended (i.e. the player has died and was sent back to the main menu) then you can populate your objects right as the first thing you do when your GameState starts:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public function GameState() { super(); Registry.gui = new GUI; Registry.player = new Player; Registry.map = new Map(level1); Registry.inventory = new Inventory; add(map); add(player); add(gui); } |
Here is the constructor of my GameState.as file. We create the objects and then add them onto the display list.
If you don’t want to “over-write” the player like this (perhaps it has stats you wish to retain no matter how many times the game is re-started) then you’d need to move the object creation elsewhere in your game. Perhaps as part of your FlxGame class. Here’s an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package { import org.flixel.*; public class GameEngine extends FlxGame { public function GameEngine() { Registry.player = new Player; Registry.reachedLevel = 0; super(640, 480, MainMenuState, 1); } } } |
It’s up to you where you do this, just don’t forget to do it!
House-Keeping
If you have objects in your Registry that you don’t need to keep should the game end, then you can create an erase function inside your Registry. All it needs to do is set the objects to null:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public static function erase():void { player = null; hud = null; debris = null; weapons = null; map = null; aliens = null; pickups = null; sentryguns = null; storyblocks = null; lazers = null; hacking = null; boss = null; bossfire = null; enemyfire = null; terminals = null; } |
And then just call Registry.erase() when your game ends, before it changes to your menu state.
This will ensure you keep memory down. As flixel doesn’t let you create any custom events, then you shouldn’t have anything left lingering by using this method.
Final check-list
1) Registry.as should be at the top level of your Project
2) All vars declared within it should be public static if you want to access them outside of the Registry class itself
3) Access it from anywhere by calling Registry.object – Do not create an instance of it.
4) If you use FlashDevelop then you will get full auto-complete of anything you put into the Registry!
5) You can put Flixel base types in there too: spaceShip:FlxSprite is perfectly valid.
6) If needs be you can also put common functions in there. But try to avoid this practise, there are better ways.
Further Reading
You can read about the Registry pattern in the book Patterns of Enterprise Application Architecture by Martin Fowler.
You could extend the Registry to be a singleton, so that only one instance of it may ever exist (and further attempts to create them would error). There are pro’s and con’s for doing this. Personally I don’t need to as I never instantiate my Registry anyway, but I can see the merits of adding that “safety net” check in.
Posted on February 12th 2011 at 11:38 pm by Rich.
View more posts in Flash Game Dev Tips. Follow responses via the RSS 2.0 feed.
39 Responses
Leave a commentMake yourself heard
Hire Us
All about Photon Storm and our
HTML5 game development services
Recent Posts
OurGames
Filter our Content
- ActionScript3
- Art
- Cool Links
- Demoscene
- Flash Game Dev Tips
- Game Development
- Gaming
- Geek Shopping
- HTML5
- In the Media
- Phaser
- Phaser 3
- Projects
Brain Food
Quick, let’s hide! I can hear the anti-static, anti-Singleton mob rolling in! 😉
I’m using a similar approach for an engine I’m developing but there are more objects that might store state than only one registry as it’s a more complex scenario. These objects are not static however since there are some drawbacks to that (obviously). so I have for example an object called Config that stores major app config properties but it’s referred via a Main class which acts kind of as a central hub and which … uhmmm … might be a Singleton. But I try to steer away slowly from making this Main class a Singleton, no matter how comfortable it is. So I try to give a reference of Main to other classes that need it (and those might give it on to sub objects etc.) in the constructor, kind of like a very simple dependency injection.
Nice article – always good to have a name even for the simple approaches. 😉
Only suggestion is to always consider limiting visibility of Registry (or any other global data) only to the required packages/classes. Basically it is good to treat classes that need such great power as “contageous” and keep an eye on them, so that those many-to-many calls are not spread across all your application.
For example, if RPG requires such complicated checks on game logic level, it is probably good idea to use strategy pattern (http://en.wikipedia.org/wiki/Strategy_pattern), so that all this game logic complexity is very separate from general RPG code (roaming around 2D land, detecting collisions, etc). And strategies ARE allowed to use registry (while the rest of the game is NOT).
It is also good not to name those “Registry”, but for example, “GameWorld” or “ActorRegistry”. This way programmer will immediately “spot” if your graphics engine started to use “ActorRegistry, and good appropriate interdependency (that model real world game rule that sometimes ARE complex and interrelated) is converted into spaghetti code. 😉
This will greatly help when one will be developing his next RPG title. Core RPG features (roaming 2D world, checking collisions) will need to be properly separate from all those game specific concerns. It is always good to just replace sprites and game rules, and have another $30000-sponsorable-title. 😉
While this approach will definitely help you get things done quickly, there is a danger that all your code will end up in Registry and you’ll basically be writing procedural code. Need to write a blogpost of my own to explain properly how I would solve the blood splatter problem… Coming soon! All knowledge is useful though and I know this will help a lot of developers get things done
A simple aproach that works fine in simple games. Instead of using a static registry (with all singleton issues you will bang your head to the wall for later on) I would recommend using a dependency injection framework (i recommend robotlegs) with an eventbus. Instead of everything depending on the registry and effectively making everything global it can keep dependencies minimal and prevent singleton issues.
@Bart Hmm Robotlegs for AS3 game development .. I’ve tried that but RL has usually way too much overhead for gamedev with all the mediators for every view class. In the end you have a mediator everywhere between your views and data models where maximum performance is desired and RL sadly doesn’t do much good to that.
The more complex the game, the less useful a single registry becomes. But let’s face it, the vast vast majority of flash games are not complex at all. They just need a simple way for objects to communicate.
Ignore the fact I used an RPG in my example, this isn’t really about where data should be stored for a game of that complexity, and in hindsight I should have picked something simpler, as the same logic for using a Registry applies equally to Space Invaders or Frogger (where a Strategy approach is overkill).
I agree the more complex the game, the more need for firewalling off your registries. But on the most part the need for this is quite limited.
Iain – there is no need for ANY code to appear in the Registry at all. It’s an object conduit / access to services. Keen to read your approach (although not if it uses events or an eventbus!)
Bart – If you’re in the realms of dependency injection then you’re already beyond the scope of this article. I would not recommend it for beginners however (and to a certain degree I wouldn’t recommend it at all for tight game loops). Robotlegs is far from perfect in games, in fact I’d actively avoid it personally (we tried it on a large client game last year and it caused more problems than it solved – we used it for an avatar making app and it was perfect). Everyone has their own preferred way of doing things though, so if it works for you that’s cool, I’m just very wary of it myself for games.
I’m not sure I see the gain in making a Registry class that’s separate from your FlxState subclass. I get that you need to use static variables to communicate between states, but that’s fairly rare in the games I’ve worked on, mainly to communicate “ok, the player chose this difficulty” or “use this map”.
I suppose one downside it avoids is, I have to keep casting FlxG.state to my subclass all over my code.
Chris – If I understand your comment correctly, you mean you do: PlayState(FlxG.state).player.castSpell vs. Registry.player.castSpell ?
All I can really see here is an unnecessary object cast and the inability to use objects cross state. I’m not going to cite “performance” at you, as I’ve no idea how/if it would impact a game. It’s definitely an un-needed runtime op for the AVM to have to make though, but I guess a minimal one. If it works for you then great. I guess if a game is simple (or cluttered 😉 enough that you wrap everything into one game state then fair play. Personally I like to keep my states as tiny as possible and split them up. If my state has gone beyond a few hundred lines it’s too big for me.
In Cat Astro Phi I had states for the intro, main menu, shmup section, exploring/maze part and the credits/end sequence. With one Registry binding them all. Especially as several of my achievements needed tracking across each of them.
@sascha You don’t have to use the Mediator pattern to use RL or a DI tool. I use RL and the viewMap all the time in game dev. I agree that the mediator is too heavy for most game dev, but leveraging DI for game dev is a win – you can loose the global data object, ensure that all your other actors have their dependancies ready to go, etc etc.
Just keep in mind that the “default” mvc framework code that comes with RL is not the only way to do DI, or even to use RL!
This helped me so much. Thank you!
@Jos I’ve been investigating a simple DI implementation with Flixel. Can you describe in a little more detail how you’d imagine Flixel and RL interacting?
The problem I have with DI / IOC is that you need to jump though the exact same hoops for the same end result, and it’s only really the DI container that has any kind of benefit.
At it’s most basic level if you are just passing in your objects “blind” and storing local references to them, you still need to spend the same amount of time locking down the methods they have, to ensure nothing can become corrupted/overwritten, just as if they were accessed via a Registry.
The biggest difference is that you’ll need a solid DI container to manage the object lifecycles, and inject them as needed. I guess the benefit is that it can hold onto the objects it needs, and can maintain any singletons or flyweights it has to look after.
I still firmly believe that it’s all too easy to “over-engineer” something, especially games. And actually that is the primary factor why so many projects never get finished. The more you learn, the more you think you should be putting into your frameworks, and the less actual “game” gets made.
In large team based projects, where lots of other developers are using and relying your objects, then a DI/container approach would be very useful (especially if it was based on say the feature set of Butterfly). Ultimately though it’s just another way of allowing objects to use each other. It doesn’t make them any more secure, or provide any extra features once you are down on the shop floor so to speak.
@Richard You’re absolutely right about one thing: the need to just SHIP IT.
Working on our Global Game Jam project a couple weekends ago was fascinating. Out team got to experience an entire product lifecycle in a weekend. The exact same kinds of problems came to light as a full-blown project: asset hand-off, a tendency to over-engineer, conflicting story direction, etc.
Thanks for posting up this article, by the way.
Yeah it’s easy to see where this over-engineering is coming from! There’s lots of evangelizing (I hate that word!) about keeping best OOP practices among ActionScript coders. I recently removed some interfaces from a project because so far I never used them, so why keep them?! Similar story! On the other hand I see some AS3 programmers who seem to still write code like in the days of AS1, throwing everything into one huge class (I admit I did that too when I first started AS2). 😉
Hey photon, this post has helped me a lot, keep up the good work
To me a lot these issues arise from the architecture used by traditional flash engines. I suggest you look into entity systems as they side step a lot of issues i’ve a written blog post about them here.
http://www.tomseysdavies.com/2011/01/15/game-architecture
Its possible to write good code and keep it simple but you may have to change your approach.
Hi Tom – Yeah I read your article (after you replied over on Iain’s blog, which I caught up with today). I’ll reserve judgement until you post some follow-ups that have AS code in that aren’t tied to your framework. I’d like to see how you would actually implement it on a code level. I know I could look at Ember to see this, but I would prefer a more “natural” implementation.
I’m working on simple 2d engine at the moment when I have the time ill let you know when i have a demo up. If you want to see a working entity system in flash then check out the Push Button Engine however there approach does have issues in my opinion. I see you joined Gary with his Zest3d engine be good to see it finally up and running.
I know this thread is about the Resgistry, but if you don’t mind I have a question about your SpecialFX/bloodspurt example: I’ve been told that one should avoid creating objects once the game/level has started. In other words, create it upfront and activate it when necessary. I’m trying to figure out how to set up my own effects class, and following your example it seems like the bloodspurt is created as it’s called. Maybe I’m misinterpreting your approach, but wouldn’t it be better to create it beforehand(?).
I’m experimenting with this right now but I don’t have anything finished yet…
Hey Jason – no I create them in a pool and recycle them. Look at my Game Dev Tips 3 and 4 for examples of doing exactly this
in fact 4 even has the Fx class in, so you can see the code completely!
Ah, very nice. I’ve been updating my project to use a registry and the FX management is now going very well. Thanks!
Very interesting! I always like to see how other as3/flixel coders solve these kinds of problems.
The approach I’ve taken is one that parallels flixel’s structure in that I have a class with static objects called G that is very much like FlxG. I also have a class called U (like FlxU) that has a lot of static utility methods. Works well enough for simple games. I guess as the game gets more complex, I’d probably start splitting stuff up if needed. I do get a bit concerned about the dependency of all classes over a single global class all the time.
Another less dependent approach I thought of was something along this example with a not so permanent singleton:
public class EnemyManager extends FlxGroup {
public static var current:EnemyManager; // could call it instance, too.
public EnemyManager() {
super();
this.current = this;
}
override public function destroy():void {
super.destroy()
this.current = null;
}
}
Then access it through the dependent classes as:
EnemyManager.current.publicMethod(…);
Hi. What You all say about pureMVC with fabrication and its dependency injection. You can store your registry data in ValueObjects shown to the world by Proxies. This is mine method for next game. What You think about that?
note pureMVC doesn’t use dependency injection but you can use it with pureMVC (big difference). Using some kind of injection would be better than using a static class or a pureMVC multiton stlye solution as it is IOC.
Tom, check the fabrication extension for PuerMVC it’s doing the job for DI
Not used that. I’d suggest that you use robotlegs which does things properly from the start.
That’s nice. I always thought this as some kind of workaround, doesn’t seem to be one, right? I’ve been calling this class of Globals instead of Registry.
It’s only matter when you want to make another game, because you want to reuse all of your classes from the other game.
if you use the photon-storm registry approach then on the next game you need to use it again, so you don’t need to change to many things.
I wonder how other engines do this (Unreal, Havok, Frostbite, etc) ?
or the big game development studios make their games?
in Unity use something called GameObject and TagManager, then you use it like this:
var enemies:Array = GameObject.FindGameObjectsWithTag (“enemy”); //Returns a list of active GameObjects tagged tag. Returns null if no GameObject was found.
http://unity3d.com/support/documentation/ScriptReference/GameObject.FindGameObjectsWithTag.html
http://answers.unity3d.com/questions/148294/send-messages-to-different-gameobjects.html
This was really helpful to me – as were all the comments too. I’m at the point in my development where it makes sense to start learning about game architecture and there is a real dearth of -good- tutorials that explain these sorts of concepts as well as you’ve done here. ( Unless there’s a secret repository full of the best stuff hidden somewhere — if so, someone please point it out!! ).
Thanks again!
Marc
Thanks for the tutorial! Very useful for my flash experiments, and I managed to adapt it to XNA. Glad you could take the time to help us all out. 😀
My personal belief is that for a hobby project, you can afford to do as you wish. However, for a commercial game that has to meet deadlines, you need to use whatever gets the job done in the quickest amount of time, that still provides reasonable performance.
There’s nothing wrong with a singleton/static class approach, and in fact, I would say in small teams or a project that requires quick turnaround, it is almost necessary. A Registry, as it’s called in this article, really simplifies the access of objects that are required across the whole game, and it really makes it possible to avoid any unnecessary passing around of objects (perfect example is in XNA.. why bother always passing around the reference to the Content Manager when you can just store it in a global, static class and just use it that way..).
At the end of the day, you, as the programmer really should know what’s happening in your code and when you use a certain method of getting something done, need to understand the benefits and risks involved, and work around or avoid the risks, while maximizing the benefits. At the end of the day, the end user will never see your code (well, in most cases at least). Who cares if it isn’t pretty, or it isn’t done “correctly”? I’d rather have a game with crap code that gets shipped and is enjoyed by users, than a game that never gets finished because the developers keep deciding to re-do everything because you save 2 CPU cycles per call by changing to something more efficient.
Hey there Rich. I just want to say thanks for the hard work. Excellent job explaining everything with style which show how much you care to share your knowledge with us. Thank you.
This was very helpful to me. However, I think there’s an error in the tutorial.
At one point you have, for the Gamestate constructor:
Registry.player = new Player;
add(player);
etc.
But I’m pretty sure you have to go
Registry.player = new Player;
add(Registry.player);