DrawImage flackert?
- VB.NET
Sie verwenden einen veralteten Browser (%browser%) mit Sicherheitsschwachstellen und können nicht alle Funktionen dieser Webseite nutzen.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Es gibt 30 Antworten in diesem Thema. Der letzte Beitrag () ist von nafets3646.
-
-
Ja du siehst es doch in der GIF.
Ich komme mit dem Spieler nicht bis an den Rand der Form, sondern irgendwo ist eine Grenze gezogen die ich ja nicht hin gemacht habe..
Code bis jetzt:
VB.NET-Quellcode
- Public Class Form1
- Private Declare Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As Int32) As Short
- Dim g As Graphics = Me.CreateGraphics
- Sub Render()
- Dim g As Graphics = Me.CreateGraphics
- paintPlayer(g)
- End Sub
- Private Sub paintPlayer(ByVal g As Graphics)
- Dim playerSprite As New Bitmap("C:\Unten.png")
- g.DrawImage(playerSprite, XPOS, YPOS, 30, 86)
- End Sub
- Dim XPOS As Integer
- Dim YPOS As Integer
- Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
- Label3.Text = XPOS
- Label4.Text = YPOS
- Dim hotkey1 As Boolean
- hotkey1 = GetAsyncKeyState(Keys.A)
- If hotkey1 = True Then
- XPOS = XPOS - 3
- Refresh()
- paintPlayer(g)
- End If
- Dim hotkey2 As Boolean
- hotkey2 = GetAsyncKeyState(Keys.D)
- If hotkey2 = True Then
- XPOS = XPOS + 3
- Refresh()
- paintPlayer(g)
- End If
- Dim hotkey3 As Boolean
- hotkey3 = GetAsyncKeyState(Keys.W)
- If hotkey3 = True Then
- YPOS = YPOS - 3
- Refresh()
- paintPlayer(g)
- End If
- Dim hotkey4 As Boolean
- hotkey4 = GetAsyncKeyState(Keys.S)
- If hotkey4 = True Then
- YPOS = YPOS + 3
- Refresh()
- paintPlayer(g)
- End If
- End Sub
- Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
- Me.DoubleBuffered = True
- SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.OptimizedDoubleBuffer Or ControlStyles.UserPaint, True)
- XPOS = 191
- YPOS = 131
- End Sub
- End Class
Wie kann ich denn das dauernd neue Laden des Bildes umgehen?
Mfg. TGS -
Du brauchst eine ordentliche Klassenstruktur. Wenn z.B. die Spielfigur in einer eigenen Klasse ist, dann kannst du dort alle Werte wie Position und aktuelles Bild speichern. Wenn sich der Zustand ändern soll veränderst du nur die Werte innerhalb der Klasse und rufst dann Invalidate auf. Dadurch wird das Paint-Event ausgelöst, in dem du dann alle Objekte auf einmal mit ihrem derzeitigen Status neuzeichnest. Das ist die einzige richtige Vorgehensweise in GDI eine Engine zu erstellen.
-
Hier ist mal ein kleines Beispiel, dass mit Doublebuffer nicht flackert. Kopier das mal in ein neues Projekt und guck obs klappt.
Spoiler anzeigen VB.NET-Quellcode
- WithEvents Timer1 As New Timer With {.Enabled = True, .Interval = 2}
- Dim counter As Single = 0
- Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
- Dim g As Graphics = e.Graphics
- With g
- .InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
- .PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
- .SmoothingMode = Drawing2D.SmoothingMode.HighQuality
- End With
- Dim radiusX As Integer = Me.Width \ 2 - 30
- Dim radiusY As Integer = Me.Height \ 2 - 30
- Dim x As Single = CSng(Math.Cos(counter) * radiusX) + Me.Width \ 2
- Dim y As Single = CSng(Math.Sin(counter) * radiusY) + Me.Height \ 2 - 25
- g.FillEllipse(Brushes.Black, x, y, 15, 15)
- End Sub
- Private Sub Timer1_Tick(sender As Object, e As System.EventArgs) Handles Timer1.Tick
- counter += 0.03F
- If counter = 359 Then counter = 0
- Me.Invalidate()
- End Sub
- Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
- Me.DoubleBuffered = True
- End Sub
-
Danke sehr, hat funktioniert.
Hier mein Code:
VB.NET-Quellcode
- Public Class Form1
- Private Declare Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As Int32) As Short
- WithEvents Timer1 As New Timer With {.Enabled = True, .Interval = 2}
- Dim counter As Single = 0
- Dim XPOS As Single
- Dim YPOS As Single
- Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
- Dim g As Graphics = e.Graphics
- With g
- .InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
- .PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
- .SmoothingMode = Drawing2D.SmoothingMode.HighQuality
- End With
- Dim playerSprite As New Bitmap("C:\Unten.png")
- g.DrawImage(playerSprite, XPOS, YPOS, 30, 86)
- End Sub
- Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
- counter += 0.03F
- If counter = 359 Then counter = 0
- Me.Invalidate()
- Dim hotkey1 As Boolean
- hotkey1 = GetAsyncKeyState(Keys.A)
- If hotkey1 = True Then
- XPOS = XPOS - 3
- End If
- Dim hotkey2 As Boolean
- hotkey2 = GetAsyncKeyState(Keys.D)
- If hotkey2 = True Then
- XPOS = XPOS + 3
- End If
- Dim hotkey3 As Boolean
- hotkey3 = GetAsyncKeyState(Keys.W)
- If hotkey3 = True Then
- YPOS = YPOS - 3
- End If
- Dim hotkey4 As Boolean
- hotkey4 = GetAsyncKeyState(Keys.S)
- If hotkey4 = True Then
- YPOS = YPOS + 3
- End If
- End Sub
- Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
- Me.DoubleBuffered = True
- End Sub
- End Class
Mfg. TGS -
Ich hab deinen Code mal ein bisschen verbessert, unter anderem hab ich die Tastenabfrage verkürzt und OPTION STRICT ON gemacht. Außerdem habe ich das Laden des Bildes verschoben, damit es nicht immer wieder aufs Neue geladen wird. Des weiteren habe ich noch das Zeichnen in die OnPaint-Sub gemacht und das Invalidaten an das Ende der Timer-Sub verschoben:
VB.NET-Quellcode
- Option Strict On 'Das Allerwichtigste, sollte in jedem Programm stehen
- Public Class Form1
- Private Declare Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As Int32) As Short
- WithEvents Timer1 As New Timer With {.Enabled = True, .Interval = 2}
- Dim counter As Single = 0
- Dim XPOS As Single
- Dim YPOS As Single
- Dim playerSprite As New Bitmap("C:\Unten.png") 'Das Laden des Bildes von der Festplatte hierhin verschieben
- Protected Overrides Sub OnPaint(e As PaintEventArgs) 'OnPaint zu Overriden ist noch einen minimalen Ticken schneller als das Event abzuwarten ;)
- With e.Graphics 'Du musst kein Graphics-Objekt deklarieren, wenn du schon eins hast
- '.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic 'Die Modes kannst du eigentlich weglassen, da ich denke, dass deine Spielfigur schon die richtige Größe hat,
- '.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality 'ansonsten kannst du sie auch wieder auskommentieren bzw. nicht so hoch stellen. Dies sollte die Performance deutlich erhöhen.
- '.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
- .DrawImage(playerSprite, XPOS, YPOS, 30, 86) 'Warum nicht gleich hier rein? :D
- End With
- MyBase.OnPaint(e)
- End Sub
- Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
- counter += 0.03F
- If counter = 359 Then counter = 0
- Dim XPOSOld As Single = XPOS
- Dim YPOSOld As Single = YPOS
- If CBool(GetAsyncKeyState(Keys.A)) Then XPOS = XPOS - 3 'kürzer und schneller, außerdem Option Strict On
- If CBool(GetAsyncKeyState(Keys.D)) Then XPOS = XPOS + 3
- If CBool(GetAsyncKeyState(Keys.W)) Then YPOS = YPOS - 3
- If CBool(GetAsyncKeyState(Keys.S)) Then YPOS = YPOS + 3
- If XPOS = XPOSOld AndAlso YPOS = YPOSOld Then Me.Invalidate() 'Invalidaten ans Ende verschoben und mit If-Abfrage versehen, da ich denke, dass du erst zeichnen willst, wenn die Werte von der Tastatur abgefragt wurden und auch nur, wenn sich irgendetwas geändert hat
- End Sub
- Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
- Me.DoubleBuffered = True
- End Sub
- End Class
//EDIT: Hab noch die Empfehlungen von ErfinderDesRades umgesetzt, allerdings habe ich das mit der Region beim invalidaten nicht ersetzt. Probiers aus :).Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „nafets3646“ ()
-
-
für DrawImage braucht man glaub keinen der Modes (InterpolationMode, .PixelOffsetMode, .SmoothingMode) zu manipulieren.
Wenn keine Taste gedrückt ist, sollteman auch kein .Invalidate() aufrufen.
Die Performance lässt sich ca. 50-fach steigern, wenn man bei Invalidate einschränkt, welches Rechteck zu neuzeichnen ist.
Ich kanns nicht ausprobieren, weil ich das Bildle nicht hab, aber hat der DoppelPuffer eine merkliche Auswirkung? -
Hab noch eine Frage.
Mit der Picturebox gings so, dass sie nicht mehr aus der Form kam:
VB.NET-Quellcode
- Dim ScreenSize As Size = Me.Size
- If PictureBox1.Left <= 0 Then
- PictureBox1.Left = 0
- ElseIf PictureBox1.Left + PictureBox1.Width >= ScreenSize.Width Then
- PictureBox1.Left = ScreenSize.Width - PictureBox1.Width
- End If
- If PictureBox1.Top <= 0 Then
- PictureBox1.Top = 0
- ElseIf PictureBox1.Top + PictureBox1.Height >= ScreenSize.Height Then
- PictureBox1.Top = ScreenSize.Height - PictureBox1.Height
- End If
Doch wie geht das nun mit GDI (Mit dem Code oben)?
Wäre nett, wenn mir da jemand helfen könnte
Danke, und mfg.
TGS -
-
Das geht dann so:
VB.NET-Quellcode
- Dim MovingRectangle As New Rectangle(New Point(10, 10), New Size(100, 100)) 'Das Rectangle, in dem sich die Figur bewegen kann
- Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
- counter += 0.03F
- If counter = 359 Then counter = 0
- Dim XPOSOld As Single = XPOS
- Dim YPOSOld As Single = YPOS
- If CBool(GetAsyncKeyState(Keys.A)) AndAlso XPOS - 3 >= MovingRectangle.X Then XPOS -= 3 'einfach noch ne zweite Bedingung, welche prüft, ob die Figur aus dem Rectangle rauslaufen würde
- If CBool(GetAsyncKeyState(Keys.D)) AndAlso XPOS + 3 <= MovingRectangle.X + MovingRectangle.Width - 30 Then XPOS += 3 'Die -30 steht für die Breite deiner Spielfigur
- If CBool(GetAsyncKeyState(Keys.W)) AndAlso YPOS - 3 >= MovingRectangle.Y Then YPOS -= 3
- If CBool(GetAsyncKeyState(Keys.S)) AndAlso YPOS + 3 <= MovingRectangle.Y + MovingRectangle.Height - 80 Then YPOS += 3 'Die -80 steht für die Höhe deiner Spielfigur
- If XPOS = XPOSOld AndAlso YPOS = YPOSOld Then Me.Invalidate() 'Invalidaten ans Ende verschoben und mit If-Abfrage versehen, da ich denke, dass du erst zeichnen willst, wenn die Werte von der Tastatur abgefragt wurden und auch nur, wenn sich irgendetwas geändert hat
- End Sub
-
Ähnliche Themen
-
GDI Rest der Form geht nicht mehr?
TheGameSiders - - Sonstige Problemstellungen