Grafik hinkt teilweise

  • VB.NET

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von ichduersie.

    Grafik hinkt teilweise

    Hallo,

    Ich programmiere momentan ein kleines spiel, bei dem ich viel zeichnen und Grafiken rotieren muss.
    Leider hängt beim Movement die Grafik manchmal kurz nach.

    Ich verwende das OwnerDrawing - zeichne also direkt im Handles MyBase.Paint Event mit e.graphics.draw usw.
    In meinem 2D Topdown-view Spiel wird der View mit der Mausbewegung um den Spieler (in der unteren häfte des Bildschirmes) rotiert.
    Weiters verwende ich einem Timer1 - bei jedem Tick wird die Bewegung des Spielers, der Enemies und der Items berechnet sowie das gesamte Feld mit MyBase.Invalidate(new Rectangle(0,0,MyBase.Width,MyBase.Height)) neu gezeichnet.
    Das Muss leider sein, da nahezu im gesamten Bildschirmbereich etwas verändert wird.
    Das ganze wirkte anfangs (time 16ms -> 60FPS) etwas holprig. Jetzt habe ich den Timer auf 10 ms-> 100FPS gesetzt, was doch recht hoch ist. Dies verbesserte aber die "holprigkeit" des Spielfelds. (und ja, form1 ist doubleBuffered).
    An was könnte das liegen, dass es so holprig wirkt?
    Vielen Dank!!!

    Weiters: die rotation der Gegenstände erfolgt mit folgendem Code in jedem TImer1.tick - kann man daran auch was verbessern?

    Quellcode

    1. Private Sub draw_img_rotate(e As PaintEventArgs, img As Image, x As Integer, y As Integer, scale_x As Double, scale_y As Double, angle As Double)
    2. Dim size As Integer = Convert.ToInt16(Math.Ceiling(Math.Sqrt(Math.Pow(img.Width, 2) + Math.Pow(img.Height, 2))))
    3. 'size ist diagonale des bildes; muss noch mit scale multipliziert werden
    4. Dim sx As Integer = Convert.ToInt16(size * scale_x) 'bitmap braucht int
    5. Dim sy As Integer = Convert.ToInt16(size * scale_y)
    6. Dim rotierte_bmp As Bitmap = New Bitmap(sx, sy) 'neue maße
    7. Dim bitmap_g As Graphics = Graphics.FromImage(rotierte_bmp)
    8. bitmap_g.TranslateTransform(size * scale_x / 2, size * scale_y / 2) 'neuer mittelpunkt
    9. bitmap_g.ScaleTransform(scale_x, scale_y)
    10. bitmap_g.RotateTransform(angle)
    11. bitmap_g.TranslateTransform(-size / 2, -size / 2)
    12. bitmap_g.DrawImage(img, New Point((size - img.Width) / 2, (size - img.Height) / 2))
    13. Dim coords As Point = New Point(x - size * scale_x / 2, y - size * scale_y / 2)
    14. e.Graphics.DrawImage(rotierte_bmp, coords)
    15. End Sub




    [EDIT] Habe gerade ein bisschen gegoogelt: Ich glaube das unerwünschte Artefakt ist das Screen Tearing. Form1 Double Buffered ist aber on... Weiß jemand vielleicht eine Lösung?
    Danke!!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dr_Gre“ ()

    Hier ist mal ein Code Beispiel um das zu vereutlichen was ich meine.
    Auf der Form ist lediglich ein Timer1 (enabled, interval 16).
    Wenn man diesen Code testet sieht man, dass die rote wandernde Linie manchmal kurzt "hinkt".
    Weiß jemand wie das behebbar wäre? Danke!!

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim up, down As Boolean
    3. Dim y As Integer
    4. Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
    5. Dim p As New Pen(Brushes.Red, 3)
    6. e.Graphics.DrawLine(p, New Point(0, y), New Point(MyBase.Width, y))
    7. End Sub
    8. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    9. DoubleBuffered = True
    10. up = False
    11. down = False
    12. y = MyBase.Height / 2
    13. Me.BackColor = Color.Black
    14. End Sub
    15. Private Sub key_press(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
    16. Select Case e.KeyCode
    17. Case Keys.Down, Keys.S
    18. down = True
    19. Case Keys.Up, Keys.W
    20. up = True
    21. End Select
    22. End Sub
    23. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    24. If down Then y += 2
    25. If up Then y -= 2
    26. MyBase.Invalidate()
    27. End Sub
    28. Private Sub key_release(sender As Object, e As KeyEventArgs) Handles MyBase.KeyUp
    29. Select Case e.KeyCode
    30. Case Keys.Down, Keys.S
    31. down = False
    32. Case Keys.Up, Keys.W
    33. up = False
    34. End Select
    35. End Sub
    36. End Class


    MSDN liefert mir als möglichen Lösungsansatz SetStyle(ControlStyles.OptimizedDoubleBuffer, True) - das hilft in diesem Codebeispiel tatsächlich etwas (kommt mir vor), aber in meinem game nicht :-/

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dr_Gre“ ()

    Ich kann dir leider nicht sagen, was das DoubleBuffered macht, aber ich hätte dir sagen können dass es nicht funktioniert :D
    Probiers mal damit: msdn.microsoft.com/de-de/libra…edgraphics(v=vs.110).aspx

    Jedoch sei gleich gesagt, dass man nicht unbedingt einen Timer zum aktualisieren nutzt.
    @ErfinderDesRades: Er meint, dass der Bildschirm flackert, wenn er neu zeichnet.

    LG :)
    @ErfinderDesRades den gesamten Source lade ich nur ungern hoch - ist auch schon sehr viel Code drin
    Ich habe jetzt noch ein bisschen mehr gegoogelt: scheinbar liegt es am Timer.Tick in dem alles stattfindet.
    Anscheinend soll man eine Stop Watch oder was ähnliches stattdessen verwenden und in dem alle sachen ausführen.
    @ichduersie Flackern tut der Bildschirm nicht. Ich probier jetzt vorher diese Stopwatch Methode und dann deinen Link.
    Danke!
    Jo. Also ohne dass man deinen Fehler reproduzieren kann, kann dir kaum mehr geholfen werden, als dass man dich mit alle möglichen Links beschmeißt - vlt. hilft ja einer.
    Wenn dein Projekt zu groß ist, könntest du auch ein klein Testprojekt machen - also genau das, was du uns eiglich aufnötigst, mit deim gezeigten Code - das könntest du auch selber machen, und fertig einstellen - statt das ich das machen muss.
    Konnte den Fehler jetzt sogar halbwegs beseitigen:
    Mein Fehler war, dass ich den GameLoop in einem Timer.Tick event drinnen hatte, welches relativ ungenau ist.
    Jetzt arbeite ich mit

    VB.NET-Quellcode

    1. Declare Function QueryPerformanceCounter Lib "Kernel32" (ByRef rückgabe As Long) As Integer
    2. Declare Function QueryPerformanceFrequency Lib "Kernel32" (ByRef rückgabe As Long) As Integer

    Durch diese Funktionen kann man ganz gut die FPS ausrechnen und einstellen wie schnell es laufen muss.
    Dadurch hat sich der Grafik-Fehler größtenteils beheben lassen.
    Manchmal ruckelt es noch minimal - dazu müsste ich glaube ich noch auf einen richtigen backBuffer zeichnen anstatt das DoubleBuffered = true zu verwenden.