Non penso che ci sia un modo accettato per implementare questo concetto, ma mi piacerebbe davvero condividere come di solito mi occupo di questo nei miei giochi. È un po 'una combinazione del modello di progettazione Command e del modello di progettazione composita .
Ho una classe base astratta per le azioni che non è altro che un involucro attorno a un Update
metodo che viene chiamato ogni fotogramma e una Finished
bandiera per indicare quando l'azione ha terminato l'esecuzione.
abstract class Action
{
abstract void Update(float elapsed);
bool Finished;
}
Uso anche il modello di progettazione composita per creare un tipo di azioni in grado di ospitare ed eseguire altre azioni. Anche questa è una classe astratta. Si riduce a:
abstract class CompositeAction : Action
{
void Add(Action action) { Actions.Add(action); }
List<Action> Actions;
}
Quindi ho due implementazioni di azioni composite, una per l' esecuzione parallela e una per l'esecuzione sequenziale . Ma il bello è che poiché parallelo e sequenza sono azioni stesse, possono essere combinati per creare flussi di esecuzione più complessi.
class Parallel : CompositeAction
{
override void Update(float elapsed)
{
Actions.ForEach(a=> a.Update(elapsed));
Actions.RemoveAll(a => a.Finished);
Finished = Actions.Count == 0;
}
}
E quello che governa le azioni sequenziali.
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;
}
}
Con questo in atto, si tratta semplicemente di creare implementazioni di azioni concrete e di usare le azioni Parallel
e Sequence
per controllare il flusso di esecuzione. Concluderò con un esempio:
// 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);
Ho usato con successo questo sistema per guidare tutto il gameplay in un'avventura grafica prima, ma probabilmente dovrebbe funzionare praticamente per qualsiasi cosa. Era anche abbastanza semplice aggiungere altri tipi di azioni composite, che venivano utilizzate per creare loop e condizionali di esecuzione.