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

1

30.09.2015, 19:14

[KI] Designentscheidungen

Hi, ich arbeite (mit C++ und SFML) an einem 2D Topdown Dungeoncrawler und bin nun soweit, dass ich eine minimale Lua-KI integriert habe. Die KI kann im Moment selbständig im Stehen angreifen (sie schwingt das Schwert erstmal nur durch die Luft ^^). Da das Gesamtsystem ein Entity-Component-System ist, habe ich entsprechend eine KI-Komponente erstellt, welche einen AiState und einen Zeiger auf eine Script Instanz besitzt. Dem Script wird beim Aufruf ein Zeiger auf den AiState mitgegeben; der State wird verwendet um zu wissen wer der Akteur ist (siehe unten, Variable object). Weiterhin kapselt er Aktionen wie attack() (um den eigentlichen Angriff auszulösen).

Ich habe im Moment folgendes Script:

Quellcode

1
2
3
onIdle = function(object)
    object:attack()
end

Sobald der Angriff nach einigen Frames fertig ist, wird die KI darüber informiert und onIdle erneut ausgelöst... Allerdings frage ich mich ob es so sinnvoll ist das Script zwischen KI-Instanzen zu teilen.

Meine Gedanken dazu:
  • Prinzipiell ist es sinnvoll das Script zu teilen, damit nicht für 100 Objekte, die eigentlich das gleiche Script verwenden, entsprechend 100 Scripte im Speicher sind - eins reicht prinzipiell.
  • Will ich, dass die KI sich "Sachen merkt" (zB die ID ihres Opfers, dem sie hinterher rennen will), wäre mein erster Ansatz das direkt im Lua abzulegen; effektiv als globale Variable. Dann teilen sich die KI-Instanzen aber auch diese globalen Variablen. Hätte ich pro KI-Instanz ein Script, hätte jeder seine eigenen globalen Variablen.
  • Dann könnte ich noch im Script eine globale Table nehmen, hinter der sich pro Objekt das "Gemerkte" befindet. Der Akteur würde dann über seine eigene ObjectID an sein "Gedächtnis" kommen.
  • Das "Gedächtnis" über den AiState zu realisieren halte ich für keine gute Idee. Zum einen wirkt das ganze relativ starr (AiState ist ja Teil des C++-Codes), und zum anderen... selbst wenn ich eine schön flexible Schnittstelle baue, müssen die Daten (die sich die KI merkt oder an die sie sich erinnert) bei jedem get und set kopiert werden. Vermutlich bin ich da mit nativen Lua-Variablen schneller.
Ich bin mir nicht so richtig sicher wie ich vorgehen sollte... Was meint ihr dazu? Oder hat jmd. sogar Erfahrungen mit dem Thema?

LG Glocke

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

2

01.10.2015, 18:11

Ist es denn realistisch dass so viele (1000) Akteure gleichzeitig berechnet werden sodass du 1000 Skriptinstanzen hättest? Ich glaube ich würde es erst mal simpel lösen und jedem Agenten eine eigene Instanz des Skriptes verpassen. Ansonsten könnte man überlegen die Skripte zu teilen und zusätzlich ein Argumentsobjekt in Lua zu erzeugen und zu hinterlegen. Möglicherweise könnte das ja einfach ein Dictionary sein welches einem Schlüssel einen Wert zuweist. Möglicherweise ist es das was du mit deinem Gedächtnis meintest, wobei ich in einem Gedächtnis andere Dinge ablegen würde. Das könnte zum Beispiel ein Ort sein an welchem ein potentieller Gegner zuletzt gesehen wurde um ihn genauer zu untersuchen. Die Skripts selbst werden aber vermutlich eigene interne Daten über Frames hinweg speichern müssen, welche dort nicht unbedingt rein gehören. Die könnten dann in diesem Dictionary abgelegt werden. Diese einzelnen Dictionaries könntest du dann in eine große Tabelle stecken welche jedem Agenten sein Dictionary zuweist. Ob du dadurch am Ende groß Einsparungen hast ist natürlich so eine Sache. Wenn deine Skripte relativ groß wären würde so ein Ansatz vielleicht sinnvoll sein. Wobei ich eigentlich schon bezweifle dass du das überhaupt benötigst, weshalb ich wie gesagt erst mal jedem seine eigene Skriptinstanz geben würde und gut.
„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.“

3

02.10.2015, 17:51

Ist es denn realistisch dass so viele (1000) Akteure gleichzeitig berechnet werden sodass du 1000 Skriptinstanzen hättest?

1-2k Objekte ist schon denkbar, wäre aber vermutlich eine Obergrenze bei der ich dann andere Probleme als den Speicherbedarf der KI habe xD.

und zusätzlich ein Argumentsobjekt in Lua zu erzeugen und zu hinterlegen. Möglicherweise könnte das ja einfach ein Dictionary sein welches einem Schlüssel einen Wert zuweist. Möglicherweise ist es das was du mit deinem Gedächtnis meintest, wobei ich in einem Gedächtnis andere Dinge ablegen würde. Das könnte zum Beispiel ein Ort sein an welchem ein potentieller Gegner zuletzt gesehen wurde um ihn genauer zu untersuchen.

Letzteres meinte ich mit Gedächtnis :) Was verstehst du dann unter dem Argumentsobjekt?
Zur Identifizierung (welches Objekt gerade gemeint ist) übergebe ich atm den AiState der KI (welcher erlaubte Operationen kapselt und die unique ID des Akteurs bereitstellt). Nur, dass ich das Objekt nicht hinterlege sondern immer per Pointer bzw. Reference dem Script übergebe.

Die Skripts selbst werden aber vermutlich eigene interne Daten über Frames hinweg speichern müssen, welche dort nicht unbedingt rein gehören.

Was meinst du damit genau?

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

4

02.10.2015, 18:12

Möchtest du einen Algorithmus nach einer bestimmten Anzahl von Schritten abbrechen und später weiter berechnen lassen müsstest du dafür Daten zwischen speichern. Als Beispiel könnte eine Wegfindung nach einer gewissen Anzahl von Schritten unterbrochen werden um Arbeitszeit abzugeben. Im nächsten Durchlauf könnte die KI die Arbeit wieder aufnehmen. Das Teilergebnis müsste dann natürlich gespeichert werden. Solche Daten meinte ich. So etwas benötigst du natürlich nur wenn du die Algorithmen unterbrechen und später wieder aufnehmen möchtest. Ansonsten würdest du das vermutlich nicht brauchen.
„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.“

5

02.10.2015, 18:19

Möchtest du einen Algorithmus nach einer bestimmten Anzahl von Schritten abbrechen und später weiter berechnen lassen müsstest du dafür Daten zwischen speichern. Als Beispiel könnte eine Wegfindung nach einer gewissen Anzahl von Schritten unterbrochen werden um Arbeitszeit abzugeben. Im nächsten Durchlauf könnte die KI die Arbeit wieder aufnehmen. Das Teilergebnis müsste dann natürlich gespeichert werden. Solche Daten meinte ich. So etwas benötigst du natürlich nur wenn du die Algorithmen unterbrechen und später wieder aufnehmen möchtest. Ansonsten würdest du das vermutlich nicht brauchen.

Ich habe überlegt ob ich das Pathfinding über mehrere Frames verteile und dafür ein eigenes Subsystem PathSystem implementiere. Dann würde die KI nur ein "NavigationEvent" (unter einer move() Methode weggekapselt) versenden.

Aber eigentlich wollte ich das Pathfinding in zwei Phasen unterteilen (1: grobe Navigation anhand vorgefertigter Wegpunkte zwischen Räumen des Dungeons; 2: "feine" Navigation zwischen zwei Wegpunkten - die dann nicht besonders weit voneinander entfernt sind).. Aber so 100%ig ist das noch nicht beschlossen. Aber dadurch würde das Pathfinding eh über mehrere Frames hin gezogen werden, wenn er bei Erreichen eines Wegpunktes den genauen Pfad zum nächsten bestimmt... Ich schwafel schon wieder xD

Werbeanzeige