Domande sull'architettura dei giochi con XNA


12

Quindi sono finalmente riuscito a giocare con XNA e ho giocato con un gioco 2D (ho un sacco di risorse artistiche da un amico che lo ha sviluppato su iOS)

Molte cose sembrano essere facili da fare ed escono fuori dagli schemi, ma sono rimasto perplesso per un sacco di cose poiché la maggior parte della letteratura (i libri che ho comprato per esempio) non presta troppa attenzione al 2D.

Gradirei davvero qualsiasi chiarimento o suggerimento di ulteriori informazioni sulle seguenti questin:

  1. Qual è lo scopo di un servizio di gioco? Comprendo l'intero linguaggio della registrazione di un oggetto come servizio in modo tale che qualsiasi altro GameComponent possa afferrarlo, tuttavia come può farlo semplicemente renderlo pubblico o statico? Ad esempio, il mio libro mi ha raccomandato di registrare l'oggetto SpriteBatch nella classe Game.cs. Non sono sicuro di come sia preferibile renderlo semplicemente pubblico / statico poiché dovrebbe esserci comunque solo un'istanza di Game (singleton)?

  2. Sono confuso su quando dovrei ereditare da GameComponent o RenderableGameComponent. Sto cercando di seguire un progetto Manager / Controller, in modo tale che tutte le entità siano create / possedute da un singolo manager e lo stesso per altre cose. Al momento ho ogni Manager / Controller ereditato da GameComponent, tuttavia come si può ottenere se l'oggetto Game possiede tutti i Manager e chiama manualmente l'aggiornamento su di essi e disegna?

  3. Ho notato che Initialize viene chiamato prima di ContentLoad (), l'ho trovato fastidioso poiché nel mio Initialize è dove mi piacerebbe creare alcune delle mie entità (ad esempio Sprite, Player ecc.), Tuttavia non posso darle il loro carico SpriteSheets o Textures poiché la chiamata per caricarli non è ancora avvenuta. Sto forse inizializzando in modo errato o le persone semplicemente assegnano la trama più in basso in ContentLoad?

Quelli sembrano essere il mio più grande " WTF " di non capire veramente

Risposte:


11

La risposta alla tua domanda è semplicemente: fai qualunque cosa funzioni. Idealmente fai ciò che è semplice e funziona. Spesso usare l'architettura integrata non è semplice perché, come stai scoprendo, devi saltare attraverso i cerchi per strutturare il tuo gioco nel modo desiderato.

Per rispondere alla prima domanda, ti rimando alla mia risposta alla domanda "Perché usare i servizi?" . La risposta breve è che i servizi sono un buon modo per evitare problemi di accoppiamento (controllo delle versioni, dipendenza, estensibilità) che non incontrerai mai in un gioco autonomo . Il più delle volte è più semplice fare un membro public(e forse anche static, se hai fretta) e preoccuparti di problemi più interessanti.

Per rispondere alla tua seconda domanda, ti rimanderò alla mia risposta alla domanda "Quali sono i contro dell'utilizzo di DrawableGameComponent per ogni istanza di un oggetto di gioco?" così come i miei pensieri sull'architettura di gioco . La risposta breve è: non v'è alcun vantaggio di utilizzare gli GameComponentoltre semplicemente creando le proprie classi e chiamando metodi come Drawe Updatese stessi. Se GameComponentcorrisponde esattamente alla tua architettura desiderata, usala sicuramente, ma quasi sempre non lo fa.

L'uso di servizi e componenti diventa davvero interessante solo se stai costruendo una libreria per il consumo di terze parti. XNA stesso fa questo - ha IGraphicsDeviceServicee GamerServicesComponent, per esempio. Questi soddisfano requisiti specifici di disaccoppiamento che in genere non si incontrano durante lo sviluppo di un gioco.

Infine, la risposta alla tua terza domanda è abbastanza semplice: basta creare le tue entità di gioco LoadContent. Non c'è nulla di particolarmente speciale Initialize.

Vale la pena sottolineare che l'intero Microsoft.Xna.Framework.Gameassieme è opzionale . Fornisce un punto di partenza estremamente utile, ma non dovrebbe in alcun modo essere considerato "l'unico modo giusto" per fare le cose.


Modo molto interessante per vederlo. Molto più realistico e alla mano della mia risposta. Meritato +1, signore.
Jesse Emond

Ho un'altra domanda! Che dire dell'origine quando disegni per un Texture2D. È comune posizionare l'origine nella metà inferiore della trama? Sto provando a fare animazioni e sto scoprendo che avere l'origine a (0,0) sta causando un leggero spostamento della trama se la larghezza e l'altezza non sono uguali
Setheron

@Setheron: dovresti davvero creare una nuova domanda, poiché non è abbastanza correlata alla domanda originale. Ho intenzione di ripristinare la modifica apportata a questa domanda. L'origine per SpriteBatch.Drawviene specificata in coordinate di pixel di trama relativamente alla parte superiore sinistra della trama (o rettangolo di origine, se ne usi uno).
Andrew Russell,

1
@Andrew: recentemente ho modificato il mio gioco in modo che fosse interamente basato su servizi anziché su public/ staticproperties. Perché? Testabilità. È quasi impossibile cambiare le cose con l'approccio della proprietà, mentre è banale se tutto è inizializzato con un IServiceProviderche può essere riempito con tutto ciò di cui la classe ha bisogno con il tuo metodo di test. Evita anche la necessità di creare un'istanza Gamedell'oggetto stesso nel test, che diventa molto disordinato.
Matthew Scharley,

Per inciso, ho ancora molte proprietà pubbliche Gamesull'oggetto. A loro si accede semplicemente tramite interfacce che vengono spinte in Game.Servicescui poi viene passato a tutto per ottenere ciò di cui hanno bisogno di nuovo.
Matthew Scharley,

3

Per la tua prima domanda, devo ammettere che non conosco davvero la risposta effettiva. Immagino che sarebbe per lo stesso motivo per cui singleton è generalmente un cattivo modello di design. Ti farò riferimento a un preventivo da questo link :

Il primo a cui abbiamo pensato (e uno dei motivi alla base dell'introduzione dei servizi) è stato quello di rendere disponibile un riferimento GraphicsDevice in un gioco.In origine avevamo il Game proprietario del GraphicsDevice ed esporlo tramite una proprietà come Game.GraphicsDevice. Il problema era che ciò vincolava strettamente il GraphicsDevice al gioco, non permettendo a qualcun altro di "possedere" il dispositivo (come un renderer) e impedendo a qualcuno di utilizzare un GraphicsDevice aggiornato in futuro senza spedire una nuova versione del gioco che non avrebbe " essere retrocompatibile.

Per la tua seconda domanda, suppongo che l'utilizzo di componenti come questo sarebbe più utile se invece seguissi un approccio basato sui componenti , come se avessi un elenco di Spritecomponenti che saprebbero disegnare e aggiornarsi invece di un manager che sa come aggiornare e disegnare ogni sprite. Sono d'accordo, sembra lo stesso, ma preferisco un design basato sui componenti perché mi piace molto l'approccio orientato agli oggetti che ha.

Per la tua terza domanda, sì, dovresti caricare qualsiasi forma di contenuto (risorse, caratteri, ecc.) Nel metodo LoadContent. Per quanto riguarda l'inizializzazione, di solito crei l'oggetto Player all'interno della funzione Initialize e poi carichi il suo contenuto in LoadContent .. O puoi semplicemente fare tutto in LoadContent se lo desideri.

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.