Bewegte Figur

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 27 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Bewegte Figur

    Guten Abend,

    ich würde ganz gerne eine sich bewegende Figur darstellen.
    Nur, was ist der beste Weg dahin?

    Hatte gedacht die Figur in emf zu erstellen, da ich mit CAD gut umgehen kann.

    Oder sollte man das alles aus der GDI machen? (Das ist aber sehr komplex, damit eine Figur zu Zeichnen)
    BMP/JPG (ist auch eine Möglichkeit :/ )

    Wollte einfach 3 Bilder immer nacheinander anzeigen. (jeweils für hoch, runter, links, rechts)

    Was meint Ihr? Was ist der beste Ansatz eine laufende Fugur darzustellen?

    kiter20
    "Mann" lernt mit seinen Projekten.
    Komplex ist GDI(+) eigentlich nicht. Es ist sehr einfach verständlich, wie ich finde.

    Ich würde auf eine GraphicsPath zurückgreifen. Oder aber du schreibst dir eine eigene Klasse dafür. Mit Bitmaps ist es natürlich auch möglich, wobei das dann eher eine starre Animation ist. Wie weit kennst du dich denn schon in GDI aus?

    LG


    Was hast du vor? Ein Spiel? In dem Fall bietet sich GDI+ NICHT an, denn es ist performance-technisch völlig am Arsch. Hier würde man dann OpenGL oder DirectX verwenden.
    Grüße
    "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

    Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!
    Ich denke mit GDI habe ich gute Grundkenntnisse. (Habe nen code um dxf einzulesen und nachzuzeichnen geschrieben.)
    Mit komplex meine ich die Figur an sich. Es ist einfacher eine Figur zu zeichnen, wenn man sofort sieht was man macht.



    Nikx schrieb:

    Ein Spiel?

    Ja.
    Aber ich denke die GDI reicht.
    Kein bewegter Hintergrund. Nur eine Figur die sich von einem Ort zum anderen bewegt . Sonst nur ein paar Objekte welche sich hin und her bewegen.
    Ich möchte mich auch nicht in OpenGL oder DirectX reinarbeiten.

    kiter20
    "Mann" lernt mit seinen Projekten.
    Da wuerde ich einfach ein Sprite-Sheet nehmen.

    z.B. Link.



    (Quick'n'Dirty)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Sprite
    2. Public Link As Image
    3. Public X, Y As Integer
    4. Public Index As Integer
    5. Public Runs As Boolean = False
    6. Public Enum Directions
    7. Left
    8. Right
    9. End Enum
    10. Public Direction As Directions = Directions.Left
    11. Public Sub New(ByVal x As Integer, ByVal y As Integer)
    12. Link = Image.FromFile("link.png")
    13. Me.X = x
    14. Me.Y = y
    15. End Sub
    16. Public Sub DrawTile(ByVal g As Graphics)
    17. Index += 1
    18. If Index > 6 Then
    19. Index = 0
    20. End If
    21. If Not Runs Then
    22. Index = 3
    23. End If
    24. Select Case Direction
    25. Case Directions.Left
    26. g.DrawImage(Link, New Rectangle(X, Y, 32, 48), New Rectangle(Index * 32, 0, 32, 48), GraphicsUnit.Pixel)
    27. Case Directions.Right
    28. g.DrawImage(Link, New Rectangle(X, Y, 32, 48), New Rectangle(Index * 32, 48, 32, 48), GraphicsUnit.Pixel)
    29. End Select
    30. Runs = False
    31. End Sub
    32. End Class

    And i think to myself... what a wonderfuL World!

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

    @Eddy du bist schon einen Schritt weiter.

    Mir geht es erst einmal um den Grundgedanken. JPG / BMP / EMF / GDI ?
    Mit was arbeitet man am besten ?

    sry Eddy, ich sollte rst lesen dann schreiben. "Sprite -Sheet" ist auch ein Weg.
    "Mann" lernt mit seinen Projekten.
    JPG und GDI sind erstmal zwei grundverschiedene Sachen. Klopp dir das bitte rein.
    JPG ist ein Bildformat, GDI ist eine Zeichenschnittstelle.

    Grüße
    "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

    Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!

    kiter20 schrieb:

    Mit was arbeitet man am besten ?


    Da du weder DirectX oder OpenGl nehmen willst, ist GDI schon eine Option, wenns nur eine kleinere Animation ist, wirds wohl reichen. WPF ist sicher auch eine gute alternative, aber wie gross da der Aufwand ist, kann ich nicht einschaetzen, das Resultat waere sicher schoener.
    And i think to myself... what a wonderfuL World!
    @Eddy Was hat denn WPF jetzt damit zu tun? Klar, für Animationen geeignet, aber fürs Zeichnen einzelner Abfolgen für Spiele ebenfalls Nonsens.

    Grüße
    "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

    Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!
    Wollte WPF nur nicht unerwaehnt lassen, aber kiter20 sagte auch:


    Kein bewegter Hintergrund. Nur eine Figur die sich von einem Ort zum anderen bewegt . Sonst nur ein paar Objekte welche sich hin und her bewegen.


    In diesem Rahmen wird man mit beiden Technologien, schon etwas nutzbares erschaffen koennen.
    And i think to myself... what a wonderfuL World!
    Es ist völlig unerheblich, in welchem Format oder mit welchem Programm du die Animation erstellst. So lange du es in deinem Programm einlesen kannst, kannst du das Männchen auch mit Word zeichnen wenn du lustig bist.
    @kiter20 Ich warne aber, die Sprite-Klasse von @Eddy ist totaler Mist.

    Grüße
    "Life isn't about winning the race. Life is about finishing the race and how many people we can help finish the race." ~Marc Mero

    Nun bin ich also auch soweit: Keine VB-Fragen per PM! Es gibt hier ein Forum, verdammt!
    Also ich hab ein paar Standard-Kriterien für bewegliche OwnerDraw-Figuren:
    1. muss sich jederzeit neu zeichnen können
    2. muss unabhängig davon jederzeit seine Bounds angeben können - das umschließende Rechteck der Figur
    3. muss natürlich eine bewegliche Positions-Angabe bereitstellen
    Könnte man glatt als abstrakte Klasse formulieren, oder als Interface - wäre vlt. keine schlechte Idee:

    VB.NET-Quellcode

    1. Public Interface IOwnerDrawFigure
    2. ''' <summary> der Bereich des Controls, den diese Figur einnimmt. </summary>
    3. ''' <remarks> vor **und** nach Ortsveränderungen ist ctrl.Invalidate(figure.Bounds) aufzurufen, um gezieltes
    4. ''' Neuzeichnen beider Bereiche anzustossen: Wo sie vorher war (löschen), und wo sie anschließend ist. </remarks>
    5. ReadOnly Property Bounds As Rectangle
    6. Property Location As Point
    7. Sub Draw(g As Graphics)
    8. End Interface
    Deine Klasse erfüllt eiglich keinen dieser Punkte richtig.
    1) erfüllt sie, aber mit unvorhergesehenem Verhalten: Beim Zeichnen verändert sie selbst ihren Zustand, reproduziert ihre Darstellung also nicht konsistent.
    Das kann zu Darstellungsfehlern führen, etwa dass ein Bein beim Gehen sowohl als das vordere als auch als hinteres dargestellt ist.

    Also Zustandsänderungen müssen vom Zeichenvorgang getrennt sein. Denn nicht nur die Anwendung löst Neuzeichnen aus, sondern auch das OS stößt Neuzeichnen an, nämlich wenn Fenster anderer Anwendungen sich über deine Anwendung bewegt werden.
    In solchen Fällen muss die Figur ihre Darstellung exakt wieder herstellen wie sie war.

    Dieser Beitrag wurde bereits 10 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ok, hab das ein wenig verbessert. Mit einem Interface finde ich auch schuggelig, hab ich mal mit rein gemacht.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Enum Directions
    2. Up = 0
    3. Right = 1
    4. Down = 2
    5. Left = 3
    6. End Enum
    7. Public Class Sprite
    8. Implements ISprite
    9. Public X, Y, Width, Height, Speed As Integer
    10. Private Direction As Directions = Directions.Down
    11. Private Link As New Bitmap("Link.png")
    12. Private Walking As Boolean = False
    13. Public Sub Move(ByVal direction As Directions)
    14. Me.Direction = direction
    15. Walking = True
    16. Select Case direction
    17. Case Directions.Up
    18. Y -= Speed
    19. Case Directions.Right
    20. X += Speed
    21. Case Directions.Down
    22. Y += Speed
    23. Case Directions.Left
    24. X -= Speed
    25. End Select
    26. End Sub
    27. Public Sub New(ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, Optional ByVal speed As Integer = 4)
    28. Me.X = x
    29. Me.Y = y
    30. Me.Width = width
    31. Me.Height = height
    32. Me.Speed = speed
    33. End Sub
    34. Public ReadOnly Property Bounds As System.Drawing.Rectangle Implements ISprite.Bounds
    35. Get
    36. Return New Rectangle(X, Y, Width, Height)
    37. End Get
    38. End Property
    39. Public Sub Draw(ByVal g As System.Drawing.Graphics) Implements ISprite.Draw
    40. Static xTileIndex As Integer = 3
    41. Dim yTileIndex As Integer = Direction
    42. xTileIndex += 1
    43. If xTileIndex > 6 Then
    44. xTileIndex = 0
    45. End If
    46. If Not Walking Then
    47. xTileIndex = 3
    48. End If
    49. Dim src As New Rectangle(xTileIndex * Width, yTileIndex * Height, Width, Height)
    50. Dim dest As Rectangle = Bounds
    51. g.DrawImage(Link, dest, src, GraphicsUnit.Pixel)
    52. Walking = False
    53. End Sub
    54. Public Property Location As System.Drawing.Point Implements ISprite.Location
    55. Get
    56. Return New Point(X, Y)
    57. End Get
    58. Set(ByVal value As System.Drawing.Point)
    59. X = value.X
    60. Y = value.Y
    61. End Set
    62. End Property
    63. End Class


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Interface ISprite
    2. ReadOnly Property Bounds() As Rectangle
    3. Property Location() As Point
    4. Sub Draw(ByVal g As Graphics)
    5. End Interface


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Imports System.Runtime.InteropServices
    3. Public Class FrmGame
    4. <DllImport("user32.dll")> _
    5. Shared Function GetAsyncKeyState(ByVal vKey As System.Windows.Forms.Keys) As Short
    6. End Function
    7. Private Link As New Sprite(100, 100, 32, 48)
    8. Private StayAlive As Boolean = True
    9. Private Looop As Thread
    10. Private Sub Looping()
    11. While StayAlive
    12. Dim up, right, down, left As Boolean
    13. up = GetAsyncKeyState(Keys.Up) <> 0
    14. right = GetAsyncKeyState(Keys.Right) <> 0
    15. down = GetAsyncKeyState(Keys.Down) <> 0
    16. left = GetAsyncKeyState(Keys.Left) <> 0
    17. If right Then
    18. BeginInvoke(Sub() Render(Directions.Right))
    19. End If
    20. If left Then
    21. BeginInvoke(Sub() Render(Directions.Left))
    22. End If
    23. If up Then
    24. BeginInvoke(Sub() Render(Directions.Up))
    25. End If
    26. If down Then
    27. BeginInvoke(Sub() Render(Directions.Down))
    28. End If
    29. If Not (up Or right Or down Or left) Then
    30. BeginInvoke(Sub() Invalidate(Link.Bounds()))
    31. End If
    32. Thread.Sleep(35)
    33. End While
    34. End Sub
    35. Private Sub Render(ByVal direction As Directions)
    36. Dim r As Rectangle = Link.Bounds()
    37. Invalidate(r)
    38. Link.Move(direction)
    39. r = Link.Bounds()
    40. Invalidate(r)
    41. End Sub
    42. Private Sub FrmGame_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    43. StayAlive = False
    44. End Sub
    45. Private Sub FrmGame_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown
    46. Looop = New Thread(AddressOf Looping)
    47. Looop.Start()
    48. End Sub
    49. Private Sub FrmGame_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    50. Link.Draw(e.Graphics)
    51. End Sub
    52. End Class


    Edit
    hab sogar noch einen kleinen Fehler in der Sub Render, da stimmte die Reihenfolge nicht.

    VB.NET-Quellcode

    1. [b][/b] Private Sub Render(ByVal direction As Directions)
    2. Dim r As Rectangle = Link.Bounds()
    3. Link.Move(direction)
    4. Invalidate(r)
    5. r = Link.Bounds()
    6. Invalidate(r)
    7. End Sub[b][/b]

    Dateien
    • SpriteSheets.zip

      (39,64 kB, 116 mal heruntergeladen, zuletzt: )
    And i think to myself... what a wonderfuL World!

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Eddy“ ()

    aber warum nennst du das Interface ISprite?
    Es kann alle möglichen ZeichenFiguren geben, eine SpriteSheet-Figur ist nur ein ganz spezieller Spezialfall davon.

    Und das mit dem Threading ist auch total komisch.
    Zieh doch einfach einen Timer aufs form, dann brauchst du weder Thread noch die Invoking-Umständlichkeit.
    Die benamung ist wirklich mehr als schlecht gewaehlt. Ein Timer haette es hier wirklich getan, war gedanklich schon dabei ein Gameloop rein zu machen, da habe ich immer mit festgelegter Framerate gearbeitet(mit GetTickCount Zeitabstaende gemessen), da sind Threads praktisch, einfach den Thead solange kein Update stattfinden soll schlafen legen(Loop mit Sleep(1)).
    And i think to myself... what a wonderfuL World!