Cosa devo considerare quando si progetta un sistema di Event Manager?


9

Mi sono dilettato con i fondamenti di un motore di gioco Java e ho raggiunto il punto in cui sono pronto per aggiungere un sistema Event Manager.

So, in teoria , cosa dovrebbe fare un Event Manager: consentire agli oggetti di "registrarsi" per determinati eventi e ogni volta che il Manager degli eventi viene avvisato di un evento, trasmetterlo agli ascoltatori "registrati". Ciò su cui sono sconcertato è come iniziare a implementarlo.

Non sono stato in grado di trovare nulla, online, sull'implementazione di un sistema di eventi da zero, quindi sto cercando input su quali sono le migliori pratiche in questo caso - cosa dovrei e non dovrei fare.

Ad esempio, è davvero necessario che ciascuno dei miei oggetti di gioco abbia un EventManagercampo? Poiché tutti i miei oggetti di gioco ereditano da una singola classe genitore astratta, penso che dovrei essere in grado di utilizzare un riferimento statico in modo che ci sia solo un'istanza di Event Manager, condivisa tra tutti gli oggetti di gioco. Faccio qualcosa di simile, con l'applet, che uso già per il rendering di ogni oggetto.

Suppongo che dovrei mantenere una raccolta di qualche tipo per ogni possibile evento sottoscritto - aggiungere e rimuovere oggetti di gioco dall'elenco, se necessario. Penso che dovrebbe essere possibile creare una coda di eventi che devono essere trasmessi, nel qual caso potrei semplicemente aggiungere "EventManager.Update ()" al loop di gioco principale e fare in modo che il Update()metodo trasmetta gli eventi che si sono verificati alla fine di ogni fotogramma. Infine, ogni oggetto avrebbe un HandleEvent(Event e)metodo, che potrebbe quindi analizzare e rispondere in modo appropriato.


Questo suona come la direzione appropriata verso l'implementazione di un tale sistema, o sto andando fuori strada e / o mancando qualcosa di abbastanza ovvio?


2
gamedev.stackexchange.com/questions/7718/… Questo è un Q / AI fornito in precedenza che può aiutarti a iniziare.
James,

@James Ah - sembra un buon collegamento. Grazie! Penso di essermi perso prima.
Raven Dreamer,

4
Alcuni suggerimenti aggiuntivi: decidere se alcuni eventi devono effettivamente avere effetto immediatamente anziché alla fine del frame, specialmente se un gestore eventi attiva eventi aggiuntivi; pensa cosa succede quando ottieni loop di eventi; se vai con una coda, forse avrai bisogno di un sistema prioritario o di un modo per bypassare la coda.
sam hocevar,

Risposte:


6

Questo può essere semplice come vuoi.

for each object in the subscriber list:
    object.notify(this event) // (or 'HandleEvent' if you prefer)

Non cercare di capire cosa dovrebbe fare un gestore di eventi, cerca di capire cosa ti serve per farlo. Il resto dovrebbe seguire da lì, o almeno, dovrebbe suggerire alcune domande più specifiche.


3
+1 per "Non cercare di capire cosa dovrebbe fare una X '- cerca di capire cosa ti serve per farlo". In effetti, non aggiungere affatto un gestore eventi fino a quando non hai bisogno di un modo disaccoppiato ma centralizzato per chiamare le funzioni.

@JoeWreschnig Oh dio sì =) "capire cosa ti serve per fare" Questo è uno dei 3 consigli principali che qualsiasi sviluppatore dovrebbe prendere a cuore.
Patrick Hughes,

All'inizio volevo essere in disaccordo con la tua seconda frase sul non aggiungere un gestore eventi perché la maggior parte dei giochi può beneficiare di un modo disaccoppiato ma centralizzato per chiamare le funzioni, ma poi ho pensato a quanti piccoli giochi che ho realizzato che non hanno fatto avere qualsiasi tipo di gestore di eventi. quindi, sì
scherzando il

3

I tre metodi essenziali richiesti da un sistema di eventi sono un metodo addListener (), un metodo removeListener () e un metodo per dispatchEvent (). Cioè, un metodo utilizzato dagli oggetti per registrare un evento, un metodo utilizzato dagli oggetti per annullare la registrazione e un metodo per trasmettere effettivamente un evento a tutti i listener. Tutto il resto è sugo.

Come noterai, avrai sicuramente bisogno di una sorta di struttura di dati per tenere traccia degli ascoltatori registrati. L'approccio più semplice sarebbe un array associativo (dizionario o un oggetto in JavaScript) che associ un vettore (o semplicemente un array a seconda della lingua) a un evento. Quel vettore è un elenco di tutti gli ascoltatori registrati; aggiungi listener all'elenco o rimuovili nei metodi add / removeListener ().

Per trasmettere un evento in dispatchEvent () può essere semplice come passare in rassegna il vettore. Puoi aggiungere più complessità al dispacciamento ordinando la priorità degli eventi o altro, ma non preoccuparti fino a quando non ne avrai bisogno. In molti casi non ne avrai bisogno.

DispatchEvent () presenta una piccola sfumatura quando si considerano quali dati passare insieme all'evento. Al livello più elementare potresti non trasmettere alcun dato aggiuntivo; tutto ciò che l'ascoltatore deve sapere è che si è verificato un evento. Tuttavia, la maggior parte degli eventi ha dati aggiuntivi che li accompagnano (ad es. Dove si è verificato l'evento) per far sì che dispatchEvent () accetti e passi alcuni parametri.

Ad esempio, è davvero necessario che ciascuno dei miei GameObjects abbia un campo "EventManagner"? Poiché tutti i miei GameObjects ereditano da una singola classe genitore astratta, penso che dovrei essere in grado di utilizzare un riferimento statico in modo che ci sia solo un'istanza di EventManager, condivisa tra tutti gli oggetti di gioco.

Esistono molti modi per fornire a tutti i tuoi oggetti di gioco un riferimento alla classe EventManager. Un riferimento statico è certamente un modo; un altro è con un Singleton. Entrambi questi approcci sono piuttosto poco flessibili, quindi la maggior parte delle persone qui intorno raccomandano un localizzatore di servizio o un'iniezione di dipendenza. Ho fatto l'iniezione di dipendenza; ciò significa un campo EventManager separato per ogni oggetto, che è ciò che sembra voler evitare, ma non sono sicuro del perché sia ​​un problema. Non è che ci sia un sacco di sovraccarico nel memorizzare un sacco di puntatori.


sì, la prima volta che ho capito e implementato l'iniezione di dipendenza era per un oggetto EventDispatcher. Una volta che l'ho messo sotto la cintura, ho avuto il prurito di riformattare molte cose con quel modello.
jhocking

0

NEGAZIONE

Non sono un programmatore Java ma ho scritto un articolo che spiega come creare un sistema di eventi in C89, uno dei linguaggi più semplici (IMHO), dai un'occhiata

https://prdeving.wordpress.com/2017/04/03/event-driven-programming-with-c-89/

Le basi della gestione degli eventi sono piuttosto semplici.

  • registra un evento con un callback
  • evento scatenante
  • scorrere gli ascoltatori per vedere se c'è una corrispondenza
  • gestore del fuoco se trovato
  • ripetere

Sapendo questo (ma non sapendo come implementarlo in Java), è facile capire che sono necessari alcuni gestori (funzioni per gestire gli eventi) e aggiungerli a un array (con puntatori, in C) accoppiato con un nome di evento. Una volta attivato un evento, memorizzi il nome dell'evento attivato e i relativi argomenti in uno stack, questo viene chiamato pool di eventi.

Quindi hai un digest degli eventi (un semplice ciclo), che apre il primo evento in quello stack, cerca di trovare un gestore per esso, e se ce n'è uno, lo esegue con i parametri.

Naturalmente, questo digest degli eventi può essere attivato ogni volta che vuoi, ad esempio una volta per frame dopo aver chiamato la tua Update()funzione.


-2

Per il campo EventManager, utilizzare una variabile statica. Anche un Singleton per EventManager sarebbe un'ottima idea.

Il tuo approccio suona bene, ma non dimenticare di renderlo thread-safe.

È utile eseguire IO-Events prima o dopo i "GameEvent", quindi in un frame ogni "GameEvent" gestisce gli stessi dati.


"Thread-save"? Hmmm
U62,

-1 per il suggerimento singleton del tutto inutile e ingiustificato.
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.