Konzeptfrage zu Pacman

raGe666

Mitglied
Morgen zusammen,

ich habe eine Frage zum Konzept bezüglich der Bewegung der Monster in Pacman. Da diese selber durch die Gänge laufen sollen, muss die Klasse Monster ja wissen, wo eine Mauer ist und wo nicht.
Das habe ich im Moment so gelöst, dass bei der Aufforderung, ein Feld zu gehen, in der move()-Methode vorher das Feld vor, hinter, rechts und links vom Monster auf den boolean isWall geprüft wird. Wenn das nördliche Feld eine Mauer ist, wird ein
Code:
int wallFlag
um 3 erhöht, wenn das östliche Feld eine Mauer ist, um 5 erhöht, beim südlichen Feld wird um 7 erhöht und beim westlichen um 11.
Somit ergeben sich verschiedene Summen dieser Zahlen anhand derer entschieden werden kann, wo man überall hinkann.
Zum Beispiel würde die Summe 12 ergeben, dass im östlichen und im südlichen Feld eine Mauer ist und das Monster somit nur nach Norden oder Westen gehen kann.

Nun erscheint mir das recht umständlich und vielleicht auch nicht so effizient, weil dann folgender Code entsteht:
[JAVA=533] public void move() {
int wallFlag = scanWalls();
int i;
Random r;

oldX = posX;
oldY = posY;

switch (wallFlag) {
case 3: moveUp();
break;

case 5: moveRight();
break;

case 7: moveDown();
break;

case 11: moveLeft();
break;

case 8: if (dir.equals("W")) {
moveUp();
} else {
moveRight();
}
break;

case 10: if (dir.equals("N")) {
moveUp();
} else {
moveDown();
}
break;

case 12: if (dir.equals("W")) {
moveDown();
} else {
moveRight();
}
break;

case 14: if (dir.equals("E")) {
moveUp();
} else {
moveLeft();
};
break;

case 16: if (dir.equals("E")) {
moveRight();
} else {
moveLeft();
}
break;

case 18: if (dir.equals("E")) {
posY++;
} else {
posX--;
}
break;

case 13: r = new Random();
i = r.nextInt(100);
if (i < 33) {
moveUp();
} else if (i < 66) {
moveRight();
} else {
moveLeft();
}
break;

case 19: r = new Random();
i = r.nextInt(100);
if (i < 33) {
moveUp();
} else if (i < 66) {
moveRight();
} else {
moveLeft();
}
break;

case 21: r = new Random();
i = r.nextInt(100);
if (i < 33) {
moveUp();
} else if (i < 66) {
moveDown();
} else {
moveLeft();
}
break;

case 23: r = new Random();
i = r.nextInt(100);
if (i < 33) {
moveRight();
} else if (i < 66) {
moveDown();
} else {
moveLeft();
}
break;
}
}

public void moveUp() {
posY--;
dir = "N";
}

public void moveDown() {
posY++;
dir = "S";
}

public void moveLeft() {
posX--;
dir = "W";
}

public void moveRight() {
posX++;
dir = "E";
}

public int scanWalls() {
int w = 0;
if (posY == 0) {
w += 0;
} else if (!(g.gameField.field[posX][posY - 1].getWall())) {
w += 3;
}
if (posX == 12) {
w += 0;
} else if (!(g.gameField.field[posX + 1][posY].getWall())) {
w += 5;
}
if (posY == 12) {
w += 0;
} else if (!(g.gameField.field[posX][posY + 1].getWall())) {
w += 7;
}
if (posX == 0) {
w += 0;
} else if (!(g.gameField.field[posX - 1][posY].getWall())) {
w += 11;
}
return w;
}[/code]

Gibt ein keine bessere, kürzere und/oder schönere Lösung, die Bewegung der Monster zu bestimmen? Trotzdem soll sie ja nicht komplett zufällig sein, also nicht auf einmal mitten im Gang umdrehen oder versuchen in eine Wand zu laufen.
 

nazar

Mitglied
Laufrichtung merken und die Wände z. B. mit Boolean[] übergeben. Spart dir nicht wirklich eine Abfrage, aber das unschöne Addieren fällt weg.

Wenn ich die Pacmanbewegungen noch richtig in Erinnerung habe, kann das Monster bei Abzweigungen abbiegen und muss dem Gang nicht folgen.
Ein anderer Ansatz wäre damit die Bewegung auch gleich in scanWalls() zu werfen, solang sie nicht direkt gegen die Laufrichtung geht. Diese kannst du scanWalls() ja mitgeben.

Für das Wegrennen bei Superpacman weiß ich jetzt nicht wirklich was. Pacman fokussieren könnte aber mit *Algorithmus klappen, falls du soetwas implementieren willst.
 

raGe666

Mitglied
klar, mit "mitten im Gang umdrehen" meinte ich natürlich, wenns nur vor/zurück gibt, dass das Monster die momentane Richtung beibehält.
Die Sache mit SuperPacman wollte ich erst noch nicht behandeln (auch wenn ich die Möglichkeit dafür offen zuhalten versuche^^), weil das im Moment noch meine Fähigkeiten übersteigt, denke ich :oops:

kannst du die Idee mit dem Boolean[] noch weiter ausführen? Kann mir im Moment noch nicht denken wie du das gemeint hast :)
 

nazar

Mitglied
Damit meinte ich nur den Return-Wert deiner scanWalls()-Methode.
Code:
boolean[] baWalls = new boolean[4];
return baWalls;
oder so.
Umgeht den Int-Return-Wert und erspart eben das Addieren.
Nun kann man nichtmehr mit Switch-Case arbeiten, aber "bEastWall=true" erscheint mir einfach schöner als 5.
 
S

SlaterB

Gast
die vierfache Wiederholung der Random-Geschichte verhinderst du allein dadurch, dass du nur aus Monstersicht agierst:
vorwärts, links rum, rechts rum, rückwärts,
was das dann jeweils bedeutet, ob auf dem Spielfeld nach Norden, Süden, Osten, Westen, kann danach in einem klaren Schritt umgerechnet werden,

und wozu ints in einer objektorientierten Sprache?
verwende Enums für die Richtungen bzw. subjektiven Werte (vorwärts, links rum, rechts rum, rückwärts),
dann eine Liste/ Set davon, falls nützlich, was mir aber gerade noch nicht so scheint, lieber:
speichere 4 boolean, das ist zwar auch etwas primitiv, aber zumindest leicher zu durchschauen als die Flags in der Zahl,
du musst hier nicht extrem sparen

Java:
linksFrei = istFrei(bestimmeFeld(monsterPosition,monsterAusrichtung, (inks)true, false, false, false));
...
statt der 4 boolean-Parameter für die Richtung dann doch ein Enum, in der Methode bestimmeFeld()
muss aber irgendwann dann doch die ganzen if/else kommen, posY + 1 usw., durch monsterRichtung sogar noch zusätzlich kompliziert

monsterRichtung könnte auch Enum sein, (Norden, Süden, Osten, Westen),
zu (vorwärts, links rum, rechts rum, rückwärts) bisschen redudant, aber lieber nicht zusammenfassen

ok, diese Methode wird jetzt ziemlich kompliziert, falls man da nicht wieder bisschen abstrahiert, x und y austauschbar macht,
nicht das Glanzstück im Sparen, wenn auch interessanter Code herauskommen kann

----

jedenfalls wird es danach interessant wenn die 4 boolean vorhanden sind, bzw. nur 3,
nach hinten interessiert im Moment anscheindend nicht oder wäre wenn dann sowieso immer frei, von dort kommt das Monster ja,
dann die Bewegung bestimmen:
ich sehe in deinem Code nicht den Fall einer T-Kreuzung, nach vorne gehts nicht weiter, aber nach links und rechts?
dann muss doch sicher 50/50 gewählt werden,

ich würde aber bei dem 33/66-Code bleiben, bzw. wähle eine der drei Richtungen, wenn frei dann dorthin, sonst wiederholen,
falls paar mal umsonst gerechnet wird, ist das kein Beinbruch,
damit ist auch T mit 50/50 abgedeckt, bei nur einer Richtung, ob geradeaus oder Ecke, wird die irgendwann auch gefunden,

schließlich noch die gewählte Richtung wiederum mit der bisherigen Monster-Ausrichtung in ein Feld umrechnen, neue Monsterausrichtung speichern usw.,

-----

jetzt fällt mir gerade auf, dass man sich bei meinem Vorschlag zu 33/66 die Variablen linksFrei usw. gleich ganz sparen kann,
einfach eine Zielrichtung ausrechnen, schauen ob dort frei, dann dorthin, sonst neu, und gut,

Umrechnungen zu den Richtungen würden dabei aber bestehen bleiben (bestimmeFeld),
deutlich kürzer zu dem vorher von mir skizzierten ist das nicht unbedingt

----

oder doch wieder auf einfacherem Niveau, weitgehend Verzicht auf Richtungen usw.:
rechne einfach nur mit Zufall 25/50/75 eines von 4 Nachbarfeldern aus,
wenn es das vorherige des Monster war (merken), dann ablehnen, wiederholen
wenn es eine Wand ist, dann ablehnen, wiederholen,
sonst dorthin ;)
dürfte den einfachen Bewegungsregeln im Moment genügen
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Allgemein (auch in bezug auf SlaterBs Einwand der Durchschaubarkeit und Nachvollziehbarkeit) : Eine Option wären "richtige" Flags - im Gegensatz zu den pseudo-Flags, die addiert werden.

Java:
private static final int NORTH = (1<<0);
private static final int SOUTH = (1<<1);
private static final int EAST = (1<<2);
private static final int WEST = (1<<3);

private int computeWalls()
{
    ...
    return NORTH | WEST; // Beispiel
}


int walls = computeWalls(...);
if ((walls & NORTH) != 0) { // Im Norden ist eine Wand }
if ((walls & WEST ) != 0) { // Im Westen ist eine Wand }
if ((walls & SOUTH ) == 0) { // Im Süden ist KEINE Wand }
...
Aber ... das sieht vom Stil her schon so aus, als würde es aus dem Original-PacMan stammen ;) Man kann sich da heute schon etwas Objektorienterung gönnen...
 

raGe666

Mitglied
danke nochmal!
Als Sozusagen-Einsteiger kann ich aber leider nichts mit
Code:
private static final int NORTH = [B](1<<0)[/B];
oder
Code:
return [B]NORTH | WEST[/B];
anfangen :oops:
Kannst du mir 1,2 Stichworte geben, unter was ich das nachlesen kann?
 

tuttle64

Bekanntes Mitglied
Die Monstersicht ist schon mal ein guter Ansatz. Leider genügt diese nicht, um aus konzeptioneller Sicht die Frage zu beantworten, wie ein Monster auf dem kürzesten Weg zum Pacman gelangt oder auch wie sich die verfügbaren Monster bewegen müssen, um Pacman einzukesseln.
 

raGe666

Mitglied
Die Monstersicht ist schon mal ein guter Ansatz. Leider genügt diese nicht, um aus konzeptioneller Sicht die Frage zu beantworten, wie ein Monster auf dem kürzesten Weg zum Pacman gelangt oder auch wie sich die verfügbaren Monster bewegen müssen, um Pacman einzukesseln.

die Monster sollen Pacman nicht aktiv verfolgen (was sie im Original auch nicht machen, sondern nur zufällig durchs Spielfeld ziehen und dabei zufällig Pacman einkreisen, glaub ich), sondern nur, in einem fernen Stadium der Spieleentwickung, vor einem Superpacman wegrennen.
 
S

SlaterB

Gast
beim Superpacman dürfte eine einfache Entfernungsbewertung der verfügbaren Felder schon gut funktionieren,
wenn links der Superpacman, dann ist das rechte Feld günstiger, da weiter entfernt, also dorthin
 

AngryDeveloper

Bekanntes Mitglied
die Monster sollen Pacman nicht aktiv verfolgen (was sie im Original auch nicht machen, sondern nur zufällig durchs Spielfeld ziehen und dabei zufällig Pacman einkreisen, glaub ich)

Ist nicht einfach nur zufällig. Die Geister haben auch jeweils ein unterschiedliches Verhalten:
GameInternals - Understanding Pac-Man Ghost Behavior
Evtl. recht interessant zu lesen.

Edit:
Hier alles sogar noch genauer. Ist aber auf der anderen Seite eh auch verlinkt:
The Pac-Man Dossier
 
Zuletzt bearbeitet:

Ähnliche Java Themen


Oben