Der TE des Thema [VB 2010] Problem bei der umsetzung eines Games wollte ein TowerDefense mit dynamischen Routen der Monster programmieren - sie sollen also von alleine um die Türme herum laufen können, noch dazu auf dem kürzesten weg. Ich habe nun einen Weg-Finde-Algorithmus ähnlich der A*-Methode in VB.NET Realisiert.
Viel zu sagen gibt es denke ich nicht, selbst wer den Algorithmus nicht versteht oder verstehen will sieht sofort, wo er den code für sich anpassen kann. Der Pfad kann in der Auflistung "Wegpunkte" nachvollzogen werden. Ebenfalls werden die Wegpunkte in das intern verwendete "MapFormat" eingetragen.
Als input wird eine scharz/weiß-bitmap verlangt (schwarz = hinderniss, weiß = begehbar). Einfacher ist es - sofern man bereits eine eigene datenstruktur aufgebaut hat - direkt auf das intern genutzte "MapFormat" zurückzugreifen und eigene Karten etc in dieses umzuwandeln.
Um etwas zur Performance zu sagen: Der Code ist mit Sicherheit an der ein oder anderen Stelle ausbesserbar, eine 100x100 pixel große bitmap berechnet es allerdings in "nullkommanix" - und 100x100 Tiles sind schon einiges finde ich - vor allem für ein TowerDefense^^
Hier mal ein Video, dass die Funktion grafisch darstellt:
Hier der Source:
Spoiler anzeigen
und ein Anwendungsbeispiel..
EDIT: Im Showroom gibt es ab jezt eine Verbesserte/Erweiterte Version als OpenSource Lib: [Release] PathFinderLib 1.0
Viel zu sagen gibt es denke ich nicht, selbst wer den Algorithmus nicht versteht oder verstehen will sieht sofort, wo er den code für sich anpassen kann. Der Pfad kann in der Auflistung "Wegpunkte" nachvollzogen werden. Ebenfalls werden die Wegpunkte in das intern verwendete "MapFormat" eingetragen.
Als input wird eine scharz/weiß-bitmap verlangt (schwarz = hinderniss, weiß = begehbar). Einfacher ist es - sofern man bereits eine eigene datenstruktur aufgebaut hat - direkt auf das intern genutzte "MapFormat" zurückzugreifen und eigene Karten etc in dieses umzuwandeln.
Um etwas zur Performance zu sagen: Der Code ist mit Sicherheit an der ein oder anderen Stelle ausbesserbar, eine 100x100 pixel große bitmap berechnet es allerdings in "nullkommanix" - und 100x100 Tiles sind schon einiges finde ich - vor allem für ein TowerDefense^^
Hier mal ein Video, dass die Funktion grafisch darstellt:
Hier der Source:
VB.NET-Quellcode
- Public Class PathFinder
- Public Sub New(ByVal _MapPath As String, ByVal _start As Point, ByVal _ziel As Point)
- Dim tmp As New Bitmap(_MapPath)
- Start = _start
- Ziel = _ziel
- MapSize = tmp.Size
- Map = New Feld(MapSize.Width - 1, MapSize.Height - 1) {}
- For x = 0 To MapSize.Width - 1
- For y = 0 To MapSize.Height - 1
- Dim tmpFeld As New Feld
- If tmp.GetPixel(x, y).R > 50 Then
- tmpFeld.Hindernis = False
- Else
- tmpFeld.Hindernis = True
- End If
- Map(x, y) = tmpFeld
- Next
- Next
- 'startet die wegsuche
- Berechne()
- End Sub
- Public Start As New Point(10, 90)
- Public Ziel As New Point(90, 10)
- Public MapSize As New Size
- Public Map(,) As Feld
- Public Wegpunkte As New List(Of Point)
- Public Event NoWay()
- Public Sub Berechne()
- Dim lastLocs As New Queue(Of Point)
- Dim tmpGüte As Integer = 0
- Dim Nachbarn As New List(Of Point)
- Nachbarn.Add(Start)
- Dim Treffer As Boolean = False
- Dim KeinWeg As Boolean = False
- Do 'Until Treffer = True
- KeinWeg = True
- For Each n As Point In Nachbarn
- lastLocs.Enqueue(n)
- If Map(n.X, n.Y).Güte = -1 Then KeinWeg = False
- Next
- If KeinWeg = True Then RaiseEvent NoWay()
- Do
- Dim loc As Point = lastLocs.Dequeue
- Dim F As Feld = Map(loc.X, loc.Y)
- If F.Güte = -1 Then
- Map(loc.X, loc.Y).Güte = tmpGüte
- If loc = Ziel Then Treffer = True
- 'nachbarpunkte der newlastlocsliste hinzufügen
- Dim x As Integer = loc.X
- Dim y As Integer = loc.Y
- Dim Ld As Point = New Point(x - 1, y - 1)
- Dim points() As Point = New Point() {New Point(x + 1, y), New Point(x - 1, y), New Point(x, y - 1), New Point(x, y + 1)}
- For Each p As Point In points
- If p.X >= 0 AndAlso p.X < MapSize.Width AndAlso p.Y >= 0 AndAlso p.Y < MapSize.Height Then
- Dim cn As Feld = Map(p.X, p.Y)
- If cn.Hindernis = False AndAlso cn.Güte = -1 Then
- Nachbarn.Add(p)
- End If
- End If
- Next
- End If
- Loop While (Treffer = False) AndAlso (lastLocs.Count <> 0) AndAlso (KeinWeg = False)
- tmpGüte += 1
- Loop While (Treffer = False) AndAlso (KeinWeg = False)
- 'rückverfolgung des weges
- If Treffer = True Then
- Wegpunkte.Add(Ziel)
- Do While tmpGüte > 0
- Map(Wegpunkte.Last.X, Wegpunkte.Last.Y).Wegpunkt = True
- Wegpunkte.Add(GetBefore(Wegpunkte.Last))
- tmpGüte -= 1
- Loop
- End If
- End Sub
- Function GetBefore(ByVal loc As Point) As Point
- Dim x As Integer = loc.X
- Dim y As Integer = loc.Y
- Dim currentGüte As Integer = Map(x, y).Güte
- Dim points() As Point = New Point() {New Point(x + 1, y), New Point(x - 1, y), New Point(x, y - 1), New Point(x, y + 1)}
- For Each p As Point In points
- If p.X >= 0 AndAlso p.X < MapSize.Width AndAlso p.Y >= 0 AndAlso p.Y < MapSize.Height Then
- If Map(p.X, p.Y).Güte < currentGüte AndAlso Map(p.X, p.Y).Güte >= 0 Then
- Return p
- End If
- End If
- Next
- End Function
- Class Feld
- Public Hindernis As Boolean = False
- Public Wegpunkt As Boolean = False
- Public Güte As Integer = -1
- End Class
- Sub ErrorMsgBox() Handles Me.NoWay
- MsgBox("Es existiert kein möglicher weg!")
- End Sub
- Public Function ToBitmap() As Bitmap
- Dim tmp As New Bitmap(MapSize.Width, MapSize.Height)
- Dim c As Color = Color.Black
- For x = 0 To MapSize.Width - 1
- For y = 0 To MapSize.Height - 1
- c = Color.Black
- If Map(x, y).Hindernis = True Then c = Color.Gray
- If Map(x, y).Wegpunkt = True Then c = Color.Red
- tmp.SetPixel(x, y, c)
- Next
- Next
- Return tmp
- End Function
- End Class
und ein Anwendungsbeispiel..
EDIT: Im Showroom gibt es ab jezt eine Verbesserte/Erweiterte Version als OpenSource Lib: [Release] PathFinderLib 1.0
Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „FreakJNS“ ()