Separazione della fisica e della logica di gioco dal codice dell'interfaccia utente


12

Sto lavorando a un semplice puzzle game basato su blocchi.

Il gioco consiste praticamente nello spostamento di blocchi nell'area di gioco, quindi è una banale simulazione fisica. La mia implementazione, tuttavia, è secondo me tutt'altro che ideale e mi chiedo se puoi darmi qualche suggerimento su come farlo meglio.

Ho diviso il codice in due aree: logica di gioco e interfaccia utente, come ho fatto con molti giochi puzzle:

  • La logica del gioco è responsabile delle regole generali del gioco (ad es. Il sistema formale di regole negli scacchi)
  • L'interfaccia utente visualizza l'area di gioco e i pezzi (ad es. Scacchiera e pezzi) ed è responsabile delle animazioni (ad es. Movimento animato dei pezzi degli scacchi)

La logica di gioco rappresenta lo stato del gioco come una griglia logica, in cui ogni unità è la larghezza / altezza di una cella sulla griglia. Quindi, per una griglia di larghezza 6, puoi spostare un blocco di larghezza 2 quattro volte fino a quando non si scontra con il bordo.

L'interfaccia utente prende questa griglia e la disegna convertendo le dimensioni logiche in dimensioni dei pixel (ovvero, la moltiplica per una costante). Tuttavia, poiché il gioco non ha praticamente alcuna logica di gioco, il mio livello di logica di gioco [1] non ha molto da fare se non il rilevamento delle collisioni. Ecco come funziona:

  1. Il giocatore inizia a trascinare un pezzo
  2. L'interfaccia utente richiede la logica di gioco per l'area di movimento legale di quel pezzo e consente al giocatore di trascinarlo all'interno di quell'area
  3. Il giocatore lascia andare un pezzo
  4. L'interfaccia utente aggancia il pezzo alla griglia (in modo che sia in una posizione logica valida)
  5. L'interfaccia utente dice alla logica di gioco la nuova posizione logica (tramite metodi mutatori, che preferirei evitare)

Non ne sono abbastanza soddisfatto:

  • Sto scrivendo unit test per il mio livello logico di gioco, ma non per l'interfaccia utente, e ho scoperto che tutto il codice complicato si trova nell'interfaccia utente: impedire al pezzo di scontrarsi con altri o il confine e farlo scattare sulla griglia.
  • Non mi piace il fatto che l'interfaccia utente descriva la logica del gioco sul nuovo stato, preferirei che chiamasse un movePieceLeft()metodo o qualcosa del genere, come nei miei altri giochi, ma non sono andato lontano con questo approccio, perché la logica del gioco non sa nulla del trascinamento e dello snap possibile nell'interfaccia utente.

Penso che la cosa migliore da fare sarebbe liberarmi del mio livello logico di gioco e implementare invece un livello fisico. Ho alcune domande al riguardo:

  1. È comune un tale livello di fisica o è più tipico che il livello di logica di gioco lo faccia?
  2. Lo snap alla griglia e il trascinamento del pezzo di codice appartengono all'interfaccia utente o al livello fisico?
  3. Un tale livello fisico funzionerebbe in genere con dimensioni di pixel o con una sorta di unità logica, come il mio livello di logica di gioco?
  4. Ho visto una volta il rilevamento delle collisioni basato sugli eventi nella base di codice di un gioco, ovvero il giocatore avrebbe semplicemente trascinato il pezzo, l'interfaccia utente l'avrebbe reso obbediente e l'avrebbe notificato al sistema fisico e il sistema fisico avrebbe chiamato un metodo onCollision () sul pezzo una volta rilevata una collisione. Cosa è più comune? Questo approccio o chiedere prima l'area di movimento legale?

[1] layer probabilmente non è la parola giusta per quello che intendo, ma il sottosistema sembra esagerato e la classe è sbagliata, perché ogni layer può essere composto da più classi.


La mia risposta mi ha aiutato, ho bisogno di ulteriori informazioni?
Will Marcouiller,

Per favore, vota e accetta la risposta se questo ha aiutato o racconta i tuoi problemi nell'implementazione di tale architettura o qualcosa del genere, ma tienici informati della tua situazione in modo che possiamo essere di migliore assistenza. =)
Will Marcouiller l'

Risposte:


3

Proverò a tentare di rispondere a questa domanda poiché posso capire cosa stai chiedendo, anche se non ho molta esperienza di sviluppo del gioco poiché sto ancora imparando.

A mio avviso, devi separare il codice GUI dalla logica di gioco e dagli oggetti del dominio, ovvero i pezzi del puzzle. Questi sono in effetti tre livelli separati - e sì, layerè un termine appropriato secondo me. Viene spesso usato per spiegare i concetti di separazione di ciascun livello degli oggetti di un sistema in sottosistemi indipendenti l'uno dall'altro.

Per quanto riguarda la programmazione orientata agli oggetti, ogni oggetto deve essere una classe. Quindi, ogni pezzo del tuo puzzle deve essere costituito da una classe per sé, e quindi dal tabellone. Il tabellone di gioco dovrebbe contenere X pezzi di puzzle a seconda delle sue dimensioni e capacità di movimento che vuoi dare al giocatore.

Quindi, ecco i miei pensieri sull'argomento - Spero che possa aiutare:

  1. Il livello della GUI: questo livello deve contenere metodi solo per visualizzare i pezzi sul tabellone per consentire l'interazione tra il gioco stesso e il giocatore;
  2. Il livello del controller di gioco: è responsabile degli input del giocatore. Questo è lo strato che dovrebbe dire a un pezzo di muoversi nelle diverse direzioni e chiedere al tabellone se ci saranno collisioni durante il movimento e così via;
  3. Il livello aziendale: questo livello deve contenere tutte le classi aziendali, ovvero i pezzi del gioco e l'oggetto del tabellone che contiene i pezzi del puzzle.

In questa architettura, il livello della GUI mostrerebbe al giocatore lo stato del gioco, la posizione di ciascun pezzo di puzzle. Il livello della GUI sarebbe quindi responsabile per ottenere gli input del giocatore e passarlo a un livello del controller di gioco sottostante, che sarebbe quindi responsabile del rilevamento delle collisioni. Se non ce n'è, allora il pezzo può essere ordinato di muoversi in quella direzione di input. Per fare ciò, dovresti semplicemente chiamare questo pezzo MoveLeft,MoveRight, ecc. metodi per spostare il pezzo. Potresti anche far sapere al tabellone quale pezzo vuoi muovere, e poi ordina da solo il movimento del pezzo, e poi il pezzo si sposta nella direzione richiesta. Questa architettura semplifica il test di ogni parte di codice nei diversi livelli e consente quindi di testare unità, test di integrazione e test funzionali.

So che questo potrebbe sembrare un po 'confuso alla vista, e grazie a Dio se non lo è! Se hai bisogno di ulteriori dettagli e aiuto, non esitare a chiedere, sarò felice di aiutarti il ​​meglio possibile anche se sono un principiante nello sviluppo del gioco.

Grazie per aver letto! =)


2
Che suona molto simile a Model View Controller.
10

Ad essere onesti, qualsiasi descrizione dell'interfaccia di sottrazione dall'implementazione sottostante suonerà come Model View Controller. Questo perché la terminologia e le tecniche utilizzate sono le stesse (astrazione dai dettagli di implementazione e separazione dell'interfaccia utente dall'implementazione). Ma presuppone un ambiente molto semplice. Ci sono più livelli qui e ci sono controller in ogni livello. Separare la vista dal modello non è abbastanza qui, devi anche separare il controllo dell'interazione dell'utente dal controllo del gioco.
MrCranky,

Mi chiedo che cosa sia così complesso qui, dal momento che stiamo spostando pezzi di un puzzle su un tabellone delimitato. I controlli sono ottenuti dalla GUI, che in effetti è un buon modo e passano a un livello di astrazione, cioè al controller di gioco. Il controller di gioco controlla le collisioni durante il movimento, quindi dice al pezzo di muoversi se non viene rilevata alcuna collisione. Il pezzo di puzzle si sposta quindi correttamente nella direzione richiesta e rivela la sua nuova posizione attraverso la sua Positionfunzione getter di proprietà, in modo che il controller di gioco ora richieda alla GUI di visualizzare questo pezzo spostato in quella nuova posizione.
Will Marcouiller,

eh, ho scritto un blog su "MVC" nello sviluppo del gioco qualche mese fa. Sì, è un buon concetto di gateway per coloro che non sono iniziati con lo sviluppo del gioco: codecube.net/2010/08/xna-for-the-everyday-developer
Joel Martinez

1
Ci scusiamo per il ritardo, purtroppo sono stato distratto dal progetto per un po '. Mi piace molto l'approccio del controller, lo adotterò!
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.