我认为没有一种公认的方法可以实现这一概念,但是我真的很想分享我平时在游戏中的处理方式。它是Command设计模式和Composite设计模式的组合。
我有一个抽象的动作基本类,它只不过是围绕Update
被调用的每个框架的方法的包装,以及一个Finished
指示动作何时完成运行的标志。
abstract class Action
{
abstract void Update(float elapsed);
bool Finished;
}
我还使用复合设计模式来创建一种能够托管和执行其他操作的操作类型。这也是一个抽象类。归结为:
abstract class CompositeAction : Action
{
void Add(Action action) { Actions.Add(action); }
List<Action> Actions;
}
然后,我有两种复合动作的实现,一种用于并行执行,一种用于顺序执行。但其优点在于,由于并行和顺序本身就是动作,因此可以将它们组合在一起以创建更复杂的执行流。
class Parallel : CompositeAction
{
override void Update(float elapsed)
{
Actions.ForEach(a=> a.Update(elapsed));
Actions.RemoveAll(a => a.Finished);
Finished = Actions.Count == 0;
}
}
和一个控制顺序动作的动作。
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;
}
}
完成此操作后,只需创建具体的动作实现,并使用Parallel
和Sequence
动作来控制执行流程即可。我将以一个示例结尾:
// 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);
在此之前,我已经成功地使用了该系统来驱动图形冒险中的所有游戏玩法,但它可能几乎可以用于任何事情。添加其他类型的复合操作(用于创建执行循环和条件)也很简单。