Monday, November 28, 2016

ai - Pattern for performing game actions


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?



Answer



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 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.




No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...