Bewegungsreichweite eines taktischen Kampfsystems

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

Skabus

Betreff: Bewegungsreichweite eines taktischen Kampfsystems

BeitragSo, Nov 15, 2009 0:11
Antworten mit Zitat
Benutzer-Profile anzeigen
Guten Abend,

Ich hab momentan etwas Zeit, deswegen brüte ich wieder über meinem Kampfsystem für Aves Certim.
Ich bin dabei auf ein etwas tiefgreifenderes Problem gestoßen und würe mich freuen wenn ihr mir
eure Ideen dazu vermitteln könntet Smile

Ich programmiere ein taktisches Kampfsystem und brauche dafür eine Routine die mir einen Array ausspuckt
in dem die Bewegungsmöglichkeiten eines Charakters enthalten sind.Die Bewegung ist ganz einfach.

->Ich haben einen Wert(Aktionspunkte) die quasi als Wärung der Bewegung fungiert.

->Meine Karte ist in 16*16 Kacheln angelegt und jede Bewegung von Kachel zu Kachel kostet 1 AP

Nun soll der aktuelle Charakter entsprechend der Aktionspunkte einen Radius angezeigt bekommen
in dem er sich bewegen kann.Dabei kann er nur soviele Schritte gehen, wie er Aktionspunkte besitzt.
Hat ein Charakter 2 AP kann er 2 Schritte gehen.Sein resultierender Aktionsradius sieht dann so aus:


user posted image


Das Kreuz ist die Position des Charakters, die grünen Felder sind begehbar die roten nicht, da da nen Stein oder ein anderes Hindernis liegt.Diese Kollisionsdaten liegen in einem Array.

Nun ist mein Ansatz gewesen, den Ausschnitt aus dem Kollisionsarray in einen temporären Array zu übertragen und dann alle nicht erreichbaren Felder dann in den temporären Array ebenfalls als "nicht begehbar" zu kennzeichnen.Als letztes müsste ich diesen temporären Array dann nur noch durch
meinen A-Star-Algorithmus jagen und ich erhalte eine genaue Bewegungsreihenfolge in welcher
ich dann genau weiß wo der Charakter lang gehen muss.


Dabei fallen mir mehrere Implementierungsprobleme auf, über die ich momentan nachgrüble und
auf die ich keine Antwort finden.

1.)Wie kann ich genau festlegen, dass exakt der verfügbare Bewegungsradius ermittelt wird.
Wenn mein Charakter z.B. ganz links oben auf der Karte steht dann kann er natürlich nur
nach rechts und unten oder diagonal nach unten laufen.

2.)Wie kann ich berücksichtigen, dass bestimmte Hindernisse den komplette Bewegung in eine Richtung
verhindern, sodass diese Richtung gar nicht weiter verfolgt wird?z.B. bei dem Beispiel oben,
wenn ein Stein direkt links,rechts,oben oder unten vom Spieler liegt und er nur 2 Schritte machen kann
dann kann er logischerweise auch nicht 2 mal nach links/rechts/unten/oben geht auch wenn
nach dem ersten Feld noch ein weites erreichbar wäre.


Ich würd mich über Ideen und Anregung zu diesem komplexen Thema freuen.
Ich hab nämlich selbst schon eine Idee wie ich es umsetzen könnte, aber so wie ich es machen
würde, würde es übermäßig kompliziert werden, mit mehreren Fakllunterscheidungen gigantischen
If-Verzweigungen und und und.Und das möchte ich wenn möglich vermeiden.

Ich hoffe auf eure Hilfe!Danke Smile


MfG Ska
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

TimBo

BeitragSo, Nov 15, 2009 0:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi Skabus,

ich würde es mit einer Rekrusiven Funktion machen.
Du kannst ja nur in 4 Richtungen gehen.
dann gehst du für die 4 Punkte , die du erreichen kannst wieder in 4 Richtungen, und das ganze AP mal.

Also sowas

NeuerSchritt(ausgangspunktx,ausgangspunkty)
in jede richtung dann NeuerSchritt() ausführen
End Function

Liebe Grüße
TimBo
mfg Tim Borowski // CPU: Ryzen 2700x GPU: Nvidia RTX 2070 OC (Gigabyte) Ram: 16GB DDR4 @ 3000MHz OS: Windows 10
Stolzer Gewinner des BCC 25 & BCC 31
hat einen ersten Preis in der 1. Runde beim BWInf 2010/2011 & 2011/12 mit BlitzBasic erreicht.
 

Ava

Gast

BeitragSo, Nov 15, 2009 0:57
Antworten mit Zitat
Im Prinzip ist das ganze auch nur ein (vereinfachter) A*, dessen Funktionsweise Du leicht abwandelst. Du suchst die Karte halt nicht nach einem bestimmten Ziel ab, sondern nach allen erreichbaren Feldern, indem Du den A* vom Ursprung (der Spielfigur) aus einfach sollange aufrufst, bis kein nächstes Feld mehr innerhalb der Bewegungsreichweite liegt. Der Ansatz mit dem temporären Array ist dafür sehr gut geeignet, so hatte ich das bei The Darkthrone auch gelöst.
 

Dreamora

BeitragDo, Nov 26, 2009 6:02
Antworten mit Zitat
Benutzer-Profile anzeigen
A* ist für sowas aber schon recht bruteforce Wink Und kaum effizient da man keinen Zielpunkt (oder halt viele unsinnige ausprobieren müsste) hat was eigentlich eine Voraussetzung für A* ist.
Damit er effizient würde muss er soweit modifiziert werden das er effektiv nur noch eine breitensuche oder dijkstra suche ist.

Die breitensuche geht dabei einfach stupide herum in abhängigkeit von der direkten feld distanz zu dir / bewegungstiefe.
Dijkstra ist da sehr viel intelligenter und wird vor allem dann interessant wenn die felder unterschiedliche kosten hat, da er jeweils das bewegungsdistanzmässig naheste feld abarbeitet. Dadurch wir die bestimmung, wann man aufhören kann "selbst lösend".
Implementationsmässig ist Dijkstra sehr einfach (kaum mehr aufwand als die breitensuche) und eine einfache "gib mir immer das kleinste Element" Datenstruktur (-> Heap, hat allermindestens 1 im Codearchive) ist alles was man dafür braucht abgesehen von ein wenig code fürs abarbeiten der Punkte sowie das hinzufügen der allfälligen nachbarpunkten, sofern sie noch nicht besucht wurden.
ob ein feld schon besucht wurde oder nicht beim check speichert ihr am einfachsten direkt in den tiles der map und reseted die flag nach der berechnung wieder (einfach das Rechteck das durch die kleinste und grösste X / Y koordinate erzeugt wird komplett resetten)
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen.

Skabus

BeitragMi, Jan 06, 2010 18:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

Ich hab jetzt Wochen über Wochen mit meinem Anzeigealgorithmus gearbeitet, mehrere Quellen gewälzt und
hab auch bereits mehrere im Ansatz funktionierende Algorithmen geschrieben.

Leider funktionieren sie letzendlich immer an einer kleiner Stelle nicht, oder sie funktionieren nur für bestimmte
Teile oder Situationen fehlerfrei...

Ich bin mitlerweile ziemlich verzweifelt.Keine Ahnung wie ich jemals nen funktionierenden Algorithmus selber
hinkriegen soll.Meine Bemühungen dahingehend waren bissher zumindest im Detail fruchtlos Sad

Daher wollte ich fragen, ob es im Codearchiv oder irgendwo ein Codebeispiel oder ähnliches gibt, was mir
diese Arbeit abnimmt.Ich habs jetzt 2 Monate versucht selbst zu machen, es funktioniert aber einfach nicht.

Würd mich freuen, wenn mir jemand nen Link oder nen Quellcode(egal welche Sprache) geben könnte,
der sich mit einem ähnlichen Thema befasst.

Wäre euch sehr dankbar Smile

MfG Ska
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

Midimaster

BeitragMi, Jan 06, 2010 19:06
Antworten mit Zitat
Benutzer-Profile anzeigen
das hört sich doch mal spannend an....

Zeig mal den besten deiner algo's, damit ich sehen kann was du bisher erreicht hast.

Hast du eine rekursive Lösung hinbekommen? Welche Deiner Fragen aus dem ersten Beitrag sind noch ungelöst?

Geht es dir nur darum, dieses 2.Array zu erhalten, oder hattest du Probeme, dies dann in der A* einzubinden?


Fragen über Fragen...

BladeRunner

Moderator

BeitragMi, Jan 06, 2010 19:35
Antworten mit Zitat
Benutzer-Profile anzeigen
Code: [AUSKLAPPEN]
SuperStrict
Global map:Int[16 , 16]
Global Targetmap:Int[16 , 16]
map[3 , 3] = 1
map[4 , 3] = 1
map[5 , 5] = 1
Local startx:Int = 3
Local starty:Int = 4
Local range:Int = 4

fillmap(map,targetmap,startx,starty,range)
drawmap(targetmap)


Function isWalkable:Int(m:Int[,],x:Int,y:Int)
   If (x >=0) And (y>=0) And (x<16) And (y<16) Then
      If m[x , y] = 0 Then Return True
   EndIf
End Function

Function FillMap(source:Int[,],target:Int[,],x:Int , y:Int , range:Int)
   If isWalkable(source,x - 1 , y) Then
      target[x - 1 , y] = 1
      If range > 1 Then fillmap(source,target,x-1 , y , range - 1)
   EndIf
   If isWalkable(source,x + 1 , y) Then
      target[x + 1 , y] = 1
      If range > 1 Then fillmap(source,target,x+1 , y , range - 1)
   EndIf
   If isWalkable(source,x , y-1) Then
      target[x , y-1] = 1
      If range > 1 Then fillmap(source,target,x , y-1 , range - 1)
   EndIf
   If isWalkable(source,x , y+1) Then
      target[x  , y+1] = 1
      If range > 1 Then fillmap(source,target,x , y+1 , range - 1)
   EndIf
End Function

Function drawmap(m:Int[,])
   For Local y:Int = 0 Until 16
      For Local x:Int= 0 Until 16
         StandardIOStream.WriteString(String(m[x,y]))
         StandardIOStream.Flush()
      Next
      Print
   Next
End Function

Das wäre mein hingesauter Ansatz dafür. Funtioniert unter BMax einwandfrei, in Targetmap sind die begehbaren Felder. Ist natürlich sehr unsauber.
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

Skabus

BeitragFr, Jan 15, 2010 1:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke für eure Antworten^^

Also ich hab es erstmal die Tage durchgetestet bei Gelegenheit.Ich dachte zunächst das Problem läge bei
meiner Methode, da ich nicht die gesamte Karte(also den gesamten Array) sondern nur einen Auschnitt
aus dem Kartenarray in einen separaten Array übertragen habe.

Allerdings habe ich bis eben das Ganze mal mit dem kompletten Kartenarray getestet und es will weiterhin nicht funktionieren.

Problem ist folgendes:

Mein Algorythmus berechnet den Radius grob korrekt, tut dies aber seltsamerweise nur manchmal
vollständig richtig.Meistens vergisst er dort wo ein Hindernis steht, quasi auch den Pfad, der hinter
dem Hindernis steht miteinzubeziehen...

Es sieht aus, als wäre der leere Bereich hinder dem Hindernis quasi der Schatten weil nur exakt hinter
dem Hindernis die Felder fehlen die eigentlich begehbar sind.

Hier mal der Code mit dem ich den Radius berechne(-1 bedeutet hier "noch nicht geprüft" wärend
0 begehbar und jeder Wert > 0 ein Hinderniss darstellt, die -1 benötige ich, damit ich später
aus allen nicht geprüften Feldern temporär eine 1 machen kann, damit mein AStaralgorithmus danach
die Felder die außerhalb des Bewegungsradius liegt als Hindernis interpretiert)

Zur Erläuterung: range ist die Bewegungsreichweite die man maximal gehen kann,diese
hängt von den AP des Charakters ab.Hat er z.B. 7 AP kann er 7 Felder gehen.
posX und posY sind die aktuelle Position, hierbei muss beachtet werden, dass
die Funktion nicht den vollständigen Bewegungsradius berechnet sondern nur für die aktuelle
Richtung, was durch dir ausgedrückt wird.
stepCount stellt den Akkumulator der Rekursion dar(wer nicht weiß was eine Rekursion mit
Akkumulator ist, kann sich z.B. hier belesen: http://www.deinprogramm.de/dmda/akku.pdf)
und ist dann gleich der range-Variable wenn alle Schritte verbraucht sind...
battleMSizeX/Y ist die Größe der Karte.
Warum ich dir und curDir genommen habe weiß ich selber nicht genau.
Es liegt wohl aan oben benanntem Problem.Die Funktion berechnet nicht den ganzen Radius sondern
nur die möglichen Pfade einer Richtung, daher brauche ich die Richtung des aktuellen rekursiven
Aufrufs und einmal die ursprüngliche Richtung.
Alles sehr doof gelöst, aber vllt.. versteht ihr jetzt warum ich verzweifelt bin^^"

Bei weiteren Unklarheiten, einfach fragen^^

BlitzMax: [AUSKLAPPEN]
 'diese Methode aktualisiert den temporären MoveArray und ermittelt anhand der Daten
'den Bewegungsradius der verfügbar ist
Method getMovement:Int(posX:Int,posY:Int,dir:Int,curDir:Int,range:Int,stepCount:Int)

'sofern noch nicht alle Schritte verbraucht sind
If(range > stepCount) Then

If(posX > -1 And posX < battleMSizeX And posY > -1 And posY < battleMSizeY) Then

'dann wird geprüft ob die aktuelle Position begehbar ist
If(tempMoveArr[posX,posY] = -1) Then

'ist das aktuelle Tile begehbar wird der Array aktualisiert
tempMoveArr[posX,posY] = 0


'nun werden alle weiter noch zu bearbeitenden Pfadmöglichkeiten
'rekursiv aufgerufen
If(dir = RECHTS) Then
If(curDir = RECHTS) Then
getMovement(posX+1,posY,dir,RECHTS,range,stepCount+1)
getMovement(posX,posY-1,dir,OBEN,range,stepCount+1)
getMovement(posX,posY+1,dir,UNTEN,range,stepCount+1)

ElseIf(curDir = OBEN) Then

getMovement(posX+1,posY,dir,RECHTS,range,stepCount+1)
getMovement(posX,posY-1,dir,OBEN,range,stepCount+1)

ElseIf(curDir = UNTEN) Then

getMovement(posX+1,posY,dir,RECHTS,range,stepCount+1)
getMovement(posX,posY+1,dir,UNTEN,range,stepCount+1)

EndIf

ElseIf(dir = LINKS) Then

If(curDir = LINKS) Then
getMovement(posX-1,posY,dir,LINKS,range,stepCount+1)
getMovement(posX,posY-1,dir,OBEN,range,stepCount+1)
getMovement(posX,posY+1,dir,UNTEN,range,stepCount+1)

ElseIf(curDir = OBEN) Then

getMovement(posX-1,posY,dir,LINKS,range,stepCount+1)
getMovement(posX,posY-1,dir,OBEN,range,stepCount+1)

ElseIf(curDir = UNTEN) Then

getMovement(posX-1,posY,dir,LINKS,range,stepCount+1)
getMovement(posX,posY+1,dir,UNTEN,range,stepCount+1)

EndIf

ElseIf(dir = OBEN) Then
getMovement(posX,posY-1,dir,dir,range,stepCount+1)
ElseIf(dir = UNTEN) Then
getMovement(posX,posY+1,dir,dir,range,stepCount+1)
EndIf

Else

Return 0

EndIf

Else

'ist die aktuelle Position nicht begehbar wird dieser Pfad nicht weiterverfolgt
Return 0

EndIf
Else

'sollte die maximale Anzahl an Schritten beendet worden sein
'wird diese Richtung beendet
Return 0

EndIf


End Method



Midimaster:

Wie du siehst habe ich mich für eine rekursive Variante entschieden.Grob stimmt das Ergebnis auch,
aber eben nur grob.Im Detail funktioniert er bei dem Hauptcharakter 100%tig, bei den 3 weiteren
Charakteren die einer anderen Position stehen funktioniert er nicht.

ICh weiß einfach nur nicht warum er mir was falsches liefert...

Es ist im übrigen sehr schwer lauffähigen Code hochzuladen da mein Programm mitlerweile an die 10000
Zeilen Code enthält...verzeiht mir also^^"

MfG Ska

BladeRunner:

Ich hatte ganz vergessen zu sagen, das dein Ansatz mir sehr hilft.Danke dafür.
Dein Ansatz ist also völlig ohne Richtungsangabe?Geht aber trotzdem vollständig alle Richtungen ab?

Ne andere Sache: Du sagst an 3 Stellen sind Hindernisse also 1 sind deine Hindernisse, warum sind
dann in targetmap noch mehr Hindernisse dazugekommen?Selbst wenn die 1 im targetmap die begehbaren Felder sind wie unterscheidest du sie da von den Hindernissen?

Also das Ergebnis kann ich leider nicht deuten^^"

Wäre nett wenn du es erklären könntest...Danke im vorraus!
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

Midimaster

BeitragFr, Jan 15, 2010 2:33
Antworten mit Zitat
Benutzer-Profile anzeigen
Ist denn das Feld nicht auch begehbar, wenn tepmMoveArr=0 ist?

Zitat:
'dann wird geprüft ob die aktuelle Position begehbar ist
If(tempMoveArr[posX,posY] = -1) Then


Stell dir vor du hast 4 AP.
X ist der Startpunkt.
Z ist ein Punkt hinter einem Hindernis, der eigentlich erreichbar sein müsste.

Der Algo beginnt z.b. so zu suchen: von x aus 2x nach links und dann 1x hoch

Code: [AUSKLAPPEN]
...z.
.0.11
.00x1
...11


bleibt noch 1 AP und der geht zufällig nach rechts, so:

Code: [AUSKLAPPEN]
...z.
.0011
.00x1
...11


dann kommt eine spätere Rekursion nie wieder auf diesen Weg:

Code: [AUSKLAPPEN]
..00..
..011
..0x1
...11


Meiner Meinung nach muss es heißen:

Zitat:
'dann wird geprüft ob die aktuelle Position begehbar ist
If(tempMoveArr[posX,posY] < 1 ) Then


oder noch besser, du notierst in die Felder den AP-Verbrauch, den es bis hier gekostet hat.

Vorbereitung:
Zunächst bekommen alle verbotenen Felder einen geringen Wert (hier:0)
Alle möglichen Felder den Wert 99. (Das wären in den Beispielen alle mit ".")
Das Startfeld x erhält auch 99
Eine Rekursion braucht dann viele Felder nicht mehr zu testen, weil man "billiger" hierhin kam:

Code: [AUSKLAPPEN]
...z.
...00
...x0
...00


nach 4 Zügen:

Code: [AUSKLAPPEN]
...z.
.3400
.21x0
...00


Andererseit wird sie das teuere 4-er Feld später noch einmal betreten dürfen:

Code: [AUSKLAPPEN]
..34.
.3200
.21x0
...00


Der Algo:

Code: [AUSKLAPPEN]
Springe in die Rekursion mit dem Startfeld (hier X).
Wenn der Wert des Feldes dort größer als dein AP-Verbrauch ist,
     nimm es ein und setze es den Wert gleich dem aktuellen AP-Verbrauch
     Starte von hier in alle 4 Richtungen mit um 1 verringertem Test-AP...
     ...und erhöhtem AP-Verbrauch
aber wenn der Wert des Feldes kleiner ist (weil verboten=0 oder weil schon billiger)
     vergiß diesen Platz.
     1 Rekursion zurück, dort die 3 anderen testen.
Ende Wenn



Der Vorteil dieser Rekursion ist, dass du im Code keine Rücksicht auf die vorangegangene Richtung nehmen musst. Du scanntst immer alle 4 Richtungen. Die aus der du hergekommen bist, hat ja schon einen niedrigeren AP-Wert:

Angenommen du bist bis auf Feld 2 gekommen und checkst nun die Umgebung:

Code: [AUSKLAPPEN]
...z.
...00
.21x0
...00


dann checkt der algo zwar auch die richtung hin zur 1, aber es kommt nur dies in Frage:

Code: [AUSKLAPPEN]
...z.
.3.00
321x0
.3.00


Versuch erst gar nicht den Code zu optimieren. Lass es die Rekursion machen!

Die richtig schönen Rekursionen sehen immer supersimpel aus!
  • Zuletzt bearbeitet von Midimaster am Fr, Jan 15, 2010 12:13, insgesamt 3-mal bearbeitet

Skabus

BeitragFr, Jan 15, 2010 10:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Vielen Dank Midimaster Very Happy

Ich werd mir sobald ich Zeit hab anhand dessen mal einen Algorithmus implementieren.

Übrigens KANN das Feld begehbar sein wenn es 0 ist, allerdings habe ich alle Felder die 0 waren -1 gesetzt
damit ich später für den AStar den Unterschied zwischen dem im Radius begehbaren Feldern und den zwar begehbaren aber nicht erreichbaren Feldern versteht.

Die Felder die nicht erreicht wurden werden nach dem Ermitteln des Bewegungsradius auf 1 gesetzt un dem AStar-Algo gegeben, damit er denkt, dass die nicht erreichbaren Felder Hindernisse sind.So wollte ich den
Bewegungsbereich auf den Algo anpassen.

Muss ich schauen in wie weit ich das mit deiner Variante anpassen muss.


MfG Ska
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

Midimaster

BeitragFr, Jan 15, 2010 10:49
Antworten mit Zitat
Benutzer-Profile anzeigen
jetzt hast du mich missverstanden:

ich spreche nur von dem temporären Feld. Dort dürfen während der Rekursion nicht schon die bereits "begangenen" Felder von weiteren Rekursionen ausgeschlossen werden.

Alle Tipps, die ich dir gegeben habe beziehen sich nur auf das temporäre Feld und wie du darin "hinter" die Hindernisse kommst.
  • Zuletzt bearbeitet von Midimaster am Fr, Jan 15, 2010 11:16, insgesamt einmal bearbeitet

Skabus

BeitragFr, Jan 15, 2010 10:59
Antworten mit Zitat
Benutzer-Profile anzeigen
Aso, gut..

Dank dir.
Ich meld mich nochmal falls es immernoch nicht funktionieren will XD

Ich versteh eine Sache nicht ganz:

Wenn ich auf meinem tempMoveArray die Startposition -1 setze und dann die
Rekursion mit dem Startpunkt(x,y) beginne, ergibt die Abfrage für mich keinen Sinn.

Denn der aktuelle Wert des Feldes ist -1 somit KLEINER als die restAp(immer, da die restAp maximal 0 werden kann) also würde ja die zweite Bedingung zu tragen kommen.

Aus deinem Pseudocode hab ichh aber verstanden, dass dies nicht für den ersten Fall sondern
für alle folgende Fälle für die das gilt passieren soll...

Kannst du mir nochmal sagen, wie genau der Algorithmus anfängt?Wäre sehr nett^^



MfG Ska
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

Midimaster

BeitragFr, Jan 15, 2010 12:05
Antworten mit Zitat
Benutzer-Profile anzeigen
du hast recht, du hast zwei Fehler in meiner Denke gefunden:
1.
beginne mit einer 99 auf der startpos! das war blöd von mir....
2.
Verglichen wird natürlich nicht mit dem Rest-Ap, sondern ob auf dem Feld bereits ein Verbrauch eingetragen worden war. Und der wird natürlich mit dem aktuellen Verbrauch verglichen.

Danke für deine Hinweise!


Hier ein Code-Versuch

Starte so:

Code: [AUSKLAPPEN]
CheckField MyX, MyY, AP, 0


hier die Funktion:

BlitzMax: [AUSKLAPPEN]
Function CheckField(X%, Y%,  AP%, Verbraucht%)
If Ap<Verbraucht Then
; alle energie bereits verbraucht, Feld checken nutzlos
Return
ElseIf (X<0) Or ( X>=BattleMSizeX ) Or (Y<0) Or (Y >=BattleMSizeY) Then
; out of Border, Feld existiert gar nicht
Return
ElseIf tempMoveArr[X,Y] < Verbraucht
; Feld wurde schon "billiger" besucht, oder ist verboten (=0)
Return
Else
tempMoveArr[X,Y] = Verbraucht
Verbraucht = Verbraucht +1
If 1=1 Then ; --------------------------------------------------
; zeige eventuell den temp.Zustand
; schritt für schritt zum zuschauen während der entwicklung
ZeichneTempMoveArr()
WaitKey()
EndIf ; --------------------------------------------------
CheckField X-1, Y , Ap, Verbraucht
CheckField X+1, Y , Ap, Verbraucht
CheckField X , Y-1, Ap, Verbraucht
CheckField X , Y+1, Ap, Verbraucht
EndIf
End Function
  • Zuletzt bearbeitet von Midimaster am Fr, Jan 15, 2010 14:35, insgesamt einmal bearbeitet

Skabus

BeitragFr, Jan 15, 2010 13:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey, jetzt scheint es nach einigen Testreihen makellos zu funktionieren!

Vielen Dank für deine Mühen, echt klasse! Very Happy


Ich meld mich nochmal falls irgendwas nicht stimmt^^

MfG Ska
"In einer so verrückten Welt, kann man um in ihr zu überleben nur eines tun, nämlich eben jenes werden: Ein Verrückter!" -Selbstzitat

aktuelles Projekt: Aves Certim - Der Galgen ist nicht weit!
Ein SNES-RPG mit Handels- und Wirtschaftselemente.
Infos?Hier: http://www.blitzforum.de/worklogs/234/
Besucht meine Seite:
www.seelenfriedhof.de.vu

BladeRunner

Moderator

BeitragFr, Jan 15, 2010 14:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Hi Skabus,
ich glaube Du hast die Ausgabe meines Codes nur falsch interpretiert.
Die Einsen in TargetMap sind nicht Blockaden sondern eben die Felder innerhalb der Reichweite. Um das Ganze mal ein wenig deutlicher zu machen, habe ich die Routine so angepasst, dass sie die Menge an AP in die Karte einträgt welche nach dem Laufen übrigbleiben.
Code: [AUSKLAPPEN]
SuperStrict
Global map:Int[16 , 16]
Global Targetmap:Int[16 , 16]
map[3 , 3] = 1
map[4 , 3] = 1
map[5 , 5] = 1
Local startx:Int = 3
Local starty:Int = 4
Local range:Int = 4

fillmap(map,targetmap,startx,starty,range)
drawmap(targetmap)


Function isWalkable:Int(m:Int[,],x:Int,y:Int)
   If (x >=0) And (y>=0) And (x<16) And (y<16) Then
      If m[x , y] = 0 Then Return True
   EndIf
End Function

Function FillMap(source:Int[,],target:Int[,],x:Int , y:Int , range:Int)
   If isWalkable(source,x - 1 , y) Then
      If target[x - 1 , y] < range Then target[x - 1 , y] = range
      If range > 1 Then fillmap(source,target,x-1 , y , range - 1)
   EndIf
   If isWalkable(source,x + 1 , y) Then
      If target[x + 1 , y] < range Then target[x + 1 , y] = range
      If range > 1 Then fillmap(source,target,x+1 , y , range - 1)
   EndIf
   If isWalkable(source,x , y-1) Then
      If target[x , y-1] < range Then target[x , y-1] = range
      If range > 1 Then fillmap(source,target,x , y-1 , range - 1)
   EndIf
   If isWalkable(source,x , y+1) Then
      If target[x  , y+1] < range Then target[x  , y+1] = range
      If range > 1 Then fillmap(source,target,x , y+1 , range - 1)
   EndIf
End Function

Function drawmap(m:Int[,])
   For Local y:Int = 0 Until 16
      For Local x:Int= 0 Until 16
         StandardIOStream.WriteString(String(m[x,y]))
         StandardIOStream.Flush()
      Next
      Print
   Next
End Function

Ich hoffe das wird nun deutlicher für Dich. So kann dein Charakter auf dem potentiellen Zielfeld nachschauen und erhält automatisch Rückmeldung ob er hinkann (AP>0) und zu welchen Kosten.
Auch ein Anzeigen der Zielfelder wird so möglich: einfach ein farbiges Feld mit geringem Alpha über alle Felder zeichnen lassen welche >0 sind in der Targetmap.
Zwei Dinge musst Du noch beachten:
1. Das Startfeld wird bei der Prüfung nicht ausgenommen, weshab es in der Regel zu einem AP weniger als den Maximalen angezeigt werden wird. Hier würde ich eine Manuelle Abfrage einbauen
2. Damit die 100% Routine korrekt arbeitet müsstest du entweder:
a) die zur Verfügung stehenden AP für die Abfrage um eins erhöhen
ODER
b) Targetmap mit -1 initialisieren und die Abfragen in der Funktion so ändern dass sie bei 0 statt bei 1 anschlagen,

da bislang die Bewegungsweite eins zu gering ist. Aber der Ansatz war ja auch nur hingesaut.

Das ganze funktioniert mit einem winzigen bissel mehr Arbeit auch mit beliebigen Arraygrössen, ohne dass Du dazu weitere Angaben bräuchtest.

HF.
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

Midimaster

BeitragFr, Jan 15, 2010 14:32
Antworten mit Zitat
Benutzer-Profile anzeigen
@BladeRunner
wie schon gesagt:

Die richtig schönen Rekursionen sehen immer supersimpel aus!

BlitzMax: [AUSKLAPPEN]
CheckField StartX, StartY, AP, 0
Function CheckField(X%, Y%, AP%, Verbraucht%)
If Ap<Verbraucht Then
Return
ElseIf (X<0) Or ( X>=BattleMSizeX ) Or (Y<0) Or (Y >=BattleMSizeY) Then
Return
ElseIf tempMoveArr[X,Y] < Verbraucht
Return
Else
tempMoveArr[X,Y] = Verbraucht
Verbraucht = Verbraucht +1
CheckField X-1, Y , Ap, Verbraucht
CheckField X+1, Y , Ap, Verbraucht
CheckField X , Y-1, Ap, Verbraucht
CheckField X , Y+1, Ap, Verbraucht
EndIf
End Function

BladeRunner

Moderator

BeitragFr, Jan 15, 2010 14:34
Antworten mit Zitat
Benutzer-Profile anzeigen
... nur hingesaut, midimaster, nur hingesaut Rolling Eyes
Ich glaube nicht dass ich irgendwo behauptet habe mein Code sei das nonplusultra oder schön.
Sonst noch Probleme damit?
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

Midimaster

BeitragFr, Jan 15, 2010 14:38
Antworten mit Zitat
Benutzer-Profile anzeigen
doch keine Probleme! Wink

Sollst dir ja nur mal anschauen, wo man in einer Rekursion das Feld checkt! Dann fallen die Fallunterscheidungen weg.

Auch der Sondercode fürs "Einsteigen" ist nicht nötig. Schon schön, oder?

BladeRunner

Moderator

BeitragFr, Jan 15, 2010 14:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Ist er bei mir nach einer kleinen Anpassung auch nicht, wie ich erwähnte.
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

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group