2012-12-20 14 views
13

Che cos'è un modo efficiente per disegnare sprite nel mio gioco 2D XNA? Per essere più concreto, ho suddiviso questa domanda in 4 domande.Best practice: disegno efficiente dello sprite in XNA


ho usato per dichiarare di Game1 SpriteBatch statica, e chiamò SpriteBatch.Begin e .Close in ogni IDrawable.Draw. Non ha funzionato bene Inoltre, dare a ciascun drawable il proprio SpriteBatch non ha funzionato bene.

Q1: Penso che sia meglio avere un esempio SpriteBatch, e solo chiamo iniziare/vicino volta. È corretto?


Attualmente, il mio Game1.Draw sembra qualcosa di simile:

spriteBatch.Begin(); 

base.Draw(gameTime); // draws elements of Game.Components 

// ... 

spriteBatch.End(); 

Q2: In questo modo, Begin viene chiamato solo una volta. È questa la strada da percorrere? Come avete risolto questo problema?


Q3: Inoltre, ogni componente ha il proprio metodo di IGameComponent.LoadContent. Dovrei caricare i miei contenuti lì? O è meglio caricare il contenuto in una classe genitore, come ad esempio Game1.LoadContent?


mi rendo conto che non avrei mai caricare lo stesso contenuto due volte, quindi mi hanno dato i miei componenti disegnabili sia statica e non statico Texture2D, e li diede 2 costruttori:

static Texture2D defaultTexture; 
public Texture2D MyTexture; 

public Enemy() 
    : this(defaultTexture) { } 

public Enemy(Texture2D texture) 
{ 
    MyTexture = texture; 
} 

protected override void LoadContent() 
{ 
    if (MyTexture == null) 
    { 
     if (defaultTexture == null) 
     { 
      defaultTexture = Content.Load<Texture2D>("enemy"); 
     } 

     MyTexture = defaultTexture; 
    } 
} 

Questo In questo modo, le trame predefinite di una classe vengono caricate solo la prima volta che viene chiamata la classe LoadContent. Tuttavia, quando il parametro texture è specificato nella funzione di costruzione, dovrò prima caricare la trama.

Q4: Penso che ci dovrebbero essere modi migliori per farlo. Sto pensando di creare un dizionario di texture con i loro nomi di risorse come stringa. Che cosa suggeriresti?

+0

lo faccio nel stessa strada. Se non ho motivo di usare il multiplo sprite batch (ad esempio per split-screen, effetti diversi, e così via), sto chiamando begin e end solo una volta nella classe principale del gioco, e disegno tutto tra questo inizio e fine. – Thaven

risposta

3

Ho usato per dichiarare SpriteBatch di Game1 statico

Non devi averlo statica. Basta fare un singleton. All'interno Draw metodo

SpriteBatch spriteBatch = ScreenManager.SpriteBatch; // singletion SpriteBatch 
spriteBatch.Begin(); 
// Draw the background 
spriteBatch.Draw(background, ... 
foreach (var enemy in enemys) 
{ 
    enemy.Draw(gameTime); 
} 
// etc. 
spriteBatch.End(); // call here end 
base.Draw(gameTime); // and then call the base class 

suppongo che è meglio avere una sola istanza SpriteBatch, e solo chiamo iniziare/vicino una volta. È corretto?

Consiglio di aprire e terminare lo SpriteBatch con un solo metodo. Ti aiuterà a evitare conflitti con SpriteBatch che ha iniziato a disegnare, ma non ha finito.

Stai aggiungendo i tuoi elementi alla raccolta globale di componenti? È una cattiva idea aggiungere drawable a questa raccolta. Non è possibile controllare l'ordine di disegno, i componenti sono globali. See this answer.

Implementare nei componenti IUpdatable e IDrawable e chiamarli nel codice in cui è necessario. Sbarazzati delle cose statiche e usa Dependency Injection istead.

Inoltre, ogni componente ha il proprio metodo IGameComponent.LoadContent. Dovrei caricare i miei contenuti lì? O è meglio caricare il contenuto in una classe genitore, come Game1.LoadContent?

È necessario caricare le risorse quando ne avete bisogno e ne siete responsabili. Non devi caricare tutti i 30 livelli quando l'utente ha appena iniziato il gioco, vero? Ad esempio, all'avvio del gioco carichi tutte le risorse necessarie per la schermata iniziale e il menu principale. Se carichi solo ciò di cui hai bisogno, il giocatore è felice che il gioco inizi velocemente. Quindi il giocatore vuole iniziare il gameplay. Qui puoi caricare le risorse su un thread separato per mantenere l'app reattiva.

Penso che ci dovrebbero essere modi migliori per farlo. Sto pensando di creare un dizionario di texture con i loro nomi di risorse come stringa. Che cosa suggeriresti?

Content.Load è già memorizzato nella cache, quindi non è necessario.

+0

Sembra che tu abbia chiamato "Disegna" sul nemico manualmente. Nel mio gioco, ho aggiunto tutti i drawable (come muri e nemici) all'elenco di 'Game1.Components', quindi' Draw' viene chiamato quando si chiama la classe base. –

+0

@RuudLenders visualizza il mio aggiornamento –

+0

+1 per indicare che 'Content.Load' gestisce le chiamate ridondanti. Tuttavia, è * che * male usare la collezione globale? Non devo controllare l'ordine di disegno. –

1

quanto si può ricavare da tutorialsaround

chiamando iniziare e terminare una sola volta è il metodo preferito.

0

Q4: Penso che ci dovrebbero essere modi migliori per farlo. Sto pensando di creare un dizionario di texture con i loro nomi di risorse come stringa. Che cosa suggeriresti?


A4: Io di solito creare un Dictionary<string, Texture2D> NameTextureDic nel mio TextureLib classe (che gestisce il caricamento delle immagini png in fase di esecuzione), così posso avere qualsiasi struttura in questo modo:

var t2d = textureLib.NameTextureDic["tree-4"];