Separa il renderer dal modello di business

4

Ho un piccolo problema di separazione delle responsabilità che spero che qualcuno possa chiarire. Ho un piccolo modello composto da 2 classi: GameBoard e GamePiece, e la relazione ovvia è che una GameBoard può avere diversi GamePoeces.

Nell'applicazione che sto implementando, GameBoard e GamePiece contengono dati relativi al rendering sullo schermo (metodi di aggiornamento / disegno, trame, ecc.) e alla loro logica (numero di quadrati di gioco, tipo di tassello, ecc.). L'aggiornamento / Drawing the GameBoard fa sì che aggiorni / disegni i pezzi. Tuttavia, al fine di mantenere il principio di responsabilità unica, ho deciso di separare la logica dal rendering. Ma ho alcuni problemi per implementarlo adeguatamente.

Sono arrivato a un paio di soluzioni e non sono sicuro quale sia il migliore:

1- Creare classi GameBoardRenderer e GamePieceRenderer (che memorizzere Textures, aggiornare e disegnare), e ogni istanza queste classi di Renderer sarebbero correlate rispettivamente a una GameBoard o GamePiece. Il problema che vedo è che mi costringe a mantenere una doppia relazione tra GameBoard e GamePiece, GameBoardRenderer e GamePieceRenderer, e assicurarmi che sia sempre coerente.

2- Crea GameBoardRenderer e GamePieceRenderer, ma falli ereditare rispettivamente da GameBoard e GamePiece, portando tutti gli elementi di rendering in quelle classi, mantenendo l'associazione alle classi GameBoard e GamePiece. Il problema è che quando chiamo il metodo Update / Draw di GameBoard, non sarò in grado di chiamare il metodo di aggiornamento e disegno di GamePieceRenderer (dato che nessuna relazione sarà disponibile).

Che cosa dovrei fare? C'è una soluzione migliore?

Grazie mille.

    
posta David Jiménez Martínez 08.12.2013 - 13:04
fonte

3 risposte

2

Di conseguenza, sembra un caso in cui i modelli Visitatori sono utili.

All'interno di questo modello, le classi GameBoard e GamePiece contengono tutta la logica relativa al gioco, ma nessuna logica di rendering. Invece, la logica di rendering per entrambe le classi GameBoard e GamePiece si trova in una classe GameRenerer .

Quando è necessario eseguire il rendering della scheda, viene creata un'istanza GameRenderer e passata al metodo GameBoard::Draw . La classe GameBoard indica quindi alla classe GameRenderer di disegnare una tavola (passando se stessa per fornire tutte le informazioni rilevanti) e chiama il metodo Draw di tutti i GamePiece s sulla scheda, passando nuovamente il GameRenderer esempio.

    
risposta data 08.12.2013 - 14:36
fonte
0

Ho avuto quasi lo stesso problema quando ho iniziato a usare XNA. Sto ancora giocando con i modelli per risolverlo, però:)

L'ultima cosa che ho provato riguarda i prestiti da MVVM. In XNA / Monogame land, puoi ereditare da una classe GameComponent e registrare quel componente con il motore di aggiornamento / rendering (potrei avere i termini sbagliati qui, ma l'idea generale è corretta).

Ecco come ho suddiviso le cose:

  • I componenti del gioco registrati con il motore di aggiornamento / rendering sono analoghi alle mie viste MVVM
  • GameComponents non registrati con l'aggiornamento / rendering engire, ma gestiti da GameComponents registrati sono analoghi ai miei MVVM ViewModels
  • Le classi Model effettive vengono iniettate nei miei GameComponents per controllare lo stato della mia GamePiece / GameBoard / etc. Queste classi modello sono completamente inconsapevoli dell'aggiornamento o della meccanica di rendering. Scriverò i miei test unitari contro questi.

Questo tipo di configurazione significa che registro solo una manciata di GameComponents con il motore (le viste). Questi GameComponents sono quindi - in un senso - associati ad altri GameComponents (the viewModels) che sono responsabili per l'attivazione degli aggiornamenti nello stato del sistema e la gestione di qualsiasi logica di controllo di rendering. Infine, questi GameComponents analoghi a ViewModel contengono ciascuno un modello che è responsabile dello stato e della logica di ciò che viene alla fine disegnato sullo schermo. La chiave qui è che il modello è completamente disaccoppiato dal motore di aggiornamento / rendering.

Ho appena iniziato ad applicare questo approccio. Sono sicuro che troverò dei problemi con esso ... ma finora mi ha aiutato a rifattorizzare un vecchio gioco XNA monolitico che ho scritto circa 5 anni fa.

    
risposta data 08.12.2013 - 13:41
fonte
0

Penso che:

  • è responsabilità del ciclo di gioco sapere quali oggetti sono disegnabili / renderizzabili. Dovresti creare una classe base / interfaccia che contenga un qualche tipo di metodo "render" o "draw", possibilmente accettando tutti gli argomenti necessari che il loop di gioco passerà quando lo chiamerai (come l'oggetto contesto GL per il rendering OpenGL, ecc.). / p>

  • ogni oggetto abilitato al rendering dovrebbe contenere il proprio codice di disegno, come implementazione del metodo di "rendering" dell'interfaccia / classe base che dovrebbero estendere. Puoi perfezionare ulteriormente questo estraendo codice di rendering comune alla classe base (se lo hai scelto tramite un'interfaccia di base) o al loop di gioco stesso, cioè per un gioco 2D basato su sprite, il ciclo di gioco potrebbe contenere tutti gli oggetti sprite reali e gli oggetti renderizzabili informano solo il ciclo di gioco che è lo sprite, e dove dovrebbero essere posizionati, ed è il ciclo di gioco stesso che esegue il codice di disegno dello sprite.

risposta data 08.12.2013 - 13:44
fonte

Leggi altre domande sui tag