Potrei impazzire con i gestori di eventi? Sto andando nella "direzione sbagliata" con il mio design?


12

Immagino di aver deciso che mi piacciono molto i gestori di eventi. Potrei soffrire un po 'di paralisi dell'analisi, ma sono preoccupato di rendere il mio progetto ingombrante o incorrere in qualche altra conseguenza imprevista delle mie decisioni di progettazione.

Il mio motore di gioco attualmente esegue il rendering di base basato su sprite con una telecamera panoramica panoramica. Il mio design è un po 'così:

SceneHandler

Contiene un elenco di classi che implementano l'interfaccia SceneListener (attualmente solo Sprites). Chiama render () una volta per tick e invia onCameraUpdate (); messaggi a SceneListeners.

InputHandler

Esegue il polling dell'input una volta per tick e invia un semplice messaggio "onKeyPressed" a InputListeners. Ho un Camera InputListener che contiene un'istanza di SceneHandler e attiva updateCamera (); eventi basati su ciò che è l'input.

AgentHandler

Chiama le azioni predefinite su qualsiasi agente (AI) una volta per tick e controllerà uno stack per eventuali nuovi eventi registrati, inviandoli a specifici agenti secondo necessità.

Quindi ho oggetti sprite di base che possono muoversi in una scena e usare comportamenti di guida rudimentali per viaggiare. Sono arrivato al rilevamento delle collisioni, ed è qui che non sono sicuro che la direzione in cui sta andando il mio progetto sia buona. È buona norma avere molti piccoli gestori di eventi? Immagino che dovrei implementare una specie di CollisionHandler.

Starei meglio con un EntityHandler più consolidato che gestisce l'intelligenza artificiale, gli aggiornamenti delle collisioni e altre interazioni di entità in una classe? O starò bene solo implementando molti diversi sottosistemi di gestione degli eventi che si scambiano messaggi in base al tipo di evento? Devo scrivere un EntityHandler che è semplicemente responsabile del coordinamento di tutti questi gestori di eventi secondari?

Mi rendo conto in alcuni casi, come il mio InputHandler e SceneHandler, che sono tipi di eventi molto specifici. Una grande parte del mio codice di gioco non si preoccuperà dell'input e una grande parte non si preoccuperà degli aggiornamenti che avvengono esclusivamente nel rendering della scena. Quindi ritengo che il mio isolamento di questi sistemi sia giustificato. Tuttavia, sto ponendo questa domanda in particolare riguardo agli eventi di tipo logico di gioco.

Risposte:


21

La progettazione basata sugli eventi prevede principalmente l'implementazione del modello di progettazione di Reactor .

Prima di iniziare a progettare componenti, è necessario dare un'occhiata ai limiti di tale modello (è possibile trovare molte informazioni al riguardo).

Il primo e principale dei problemi è che i gestori devono tornare rapidamente , come sanno tutti quelli che hanno lavorato serius su framework basati su GUI e su applicazioni javascript.

Quando sviluppi ogni applicazione con una discreta complessità , prima o poi dovrai affrontare un gestore che fa un lavoro complesso che richiede tempo .

In questi casi è possibile distinguere due situazioni (non necessariamente reciprocamente esclusive):

Complesso evento-correlati responsabilità e complessi da eventi non correlati responsabilità.

Complesse responsabilità legate all'evento:

Nel primo caso sono state unite troppe responsabilità in un unico gestore dei componenti : vengono eseguite troppe azioni in risposta a un evento o ad esempio sono in esecuzione sincronizzazioni.

In questo caso, la soluzione è quella di dividere il gestore in gestori diversi (in oggetti diversi se necessario) e lasciare che un handle esegua eventi invece di chiamare direttamente il codice di gestione. Ciò consentirà di consentire la gestione di un evento con priorità più elevata in quanto il gestore principale è tornato dopo aver aggiunto gli eventi alla coda degli eventi.

Un'altra soluzione è consentire a un'entità esterna di generare eventi e consentire agli altri di iscriversi se interessati (l'evento di temporizzazione è l'esempio più banale che puoi generalizzare).

Responsabilità complesse non correlate ad eventi:

Il secondo caso si verifica in presenza di una complessità intrinseca nell'azione da eseguire dopo un evento: ad esempio, è necessario calcolare un numero di fibonacci dopo un evento.

Qui il modello di Reactor sostanzialmente fallisce , vale la pena spartire l'algoritmo di generazione dei fibonacci in piccoli pezzi che sparano eventi al termine per innescare il passaggio successivo.

Qui la soluzione è quella di mescolare un progetto filettato al reattore , la buona notizia è che se la complessità è intrinseca (quindi stai leggendo la sezione giusta) è molto probabile che sia possibile avviare un thread indipendente che funzioni e che deve sapere poco o nulla del resto dei componenti relativi al reattore.

Per gestire questo tipo di situazioni, ho trovato utile adottare una coda di lavoro su un pool di thread flessibile .

Quando un gestore deve avviare un'azione lunga, incapsula quell'azione in un'unità di lavoro da inserire nella coda lavori. Questa azione incapsulata deve avere un mezzo per innescare eventi nel thread del reattore. Il gestore code lavori può essere eseguito nel proprio thread o nel thread del reattore e reagire all'evento "newJob".

Il gestore code lavori procede come segue:

  • alloca un'unità di lavoro a un thread dal pool di thread flessibile usando il suo algoritmo shedule se il pool è in grado di fornire un thread (esiste un thread gratuito o è consentita la creazione di un nuovo thread)

  • ascolta il pool stesso per vedere se un'unità di lavoro è terminata, quindi un thread può essere recuperato per eseguire un'altra unità in sospeso, se presente.

Utilizzando il meccanismo di attivazione degli eventi, un'unità di lavoro può attivare eventi per notificare il completamento, lo stato di aggiornamento, gli avvisi, gli errori o ogni volta che è necessario. Il pool di thread flessibile garantisce un buon utilizzo delle risorse evitando al contempo il dead thread di bloccare l'intero sistema; la coda dei lavori consente di scegliere quale tipo di priorità assegnare a diversi tipi di azioni poiché si sa che richiederanno una quantità consistente di risorse computazionali.


3
+1 per essere molto accurato. Alcuni link per il curioso lettore sarebbero fantastici.
sam hocevar,

1

Nella maggior parte dei casi l'utilizzo di eventi rispetto ad altre opzioni può spesso migliorare la velocità e il decentramento. Penso che se puoi usare molti eventi, dovresti andare per questo.

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.