Entwickler-Ecke

Multimedia / Grafik - PacMan - KI Fragen


mimi - So 16.03.03 15:00
Titel: PacMan - KI Fragen
Hallo,

ich möchte eine Pacman KI schreiben, aber wie? ich habe mal folgendes versucht:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
if Game.ki[i].Gehe = True then begin
      x:=Game.ki[i].x; y:=Game.ki[i].y;

      if (Game.Karte[x,y+1].Typ <> _Monster) and (Game.Karte[x,y+1].Typ <> _Wand) and (Game.ki[i].dir = _none) then begin
        Game.ki[i].dir:=_oben;
        Game.Karte[x,y].Typ:=_None;
        Inc(y);
        Game.Karte[x,y].Typ:=_monster;
        Game.ki[i].y:=y;
        Game.ki[i].Gehe:=False;
      end
      else
        Game.ki[i].dir:=_none;

      if (Game.Karte[x,y-1].Typ <> _Monster) and (Game.Karte[x,y-1].Typ <> _Wand) and (Game.ki[i].dir = _none)then begin
        Game.ki[i].dir:=_unten;
        Game.Karte[x,y].Typ:=_None;
        dec(y);
        Game.Karte[x,y].Typ:=_monster;
        Game.ki[i].y:=y;
        Game.ki[i].Gehe:=False;
      end
      else
        Game.ki[i].dir:=_None;


      if (Game.Karte[x-1,y].Typ <> _Monster) and (Game.Karte[x-1,y].Typ <> _Wand) and (Game.ki[i].dir = _none)then begin
        Game.ki[i].dir:=_links;
        Game.Karte[x,y].Typ:=_None;
        dec(x);
        Game.Karte[x,y].Typ:=_monster;
        Game.ki[i].x:=x;
        Game.ki[i].Gehe:=False;
      end
      else
        Game.ki[i].dir:=_None;

      if (Game.Karte[x+1,y].Typ <> _Monster) and (Game.Karte[x+1,y].Typ <> _Wand) and (Game.ki[i].dir = _none)then begin
        Game.ki[i].dir:=_rechts;
        Game.Karte[x,y].Typ:=_None;
        inc(x);
        Game.Karte[x,y].Typ:=_monster;
        Game.ki[i].x:=x;
        Game.ki[i].Gehe:=False;
      end
      else
        Game.ki[i].dir:=_None;

    end;

dieser weg scheint nicht zu funktionieren: weil die kI geht immer in die untere linke ece warum? ich möchte gerne das die KI(9 stück) verschiedene wegen gehen. Es soll auch KIs geben die dir folgen, es soll auch noch welche geben die den KI typ ändern können;)

kann mir da jemmand weiter helfen ?


maximus - Mo 17.03.03 13:31

Hi mimi.

Ich hab auch mal ein pacMan gemacht. Wenn ich das richtig sehe willst du eine ki für die Geister? Hab es auch hinbekommen das die geister in deine richtung gehen wenn sie dich jagen und umgekehrt wenn du sie jagst.

Ich habs recht simple gemacht:

1. richtung vom geist zu dir feststellen -> zB: dir := [up, right];
2. schnittmenge vom aktuellen wegPunkt des geistestes: possible := map[ghost.x,ghost.y].dirs * dir;
3. Aus den verbleibenden elementen im set mit random eins aussuchen.
4. Und ab die post :D

Wenn du die geister jagst muss 'dir' natürlich umgekehrt werden! Vielleicht kannst du das ja für deinen Ansatz verwenden...muss zugeben ich hab ihn nicht analysiert...weil keine erklärung dabei ist.

viel spass!

PS: Wustet ihr dass PacMan früher mal PuckMan hiess...nur da hatten sich die automaten kids ein scherz draus gemacht und das 'P' zu einem 'F' umgekrazt -> FuckMan :D


mimi - Mo 17.03.03 16:23

mein problem ist die weg suche....
Die KI muss denn weg selber suchen und das schaffe ich nicht.
Auf einer fläche wo keine hindernisse sind, würde ich das mit sicherheit schaffe. Aber bei Packman sind ja hindernisse(leider)

was für eine erklärung zum qullcode hättes du denn gerne ?


tommie-lie - Mo 17.03.03 17:59

Na, wenn das dein Problem ist, ist doch maximus' Weg ideal:
Du schaust zuerst, in welche Richtung der Geist auf "freiem Feld" laufen müsste. Zum Beispiel nach up/right. Jetzt ist aber oberhalb von ihm eine Wand, da kann er nicht lang. Also geht er nur nach rechts. Bei jedem Schritt wird erneut geprüft, ob er jetzt endlich nach oben und rechts kann. Irgendwann ist dann eine Lücke in der Wand, sodaß er nach oben kann, dafür aber nicht mehr nach rechts. Also geht er jetzt nur noch nach oben. Entweder hat er den PacMan dann schon eingeholt (sind die Geister schneller?), oder es kommt wieder 'n Wand und er muss wieder nur nach rechts. Oder er ist nun endlich auf der gleichen "Zeile" wie der PacMan und muss nur noch den Gang nach rechts, bis der den PacMan eingeholt hat. Ist eine einfache if-Abfrage:
Schaue wohin der Geist soll -> wenn Wand, da nicht lang, sondern die zweite Richtung.
Einziges Problem ist dann, wenn der Pacman quasi genau neben dem Geist steht, und nur durch eine Wand von ihm getrennt ist. Dann müsste er z.B. nur nach rechts gehen, geht aber nicht.
Da habe ich schon verschiedene Implementationen gesehen, und die einfachste ist, in so einem Fall den Geist einfach stehen zu lassen, bis der Pacman sich weiter bewegt hat. Wenn man mehrere Geister hat, fällt das eigentlich kaum auf, bzw stört nicht so sehr. Bei einem Geist ist das dann allerdings ziemlich blöd. Eine schwierigere Implementation wäre die Wegfindung des Geistes auch bei einer solchen Situation. Dafür müssen aber generell die Schritte des Geistes im Vorraus berechnet werden (denn wenn er jetzt einen Schritt in eine zufällige Richtung macht, würde die nächste Abfrage wieder den gleichen Schritt zurükmachen -> in Richtung PacMan), was die ganze Angelegenheit schwieriger macht.

Das von maximus angesprochene Überprüfen der groben Richtung (also oben, unten, rechts und links) lässt sich ebenfalls mit ein paar if-Abfragen erledigen, wenn du dien Spielfeld in einem Array gespeichert hast (wovon ich nach einem Überfliegen deines Codes ausgehe). Da lässt sich dann die relative Position zum PacMan anhand der Inidzes, also der Positionen innerhalb des Arrays, ablesen.


maximus - Mo 17.03.03 18:20

Achso. Hast du das game nicht matrix-basiert gemacht?

Ich hab damals das spielfeld mit ner array-matrix gemacht und auf jedem wegpunkt den kreuzungsTyp gespeichert. In der kreuzugs-definition stand dann zB:

crossRoad[2] := [dkUp, dkRight];

die richtungen hab ich noch als vectoren definiert:

Type TDirKinds = (dkUp,dkDown,dkleft, dkRigth);

const dirs : array[0..3] of TPoint = ((x:0,y:-1),(x...)...);
...
Dann konnte ich mit ' theDir := dirs[word(dkUp)]; 'die richtung bestimmen.

Das hift dir allerdings nicht direkt weiter :) Deshalb meine frage: ist es matrix basiert?

Meine methode war halt nur so ungefähr! Hatte aber den effekt, dass die Geister einen gejagt haben. Ich hatte allerdings das gleiche problem, als es darum ging die geister wieder, auf dem kürzesten wege, zum 'GhostHome' laufen zu lassen, so bald man sie gekillt hatte. Ich hab einfach, auf einen zweiten map-layer, auf jeden punkt infos für den geist gespeichert/generiert.

Dein prob. erfordert aber ein dynamischen labyrinth-such-algo...such mal bei google nach 'mazes' algos.

mfg mx.


tommie-lie - Mo 17.03.03 18:37

Game.Karte[x,y].Typ:=_None;
Daraus schließe ich, daß Karte ein Property von Game ist, und daß es in Form eines Arrays vorliegt. Typ ist dann vermutlich _PacMan, _Ghost, _Wand und _None.
Und dann kann man anhand der Position feststellen, wo sich der Geist relativ zum PacMan befindet und dementsprechend ein Set füllen (ich hoffe, die Geister sind auch Klassen, sodaß die ein Property "Direction" kriegen können). Und einen wirklichen Labyrinth-Algo braucht man eben nur, wenn man mein Szenario mit der Wand direkt zwischen PacMan und Geist auhc noch berücksichtigen will. Aber wie gesagt, ich habe uach schon PacMans gesehen, bei denen sich dann die Geister nicht bewegt haben, bis sich der PacMan dann endlich mal entschlossen hatte, sich woanders hinzubewegen.


maximus - Di 18.03.03 11:26

@tommmie-lie: Wenn man sich an das original halten will, dann sollten die geister nicht stehen bleiben...sieht glaub ich auch merkwürdig aus! Wenn der geist keine sinnvolle richtung, zum PacMan, einschlagen kann, dann kann er ja aus den verbleibenden richtungen eine zufällig aussuchen.

Mit den oben beschriebenen Verfahren waren die Geister so gut, dass ich die wahrscheinlichkeit senken musste, sodass die geister sich auch mal irren.


tommie-lie - Di 18.03.03 15:37

aber das Problem ist, daß er dann beim nächsten Schritt wieder den gleichen Schritt zurückmachen muss. Vielleicht sagt ein ASCII-Bildchen mehr als tausend Worte:
G = Ghost
P = PacMan

Quelltext
1:
2:
3:
|   |
| G |__P
|______

Nu müsste er eigentlich nach rechts gehen, da ist aber 'ne Wand. Also wählt der Zufall "oben" aus. Dann sieht das Bild so aus:

Quelltext
1:
2:
3:
| G |
|   |__P
|_____

Und schon würde der richtige Wegfindungs"algo" wieder greifen, denn jetzt kann er ja nach unten/links gehen, bzw niur nach unten, aber näher an den PacMan ran. Und daraus resultiert wieder das erste Bild. Oder hab' ich jetzt deinen Weg nicht ganz verstanden?


maximus - Di 18.03.03 17:36

Ich denke du hast es verstanden :) Bei deinem bild wechselt der geist ja zwei die richtung. Ich würde im zweifelsfall den geist immer in die entgegen gesetzte richtung laufen, aus der er kommt. Also für diesen spezialfall auf die verfolgung verzichten...oder die richtung, aus der er kommt, aus der liste der möglichen richtungen löschen. Somit kann er nicht anders, als nach unten zu laufen(wenn er von oben kommt) :D

Auf jedenfall kann man damit brauchbare ergebnisse erzielen...wenn alle vier geister super exakt auf einen zustürmen hat man eh keine chance, was dann zeimlich frustrierend wäre.

auf bald. maximu