Come implementare il comportamento in un'architettura di gioco basata su componenti?


21

Sto iniziando a implementare l'IA dei giocatori e dei nemici in un gioco, ma sono confuso su come implementarlo al meglio in un'architettura di gioco basata su componenti.

Supponiamo che io abbia un personaggio giocatore seguente che può essere fermo, che corre e che fa oscillare una spada. Un giocatore può transitare nello stato della spada dell'oscillazione sia dallo stato stazionario che da quello corrente, ma poi l'oscillazione deve essere completata prima che il giocatore possa riprendere a stare in piedi o correre. Durante lo swing, il giocatore non può camminare.

A mio avviso, ho due approcci di implementazione:

  • Crea un singolo componente AI contenente tutta la logica del giocatore (disaccoppiato dal componente reale o incorporato come componente PlayerAIC). Posso facilmente applicare le restrizioni statali senza creare accoppiamenti tra i singoli componenti che compongono l'entità giocatore. Tuttavia, il componente AI non può essere suddiviso. Se ho, ad esempio, un nemico che può solo stare in piedi e camminare o solo camminare e occasionalmente dondolare una spada, devo creare nuovi componenti AI.
  • Suddividere il comportamento in componenti, ognuno identificando uno stato specifico. Quindi ottengo un StandComponent, WalkComponent e SwingComponent. Per applicare le regole di transizione, devo accoppiare ciascun componente. SwingComponent deve disabilitare StandComponent e WalkComponent per la durata dello swing. Quando ho un nemico che sta solo in giro, facendo oscillare una spada di tanto in tanto, devo assicurarmi che SwingComponent disabiliti WalkComponent solo se è presente. Sebbene ciò consenta di migliorare i componenti di mix-and-matching, può portare a un incubo di manutenibilità poiché ogni volta che viene aggiunta una dipendenza, i componenti esistenti devono essere aggiornati per giocare bene con i nuovi requisiti posti dalla dipendenza sul personaggio.

La situazione ideale sarebbe che un progettista potesse costruire nuovi nemici / giocatori trascinando i componenti in un contenitore, senza dover toccare una singola linea di motore o codice di script. Anche se non sono sicuro che la codifica degli script possa essere evitata, voglio mantenerla il più semplice possibile.

Riassumendo: dovrei raggruppare tutta la logica AI in un componente o suddividere ogni stato logico in componenti separati per creare più facilmente varianti di entità?

modifica : sospetto che ci sia un po 'di confusione su ciò che intendevo con la prima e la seconda situazione. Ho provato a spiegarlo nel diagramma seguente.

Diagramma dei componenti

Nota la relazione tra i singoli stati e l'entità. Nella prima situazione, un componente AI viene pre-costruito prima di essere inserito nell'entità. Un designer può selezionare solo da una serie distinta di componenti AIC resi disponibili dal programmatore. La seconda situazione ha i diversi stati allo stesso livello di altri componenti. Un designer può ora creare un'entità con AI unica senza interferenze di un programmatore.

La domanda è: queste sono le uniche due opzioni per strutturare l'IA in un'entità basata su componenti e, in caso affermativo, cosa darebbe la massima flessibilità?


Penso che una buona risposta dipenderà da dove vuoi far rispettare l'esclusività delle azioni. Se vuoi che sia negli oggetti stessi, il design sarebbe molto diverso rispetto a dire, applicandolo attraverso l'interfaccia drag and drop (Questo stato ha già un'azione di movimento quindi non può averne un'altra, questo contenitore di transizione di stato contiene già uno stato finale basato sul tempo, ecc. o altro).
James,

2 non è un'opzione praticabile.
Coyote,

Risposte:


6

Se hai intenzione di avere più nemici o giocatori possibili che non riesci a immaginare in questo momento, allora dovresti assolutamente romperlo. Quello che stai descrivendo nel secondo punto è fondamentalmente il modello di stato .

Penso di essere d'accordo con Gregory sul fatto che non dovresti avere componenti di stato stand and walk separati. È solo un componente di movimento con velocità 0. D'altra parte, se hai oggetti che non possono muoversi, devi o dividerlo o semplicemente mettere una sorta di restrizione booleana nello stato di movimento che impedisce di avere una velocità diversa da zero .

Per il giocatore non penso che debba essere completamente separato. Può comunque utilizzare tutti gli altri componenti, con l'aggiunta di un componente di input. Questo componente guida le transizioni tra gli stati, mentre nel nemico è controllato da un'intelligenza artificiale predefinita o, se lo desideri, diverse sottoclassi di intelligenza artificiale tra cui i tuoi progettisti nemici possono scegliere.

modifica: in realtà, per i tuoi nemici fermi, piuttosto che limitare la componente di movimento, dai loro una componente AI fissa che non sceglie mai di spostarli.


Un modello di stato non implica la prima situazione? Ciò comporta un singolo componente AIC che implementa una macchina a stati contenente diversi oggetti a stati. Ciò che intendevo con la seconda opzione era che WalkComponent e SwingComponent sono dello stesso tipo, ad esempio, RenderComponent e PhysicsComponent.
fantasma,

@ghostonline Per quanto riguarda l'idea, in un certo senso. In attuazione, non proprio. AIComponent sarebbe separato, come nel secondo diagramma. Non conterrebbe gli altri componenti. La domanda più importante per la tua seconda situazione è, se il progettista sceglie solo componenti senza un programmatore, come fa l'entità a sapere quando cambiare stato? Stati diversi implicano transizioni di stato diverse: qualcuno deve ancora specificarle.
Tesserex,

Intendi aggiungere un componente AIC all'entità nel diagramma 2, che controllerà il componente Stand / Walk / Swing? La mia idea era che i componenti inviano segnali di blocco o di attivazione a determinate condizioni. Ad esempio, SwingComponent emetterebbe segnali generici, ad esempio il segnale "bound_feet" all'avvio e "release_feet" al termine dell'oscillazione. WalkComponent si disabiliterebbe e si abiliterebbe in base a questi segnali. Poiché le "transizioni di stato" sono incapsulate nei componenti stessi, il progettista non avrà bisogno di un programmatore che colleghi i componenti insieme.
fantasma,

@ghostonline Funziona bene per le cose che hanno regole fisse come "non si può camminare mentre si dondola" ma che dire delle transizioni tra stand e walk? Se stare in piedi ha il controllo, come farà a provare a camminare? La logica in piedi potrebbe voler scegliere se camminare o dondolare, che è influenzato dalla totale assenza di un'abilità di deambulazione - in quel caso dovrebbe sempre scegliere di oscillare. Ma penso che tu sia sulla buona strada.
Tesserex,

2

Almeno terrei Player AI (o quello che chiamerei Player Controller) come componente proprio. Con la maggior parte dei giochi, il giocatore è fondamentalmente abbastanza diverso dagli NPC che non puoi generalizzare l'uno dall'altro se non in basi come i punti ferita.

Per gli NPC, vedo StandComponent e WalkComponent come aspetti della stessa cosa. Hai mai un WalkComponent senza StandComponent? Ne dubito. Allo stesso modo, un RunComponent sarebbe semplicemente un WalkComponent con una velocità maggiore e animazioni diverse. Riesco a vedere il valore di avere un NPCMovementComponent e un NPCSwordFighterComponent separato, ma anche quello mi sembra troppo ingegnoso.


Non separerei così tanto il movimento degli NPC e quello dei giocatori. Le azioni di movimento che guidano le animazioni e la fisica potrebbero sicuramente essere condivise; è ciò che seleziona le azioni o le transizioni che sono diverse (il giocatore prende input mentre AI è ... AI). Sono d'accordo che avresti un PlayerController, ma avresti anche un AIController, entrambi i quali potrebbero utilizzare Componenti di movimento / Componenti di oscillazione per svolgere il vero lavoro di animazione / fisica.
homebrew

Vero. Suppongo che tutti gli oggetti in movimento abbiano un componente PhysicsComponent o MovementComponent che gestisca il loro movimento e che PlayerController e AIController lo utilizzino per gestire il movimento. Il movimento dovrebbe sicuramente essere un componente separato, poiché potrebbero esserci delle cose che devono muoversi che non hanno AI o hanno l'IA più semplice possibile (oggetti di fisica stupida come casse o spazzatura).
Gregory Avery-Weir,

2

Prima vorrei creare un componente State e quindi creare una macchina a stati per gestire le transizioni. Rendilo abbastanza generico da poterlo utilizzare per i tuoi giocatori e la tua IA. Questo assicurerà che l'IA giochi secondo le stesse regole e che non devi cambiare la logica quando cambi il modo in cui funzionano gli stati del giocatore rispetto agli stati dell'IA.

Macchina a stati finiti C ++

Quanto sopra ha un esempio concreto di una macchina a stati in c ++ che può essere usata sia dai giocatori che dall'IA.


1

Quello che vuoi è un componente che gestisca il movimento dei personaggi (giocatore e NPC). Il componente AI o un componente giocatore invierà comandi a questo componente di movimento e controllerà se l'azione può essere avviata. Questo incapsulerà i tuoi vincoli di movimento in un singolo componente. Il tuo codice AI e il codice giocatore non devono sapere come viene eseguita la spada swing. L'intelligenza artificiale avrebbe stati interni, ad esempio Inattivo, Attaccare, Fuggire.


1
TYPO: "Riceverà ..." che cosa dal componente AI?
Cucciolo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.