Pacman Wegfindung... Meine Geister sind dumm

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

M0rgenstern

Betreff: Pacman Wegfindung... Meine Geister sind dumm

BeitragFr, Apr 30, 2010 15:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey Leute.

Ich hab schon wieder ein Problem mit meinem Pacman Klon.
UNdzwar bei der Wegfindung an Kreuzungen.
Das Problem ist folgendes: Der Geist erkennt sehr wohl, dass er eine Kreuzung erreicht (sehe ich an einer Ausgabe im Debuglog und an seinem Verhalten), aber: Er bewegt sich entweder weiter in seine momentane Richtung oder in die entgegengesetzte, aber scheinbar niemals in die dritte mögliche. Das bedeutet, dass er im Prinzip immer auf der gleichen "Ebene" im Level bleibt.
Hier hab ich mal den Code der Funktion, die den neuen Weg auswählt:

BlitzMax: [AUSKLAPPEN]
Method GetWay(pCollLeft:Int, pCollRight:Int, pCollUp:Int, pCollDown:Int)
Local iOldDirection:Int = idirection
Local iWays:Int
Local itries:Int = 0, iNewDirection:Int = 0
Local iSum:Int = 0

If pCollLeft = 0 Then
iWays:+1
iSum = iSum + 3
EndIf
If pCollRight = 0 Then
iWays:+1
iSum = iSum + 4
EndIf
If pCollUp = 0 Then
iWays:+1
iSum = iSum + 1
EndIf
If pCollDown = 0 Then
iWays:+1
iSum = iSum + 2
EndIf

DebugLog " Direction vorher " + iDirection + " bei Zeit=" + MilliSecs()

If iWays = 3 Then
If ((iLastSearch + iSearchStart) < MilliSecs()) Then
Repeat
iSearchStart = MilliSecs()
itries:+1
'Hier wird die Richrung in Abhängigkeit von der Prüfsumme neu zugewiesen.
If iSum = 6 Then 'Hoch, Runter, Links
iDirection = Rand(1, 3)
End If
If iSum = 7 Then 'Hoch, Rechts, Runter
iDirection = Rand(1, 3)
If iDirection = 3 Then iDirection = 4
EndIf
If iSum = 8 Then 'Links, Hoch, Rechts
iDirection = Rand(2, 4)
If iDirection = 2 Then iDirection = 1
EndIf
If iSum = 9 'Links, Runter, Rechts
iDirection = Rand(2, 4)
EndIf

'Überprüfen, dass er nicht einfach rückwärts läuft
If (iDirection <> iOldDirection) Then iNewDirection = 1
If (iOldDirection = 1) And (iDirection = 2) Then iNewDirection = 0
If (iOldDirection = 2) And (iDirection = 1) Then iNewDirection = 0
If (iOldDirection = 3) And (iDirection = 4) Then iNewDirection = 0
If (iOldDirection = 4) And (iDirection = 3) Then iNewDirection = 0
Until ((iNewDirection = 1) Or (itries > 20))
EndIf
Else
iDirection = iOldDirection
EndIf

DebugLog "Felder um Spieler herum:"
Local locx:Int, locy:Int
locx = fx / iTileSize
locy = fy / iTileSize
DebugLog " Ich bei: (" + locx + "/" + locy + ")...Inhalt=" + iGameMap[locx, locy, 1]
DebugLog "Wege: " + iWays


locx = fx / iTileSize
locy = (fy - fSpeed - iTileSize / 2) / iTileSize
DebugLog " Oben bei: (" + locx + "/" + locy + ")...Inhalt=" + iGameMap[locx, locy, 1]
locx = fx / iTileSize
locy = (fy + fSpeed + iTileSize / 2) / iTileSize
DebugLog " Unten bei: (" + locx + "/" + locy + ")...Inhalt=" + iGameMap[locx, locy, 1]
locx = (fx - fSpeed - iTileSize / 2) / iTileSize
locy = fy / iTileSize
DebugLog " Links bei: (" + locx + "/" + locy + ")...Inhalt=" + iGameMap[locx, locy, 1]
locx = (fx + fSpeed + iTileSize / 2) / iTileSize
locy = fy / iTileSize
DebugLog "Rechts bei: (" + locx + "/" + locy + ")...Inhalt=" + iGameMap[locx, locy, 1]

DebugLog " Direction nachher: " + iDirection

End Method


Die macht im Prinzip nichts anderes, als nachzuschauen, ob 3 Wege frei sind, eine Prüfsumme zu errechnen und demnach eine neue Richtung zufällg auszuwählen.

Die Übergabe an die Methode GetWay findet hier statt:

BlitzMax: [AUSKLAPPEN]
	Method Move()
Local iTileX:Int = fx / itilesize
Local iTileY:Int = fy / itilesize
Local fnewX:Float = fx
Local fNewY:Float = fy
Local iSet:Int = 0

Local iTileX1:Int
Local iTileX2:Int
Local iTileY1:Int
Local iTIleY2:Int


Select iDirection
Case 1 'Hoch

fNewY = fy - fSpeed

iTileX1 = fx / iTilesize
iTileY1 = (fNewY - itilesize / 2) / iTilesize
iTIleY2 = (fNewY + itilesize / 4) / iTilesize

If iGameMap[iTileX1, iTileY1, 1] = 0 Then
iSet = 1
fy = fNewY
EndIf



Case 2 'Runter

fNewY = fy + fSpeed

iTileX1 = fx / iTilesize
iTileY1 = (fNewY + itilesize / 2) / iTilesize

If iGameMap[iTileX1, iTileY1, 1] = 0 Then
iSet = 1
fy = fNewY
End If



Case 3 'Links

fnewX = fx - fSpeed

iTileY1 = fy / iTilesize
iTileX1 = (fnewX - itilesize / 2) / iTilesize

If iGameMap[iTileX1, iTileY1, 1] = 0 Then
iSet = 1
fx = fnewX
End If

Case 4 'Rechts

fnewX = fx + fSpeed

iTileY1 = fy / iTilesize
iTileX1 = (fnewX + itilesize / 2) / iTilesize

If iGameMap[iTileX1, iTileY1, 1] = 0 Then
iSet = 1
fx = fnewX
End If

End Select

'Berechnung hier:
Local iCollLeft:Int = igamemap[itilex1 - 1, itiley1, 1]
Local iCollRight:Int = igamemap[itilex1 + 1, itiley1, 1]
Local iCollDown:Int = igamemap[iTilex1, iTileY1 + 1, 1]
Local iCollUp:Int = igamemap[iTileX1, iTileY1 - 1, 1]

If iSet = 1 Then
'Übergabe:
GetWay(iCollLeft, iCollRight, iCollUp, iCollDown)
EndIf

If iSet = 0 Then
GetDirection()
End If

End Method


Berechnet wird alles für die Tiles wie ihr sehen könnt in der Move Methode.

Tut mir leid, aber ich kann meinen Fehler echt nicht finden.
Ist die Art wie ich das mache eigentlich okay, oder gibts da ne bessere Möglichkeit?

Wäre echt toll wenn mir jemand helfen würde.

Lg, M0rgenstern

ProggerOrk

BeitragFr, Apr 30, 2010 16:54
Antworten mit Zitat
Benutzer-Profile anzeigen
hmm deinen Code hab ich mir jetzt nicht ganz angesehen. Aber ich hab das so gemacht:

Code: [AUSKLAPPEN]
global FreeWay:byte[3]   'Diese Variable speichert die 3 freien Wege (maximal)
global FreeWaySum:byte 'Diese Variable speichert wieviele freie Wege es gibt...


und danach einfach(Kollisionsprüfung natürlich vorrausgesetzt:

Code: [AUSKLAPPEN]
NextDirection = FreeWay[rand(0,FreeWaySum-1)]


Und einen neuen freien Weg ordnest du einfach z.B so zu


Code: [AUSKLAPPEN]
FreeWaySum:+1
FreeWay[FreeWaySum-1] = Direction
Aktuelles Spiel: Treasure Miner
Mehr Informationen unter:
http://www.pucupo-games.de

M0rgenstern

BeitragFr, Apr 30, 2010 17:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Du, sorry.
Aus deinem Code werde ich nicht so wirklich schlau.
Ich habe ja vier Richtungen.
Könntest du mir das bitte ein wenig genauer erklären?

Was ich efinach seltsam an meinem Code finde: In einer SChlaife, die maximal 100 durchläufe haben kann, schafft er es scheinbar aus 3 zufälligen Zahlen 100mal genau die beiden rauszusuchen die dann dazu führen, dass er die alte Richtung beibehält bzw die entgegengesetzte einschlägt (Wenn die Schleife hundertmal durchlaufen wurde, dann wird einfach die letzte Zahl übernommen die er zufällig erhalten hat).

Lg, M0rgenstern

ProggerOrk

BeitragSa, Mai 01, 2010 2:13
Antworten mit Zitat
Benutzer-Profile anzeigen
ja kann ich machen^^

Du hast ja insgesamt genau 4 Richtungen, wobei 1 Richtung ja die Richtung ist, aus welcher der Gegner ja gerade kommt. Sprich du musst nur die Wege hinzufügen, die auch wirklich begehen werden können.

Code: [AUSKLAPPEN]
FreeWay[3]:byte


ist ein Array, welches genau maximal 3 Werte speichert. Sprich maximal die üblichen 3 Richtungen , die der Gegner laufen kann.

Das bedeutet du überprüfst vorher alle 3 Richtungen, ob sie frei sind oder nicht. Falls die Richtung frei ist fügst du diesem Array die neue Richtung hinzu.

Code: [AUSKLAPPEN]
FreeWaySum:+1
FreeWay[FreeWaySum-1] = Direction


Dadurch wird in diesem Fall die variable erhöht , die dir anzeigt das eine zusätziche Richtung hinzugefügt wurde. "FreeWay" speichert also quasi allle freien Richtungen, die vorhanden sind.

Da du auch die Anzahl der freien Wege hast "FreeWaySum" , kannst du ganz einfach eine der freien Richtungen per Rand bestimmen...

Code: [AUSKLAPPEN]
NextDirection = FreeWay[rand(0,FreeWaySum-1)]


Musst halt vorher per Collisionsabfrage bestimmen ob die Richtung frei ist, falls ja wird sie dem Array hinzugefügt, ansonsten nicht.

"FreeWaySum" , wird dann am Ende des Schleifendurchgangs wieder auf 0 gesetzt und danach wird fleißig wieder die freien Richtungen hinzugefügt^^

Bin nicht so gut im Erklären und zusätzlich kommt noch der Alkohol im Spiegel xD

hehe^^ aber so funktioniert das eigtl ganz gut. und er kann halt auch wirklich nur die Richtung generieren, die wirklich frei und vorhanden ist.
Aktuelles Spiel: Treasure Miner
Mehr Informationen unter:
http://www.pucupo-games.de

M0rgenstern

BeitragSa, Mai 01, 2010 12:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Also, das Prinzip hab ich verstanden.
Hört sich auch super an.
Aber der Geist zeigt immernoch das gleiche Verhalten wie vorher.
Hier mal der neue Code:

BlitzMax: [AUSKLAPPEN]
	Method GetWay(pCollLeft:Int, pCollRight:Int, pCollUp:Int, pCollDown:Int)
Local iOldDirection:Int = idirection
Local iWays:Int = 0
Local itries:Int = 0, iNewDirection:Int = 0
Local iSum:Int = 0

If pCollLeft = 0 Then
iWays:+1
iSum = iSum + 3
bfreeways[iways - 1] = 3
EndIf
If pCollRight = 0 Then
iWays:+1
iSum = iSum + 4
bfreeways[iways - 1] = 4
EndIf
If pCollUp = 0 Then
iWays:+1
iSum = iSum + 1
bfreeways[iways - 1] = 1
EndIf
If pCollDown = 0 Then
iWays:+1
iSum = iSum + 2
bfreeways[iways - 1] = 2
EndIf

DebugLog " Direction vorher " + iDirection + " bei Zeit=" + MilliSecs()

If iWays = 3 Then
If ((iLastSearch + iSearchStart) < MilliSecs()) Then
Repeat
iSearchStart = MilliSecs()
itries:+1
idirection = bfreeways[Rand(0, iways - 1)]
If (idirection <> iolddirection) Then inewdirection = 1
Until ((iNewDirection = 1) Or (itries > 20))
EndIf
Else
iDirection = iOldDirection
EndIf



End Method



Ich hab hier mal den Download, damit man sich vielleicht selbst ein Bild machen kann.
Einfach die WM-Man(main).debug.exe starten und dann mal enter drücken.

https://www.blitzforum.de/upload/file.php?id=8460

Lg, M0rgenstern

ProggerOrk

BeitragSa, Mai 01, 2010 12:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Moin,

warum eigentlich eine RepeatSchleife? In das Array "bfreeways" sollen nur die Richtungen gespeichert werden die auch erlaubt sind, bzw auch frei ohne Kollision sind.

Durch das "Rand" kannst du dann eigentlich immer eine richtige Richtung rauspicken ohne mehrere Versuche zu starten. Das ganze kann man natürlich dann noch verfeinern, mit der Bewertung der jeweiligen Position , aber das brauchen wir gerade ja nicht.

Er soll halt nur die alte Richtung einschlagen, wenn es keine Möglichkeiten gibt sprich "iWays = 0" ..

Und die alte Richtung , soll dann wahrscheinlich auch die Richtung sein aus der er kam? Oder soll er auch umkehren, auch wenn es mehrere Möglichkeiten gibt?

Falls nicht musst du , wenn er nach rechts geht, die linke Seite sperren, außer es gibt keine anderen Möglichkeiten.

Noch ein kleiner Code:

Dafür gehe ich davon aus das 0 = oben , 1 = rechts, 2 = unten und 3 = links ist und ich habe dein pCollLeft usw in ein Array verfrachtet um es einfacher abzufragen.

Code: [AUSKLAPPEN]
Global pColl:byte[4]
   
Method GetWay()
   
      Local iOldDirection:Int
      Local iWays:Int = 0
      
      'Kehre die Richtung um und sperre den Rückweg
      Select iDirection
         Case 0
            iOldDirection = 2
         Case 1
            iOldDirection = 3
         Case 2
            iOldDirection = 0
         Case 3
            iOldDirection = 1
      End Select
      
      'Hier wird geprüft ob die Richtung frei ist und nicht der gesperrten Richtung entsperrt
      For Local i:int = 0 To 3
         If pColl[i] = 0 And i <> iOldDirection Then
            iWays:+1
            bfreeways[iWays-1] = i
         End If
      Next
      
      'Nun haben wir die freien Richtungen, die er gehen kann
      'Aber wir müssen noch prüfen ob mindestens 1 Weg frei ist, falls nicht kehre um
      If iWays = 0 Then
         iDirection = iOldDirection
      Else
         iDirection = bfreeways[rand(0,iways-1)]
      End If
      
   End Method
Aktuelles Spiel: Treasure Miner
Mehr Informationen unter:
http://www.pucupo-games.de

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group