Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm making a game in as3 using flash develop and flash cs5. Everything is object oriented. I was wondering, should I have one "gateway" class that has a property-reference to all instantiations of other classes, and I just pass this gateway class to new objects, so they have access to every class. Like so:

 var block:Block = new Block(gateway);

 //In the block class:
 this.gateway.player.setHealth(100);
 //Or:
 this.gateway.input.lock();

Is this like a singleton pattern or something? Should I do this?

share|improve this question
add comment

3 Answers

This is called the context object design pattern, and it is better than the singleton pattern.

  • Context objects aid testing, because you can pass mock contexts to functions you want to test. Singletons hinder it, because to mock singletons you need to make them not singletons.
  • Context objects makes your "global state" explicit, and therefore easier to reason about. If a function doesn't take a context object, you know it doesn't use any global context state. You have no such guarantee with singletons or global variables.
  • Context objects are very slightly slower if you don't use them, because you add another parameter to all your function calls. They can be faster than globals if you do use them, and are nearly always faster than singletons.
  • Context objects are easier to implement; usually they live on the heap or stack in a normal way. Singletons have tricky issues involving threading in many languages.

So no, this is not a singleton, it's way better than a singleton.

However, you're still passing around a crapload of state - the fact you're keeping it all in a single local variable makes it more explicit, but still creates major conflation of concerns. Keep in mind the one responsibility rule. It makes some sense for there to be a context that owns the player and the current level - they're related - but why does the same context own your keyboard input?

Consider different levels of contexts, for example:

  • GameplayContext - owns the player, enemies, the level geometry, etc.
  • InputContext - owns keyboard and mouse handles, input events, etc.
  • GraphicsContext - owns textures, the window handle, etc.
  • GlobalContext - owns a GameplayContext, a GraphicsContext, and an InputContext. This is where you want to apply the service locator pattern, to be able to swap out some contexts for others as needed. And maybe, for quick iteration and testing, this should be in a real global variable - just realize that whenever you use it, you're building up tech debt.

These contexts still conflate concerns somewhat - maybe some event handler takes a GameplayContext and really only needs the player - but the responsibilities are clearly laid out. You know that something that takes a GameplayContext won't load a texture; something taking an InputContext can't kill a player.

share|improve this answer
    
+1 Good answer. Some of the speed or threading concerns don't really apply in this context though (ActionScript3 doesn't support threading and a lot of speed improving mechanisms that work in C++ don't apply when using AS3). –  bummzack Nov 19 '10 at 11:05
    
I don't know much about the AS3VM, but in most dynamic languages, the cost of passing/receiving/using a local is still faster (array lookup) than the cost of looking up a global (hash lookup), and much faster than calling a function (craploads of stuff) to get at it. So I think that advice still applies. –  user744 Nov 19 '10 at 11:51
add comment

This doesn't look like the Singleton pattern. The way I understand it, you're passing an object with references to important game-objects to all of your instances.

If this would be the Singleton pattern, you would have:

AudioManager.getInstance().playSound(XY);

Whereas in your case you might have:

this.gateway.getAudioManager().playSound(XY);

It looks basically the same, but it really isn't. If you would want to replace AudioManager with a new (extended class) like ExtendedAudioManager, you would hit a wall using the Singleton pattern. Your gateway approach will handle that just fine though.

The drawback of your approach is that you'll have to pass around the gateway everywhere. The service locator pattern (proposed by Joe Wreschnig in this thread), looks like a good replacement for your "gateway pattern".

Sometimes it's better to just run with the simple and straightforward method instead of over-designing things though. Especially when it's a small project or a prototype. Maybe you could make that gateway some sort of a global variable.. eg. Game.gateway and run with it.

share|improve this answer
add comment

Most solutions to this problem, including the Singleton pattern, involve the use of static variables. If you'll only ever have one player, you can just have Player be a singleton class, which means you could access the Player instance through something like Player.currentPlayer. Many people rage against Singletons, however. You could also have a ResourceManager or similar class that contains static references to various useful global or pretty-darn-global variables. In your code, you might as well make "Gateway's" variables statically accessible instead of inflating your code by passing it around everywhere.

share|improve this answer
    
The question has changed substantially since I made this answer, enough that it doesn't seem worth it to edit it. –  Gregory Avery-Weir Nov 19 '10 at 14:58
2  
Apart from the title, nothing changed in the question. –  bummzack Nov 19 '10 at 17:33
1  
What? Nothing has changed other than the title. -1 –  AttackingHobo Nov 19 '10 at 18:05
    
I think I was thinking of the title here; I remember the original title being something like "How should I do this?" It's totally possible that I misread the initial title/question when I made the answer. –  Gregory Avery-Weir Nov 22 '10 at 4:17
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.