Pathfindung Modul/Funktion

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

 

jeykey

Betreff: Pathfindung Modul/Funktion

BeitragMi, Sep 30, 2009 12:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich bin auf der Suche nach einen guten Pathfindung Modul oder einer Funktion. Ich habe mich auch schon einige Zeit damit beschäftigt und auch den A* Algorithmus selbst in BlitzMax programmiert. Allerdings habe ich so meine Zweifel, was die Geschwindigkeit meiner Eigenkreation betrifft. Kennt jemand möglicherweise ein fertiges Modul. Wie gesagt ich bin ziemlicher Anfänger und dieses Thema erscheint mir bisher eine Nummer so groß, es scheint mir so, als ob es keine optimale Lösung gibt.

Als Karte (ich nenne es Kollisionsmatrix) verwende ich ein 2d Byte Array. Meine Maps sind etwa maximal 100 * 100 Felder groß. Mein komplettes Wissen zu diesen Thema basiert größtenteils auf diesen Artikel:
http://www.policyalmanac.org/g...al_de.html

Gruß
jeykey

kriD

BeitragMi, Sep 30, 2009 17:07
Antworten mit Zitat
Benutzer-Profile anzeigen
für B3d gibts einen recht schnellen A* code (ich weiß allerdings nichtmehr, ob ich den von hier oder von woanders hab). das umprogrammieren dürfte nicht so schwer sein Smile

lg kriD
Wenn ich du wäre, wäre ich lieber ich!

BladeRunner

Moderator

BeitragMi, Sep 30, 2009 17:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe meine Funktionen im Codearchiv hinterlassen.
Einfach mal suchen.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92
 

jeykey

BeitragDo, Okt 01, 2009 16:46
Antworten mit Zitat
Benutzer-Profile anzeigen
@BladeRunner: Dein Algorithmus sieht ziemlich gut aus, danke.

Ich habe jetzt mal versucht meinen Algorithmus zu optimieren, allerdings ist er jetzt nicht mehr so universell einsetzbar, was aber für mein Spiel eh nicht nötig ist.

Hier mal der Code, vll findet jemand was zum Verbessern der Geschwindigkeit:
BlitzBasic: [AUSKLAPPEN]
SuperStrict

Graphics 1000, 1000

' Die Map erzeugen
Global map:Byte[,] = New Byte[100, 100]
For Local x:Int = 0 To 99
For Local y:Int = 0 To 99
If (Rand(0, 4) = 0) Then
map[x, y] = True
End If
Next
Next

Global aStar:TAStar = TAStar.Create(map, 100, 100)

While Not KeyDown(KEY_ESCAPE)
Cls
Local s:Int = MilliSecs()
DrawMap()
SetColor(0, 255, 0)
aStar.FindWay(0,0,MouseX() / 10, MouseY() / 10)
'Print GCMemAlloced()
SetColor(255, 255, 255)
DrawText(MilliSecs() - s, 0, 0)
Flip
Wend

' Zeichnet die Map
Function DrawMap()
SetColor(255, 255, 255)
For Local x:Int = 0 To 99
For Local y:Int = 0 To 99
If (map[x, y] <> 0) Then
DrawRect(x * 10, y * 10, 10, 10)
End If
Next
Next
End Function

' A* Klasse (nur für 2D Maps)
Type TAStar
Field startX:Int' Hier beginnt die Suche
Field startY:Int' Hier beginnt die Suche
Field endX:Int' Hier endet die Suche
Field endY:Int' Hier endet die Suche
Field collisionMap:Byte[,]' Speichert die Kollisionsmatrix
Field jointMap:TAStarJoint[,]' Speichert die Knotenpunkte
Field mapSizeX:Int
Field mapSizeY:Int
Field openList:TList' Die offene Liste
Field closedList:TList' Die geschlossene Liste
Field currentJoint:TAStarJoint' Gibt immer den momentanen Knotenpunkt an

' Erstellt eine neue A* Instanz
Function Create:TAStar(collisionMap:Byte[,], mapSizeX:Int, mapSizeY:Int)
Local aStar:TAStar = New TAStar
aStar.collisionMap = collisionMap
aStar.mapSizeX = mapSizeX
aStar.mapSizeY = mapSizeY
aStar.openList = CreateList()' Die offene Liste erstellen
aStar.closedList = CreateList()' Die geschlossene Liste erstellen
Return aStar
End Function

' Versucht den Weg vom Start zum Zielpunkt zu finden
Method FindWay(startX:Int, startY:Int, endX:Int, endY:Int)
' Initialisierungsphase
Self.startX = endX
Self.startY = endY
Self.endX = startX
Self.endY = startY
Self.jointMap = New TAStarJoint[Self.mapSizeX, Self.mapSizeY]' Die Knotenmatrix erstellen
If (Self.collisionMap[endX, endY] = True) Then
Return
End If
Self.currentJoint = TAStarJoint.Create(Self, Null, Self.startX, Self.startY)' Der Starknoten hat keinen Vorgänger
Self.openList.AddLast(Self.currentJoint)' Den Anfangspunkt ganz normal in die offene Liste eintragen
' Beginn des A* Algorithmus
Self.currentJoint.GetAdjacentJoints()' Anliegende Knoten untersuchen
Self.currentJoint.Close()' Den momentanen Knotenpunkt in die geschlossene Liste verschieben
' Jetzt als nächsten momentanen Punkt den mit den niedrigsten F - Kosten wählen
While (True)
If (Self.openList.IsEmpty() = True) Then
Exit
End If
Self.currentJoint = TAStarJoint(Self.openList.First())
Self.currentJoint.Close()' Den momentanen Knotenpunkt in die geschlossene Liste setzen
Self.currentJoint.GetAdjacentJoints()' Anliegende Knotenpunkte suchen

' Debug
'Print currentJoint.x + "|" + currentJoint.y + " - " + currentJoint.fCosts + " - " + currentJoint.gCosts + " - " + currentJoint.hCosts

If (Self.currentJoint.x = Self.endX And Self.currentJoint.y = Self.endY) Then
Exit
End If
Wend
' Jetzt den Pfad zurückberechnen
Local searchJoint:TAStarJoint = currentJoint
While (True)
DrawRect(searchJoint.x * 10, searchJoint.y * 10, 10, 10)
If (searchJoint.parentJoint = Null) Then
Exit
Else
searchJoint = searchJoint.parentJoint
End If
'Print searchJoint.x + "|" + searchJoint.y
Wend
Self.jointMap = Null
Self.openList.Clear()
Self.closedList.Clear()
End Method

' Fügt den Knotenpunkt zur offenen Liste hinzu
Method AddToOpenList(joint:TAStarJoint)
Self.jointMap[joint.x, joint.y] = joint
' Automatisch richtig einordnen, der Knotenpunkt mit den kleinsten F Wert ist immer der erste in der Liste
For Local searchJoint:TAStarJoint = EachIn Self.openList
If (joint.fCosts <= searchJoint.fCosts) Then
Self.openList.InsertBeforeLink(joint, Self.openList.FindLink(searchJoint))
Return
End If
Next
Self.openList.AddLast(joint)
End Method
End Type

' Ein vom A* verwendeter Knotenpunkt
Type TAStarJoint
Field aStar:TAStar
Field parentJoint:TAStarJoint' Die
Field x:Int
Field y:Int
Field fCosts:Int' Die F - Kosten
Field gCosts:Int' Die G - Kosten
Field hCosts:Int' Die K - Kosten
Field inOpenList:Byte = False' Gibt an ob sich der Punkt in der offenen Liste befindet
Field inClosedList:Byte = False' Gibt an ob sich der Punkt in der geschlossenen Liste befindet

' Erstellt einen neuen Knotenpunkt
Function Create:TAStarJoint(aStar:TAStar, parentJoint:TAStarJoint, x:Int, y:Int)
Local joint:TAStarJoint = New TAStarJoint
joint.aStar = aStar
joint.parentJoint = parentJoint
joint.x = x
joint.y = y
Return joint
End Function

' Sucht anliegene Knotenpunkte
Method GetAdjacentJoints()
Self.GetJoint(Self.x - 1, Self.y)
Self.GetJoint(Self.x + 1, Self.y)
Self.GetJoint(Self.x, Self.y - 1)
Self.GetJoint(Self.x, Self.y + 1)
End Method

' Versucht den Punkt an dieser Stelle in die offene Liste aufzunehmen
Method GetJoint(x:Int, y:Int)
' Prüfen ob der Punkt überhaupt in der Map liegt
If (x >= 0 And x < Self.aStar.mapSizeX And y >= 0 And y < Self.aStar.mapSizeY) Then
' Der Punkt befindet sich in der Map, doch ist er auch begehbar?
If (Self.aStar.collisionMap[x, y] = False) Then
' Der Punkt ist begehbar, doch er darf nicht bereits in der offenen oder geschlossenen Liste sein
If (Self.aStar.jointMap[x, y] = Null) Then
Self.inOpenList = True
' Jetzt eine Knotenpunkt Instanz dieses Punktes erstellen
Local joint:TAStarJoint = TAStarJoint.Create(Self.aStar, Self, x, y)
joint.CalculateCosts()
Self.aStar.AddtoOpenList(joint)' Den Knotenpunkt in die offene Liste eintragen
Else If (Self.aStar.jointMap[x, y].inOpenList = True) Then
'DebugSTop
End If
End If
End If
End Method

' Berechnet die Kostendaten dieses Punktes
Method CalculateCosts()
Self.gCosts = Self.parentJoint.gCosts + 10
Self.hCosts = (Abs(Self.x - Self.aStar.endX) + Abs(Self.y - Self.aStar.endY)) * 10
Self.fCosts = Self.gCosts + Self.hCosts
End Method

' Verschiebt den Punkt in die geschlossene Liste
Method Close()
Self.inOpenList = False
Self.inClosedList = True
Self.aStar.openList.Remove(Self)
Self.aStar.closedList.AddLast(Self)
End Method
End Type

kreisman

BeitragMo, Okt 05, 2009 19:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Du könntst z.b. für die OpenList anstelle einer Liste eine Sorted List oder noch besser einen Heap(wie auch von Patrick Lester in einem anderen Artikel gezeigt) benutzen, mit dem es schneller ist den Knoten in der Openlist zu finden, der den niedrigsten F-Wert besitzt. Dreamora hat da ein ganz gutes Beispiel im Codearchive gepostet. https://www.blitzforum.de/foru...hp?t=19489 Es ist zwar schon ein bisl älter aber zeigt ganz gut wie der funktionert.

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group