2013-06-07 16 views
5

Ich habe ein Scrolling-Shooter-Spiel portiert, das ich in XNA über Linux mit MonoGame erstellt habe. Fast alles ist reibungslos gelaufen, aber ich habe ein Problem an einem bestimmten Ort mit SpriteBatch.Draw() Aufruf der Framerate. Der Großteil des Spiels läuft gut ohne Schluckauf. Es zieht eine große Anzahl von Gegnern und eine große Anzahl von Kugeln auf einmal ohne jegliche Verlangsamung. Der Teil, der die ausgelassenen Rahmen verursacht, ist jedoch ein mehrschichtiger Bildlaufhintergrund. Die relevanten Abschnitte des Codes sind hier.Monogame XNA niedrige Bildrate von wenigen Draw() -Aufrufen

Level.cs:

public void Draw(SpriteBatch spriteBatch) 
{ 
    foreach (ScrollingBackgroundLayer sbl in scrollingBackground) 
    { 
     sbl.Draw(spriteBatch); 
    } 
} 

Die "scrollingBackground" oben ist eine Liste von ScrollingBackgroundLayers, die entsprechenden Abschnitte davon sind:

ScrollingBackgroundLayers.cs:

Vector2[] scrollingBackgroundImages; 
public float DrawLayer; 

public ScrollingBackgroundLayer(GameScene newScene, Texture2D texture, float scrollSpeed, Color color) 
{ 
    layerColor = color; 
    layerSpeed = scrollSpeed; 
    layerTexture = texture; 
    thisScene = newScene; 

    Initialize(); 
} 

public void Initialize() 
{ 
    scrollingBackgroundImages = new Vector2[2]; 

    for (int i = 0; i < 2; i++) 
    { 
     scrollingBackgroundImages[i] = new Vector2(0, thisScene.ScreenArea.Height - (layerTexture.Height * i)); 
    } 
} 


public void Update(GameTime gameTime) 
{ 
    for (int i = 0; i < scrollingBackgroundImages.Length; i++) 
    { 
     scrollingBackgroundImages[i].Y += (float)gameTime.ElapsedGameTime.TotalSeconds * layerSpeed; 

     if (layerSpeed > 0 && scrollingBackgroundImages[i].Y >= thisScene.ScreenArea.Height) 
     { 
      scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y - layerTexture.Height * 2)); 
     } 
     else if (layerSpeed < 0 && scrollingBackgroundImages[i].Y + layerTexture.Height <= 0) 
     { 
      scrollingBackgroundImages[i] = new Vector2(scrollingBackgroundImages[i].X, (scrollingBackgroundImages[i].Y + layerTexture.Height * 2)); 
     } 
    } 
} 

public void Draw(SpriteBatch spriteBatch) 
{ 
    foreach (Vector2 sb in scrollingBackgroundImages) 
    { 
     spriteBatch.Draw(layerTexture, sb, null, layerColor, 0f, Vector2.Zero, 1f, SpriteEffects.None, DrawLayer); 
    } 
} 

Alle von Die Framerate-Probleme gehen weg, sobald ich den Aufruf von ScrollingBackgroundLayer.Draw() auskommentiere, so dass dies ein ziemlich großer Hinweis zu sein scheint, dass das Problem von S kommt Der Versuch von priteBatch, die Scroll-Ebenen zu zeichnen. Offensichtlich möchte ich herausfinden, warum das passiert. Ich habe ein paar andere Probleme mit SpriteBatches untersucht und die häufigste Sache, die auf eine Antwort hinweist, ist die Tatsache, dass ein neuer SpriteBatch immer dann erstellt wird, wenn die Textur geändert wird, aber selbst wenn der SpriteSortMode auf Textur gesetzt wurde, gab es keine Verbesserungen.

Die Framerate-Abnahme erfolgt auf einer Bühne des Spiels, die 7 verschiedene ScollingBackgroundLayers hat, von denen jede eine separate Textur zeichnet, die etwa 700 Pixel breit und 900 hoch ist (jeder Layer sollte dies nicht mehr als 2 Mal tun) der Scroll-Effekt). Ich habe das Gefühl, dass ich etwas Offensichtliches vermissen muss, weil das Spiel manchmal bis zu 2-300 Kugeln mit exakt der gleichen Überlast rendert, also sollten weitere 14 Aufrufe ein Tropfen auf den heißen Stein sein. Ist das einfach ein Problem beim Versuch, Texturen zu zeichnen, die zu groß sind, um von SpriteBatch effektiv gehandhabt werden zu können? Das ist kein Problem in der Windows-Version, also frage ich mich, ob es keine plattformspezifische Problemumgehung gibt oder ob MonoGames Implementierung von Draw nur ineffizient ist. Jede Rückmeldung wäre willkommen.

Volle Quelle für Interessenten:

Linux - https://github.com/cmark89/AsteroidRebuttal-Linux
Fenster - https://github.com/cmark89/AsteroidRebuttal

Edit: Ich habe versucht, mit ihm ein bisschen mehr bastelt. Ich änderte den Aufruf von Draw(), um sicherzustellen, dass das Zielrechteck dem ausklappbaren Bereich des Bildschirms entsprach, aber es gab keine merkliche Änderung. Ich habe die Textur gegen eine sehr kleine getauscht und das hat die Verzögerung beseitigt, also denke ich, dass es etwas mit der Größe der Textur zu tun hat.

Edit 2: Okay, ich landete nur bei der Kugel und zerschnitt die Transparenzschichten, die ich benutzte (wie eine Art nicht fauler Typ). Es hat das Problem gelöst, vermutlich weil es nicht mehr viele nutzlose Pixel rendern muss, aber ich frage mich immer noch, warum das nur ein Problem unter Linux ist. Auch wenn ich mein Problem vorläufig gelöst habe, werde ich das für eine Weile offen lassen, für den Fall, dass irgendjemand etwas darüber weiß, was den drastischen Leistungsunterschied verursachen könnte.

+1

Ich kann mich nicht wirklich an die Performance-Kosten für verschiedene Dinge erinnern, aber GPU zu zwingen, so viele hochauflösende Texturen zu zeichnen, ist wahrscheinlich keine sehr gute Idee und etwas, das man anders gestalten könnte. Wenn Speicher mir richtig dient, würden diese Texturen am Ende 1024 * 1024 Texturen (wegen der Macht der 2-Anforderung und der Neuherstellung in diese Größe während der Laufzeit) sein, wenn sie an die GPU gesendet werden. –

+0

Das Problem in diesem Fall ist, dass jedes Bild des Hintergrunds mit einer anderen Geschwindigkeit scrollt oder eine andere Transparenzstufe hat. Einige von ihnen könnte ich definitiv hacken und Ebenen erstellen, die in kleineren Bereichen des Bildschirms zeichnen, aber einige von ihnen (meist Transparenzschichten) sind nicht so einfach. Ich war mir nicht bewusst, dass die GPU sowieso die Nicht-Power von zwei Texturen änderte; vielleicht werde ich die Größe ändern und sehen, ob sich etwas ändert. Unabhängig von den Optimierungen, die ich in Betracht ziehen werde, bin ich wirklich verwirrt, warum dieses Problem unter Windows nicht auftritt. – cmark89

Antwort

2

In dieser Situation würde ich vorschlagen, dass Sie stattdessen einen Shader verwenden, um dies zu erreichen. Sie werden sehen, dass Ihre Leistung dadurch explodiert.Werfen Sie einen Blick auf die folgenden:

http://www.david-gouveia.com/scrolling-textures-with-zoom-and-rotation/

es auf diese Weise tun, wird eine Menge CPU-Auslastung verringern, und machen Sie Ihre GPU tun den Großteil der Arbeit.

Sie können auch Ihre Texturen in Potenzen von 2 statt 700x900 speichern. (Mach etwas wie 512x512). Ihre Grafikpipeline hat einen Leistungsschub in Bezug auf Texturen mit einer Zweierpotenz.

+0

Ich untersuche das, aber es könnte zu viel für das sein, was ich tun muss. Vielleicht, weil Shader mich in Panik versetzen. Ich melde mich bei dir, wenn ich die Chance habe, das zu versuchen. – cmark89

+0

Das ist kein Overkill, ich versichere Ihnen, es ist sehr einfach. Sie müssen nicht einmal etwas über Shaders wissen, um das zum Laufen zu bringen;) – jgallant

+0

Ich bin nicht dazu gekommen, das zu versuchen, da ich am Ende nur eine einfachere Arbeit verwendet habe, aber da dies die einzige Antwort ist, markiere ich sie als akzeptiert. Es sieht tatsächlich wie eine sehr nette Lösung aus, wenn Sie die Effektdatei zum Laufen bringen können (tangential ist dies offenbar eine Tortur mit der aktuellen Version von MonoGame, weshalb ich es nicht ausprobiert habe). – cmark89