Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

equinox

Frischling

Beiträge: 56

Beruf: Student

  • Private Nachricht senden

11

01.06.2017, 09:42

Die Kosten kannst du prinzipiell modellieren wie du möchtest, hauptsache sie passen zu deiner Heuristik. Damit meine ich, dass es keinen Sinn macht zu sagen die Kosten von einem Tile zu einem Nachbarn betragen immer 20, aber die Heuristik berechnet die euklidische Distanz anhand der X und Y Koordinaten und liefert entsprechend einen verhältnismäßig zu geringen Schätzwert.

Um mal auf die eingeworfenen "Dynamischen Hindernissen" einzugehen, da gibt es eine modifizierte Variante des A*-Algorithmus, der häufig D* genannt wird.

12

04.06.2017, 13:30

Hallo nochmal,

tut mir Leid, dass ich nochmal nachfrage, aber:

Ich kapier einfach nicht, warum ich meine TileMap nicht nur einmal im Konstruktor laden kann und zwar so, dass es läuft. Ich habe ja schon geschrieben, dass es ab ca. 50 Einheiten anfängt zu ruckeln, unabhängig von dem was Schorsch mir erklärt hat, denn das ist eine weitere Verbesserung, oder? Es funktioniert momentan nur, wenn ich den A* statisch mache in meiner Levelklasse und diesem das gesamte Spielfeld mit gebe. In meiner update()-Methode rufe ich dann die statische A*-Methode findPath(), natürlich zur Laufzeit auf. Ein Bekannter riet mir aber soviel wie nur geht in den Konstruktor zu packen, vor allem das Spielfeld. Bei den Nachbarn für den A*, müsste es genauso sein, dass man die im Konstruktor nur einmal lädt, so dass alle möglichen Nachbarknoten schon bei der Initialisierung der Karte bekannt sind , oder?
Ich checks einfach nicht und es hält mich ungemein auf. Wäre für konkrete Hilfe am Code dankbar.

Gruß Javaist

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

13

04.06.2017, 19:16

Dein Problem ist immer noch dass du deinen Graphen bei jedem Aufruf vom A* neu berechnest. Das ist natürlich Mist und sollte einfach vorher nur ein mal passieren. Das kann jetzt in irgendeinem Konstruktor sein, oder aber auch irgendwo anders. Wichtig ist dass der Graph ein mal erstellt wird und nicht jedes mal aufs neue. Ich hab dir ja erklärt wie du dir deine Klasse dafür komplett sparen könntest. Wenn du das nicht benutzen willst dann zieh den nötigen Code zumindest aus dem A* raus. Wenn du dabei Probleme bekommst musst du den Debugger benutzen. Wir kennen zu wenig von deinem Code um das Problem aktuell zu erkennen. So wie du es beschreibst dürfte das Problem nicht auftauchen. Also schnapp dir den Debugger und guck wo und warum das Problem auftritt.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

14

05.06.2017, 09:00

Also, das ist wirklich das Problem, wenn der A* das Spielfeld nicht hat (A* ist übrigens static), dann versucht er den nächsten Nachbarn zu finden und findet ihn nicht, der A* kackt ab und hängt fest, so versteh ich das jedenfalls. A* bekommt praktisch nur die initialisierten Werte vom Spielfeld und nicht mehr, also das ganze, so wie ich es möchte.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

15

05.06.2017, 11:27

Er muss schon in irgendeiner Form die gesamte Welt bekommen. Ansonsten kann er sie ja nicht suchen.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

16

05.06.2017, 13:39

Falls du Skype hast findest du mich als "Thomas Jagust" Garfield Symbol. R uf einfachan bin heute ganzen tag on.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

17

05.06.2017, 13:56

Falls du Skype hast findest du mich als "Thomas Jagust" Garfield Symbol. R uf einfachan bin heute ganzen tag on.

Da hab ich keine Zeit für und an sich haben wir ja extra das Forum. Ich hab ja an sich schon erklärt worum es geht. Du machst deine TielMap Klasse um den Graphen darzustellen. Anstatt das alles zu machen kannst du den impliziten Graphen benutzen den du schon hast. Soll heißen du hast deine Map Daten, du weißt welche Nachbarfelder es zu einem Feld gibt und du weißt ob so ein Feld begehbar ist oder eben nicht. Das ist alles was du im A* an Wissen brauchst. Ließ dir meine vorherigen Antworten noch mal durch.
Wenn du unbedingt bei deiner extra Klasse bleiben willst und alle Daten doppelt haben möchtest dann machst du das nicht in A* sondern ein einziges mal im gesamten Programm, speicherst diese ganzen Daten ab und benutzt sie im Algorithmus einfach nur noch. Nicht mehr und nicht weniger. Dabei sollst du nicht nur ein einzelnes Feld erzeugen sondern eben alle. Ansonsten kann es ja nicht funktionieren. Da liegt ja dein aktuelles Problem und das hast du ja schon selbst so beschrieben. Vielleicht hast du einfach grad ein Brett vorm Kopf und eine Pause in der du den Kopf frei kriegst hilft weiter.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

18

05.06.2017, 14:13

HHHHHHH ja vielleicht hast du ja recht. Also nochmal kurz:
AStern in eine Klasse
Level samt grid in eine Klasse
richtig?

und der Aufruf vom ASern als statische Methode bei den Einheiten
richtig?

und vorher natürlich prüfenob begehbar oder eben nicht?

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

19

05.06.2017, 15:15

Jein. A* ist ein Algorithmus auf einem Graphen. Ein Graph besteht normalerweise aus einer Menge von Knoten und einer Menge von Kanten zwischen diesen Knoten. Bei deiner Karte entspricht jetzt jede Begehbare Zelle einem Knoten in diesem Graphen. Sind zwei dieser begehbaren Zellen direkt nebeneinander so gibt es eine Kante zwischen diesen beiden Knoten im Graphen. Mit implizit meine ich jetzt dass du deine Map an sich schon besitzt. sagen wir du möchtest einen Knoten expandieren. Dein knoten ist irgendeine Zelle auf deiner Karte. Du weißt welche Nachbarzellen es zu dieser Zelle gibt. Jetzt betrachtest du von diesen Nachbarzellen nur diejenigen die begehbar sind. Das sind deine von deinem aktuellen Knoten aus erreichbaren Knoten.
Das hat nichts damit zutun ob dein Algorithmus jetzt in einer statischen Klasse ist oder nicht. Das macht überhaupt keinen Unterschied. Dein Problem ist dass du aktuell beim Aufruf vom A* für jedes Feld auf deiner Karte ein neues Objekt erstellst. Nehmen wir mal an deine Karte bestünde aus 500 Zellen. Dann würde ein Aufruf von A* 500 Objekte erstellen die dir überhaupt keine neue Information liefern. Am Ende werden diese alle wieder verworfen. Überlegen wir mal was passiert wenn du 30 Einheiten hast die gleichzeitig den Weg berechnen, dann hättest du 30 * 500 Objekte die erstellt und wieder gelöscht werden. löschen ist in diesem Fall allerdings relativ. Der Garbage Collector erledigt das für dich und so weißt du nicht mal ob diese direkt am Ende oder irgendwann später gelöscht werden. Du pumpst deinen Speicher unglaublich voll.
Zusätzlich weiß ich nicht in wie fern du den Algorithmus aktuell eingebaut hast. Ob du den Weg ein mal berechnest und dann von der Einheit ablaufen lässt bis es einen neuen Weg gibt oder aber den Weg jeden Frame neu berechnen lässt. Du sagst dein Spiel wird langsam weshalb ich vermute dass du letzteres tust. Dadurch erzeugst du am laufenden Band unglaublich viele Objekte die sofort wieder zerstört werden was am Ende unglaublich viel unnötige Arbeit ist. Um solche Probleme zu lösen gibt es Ansätze, in deinem Fall heißt der Ansatz aber eigentlich dass du den ganzen Kram raus wirfst.

Also noch mal kurz. Du hast eine einzelne Karte. Bei dieser musst du die Nachbarn von Zellen bestimmen können. Außerdem musst du prüfen können ob eine Zelle begehbar ist. Wenn eine Einheit von A nach B wandern soll dann ruft sie ein einziges mal den Algorithmus auf welcher ihr einen Pfad zurück gibt. Ab jetzt läuft sie einfach diesen Pfad ab bis sie ein neues Ziel bekommt, dann wird A* eben neu aufgerufen. Ob A* jetzt eine Methode, in einer Klasse oder in einer statischen Klasse steckt macht erst mal keinen Unterschied.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

20

09.06.2017, 08:12

Hallo nochmal,

ich kapiere es nicht und damit meine ich nicht was du mir erklärt hast.
So. Ich habe das Nodegrid in einen Konstruktor gepackt. Das mit dem findPath siehst du richtig, das lade ich pro Frame. Das Problem ist aber, wie soll findPath auf Benutzereingaben reagieren können, wenn man den Pfad nur einmal lädt ? Die Einheit wird zwar zur Laufzeit erzeugt, denn die können ja mehr oder weniger werden, aber wenn ich den A* im Konstruktor der Einheit aufrufe, gibt das ja keinen Sinn, denn geladen ist geladen. Du hast übrigens Recht, es ist egal ob findPath statisch ist oder nicht habe ich nachgelesen (Insel...).
Aber wo lädt man findPath denn sonst, als zur Laufzeit ?
Das einzige was mir noch einfällt ist die main(), aber da müsste ich das ganze Programm umstellen.

Werbeanzeige