Grafik zeichnen - Timer - Performance

phap69

Mitglied
Hallo da draußen,

ich habe eine großes verständnisproblem, was das Zeichnen von Grafik angeht, damit verbunden die Performance eines Programmes.

Wenn ich es recht verstehe, wird die Grafikfläche im Event OnPaint immer neu gezeichnet, wenn diese per Refresh() angestoßen wird. Wenn ich ein/oder mehrere bewegte Objekte darstellen will muss dazu ja ein Timer laufen der den Refresh() Befehl in periodischen Abständen ausführt. Ich hoffe ich sehe das sioweit richtig.

Da ich bei einem kleinen Projekt an deutliche Performance Grenzen geraten bin (eigentlich unverständlicherweise, da ich nicht wirklich viele Objekte bewege). Ich habe daraufhin ein kleines Testprogramm geschrieben, welches in einem Timer all paar Intervalle ein neues Objekt erzeugt. Die Objekte bewegen sich nun innerhalb einer Fläche durcheinander und immer wenn sie aufeinander treffen sollen das kleinere der beiden kollidieren Objekte gelöscht werden.
Die Kollisionsprüfung läuft in ener verschachtelten Schleife ab.

Hier mal ein bisschen Code zum Verständnis:

Code:
private void timer1_Tick(object sender, EventArgs e)
        {
            if (counter % 20 == 0 )
            {
                Ball b = new Ball(Width, Height); //Neues Ballobjekt erzeugen
                balls.Add(b);
            }
            for (int i = 0; i < balls.Count; i++)
            {
                balls[i].Move(Width, Height); //Ball bewegen
                balls[i].CheckCollision(balls[i], balls); //Prüfe auf Kollision
            }
            for (int i = 0; i < balls.Count; i++)
            {//Kollidierte Bälle löschen
                if (balls[i].DeleteMe) { balls[i] = null; balls.RemoveAt(i); GC.Collect(); }
            }
            Refresh();
            counter++;
            
        }

Die Bälle werden in einem List<> gespeichert. In der CheckCollision ()Methode läuft folgendes:

Code:
public void CheckCollision(Ball b,List<Ball> balls)
        {        
            for (int i = 0; i < balls.Count; i++)
                {
                  if ((balls[i].rect).IntersectsWith(b.rect))
                        {//Kollision
                           if (b.Size.Width > balls[i].Size.Width)
                            {
                            balls[i].DeleteMe = true;
                            }
                            else if (b.Size.Width < balls[i].Size.Width)
                            {
                                b.DeleteMe = true;
                            }
                           break;
                        }
                    }    
                
            }

Auf meinem PC läuft das Ganze klaglos und schnell, auf PCs mit nur ca 3GB Ram ist eine erhebliche Verzögerung zu erkennen. Kann das normal sein, oder habe ich einen komplett falschen Ansatz zur Dasrtellung?
Was passiert eigentlich, wenn der Durchlauf der Schleife mehr Zeit in Absporuch nimmt als ein Timer Tick?

Bin für jede Hilfe dankbar.
 

ksk

Erfahrenes Mitglied
Zuerst mal musst den Timer stoppen damit der aktueller Task abgearbeitet werden kann ohne das ein weiteres dazu kommt.
Als nächstes würde ich dir empfehlen das du all das was du im Timer-Event machst ins onPaint auslagerst.
Und im Timer-Event Invalidate() aufrufst.
Bsp:
Code:
timer1.Stop();
Invalidate();
ImageAnimator.UpdateFrames();
timer1.Start();

Zusätzlich würde ich für die Kollision, statt einer Schleife Linq verwenden.
Und zum Schluss nicht vergessen DoubleBuffer nach InitializeComponent im Konstruktor zu setzen
Code:
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);


Lg
ksk
 

Neue Beiträge