Langsame Leistung bei einer A * -Implementierung in einem Tower Defense-Spiel

9

Ich mache ein Tower Defense-Spiel in Flash ohne vordefinierten Pfad.

Obwohl mein Raster 40x40 (klein?) Ist, hat A * bei jeder Neuberechnung Probleme. Also habe ich meine eigenen Änderungen vorgenommen, um die Neuberechnung zu vereinfachen, und die Anzahl der berührten Zellen ist auf etwa 900 gesunken (bei Änderungen in der Nähe der Wurzel). Es friert immer noch für eine sehr kurze, aber nachweisbare Zeit ein, wenn ein neuer Turm aufgestellt wird.

Ist dies ein Implementierungsproblem oder ist 40x40 einfach zu viel?

Bearbeiten:

Die Struktur meines Codes:

  • Alle Daten werden in einem 2D-Array von Zellen gespeichert.
  • Jede Zelle enthält ihr übergeordnetes Element in Pfadrichtung (1-8 im Uhrzeigersinn) und ein bitweise codiertes Array ihrer untergeordneten Elemente im Pfad (jedes Bit repräsentiert ein untergeordnetes Element).
  • Die Suche wird von A * mit der Schätzung der euklidischen Entfernung durchgeführt.
Dani
quelle
Sie müssen hier viel genauer sein. Wir haben keine Ahnung, wie Ihr Code aussieht, wie er strukturiert ist usw. Daher können wir keine Schlussfolgerungen darüber ziehen, was ihn langsam macht.
Sean James
1
Als ich A * zum letzten Mal implementiert habe, erinnere ich mich, dass es in höchstens 1 ms durch ein 64x64-Raster lief . Also ja, es scheint ein Problem mit Ihrer Implementierung zu sein. Ich schlage vor, Ihren Code oder dessen Inhalt zu veröffentlichen, damit wir Ihnen weiterhelfen können.
Marc Müller
Siehe die Bearbeitung, die ich hinzugefügt habe
Dani
1
Wenn 40x40 zu langsam ist, stehen die Chancen gut, dass Sie etwas sehr Falsches tun. Geben Sie entweder Ihren Code ein oder profilieren Sie ihn. Alternativ können Sie es vergrößern und sehen, was passiert. Wenn ein 80x80-Raster mehr als viermal so lange dauert, ist dort etwas extrem kaputt.
ZorbaTHut
Kann der Titel bitte etwas informativer sein?
Tenpn

Antworten:

4

Ich kann nicht kommentieren, aber erstes Profil in Flex, alles andere ist Vermutung.

Jonathan Fischoff
quelle
Wie kann ich ein Flash-Projekt in Flex profilieren?
Dani
Ja und nein. Ich glaube nicht, dass Sie das Flash-Projekt direkt laden. Ich denke, Sie könnten in der Lage sein, die SWF ohne Quelle zu profilieren und trotzdem Informationen auf Funktionsebene zu erhalten. Ich würde eine Google-Suche nach "Profiling eines Flash-Projekts in Flex" oder ähnlichem durchführen. Ich habe das getan und bekommen: flexblog.edchipman.ca/… was vielversprechend aussieht.
Jonathan Fischoff
Danke, hat mir wirklich geholfen, den problematischen Teil zu finden (war nicht im Algorithmus, siehe Kommentar zur Frage)
Dani
13

Ich gehe davon aus, dass TD "Tower Defense" ist.

Ich denke, A * geht dafür etwas über Bord.

Füllen Sie zu Beginn des Spiels den Spielbereich von den Ausgangspunkten aus, um eine Bewegungskarte zu erstellen:

 |---------|
 |5|4|3|3|3|
 |5|4|3|2|2|
->5|4|3|2|1->
 |5|4|3|2|2|
 |5|4|3|3|3|
 |---------|

und Bewegung ist immer in Richtung eines Quadrats mit einem niedrigeren Wert.

Wenn der Spieler einen Turm platziert, aktualisieren Sie jedes der acht benachbarten Felder: Setzen Sie für jedes Feld seinen Bewegungswert auf eins mehr als den niedrigsten benachbarten Wert. Wenn sich der Wert ändert, wiederholen Sie den Vorgang, der auf dem aktualisierten Quadrat zentriert ist. Um zu überprüfen, ob der Weg zum Ausgang nicht blockiert ist, stellen Sie sicher, dass alle Quadrate neben einem Quadrat mit einem niedrigeren Wert liegen.

Wenn der Spieler einen Turm entfernt, setzen Sie den Bewegungswert auf eins mehr als das niedrigste benachbarte Feld und wiederholen Sie den obigen Vorgang.

Ein einfacherer Ansatz wäre, die Flutfüllung erneut durchzuführen.

Skizz
quelle
6
Das erneute Ausfüllen der Flut ist teurer als das Ausführen von A * für eine kleine Anzahl von Einheiten - ungefähr die Länge der Platine - zumindest in algorithmischer Hinsicht (und da dies Flash ist, können nicht-algorithmische Konstanten wie das Speicherlayout wahrscheinlich ' nicht sehr effektiv eingesetzt werden). Dies ist jedoch ein sehr gutes Modell für viele Kommunikationseinheiten und wird als kollaborative Verbreitung bezeichnet - scalablegamedesign.cs.colorado.edu/wiki/Collaborative_Diffusion .
@ Joe Wreschnig: Wow schöner Link. Ich habe diese Technik schon einmal angewendet, wusste aber nie, wie sie heißt. Vielen Dank.
Tenpn
@ Joe, solange es mindestens ein paar Barrieren auf der Karte gibt, denke ich nicht, dass dies ineffizienter wäre, als A * anzurufen. Das heißt, ich glaube, nur für eine weit geöffnete, fast barrierefreie Karte mit wenigen Einheiten könnte es schlimmer sein.
edA-qa mort-ora-y
@edA: Per Definition muss eine Flutfüllung schließlich jeden zugänglichen Punkt auf der Karte berühren. A * liefert nachgewiesene Obergrenzen für die Anzahl der Punkte, die berührt werden müssen. Dies ist höchstens jeder zugängliche Punkt auf der Karte und normalerweise weit weniger. Die Flutfüllung ist ein einfacherer Algorithmus, um Dinge wie das Speicherlayout zu optimieren, aber wie gesagt, in Flash spielt das wahrscheinlich keine Rolle.
@ Joe, das ist, was ich argumentiere, ist, dass selbst mit nur einer Handvoll Türmen das A * wahrscheinlich fast alle Räume berühren wird. Aber für N Monster muss es nur total_squares / N überschreiten, um weniger effizient zu sein als die Flutfüllung.
edA-qa mort-ora-y
2

Seltsam, ich dachte, ich hätte darauf geantwortet, aber die Antwort scheint weg zu sein. Stellen Sie Ihren Suchalgorithmus so ein, dass er in mehreren Schritten aktualisiert werden kann. Wenn Sie also einen Turm platzieren und eine Animation abspielen, können Sie jedes Bild ein wenig bearbeiten und haben zwischen einer halben und einer Sekunde Zeit, um Ihr Bild zu aktualisieren A * ohne merkliche Pause. Es ist Latenz - wenn Sie es nicht beschleunigen können, finden Sie einen Weg, es zu verbergen. Das Abspielen einer Animation beim Platzieren eines Turms wäre für ein Spiel selbstverständlich und ein guter Ort, um es zu verstecken.

Kaj
quelle
Dies ist im Allgemeinen eine gute Idee, aber schlecht für diese spezielle Frage. Ein * in einem so kleinen Raster sollte fast augenblicklich sein und nicht viel Zeit in Anspruch nehmen.
Davr
Meinetwegen. Dies ist die einzige Antwort, die ich geben könnte, um das Problem zu lösen, ohne die Implementierungsdetails zu kennen, die die Verlangsamung verursachen würden.
Kaj
0

Zunächst könnten Sie Ihr Array in einen Vektor ändern - dies sollte Ihnen einige Geschwindigkeitsverbesserungen bringen. Wenn Sie den Code veröffentlichen, können wir möglicherweise weitere Optimierungen vorschlagen.

Iain
quelle
0

Ich würde vermuten, dass Ihre Verlangsamung darauf zurückzuführen ist, dass Sie einen Pfad für alle Zeichen gleichzeitig berechnen. Das Berechnen eines Pfades für ein Zeichen ist schnell, aber wenn die Szene zwei Dutzend Zeichen enthält, kann dies ins Stocken geraten.

Stattdessen sollten Sie die Last auf einige Frames verteilen. Versetzen Sie Ihre KI-Updates, damit verschiedene Charaktere ihren Pfad in verschiedenen Frames aktualisieren. Es wäre wirklich auffällig, wenn ein Charakter erst eine Sekunde später reagieren würde, aber nur ein Frame wird keine schlechten Reaktionen hervorrufen.

jhocking
quelle
Dies wurde vor fast einem Jahr beantwortet und nur wegen Graces Bearbeitungsarbeit gestoßen. (Es hatte nichts mit zu vielen Zeichen zu tun.)
Danke für die Information. Ich habe die Daten nicht bemerkt.
Jhocking