2

I've been going through all the design patterns in context of game programming form this book, before starting my next big project. Apart from that I've been reading about them in more general context. The one I have trouble undertanding is the command pattern, specifically the part about using it for game AI.

The author says:

The decoupling here between the AI that selects commands and the actor code that performs them gives us a lot of flexibility. We can use different AI modules for different actors. Or we can mix and match AI for different kinds of behavior. Want a more aggressive opponent? Just plug-in a more aggressive AI to generate commands for it. In fact, we can even bolt AI onto the player’s character, which can be useful for things like demo mode where the game needs to run on auto-pilot.

This part makes me think that the main point of using the command pattern is the ability to mix different AI modules with different actors. Isn't this functionality achievable with a simple interface? In all the other, more general books the main benefits of this pattern are: postponing the execution, queuing commands, logging and undo functionality.

So to summarize: Is the command pattern useful for decoupling game AI for the actors even if I don't need any core functionality it provides?

2

Just to extend a little bit on Robert Harvey's already excellent answer in a way that might click a bit more with you:

Isn't this functionality achievable with a simple interface? In all the other, more general books the main benefits of this pattern are: postponing the execution, queuing commands, logging and undo functionality.

In that case you are directly utilizing the receiver instead of having this command abstraction in the middle.

Let's say I crate an ICommandable interface instead of using the commands. How is that different functionally? I know that it's different structurally: I'm completely omitting the [Command object] part, but I can't see what's the decoupling advantage here. In both cases I need to know what's the receiver, when creating the command/calling the interface function. Am I missing something?

Firstly if you want to introduce new commands to your system, then it would require rather intrusive centralized changes to this ICommandable interface. Moreover each new function you add to that interface would have to be implemented by every concrete Commandable that implements that interface which could make such extensions particularly costly if you have more than one of these.

Secondly it doesn't allow you to sandwich new functionality between invoker and receiver. Undoing and logging and queuing and parallelizing are just some examples of the kind of functionality you might want to add (and even possibly in hindsight) between invoker and receiver.

In my case on top of all these things, we also have commands being registered by third parties whose plugins are loaded by users at runtime (we use the factory pattern to allow such registration and instantiation of commands by name). The registration of a new command causes that command to be displayed in the UI automatically as well as now being accessible to both the native code and our embedded scripting language. It allows that command to be invoked in various ways by users from clicking on GUI elements or typing in commands into the "command" (scripting) console or writing a script in their own file and adding that as a plugin or writing a C++ plugin and building it and loaded it dynamically. You probably don't need all these bells and whistles but they're additional examples of what sort of rich behaviors you can get with the command pattern when you combine it with factory.

But also going back to functionality you can sandwich in between, in our case since plugins written by third parties (who might not always write the most sound code) can register commands for execution, some poorly-written plugins might have a tendency to crash bringing our host application down in flames along with it. So we actually launch a separate process and execute the command there with IPC to synchronize changes if that command succeeds. That has had the practical effect of making our host application almost "crash-proof".

And that's just another example of functionality you can sandwich in between invoker and receiver. It is very useful in my experience and provides a lot of breathing room that way for what I consider a rather trivial upfront cost (though I might think of it as trivial partially because I've been using this basic pattern in some form or another for as far back as I can remember).

  • Doh, I didn't mean to steal accepted answer (I feel so rude when that happens). I still think Robert's is better and more precise technically. In my case I'm just not so smart so I'm used to dumbing down explanations if only to make better sense of it to me and wanted to try to just pitch in that way to complement his nicer answer. :-D – Dragon Energy Dec 10 '18 at 16:58
6

Isn't this functionality achievable with a simple interface?

Not quite. There's also an object in the pattern that acts as an intermediary between the caller and the receiver.

[Caller] --> [Interface] --> [Command object] --> [Receiver]

That's where the decoupling comes in. The caller knows nothing about the receiver, nor does the receiver know anything about the caller. Another bit of software that knows about both the receiver and the caller wires up the objects at runtime.

This pattern shows up frequently in UI technologies like WPF, where Command objects are used instead of ordinary Events. It facilitates the use of Model-View-ViewModel (MVVM), where UI is decoupled from the underlying business logic.

Is the command pattern useful for decoupling game AI for the actors even if I don't need any core functionality it provides?

Well, the decoupling is the "core functionality" that Command provides, so you'll have to decide if you need that level of decoupling or not.

Further Reading
Command pattern on Wikipedia

  • 1
    The caller knows nothing about the receiver, nor does the receiver know anything about the caller. Let's say I crate an ICommandable interface instead of using the commands. How is that different functionally? I know that it's different structurally: I'm completely omitting the [Command object] part, but I can't see what's the decoupling advantage here. In both cases I need to know what's the receiver, when creating the command/calling the interface function. Am I missing something? – Wojtek Wencel Oct 15 '18 at 17:45
  • In your scenario the caller must still know about the receiver. See stackoverflow.com/a/32597828 – Robert Harvey Oct 15 '18 at 18:30
  • In the answer you linked the author says that the pattern encapsulates everything required to take an action and allows the execution of the action to occur completely independently of any of that context and then provides an example where this encapsulation is used to schedule a command execution. So here is my main question again: how is this pattern helpful if I don't need to schedule, log, undo, etc. commands and they don't need to be passed to another object to be executed? – Wojtek Wencel Oct 15 '18 at 19:33
  • It might not be. As always, it is up to you to evaluate a given technique within the context of your specific project. For me, the critical line of code in that Stack Overflow answer is this one: new Button("Turn on light", light.turnOn()); where light is your Command object. – Robert Harvey Oct 15 '18 at 19:42
  • I understand how it helps in this case, but that's also not how you would use it for game AI. – Wojtek Wencel Oct 15 '18 at 19:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.