Blitting-Geschwindigkeit erhöhen?

9

Ich arbeite an einem 2D-Side-Scroller in PyGame. Für jede Karte verwenden wir eine Textur (dies ist die tatsächliche Größe der Textur):

Kartentextur

Dann laden wir das Bild mit diesem Code:

sprite = pygame.image.load("Maps/MapTesting.png")
sprite.convert()
sprite = pygame.transform.scale(sprite,
              (sprite.get_width()*6, sprite.get_height()*6))

Wie Sie sehen können, wird die Textur sechsmal gesprengt, um die eigentliche Kartentextur zu erstellen. Im Durchschnitt ist diese Textur etwa 4500x800. Diese Textur muss bei jedem Frame auf den Bildschirm übertragen werden , da der gesamte Bildschirm verschmutzt ist (dank des seitlichen Bildlaufs). Wir machen das mit diesem Code:

screen.blit(sprite, (0, 0),
(cameraposx, cameraposy, windowheight, windowwidth))

Und es funktioniert. Das Problem ist, dass es ziemlich langsam ist: Ich bekomme magere 40 FPS auf einem anständigen PC, und das ohne die tatsächlichen KI / Objekte, während wir 60 FPS anstreben. Wie können wir das beschleunigen?


Beachten Sie, dass der obige Code bereinigt und aus dem Kontext genommen wird. Den vollständigen Code finden Sie hier: https://github.com/nightcracker/PyGG2

Und zu guter Letzt, während das obige Bild wie 8-Bit aussieht, gibt es Elemente im Spiel, die mehr Bittiefe erfordern.

orlp
quelle
Teilen Sie die Textur auf eine normale Größe auf, z. B. 1024 pro Block, und teilen Sie jeweils nur die beiden relevanten Elemente auf.
Jari Komppa
@JariKomppa: Versucht es, hat keine Auswirkung auf das Blitting (Pygame ist klug genug, um nur das Rect zu blit, das ich ihm sage), nur die Speichernutzung.
Orlp
Sie könnten ... kein Pygame (trollface.jpg) verwenden ... jkjk, in diesem Fall schätze ich, dass dort nicht Ihre Verlangsamung auftritt. Haben Sie es ausgiebig getestet?
Ultifinitus
@ultifinitus: Ja, ich habe es mit cProfile profiliert.
Orlp
Was ist der Geschwindigkeitsunterschied, wenn Sie ihn in seiner tatsächlichen Auflösung anzeigen? Was ist, wenn Sie das größere Bild vorberechnen?
Ultifinitus

Antworten:

7

Lassen Sie mich einige allgemeine verglichene Optimierungen auflisten, die sich auf das Blitzen von Pixeln auf eine Oberfläche beziehen (aus meiner Erfahrung).

1) Normalerweise werden Palettenbilder (indizierte Bilder) beim Überblenden einer zusätzlichen Umleitungsstufe unterzogen (um die Farbe zu erhalten). Daher sind sie beim Überblenden im Vergleich zu Echtfarbbildern langsam.

2) Echtfarbige Pixeldaten (vorausgesetzt, ohne Alpha-Say24-Bit-Daten) können sehr schnell ausgeblendet werden, da wir für jede Scanlinie des Bildes (wenn wir einen Teil des Bildes kopieren) einen Memcpy in den Geräte-Frame-Puffer erstellen können Wenn es sich bei den zu überblendenden Daten um ein Vollbild handelt, können wir die gesamten Daten direkt speichern, was viel schneller ist!

3) Das Blitting von Alpha-Pixeldaten ist am teuersten, da es die Berechnung der einzelnen Komponenten umfasst und wir sie erneut in RGB-Daten packen müssen. In einfachen Worten mehr Operationen für jedes Pixel, um die endgültige Farbe zu erhalten!

Finalrgb = Alpha*(Srgb) + (1-Alpha)*Drgb (this is for normal blend equation)
    where Srgb is source-rgb (we need to apply for each of the component for final color)
       Drgb is the color that will be there in the destination buffer.

Ich habe noch nie an pyGame gearbeitet. Aber ein kurzer Blick auf den Quellcode lässt mich vermuten, dass es 'sdl'-Blit-Funktionen unter der Haube verwendet. Normalerweise ist Sdl-Blit sehr schnell und optimiert. Machen Sie also noch einmal nicht die oben genannten Punkte und das Profil noch einmal! Viel Glück!

* Update: * Das Einstellen des Farbschlüssels entspricht dem Hinzufügen eines zusätzlichen Häkchens, wenn jedes Pixel auf der Oberfläche ausgeblendet wird.

       for(eachPixelColor in allPixels)
         {
            if(eachPixelColor is NOT colorKeyColor)
            {
              copy color to the frame buffer!
            }

         }

Wenn Sie also sehen, dürfen wir memcpy nicht verwenden, da wir die Farbgültigkeit jedes Pixels überprüfen müssen!

Ayyappa
quelle
Ok, wie sich herausstellt, ist es ein Aufruf, sich set_colorkeyin die Kartentextur einzufügen und ihr einen (teuren) Alphakanal zu geben. Ein convertFehler, der behoben ist, und jetzt habe ich 150 FPS stabil auf diesem Mist-PC. Vielen Dank!
Orlp
Sie werden in Bezug auf den Farbschlüssel bearbeiten und sogar vergessen, einige Informationen darüber hinzuzufügen: D
Ayyappa
5

sprite.convert() tut nicht das, was du denkst.

sprite = sprite.convert() ist was du brauchst.

Kylotan
quelle
Woops, ich habe zwar sprite = sprite.convert()im echten Code :)
Orlp
Aha gut. :) In diesem Fall habe ich Ihnen nicht viel zu bieten, außer Pyglet anstelle von Pygame zu verwenden oder pyOpenGL direkt zu verwenden, wenn Sie mit OpenGL vertraut sind.
Kylotan
@Kylotan: guter Fang Kumpel! Ich habe es nicht überprüft :)
Ayyappa
oder noch besser:sprite = pygame.image.load("Maps/MapTesting.png").convert()
MestreLion