Molte fonti di movimento in un sistema di entità


9

Sono abbastanza nuovo all'idea dei sistemi di entità, avendo letto un sacco di cose (utilmente, questo fantastico blog e questa risposta ).

Anche se ho qualche problema a capire come qualcosa di semplice come riuscire a manipolare la posizione di un oggetto da un numero indefinito di fonti.

Cioè, ho la mia entità, che ha un componente di posizione. Poi ho qualche evento nel gioco che dice a questa entità di muoversi di una data distanza, in un dato tempo.

Questi eventi possono accadere in qualsiasi momento e avranno valori diversi per posizione e tempo. Il risultato è che sarebbero stati composti insieme.

In una soluzione OO tradizionale, avrei una sorta di MoveByclasse, che contiene la distanza / tempo, e un array di quelli all'interno della mia classe di oggetti di gioco. Ogni fotogramma, scorrerei attraverso tutti MoveBye lo applicherei alla posizione. Se a MoveByha raggiunto la fine, rimuoverlo dall'array.

Con il sistema di entità, sono un po 'confuso su come dovrei replicare questo tipo di comportamento.

Se ce ne fosse solo uno alla volta, invece di essere in grado di combinarli insieme, sarebbe abbastanza semplice (credo) e assomiglierebbe a questo:

PositionComponent contenente x, y

MoveByComponent contenente x, y, time

Entityche ha sia a PositionComponentche aMoveByComponent

MoveBySystemche cerca un'entità con entrambi questi componenti e aggiunge il valore di MoveByComponenta PositionComponent. Quando timeviene raggiunto, rimuove il componente da quell'entità.

Sono un po 'confuso su come farei la stessa cosa con molte mosse.

I miei pensieri iniziali sono che avrei:

PositionComponent, MoveByComponentcome sopra

MoveByCollectionComponentche contiene una matrice di MoveByComponents

MoveByCollectionSystemche cerca un'entità con a PositionComponente a MoveByCollectionComponent, che scorre attraverso la MoveByComponents al suo interno, applicando / rimuovendo secondo necessità.

Immagino che questo sia un problema più generale, avere molti componenti uguali e volere che un sistema corrispondente agisca su ciascuno di essi. Le mie entità contengono i loro componenti all'interno di un hash di tipo componente -> componente, quindi rigorosamente hanno solo 1 componente di un tipo particolare per entità.

  1. È questo il modo giusto di guardarlo?

  2. Un'entità dovrebbe sempre avere un solo componente di un determinato tipo in ogni momento?


1
Sembra un po 'come se la MoveByfunzionalità fosse una specie di velocità? Sembra che tu sia sulla buona strada. Per la tua seconda domanda, ci sono molte diverse implementazioni di sistemi entità / componenti. Quello descritto nella mia risposta che hai collegato avrebbe solo un componente di un determinato tipo.
MichaelHouse

In un certo senso, ma la differenza è che questa velocità è valida solo da una volta all'altra, e molti di essi possono essere combinati insieme contemporaneamente. Penso di aver solo bisogno di rassicurazioni, sono stato OO rigoroso (anale, quasi) per i miei giochi in passato - che anni dopo nello stesso progetto, ha paralizzato la nostra velocità di produzione - e questo è un territorio scarsamente sconosciuto;) . Ottima risposta sull'altro post tra l'altro, ha aiutato a chiarire alcune cose
Sticky

Lo faccio in questo modo: ho PlayerInputComponent e AIInputComponent (o sistemi) che diranno a MobileBehaviorComponent che facendo clic sulla tastiera o su AI pensando che il mobile dovrebbe spostarsi da qualche parte, MobileBehaviorComponent memorizzerà che dovrebbe spostarsi da qualche parte (ha FSM all'interno per le azioni mobili) e alcuni sistemi lo sposteranno. La tua granularità è troppo, con componenti di livello superiore, come Transform, Model, Light, Mob, tutto funziona altrettanto bene. Inoltre non ho mai avuto bisogno di rimuovere i componenti: li penso più come qualcosa che descrive l'oggetto di gioco, quindi non può semplicemente scomparire.
Kikaimaru,

Questo particolare esempio di MoveBy era solo un esempio. La domanda era più su come mescoli le cose insieme in quel modo. Se devo dire specificamente 'sposta di x = 5 e y = 6 in 5 secondi' 'sposta di x = 10 y = 2 in 10 secondi', allo stesso tempo, è come farei?
Appiccicoso

Cosa intendi con "composto insieme"? Ti piace aggiungere velocità? Quindi, se hai composto move x by 10 in 2 secondse move x by -10 in 2 secondsl'entità rimarrebbe perfettamente immobile?
Tom Dalling,

Risposte:


6

Per il tuo scenario, in genere aggiungiamo tre componenti a un oggetto gioco:

  1. TransformComponent (posizione, orientamento, scala)
  2. VelocityComponent (velocità, direzione)
  3. ControllerComponent

Quando gli oggetti di gioco necessitano di un qualche tipo di funzionalità AI come muoversi lungo un percorso come descritto, assegniamo un controller AIC al suo elenco di componenti. I controllori AIC non sono altro che un involucro che fa da passo a un albero comportamentale. L'albero del comportamento è il luogo in cui progettiamo l'effettiva funzionalità che vogliamo che l'oggetto di gioco esegua come:

BehaviorTree* tree(new SequentialNode());
tree->addChild(new MoveToNode(x,y,z));
tree->addChild(new WaitNode(30));
tree->addChild(new MoveToNode(a,b,c));
tree->addChild(new WaitNode(30));
gameObject->addComponent(new AIController(tree));

Il sottosistema AI gestisce AIController e quindi il sottosistema spunta il controller che a sua volta fa un passo all'albero del comportamento. MoveToNode () esamina la posizione / l'orientamento attuale, calcola un vettore di direzione e la velocità in cui si desidera spostarsi in base agli argomenti del costruttore e imposta i valori sul componente velocità. Il sistema di movimento è responsabile della lettura dei componenti del movimento con valori e dell'applicazione della fisica aggiornando di conseguenza la posizione / orientamento.

Il codice precedente sposta semplicemente un oggetto di gioco dalla posizione di spawn a x, y, z nello spazio mondiale, quindi attende almeno 30 secondi, quindi sposta l'oggetto di gioco nella posizione a, b, c e quindi attende altri 30 secondi. Al termine dell'attesa, la sequenza comportamentale è terminata, quindi si ripete dall'inizio.

Ciò consente di definire facilmente qualsiasi funzionalità AI necessaria per tutti i contenuti autonomi nel sottosistema AI con un impatto minimo sul sottosistema Entità. Consente inoltre di mantenere snello l'elenco dei componenti del sistema di entità senza troppa granularità.


1

Un'opzione è quella di aggiungere controller al tuo design. Le entità possiedono i dati per rappresentare la posizione (nel caso del mio motore hanno dati che ricordano anche le posizioni precedenti, quindi posso conoscere il vettore di velocità e se vengono spostati o teletrasportati), ma non sanno nulla di fisica o AI. I controller spostano entità e puoi avere molti controller che interessano la stessa entità o un controller che influenza varie entità.

Ad esempio: crea una classe Controller di base con un metodo run () o se non ti piace il nome chiamalo think (), update () o tick (). Quindi erediti da esso e crei MoveController, NPCController, PlayerInputController (per l'entità giocatore), PhysicController; quindi si implementa il metodo run (). Vorrei inserire MoveByComponent in MoveController e non in Entity.

Questi controller possono essere istanziati da ciascuna entità se detengono dati specifici di un'entità. Possono essere distrutti o reimpostati per il riutilizzo di questi ultimi. Inoltre puoi usare un Controller per muovere un gruppo di entità, ad esempio in una partita RTE, se devi spostare varie unità come gruppo, avere un controller per ogni unità può danneggiare le prestazioni del gioco, quindi puoi semplicemente assegnare tutte le unità su un GroupController o LegionController e lasciarlo spostare le unità come parte di un gruppo organizzato. Quando combatti, se il gioco consente il comportamento di una singola unità, e probabilmente la maggior parte dei giochi lo fanno, dovrai passare a un UnitController ma è meglio farlo solo quando necessario rispetto all'inizio.

Nel mio gioco di sviluppo ho un MoveController che sposta entità seguendo un percorso, esiste un MoveController per ogni NPC e il personaggio del giocatore. Occasionalmente ne viene creato uno per scatole o rock che il giocatore può spingere. Il PhysicController, solo un'istanza, che controllerà le posizioni di tutte le entità assegnate ad essa, se un'entità si scontra con un'altra entità assegnata, viene calcolata la posizione risultante di entrambe (effettivamente fa più di quello ma si ottiene l'idea). NPCController è l'IA, un'istanza per NPC. Controlla la situazione dell'NPC e decide dove spostarsi, quindi spinge il percorso verso un MoveController, che in realtà sposta l'NPC. I controller hanno una priorità, quindi posso determinare in anticipo il loro ordine, PhysicController è l'ultimo ad essere eseguito.

Sostengo i controller ma non è l'unica opzione "corretta". Ad esempio, ricordo un'interfaccia Entity nel motore Cafu che ha il metodo think () nell'entità stessa, l'utente della classe deve ereditare da Entity e implementare think (), ricordo una classe derivata chiamata CompanyBot (che viene fornita con l'esempio gioco) che eseguono un controllo delle collisioni in quel metodo, dato che si chiama "pensa" possiamo supporre che ci sia anche il codice AI. Mentre il motore NeoAxis (l'ultima volta che l'ho esaminato) ha l'IA e la fisica separate dalle entità.

Esiste un modello di controller che ho ascoltato. Forse dovresti cercarlo, e probabilmente non è esattamente quello di cui sto parlando qui, ma sembra anche una buona soluzione.


Questo è fondamentalmente il design OO che abbiamo già in questo momento. Un'entità, con derivati ​​(Personaggio, Mostro) ecc. Ho guidato una squadra di noi che ha lavorato a questo gioco a tempo pieno per quasi 2 anni, e con tutti che hanno cambiato le cose a piacimento, è diventato orribile, orribile codebase - e sta iniziando a impiegare un tempo imbarazzante per far arrivare le nuove funzionalità. L'idea di Entity System sembra essere esattamente quello che sto cercando, quindi mentre la tua risposta non è abbastanza pertinente, dovresti leggere tu stesso i link nella parte superiore della domanda, vedere se possono aiutarti :)
Appiccicoso

@Sticky Devo ammettere che il Node System plus Entity fatto di componenti è un modo intelligente di rappresentare i diversi sistemi necessari rispetto al mio approccio di controller suggerito che è come una versione meno evoluta. Dopo tutto non hai davvero bisogno della mia risposta.
Hatoru Hansou,

Nessun problema. Il modo OO ha i suoi vantaggi, ma le cose diventano brutte, veloci
Sticky
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.