2016-04-04 11 views
-1

Ich mache eine Gravitation/Sonnensystem Simulation und wenn die Simulation läuft bekomme ich nur 5 fps. Hier ist der relevante Teil meines Code:Eine sehr schlechte Framerate in der VB.net-Physiksimulation. Irgendwelche Vorschläge?

Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles picSpace.Paint 
    earth.displayX = Math.Round(earth.positionX) 
    earth.displayY = Math.Round(earth.positionY) 
    e.Graphics.FillEllipse(Brushes.Blue, earth.displayX - 5, earth.displayY - 5, 10, 10) 
    e.Graphics.FillEllipse(Brushes.Yellow, sunX - 10, sunY - 10, 20, 20) 
    distance() 
    position() 
End Sub 

Sub distance() 
    dX = sunX - earth.positionX 
    dY = sunY - earth.positionY 
    If (earth.positionX >= sunX) And (earth.positionY <= sunY) Then 
     dX *= -1 
    Else 
     If (earth.positionX >= sunX) And (earth.positionY >= sunY) Then 
      dX *= -1 
      dY *= -1 
     Else 
      If (earth.positionX <= sunX) And (earth.positionY >= sunY) Then 
       dY *= -1 
      Else 
       If (earth.positionX <= sunX) And (earth.positionY <= sunY) Then 
        'do nothing 
       End If 
      End If 
     End If 
    End If 

    d = Math.Sqrt((((dY) * 1000000)^2) + (((dX) * 1000000)^2)) 
    d = d * 1000 
End Sub 

Sub position() 
    If first = False Then 
     earth.positionX += ((((earth.oldVelocityX + earth.velocityX)/2) * simulationSpeed)/1000000000) 
     earth.positionY += ((((earth.oldVelocityY + earth.velocityY)/2) * simulationSpeed)/1000000000) 
     orbit(0, counter) = earth.positionX 
     orbit(1, counter) = earth.positionY 
     counter += 1 

     ReDim Preserve orbit(1, counter) 
     lblPositionX.Text = "X: " & Math.Truncate(earth.positionX) 
     lblPositionY.Text = "Y: " & Math.Truncate(earth.positionY) 
    End If 
    F = (earth.mass * sunMass * G)/(d^2) 
    theta = Math.Atan(dX/dY) 
    If (earth.positionX >= sunX) And (earth.positionY <= sunY) Then 
     earth.forceX = F * Math.Sin(theta) * -1 
     earth.forceY = F * Math.Cos(theta) 
    Else 
     If (earth.positionX >= sunX) And (earth.positionY >= sunY) Then 
      earth.forceX = F * Math.Sin(theta) * -1 
      earth.forceY = F * Math.Cos(theta) * -1 
     Else 
      If (earth.positionX <= sunX) And (earth.positionY >= sunY) Then 
       earth.forceX = F * Math.Sin(theta) 
       earth.forceY = F * Math.Cos(theta) * -1 
      Else 
       If (earth.positionX <= sunX) And (earth.positionY <= sunY) Then 
        earth.forceX = F * Math.Sin(theta) 
        earth.forceY = F * Math.Cos(theta) 
       End If 
      End If 
     End If 
    End If 
    a = F/earth.mass 
    earth.accelerationX = earth.forceX/earth.mass 
    earth.accelerationY = earth.forceY/earth.mass 
    earth.oldVelocityX = earth.velocityX 
    earth.oldVelocityY = earth.velocityY 
    earth.velocityX = earth.oldVelocityX + (earth.accelerationX * simulationSpeed) 
    earth.velocityY = earth.oldVelocityY + (earth.accelerationY * simulationSpeed) 
    first = False 
    Me.Refresh() 
End Sub 

Ursprünglich hatte ich einen großen Teil des Codes in einem Do ... Loop und die Framerate war in Ordnung, aber ich konnte nicht mit irgendwelchen Kontrollen interagieren, während die Schleife war Laufen. Wenn ich es wie oben gezeigt mache, kann ich mit den Steuerelementen interagieren, aber die Framerate ist sehr abgehackt. Jede Hilfe würde sehr geschätzt werden.

+2

Nicht im Zusammenhang mit Ihrem Leistungsproblem, aber als allgemeine .NET-Empfehlung bevorzugen Sie immer das Überschreiben der Ereignisbehandlung. Überschreiben Sie in diesem Fall die Methode 'OnPaint', anstatt das Ereignis 'Paint' zu verarbeiten: http://StackOverflow.com/a/3670912/172769 –

+2

Ich würde auch sagen, dass die Handhabung in 'Form.Paint' nicht geht sehr deterministisch sein, wie es zu oft (oder nicht genug) genannt werden kann. Ich würde empfehlen, eine Timer basierte Berechnung zu versuchen. Ich meine, Sie können immer noch die Formen in Paint zeichnen, aber lassen Sie den Kalkül Teil, vielleicht auf einem Hintergrund Arbeiter ausgelöst jede Sekunde (oder welche Zeitbasis Sie für Ihre Simulation am besten halten) –

Antwort

1

Aufruf Refresh aus Paint ist sehr merkwürdig. Ein mögliches Leistungsproblem besteht darin, dass das gesamte Formular dazu gezwungen wird, einschließlich des Hintergrunds neu zu streichen. Ich würde 2 Dinge vorschlagen:

Erstellen Sie ein Timer-Objekt, und führen Sie die Berechnung und Updates von innerhalb Timer_Tick-Ereignis.

Entfernen Sie dann den Me.Refresh-Befehl von Unterposition(), so dass Position() und Abstand() nur Berechnungen ausführen. Fügen Sie einen Anruf zu Me.Invalidate() am Anfang hinzu und beenden Sie des Timer_Tick, indem Sie ihm das Rechteck übergeben, das den Ort der Erde enthält. Dadurch werden nur die alten und neuen Standorte neu gezeichnet und viele unveränderte Hintergründe werden nicht neu gezeichnet. Ihre Paint-Methode ist dann wahrscheinlich nur die 2 FillEllipse-Zeilen.

+0

Ich habe es versucht, aber es funktioniert nicht . Das Timer Tick Event sieht so aus, ist das korrekt? 'Private Sub Timer1_Tick (Absender als Gegenstand, e As EventArgs) Griffe Timer1.Tick Me.Invalidate() Entfernung() Position() Me.Invalidate() End Sub' – Lee

+0

@Lee - In welcher Weise doesn‘ t arbeiten? Ist der Timer aktiviert und mit einem relativ kurzen Intervall? –

+0

Ja, es hat ein Intervall von 20. Es soll anfangen zu simulieren, wenn der Benutzer klickt. (Die anfängliche Position der Erde ist, wo der Benutzer klickt). Wenn Sie jedoch den neuen Code verwenden, passiert nichts, wenn Sie klicken. – Lee

Verwandte Themen