Uso di Observer Pattern per agire selettivamente sugli eventi

3

Attualmente sto architettando un piccolo dungeon crawl in stile RPG (in Unity), e sono un po 'bloccato su come aggiornare vari oggetti quando le cose cambiano, mentre non non sono in aggiornamento oggetti. Per questa domanda, userò il mio attuale progetto come esempio, ma la domanda stessa può essere applicata a qualsiasi situazione in cui più tipi diversi di Osservatori guardano ciascuno un singolo Soggetto.

Il design a cui sono attualmente orientato per le interazioni tra oggetti nel mio gioco implementa il Pattern di progettazione degli osservatori , dove ho un singolo Soggetto (chiamiamolo GameEventManager ), e ogni oggetto interattivo è un Osservatore di questo Soggetto (questo include cose come giocatore, nemici, oggetti interattivi sul terreno, ecc.).

Quando si verifica un evento (diciamo che un utente colpisce la barra spaziatrice per sparare a una freccia contro un nemico selezionato), il piano corrente che ho per la vita dell'azione può essere suddiviso in passaggi:

  1. Il sistema di input (non un Observer, ma contiene un riferimento al Subject), invia un Event a GameEventManager per la trasmissione nel posto giusto. Non ho ancora progettato la classe Event , per semplificare il problema e nel caso sia necessario riprogettare le cose.
  2. Il GameEventManager trasmette Event a Player con le informazioni pertinenti.
  3. Il Player , comprendendo un Event è venuto nel dire di sparare a una freccia, fa alcuni calcoli interni (come sottrarre dalla munizione totale che ha, magari eseguendo visivamente una sorta di animazione) ed emette un nuovo Event al GameEventManager che dice che Player ha sparato una freccia su "enemy2".
  4. Il GameEventManager trasmette Event a "enemy2".
  5. "Enemy2" riceve Event , si rende conto che è stato sparato e muore in qualche modo.

Quindi la domanda è: come fa GameEventManager a sapere dove passare intorno a tutti questi diversi tipi di eventi (ad esempio, l'evento movimento deve andare solo al giocatore, e la freccia deve andare solo a "nemico2"). Inoltre, una volta che l'evento raggiunge i suoi obiettivi designati, in che modo questi osservatori sanno cosa fare con l'evento (ad esempio, come fa il giocatore a sapere di tirare una freccia e non subire danni?).

Ho fatto qualche ricerca sugli esempi di Observer, ma la maggior parte sono oscenamente complessi e astratti, o sono semplicemente semplici "Il soggetto emette un evento per TUTTI gli osservatori, e TUTTI gli osservatori interagiscono con OGNI evento che ottengono", che non è quello che ho voglio a tutti (una freccia sparata a "enemy2" non dovrebbe influenzare "enemy1" in alcun modo).

Scusa se questo è un po 'astratto, mi piace avere un piano prima di iniziare a creare il codice.

Inoltre, come parte a parte, sono pienamente consapevole che in Unity posso avere un GameObject direttamente in interazione con un altro, ma lo scopo di questo intero progetto è di rendere tutto il più possibile polimorfo e riutilizzabile, e la maggior parte dei tutorial di Unity semplicemente non toccare affatto l'estensibilità.

    
posta Ben Schwabe 31.01.2018 - 21:04
fonte

4 risposte

2

Per me questo forse non è il miglior caso d'uso per il modello di osservatore, dal momento che richiederebbe al soggetto di richiedere un carico di conoscenza di chi lo sta osservando e quando un particolare osservatore dovrebbe essere informato. Solo a pensarci e su come separare l'osservatore che viene notificato in base a quali condizioni avessi il mio modo di voler mettere la maggior parte dell'intera logica di gioco nell'oggetto o qualcosa che tirava le sue stringhe e dicendole esattamente a chi notificarlo.

L'idea principale del modello di osservatore è disaccoppiare e astrarre il soggetto dagli osservatori, in modo che tu possa fare cose come attaccare chiunque / qualsiasi cosa a osservare il soggetto mentre passa attraverso i cambiamenti di stato in modo che chiunque / qualunque cosa possa sapere a proposito. Il soggetto non deve sapere molto su chi lo sta osservando, e sicuramente non ha alcuna informazione concreta su chi lo sta osservando. È una mentalità trasmessa come, "Per chi sta ascoltando là fuori, è successo qualcosa", non, "il giocatore ha sparato una freccia così avrei dovuto notificare questo nemico esatto nella sua linea di vista su come essere colpito". Questo è il modo in cui TMI è a conoscenza dei suoi osservatori.

A volte un'implementazione di un osservatore potrebbe distinguere i soggetti da un concetto astratto che non richiede molta conoscenza su di loro, come un osservatore group : "notifica questo gruppo di osservatori". Ma è ancora molto senza meta . Il tipo inimmaginabile di trasmissione agli osservatori che si iscrivono dovrebbe essere una specie di modello di pensiero quando si considera se utilizzare o meno il modello di osservatore, e ciò che si è tentati di fare qui è lontano dall'essere privo di scopo (ha lo scopo di una freccia sapientemente tirata portando a un colpo alla testa - scusa, scherzo zoppo).

Invece penso che tutto ciò di cui hai bisogno siano davvero astrazioni per concetti come giocatori e nemici (o forse una "Creatura" o qualcosa che li unifica - modi infiniti per andare qui). E potresti aver bisogno di una o più cose per elaborare la tua logica di gioco. Ad esempio, l'evento di input per la barra spaziatrice potrebbe far scattare al giocatore una freccia che fa tutte le cose che hai elencato come sottrarre il conteggio delle munizioni. Quindi, con il proiettile di freccia creato (che potrebbe anche essere astratto come un "proiettile" anziché, in particolare, "freccia"), potresti avere qualcosa da invocare nel ciclo di gioco come un sistema fisico che sposta / elabora tutti i proiettili nel gioco. Quando collide con un'entità come una "creatura" o qualcosa di simile (qualcosa di astratto in modo da non dover distinguere come un orco da un folletto), potresti chiamare una funzione astratta che la fa colpire dal proiettile .

Questo è un esempio piuttosto semplicistico, ma qualcosa in questo senso, tuttavia ciò viene fatto semplicemente astratizzando le tue entità di gioco piuttosto che usando il modello di osservatore.

    
risposta data 31.01.2018 - 23:22
fonte
2

Dai uno sguardo al modello di catena di responsabilità e forse puoi concatenare entrambi i modelli.

    
risposta data 31.01.2018 - 21:53
fonte
2

Un'altra possibilità è provare completamente un approccio diverso, come "Functional Reactive Programming" (FRP). Afferma di risolvere diversi inconvenienti del modello di osservatore. Dopo aver tentato un programma javafx con gli osservatori e attualmente facendo un'applicazione basata su FRP, sono quasi d'accordo. Ci sono molte librerie open source: Sodium FRP, Reactive Banana, Elm, UniRx per Unity; e molto se informazioni, ad esempio link o capitoli introduttivi gratuiti di Manning.

    
risposta data 01.02.2018 - 02:15
fonte
1

Per il tuo scopo potresti considerare uno schema ben noto per la programmazione di eventi (normalmente per scopi IO), schema del reattore .

L'idea è di scindere il codice specifico dell'applicazione dall'implementazione del reattore.

Sotto questo modello definirai una serie di funzioni (handler) che verranno chiamate quando si verifica un evento. È un modo ordinato e organizzato per gestire la programmazione orientata agli eventi.

    
risposta data 02.02.2018 - 06:22
fonte

Leggi altre domande sui tag