Qual è l'approccio corretto alla progettazione di classi orientato agli oggetti nello sviluppo di giochi?


31

Sono nel mezzo dello sviluppo di un gioco basato su sprite 2D per Windows 7 Phone, usando XNA. La formazione e le esercitazioni disponibili sono piuttosto utili, ma il problema che devo affrontare è che ognuno di loro si avvicina in modo diverso al proprio design di classe e il codice non è particolarmente ben ponderato. Di conseguenza, è stato difficile per me comprendere bene quali responsabilità dovrei affidare a una determinata classe.

Ad esempio, potrei avere una classe sprite di base BaseSpriteche sa come disegnare se stessa, controllare le collisioni, ecc. Potrei quindi avere una AnimatedSpriteclasse che saprebbe navigare nel suo foglio sprite, una ExplodingSpriteclasse e così via. Questa tecnica è dimostrata nell'esempio di Space Invaders nei materiali Jumpstart Session 2 di Windows 7 .

In alternativa, potrei invece posizionare la maggior parte del rendering e della gestione della responsabilità del gioco in una GameScreenclasse; quella classe e le sue classi derivate si comportano più come moduli o pagine Web in termini di responsabilità. Le classi Sprite sono contenitori più semplici con molta meno logica.

Questa è la tecnica utilizzata nel gioco Alien Sprite di Windows 7 Phone Training Kit e in altri esempi di manager dello stato di gioco.

Qual è l'approccio corretto alla progettazione di classi orientato agli oggetti nello sviluppo di giochi?

Risposte:


26

Uso un approccio più orientato ai componenti, in cui avresti una classe Sprite che ha componenti come Visual, Collision, Animation, Input, ecc. Con questo approccio non finisco per avere una gerarchia di classi profonda (che è buona) .

Per alcune informazioni sulla progettazione orientata ai componenti, vedere qui .


2
+1 l'articolo a cui ti sei collegato è stato fantastico. Ero così concentrato sul puro design OO, ho completamente trascurato il modello di componente / decoratore.
Josh E,

1
Il modello componente non è davvero "meno puro" OO :)
Srekel,

2
Infatti. OO è spesso equiparato all'eredità. Ma l'eredità è solo uno strumento che OO offre, la composizione è un altro.
Haffax,

Solo così. Avrei dovuto essere più preciso nella mia formulazione; quello che volevo dire è che mi sono concentrato molto sul lato ereditario di OO invece di pensare ai modelli di progettazione OO / altri aspetti OO che potrebbero aiutarmi a raggiungere ciò che volevo.
Josh E,

Mentre un approccio basato sulla comoposizione è abbastanza ovvio e usato frequentemente, devo ancora vedere una soluzione per mantenere portatile il componente di rendering. Qualsiasi suggerimento sarebbe fantastico.
Andreas,

11

Nei giochi, il modello Component è una soluzione comune.


questo è un altro articolo fantastico - vale la pena leggere.
Josh E

1
Ottimo, fantastico, ottimo articolo!
Kevin,

6

I Principi SOLIDI si applicano tanto alla progettazione del codice di gioco che a qualsiasi altra professione, almeno fino a quando non arriverai a ottimizzare, quindi utilizzerei il tuo primo esempio come punto di partenza.

Vorrei andare oltre, perché BaseSprite sembra che abbia la tendenza a diventare una megaclasse. Il principio di responsabilità singola impone che la collisione, il rendering e la navigazione debbano essere tutti gestiti da componenti, piuttosto che singole voci in una gerarchia di classi. La classe di detenzione di tutti questi componenti dovrebbe solo gestire la spinta delle posizioni mondiali tra di loro.


5

Negli ultimi progetti mi sono orientato maggiormente verso un approccio in stile MVC.

All'inizio non eravamo sicuri che avrebbe funzionato, ma ha funzionato perfettamente.

Modello

Gli oggetti dati. Solo i dati puri. Nessun comportamento, nessun rendering.

Gestore dati. Semplicemente gestendo "elenchi" di oggetti dati. (Può anche essere migliorato per supportare il pooling.)

vista

Li chiamiamo renderer. Per ogni tipo di oggetto dati esiste un renderer. Quando viene chiamato con un gestore, eseguirà il rendering di tutti gli oggetti in quell'elenco.

controllore

Come i renderer, ma controlla il comportamento.

Esempio

ShipManager ha un elenco di navi. ShipController sposta le navi in ​​base al loro stato. Lo ShipRenderer renderà le Navi in ​​base al loro stato.

Perché

In questo modo la vista e la logica sono rigorosamente separate. Rende il porting su una nuova piattaforma abbastanza semplice. Anche l'ottimizzazione del layout dei dati all'interno di XxxManager è molto semplice.


2
Ti sto votando perché sono stufo di vedere più o meno nudo "Usa MVC" come risposta accettabile. Se stai sviluppando su qualsiasi piattaforma moderna, stai già utilizzando MVC a più livelli. Non è una risposta specifica e non è una buona risposta, perché in realtà non dice alle persone come strutturare le classi, che è specifica per compito / dominio. Finisci con un sacco di persone che scrivono "class Modal ...; class View ...; class Controller ..." MVC è un modello con un buon potere esplicativo di alto livello quando si parla di codice esistente. Non è un modello con un buon potere di pianificazione.

4
@Joe ho capito bene, ma trovo la tua scelta di parole superflua. Ho appena spiegato come lo facciamo. Poiché la scelta dell'architettura di livello superiore rende obsoleta la scelta del progetto di livello inferiore, la considero una risposta valida.
Andreas,
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.