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.

Is there a generally accepted pattern for performing various actions within a game? A way a player can perform actions and also that an AI might perform actions, such as move, attack, self-destruct, etc.

I currently have an abstract BaseAction which uses .NET generics to specify the different objects that get returned by the various actions. This is all implemented in a pattern similar to the Command, where each action is responsible for itself and does all that it needs.

My reasoning for being abstract is so that I may have a single ActionHandler, and AI can just queue up different action implementing the baseAction. And the reason it is generic is so that the different actions can return result information relevant to the action (as different actions can have totally different outcomes in the game), along with some common beforeAction and afterAction implementations.

So... is there a more accepted way of doing this, or does this sound alright?

share|improve this question
    
It sounds good, the question is what do you mean by queue? Most games have very quick response? "AI can queue up different action" –  Arthur Wulf White Sep 25 '12 at 19:25
    
Good point. There is no queue. It just needs to know if is busy, and if not, execute action. –  Arkiliknam Sep 25 '12 at 19:28
add comment

1 Answer

up vote 15 down vote accepted

I don't think there's one accepted way of implementing this concept, but I'd really like to share how I usually deal with this in my games. It's a bit of a combination of the Command design pattern and the Composite design pattern.

I have an abstract base class for actions which is nothing more than a wrapper around an Update method that gets called each frame, and a Finished flag to indicate when the action has finished running.

abstract class Action
{
    abstract void Update(float elapsed);
    bool Finished;
}

I also use the composite design pattern to create a type of actions that is capable of hosting and executing other actions. This too is an abstract class. Boils down to:

abstract class CompositeAction : Action
{
    void Add(Action action) { Actions.Add(action); }
    List<Action> Actions;
}

Then I have two implementations of composite actions, one for parallel execution and one for sequential execution. But the beauty is that since parallel and sequence are actions themselves, they can be combined in order to create more complex execution flows.

class Parallel : CompositeAction
{
    override void Update(float elapsed) 
    {
        Actions.ForEach(a=> a.Update(elapsed));
        Actions.RemoveAll(a => a.Finished);
        Finished = Actions.Count == 0;
    }
}

And the one that governs sequential actions.

class Sequence : CompositeAction
{
    override void Update(float elapsed) 
    {
        if (Actions.Count > 0) 
        {
            Actions[0].Update(elapsed);
            if (Actions[0].Finished)
                Actions.RemoveAt(0);
        }
        Finished = Actions.Count == 0;
    }
 }

With this in place it's simply a matter of creating concrete action implementations, and using the Parallel and Sequence actions to control the flow of execution. I'll end with an example:

// Create a parallel action to work as an action manager
Parallel actionManager = new Parallel();

// Send character1 to destination
Sequence actionGroup1 = new Sequence();
actionGroup1.Add(new MoveAction(character1, destination));
actionGroup1.Add(new TalkAction(character1, "Arrived at destination!"));
actionManager.Add(actionGroup1);

// Make character2 use a potion on himself
Sequence actionGroup2 = new Sequence();
actionGroup2.Add(new RemoveItemAction(character2, ItemType.Potion));
actionGroup2.Add(new SetHealthAction(character2, character2.MaxHealth));
actionGroup2.Add(new TalkAction(character2, "I feel better now!"));
actionManager.Add(actionGroup2);

// Every frame update the action manager
actionManager.Update(elapsed);

I have successfully used this system to drive all of the gameplay in a graphic adventure before, but it should probably work for pretty much anything. It was also simple enough to add other types of composite actions, which were used for creating execution loops and conditionals.

share|improve this answer
    
That looks like a very nice solution. Out of curiosity, how then do you let the UI know what to draw? Do your game objects (like characters) contain state which is used to identify what happened for rendering purposes, or is it the action itself that does that? –  Arkiliknam Sep 25 '12 at 21:00
1  
Usually my actions only change the state of the entities, and any changes to the rendered output occur as a consequence of that state change, not by means of the actions themselves. For example, with an immediate-mode renderer there's no extra step required since the Draw method is already built on top of the state of the entity, and changes are automatic. In a retained-mode renderer like Flash, you could use the observable pattern to make changes to your entities propagate to the display objects, or make the connection manually inside the entity itself. –  David Gouveia Sep 25 '12 at 21:08
1  
In the first situation, let's say that your Character class has a Position property, and a Draw method which reads what the current value of Position is and draws the correct image there. In this situation, you only need to update the value of Position that the result will be automatically seen on the screen. –  David Gouveia Sep 25 '12 at 21:14
1  
The second situation is, when your Character has a Position property, but it delegates rendering to some sort of Sprite object which is being automatically rendered by a scene graph or something. In this situation you have to ensure that both the character's position and the sprite's position are always in sync, which involves a bit more work. Still, in either case, I don't see why the action manager should have anything to do with it. :) –  David Gouveia Sep 25 '12 at 21:16
1  
Both methods have advantages and disadvantages.. I went with the second method for my 2D game, and I've regretted it at times because it's significantly more complicated to keep everything in sync. But there are advantages too, for instance when trying to detect which entity was clicked, or what should or not be drawn, because everything that will be rendered is contained within the same data structure instead of scattered between N entity types. –  David Gouveia Sep 25 '12 at 21:20
add comment

Your Answer

 
discard

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

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