Leistung bei GDI+ Maximieren

  • VB.NET

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Leistung bei GDI+ Maximieren

    Hey Leute,

    ich arbeite gerade an einem Spiel, welches komplett auf GDI+ basiert.
    Alledrings muss der PC mit vielen Arrays rechen, welches ihn anscheinend überlastet und mit gerade mal ~30 FPS zeichnet.
    Wie kann ich den denn Schneller zeichnen, bzw. die FPS maximieren.

    Vielen Dank für eure Antworten,

    Peter
    Hi
    Das kommt komplett auf deinen Code und das Spiel an.
    - Wie und was zeichnest du genau? Zeichnest du jedes mal die gesamte Fläche neu, auch wenn das nicht nötig ist?
    - Verwendest du einen Puffer?
    - Zeichnest du im Paint-Event? Ist die Größe des Controls immer gleich groß?
    - Verwendest du Timer?

    Kannst du bitte noch ein wenig Code rüberrücken oder das Programm wenigstens so beschreiben, dass wir etwas damit anfangen können?

    Gruß
    ~blaze~
    - invaliadate(bereich) benutzen: also wenn möglich nicht ALLES neuzeichnen lassen, sondern nur das was sich verändert.
    Autorennen: unter umständen verändert sich ja nur die stellen wo das auto vorher war und jetzt ist

    - so viel wie möglich im vorraus machen: Berechnungen die immer gleich bleiben, zusammenhängende grafiken als bitmap zwischenspeichern anstatt sie immer wieder neu zu zeichnen
    Autorennen: Dein Auto setzt sich aus Reifen, Karosserie und Fenstern zusammen die als einzeldatei vorliegen. in einer datei würde der "zusammen-zeichnen"-prozess entfallen

    - verwende nicht And, sondern Andalso! jenachdem wie häufig dieses in der Zeichenroutine aufgerufen wird kannst du das ein oder andere Frame raushauen^^

    - verwende alternative GDI+ methoden zum zeichnen
    Du willst ein Raster zeichen: zeichne nicht jede linie einzeln, sondern benutze einen texture-brush der quadrate auf die fläche zeichnet! um solche dinge herauszufinden einfach etwas mit der stopwatch-klasse messen und mit GDI tüfteln^^

    ansonsten schreibe wie blaze schon sagte mehr zu deinem spiel, lass etwas code rüberwachsen und vllt einen screenshot^^
    lg
    Okay, ich habe jetzt den wehsentlichen Code kopiert.
    Das Spiel ist überigens die zweite Version von [Beta] CopterCrash - v0.7 .
    Damals habe ich allerdings keine Arrays benutzt, heute bin ich Fortgeschrittener.

    VB.NET-Quellcode

    1. For i As Integer = 0 To 47
    2. 'Obere Reihe
    3. e.Graphics.FillRectangle(New SolidBrush(balkencolor1), xi, 1, 10, balkenarray(i))
    4. e.Graphics.DrawRectangle(New Pen(Brushes.Black, 2), xi, 1, 10, balkenarray(i))
    5. 'Untere Reihe
    6. e.Graphics.FillRectangle(New SolidBrush(balkencolor1), xi, balkenarray(i) + abstand(level), 10, 500)
    7. e.Graphics.DrawRectangle(New Pen(Brushes.Black, 2), xi, balkenarray(i) + abstand(level), 10, 500)
    8. xi += 10
    9. Next


    //EDIT: Zeichnen tue ich übrigens im Form1.Paint Event
    Pack Deine Berechnungen in einen separaten Thread.
    Sieh Dir mal an:

    VB.NET-Quellcode

    1. Imports System.Threading.Tasks
    2. '...
    3. Parallel.For(...)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Außerdem würde ich einen Puffer auf Me.CreateGraphics() erzeugen, wenn die Größe des Fensters fest ist und dann im Paint-Event den Puffer rüberkopieren. Außerdem würde ich mir eine abstrakte Klasse/ein Interface anlegen, das mit zu zeichnende Elemente angibt und den Bereich der Elemente. Es macht keinen Sinn, immer alle Elemente zu zeichnen, wenn man sie gar nicht braucht. Mit RectangleInstance.IntersectsWith(Rectangle) überprüfst du, ob das neugezeichnete Rechteck sich mit dem des gezeichneten Elements überlappt. Wenn das der Fall ist, kannst du noch überprüfen, ob auch die neugezeichnete Region (also Clip) sich mit dem Element überlappt, das musst du aber nicht (ist wahrscheinlich performanter, das nicht zu tun). Beim neuzeichnen würde ich, wie oben bereits genannt wurde Bitmaps als Zwischenspeicher benutzen (vor allem für die Balken) und CompositingMode auf Drawing2D.CompositingMode.SourceCopy stellen, da du ja opake Balken hast und damit das Alphablending bzw. die Abfrage nach dem Alphablending wegfällt. Außerdem wäre es von Vorteil, DrawImageUnscaled zu verwenden.
    Für den Puffer von CreateGraphics() verwendest du am besten BufferedGraphics (per BufferedGraphicsManager.Current.Allocate kannst du den Puffer anlegen). BufferedGraphics.Graphics enthält das Graphics-Object, BufferedGraphics.Render zeichnet das dann auf das ursprüngliche Graphics-Objekt. BufferedGraphics.Dispose löscht den Puffer abschließend. Im Paint-Event würde ich, wie gesagt, Render aufrufen. An anderer Stelle würde ich das Rendern in einem anderen Thread durchführen und das BufferedGraphics-Objekt synchronisieren, damit darauf im Paint-Event nicht während dem Rendervorgang zum Präsentieren zugegriffen wird.

    Gruß
    ~blaze~