From afad1017a530875584afa7ecea5b678d48aa2c7b Mon Sep 17 00:00:00 2001 From: Matt Low Date: Thu, 26 Dec 2019 16:13:29 +0400 Subject: [PATCH] Implement FrightBehaviour This took way too long. --- core/src/com/me/pacman/entity/Ghost.java | 77 +++++++++++++++++--- core/src/com/me/pacman/entity/Pacman.java | 4 +- core/src/com/me/pacman/entity/ai/Target.java | 4 + core/src/com/me/pacman/state/PlayState.java | 17 +++-- 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/core/src/com/me/pacman/entity/Ghost.java b/core/src/com/me/pacman/entity/Ghost.java index 9f4dffe..e7963ea 100644 --- a/core/src/com/me/pacman/entity/Ghost.java +++ b/core/src/com/me/pacman/entity/Ghost.java @@ -8,6 +8,8 @@ import com.me.pacman.entity.ai.Target; import com.me.pacman.level.LevelTile; import com.me.pacman.state.PlayState; +import java.util.ArrayList; + public class Ghost extends MovableEntity { public static final Direction[] GHOST_ORDER = { Direction.UP, Direction.LEFT, Direction.DOWN, Direction.RIGHT }; @@ -17,8 +19,8 @@ public class Ghost extends MovableEntity { public Behaviour currentBehaviour; public Behaviour chaseBehaviour; - public Behaviour freightBehaviour; public Behaviour scatterBehaviour; + public Behaviour frightBehaviour; public TextureRegion[][] sprite; @@ -26,13 +28,13 @@ public class Ghost extends MovableEntity { private int counter = 0; public Ghost(PlayState state, float x, float y, Direction direction, int spriteIndex, - Behaviour chaseBehaviour, Behaviour freightBehaviour, Behaviour scatterBehaviour) { + Behaviour chaseBehaviour, Behaviour scatterBehaviour) { super(state, x, y, 7.03f, true, direction, 0.1f); this.state = state; this.spriteIndex = spriteIndex; this.chaseBehaviour = chaseBehaviour; - this.freightBehaviour = freightBehaviour; this.scatterBehaviour = scatterBehaviour; + this.frightBehaviour = new FrightenedBehaviour(state); sprite = state.getGame().assets.ghosts; } @@ -53,7 +55,7 @@ public class Ghost extends MovableEntity { public void update(float dt) { super.update(dt); - if (!state.paused && age % 20 == 0) { + if (age % 20 == 0) { counter++; } @@ -66,16 +68,19 @@ public class Ghost extends MovableEntity { } Target target = currentBehaviour.getTarget(); - Vector2 ahead = new Vector2((int) pos.x, (int) pos.y).add(currDirection.getVector()); + if (target == null) { + // no target, carry on current course + return; + } - Direction bestDirection = null; + Vector2 ahead = new Vector2((int) pos.x, (int) pos.y).add(currDirection.getVector()); float shortest = Float.MAX_VALUE; + Direction nextDirection = null; for (Direction dir : GHOST_ORDER) { if (dir.isOpposite(currDirection)) { continue; } - Vector2 adjacent = dir.getVector().add(ahead); LevelTile nextTile = state.level.getTile(adjacent); if (nextTile != null && nextTile.isPassable()) { @@ -83,14 +88,12 @@ public class Ghost extends MovableEntity { float d = target.distance_sqr(adjacent); if (d < shortest) { shortest = d; - bestDirection = dir; + nextDirection = dir; } } } - if (bestDirection != null) { - setNextDirection(bestDirection); - } + setNextDirection(nextDirection); } private class ReturnToBase extends Behaviour { @@ -108,4 +111,56 @@ public class Ghost extends MovableEntity { } + private class FrightenedBehaviour extends Behaviour { + + private Target target; + + public FrightenedBehaviour(PlayState state) { + super(state); + } + + @Override + public Target getTarget() { + if (target != null && !target.targetReached(pos)) { + return target; + } + + ArrayList adjacentTiles = new ArrayList<>(3); + ArrayList possibleTurns = new ArrayList<>(3); + Vector2 ahead = new Vector2((int) pos.x, (int) pos.y).add(currDirection.getVector()); + + for (Direction dir : GHOST_ORDER) { + if (dir.isOpposite(currDirection)) { + // Don't consider going backwards + continue; + } + Vector2 adjacent = dir.getVector().add(ahead); + LevelTile nextTile = state.level.getTile(adjacent); + if (nextTile != null && nextTile.isPassable()) { + adjacentTiles.add(adjacent); + possibleTurns.add(dir); + } + } + + if (possibleTurns.size() == 0) { + // No possible turns means no valid tiles ahead, which would be the tunnel. + target = null; + } else if (possibleTurns.size() == 1) { + if (possibleTurns.get(0) == currDirection) { + // can only go straight, so no target + target = null; + } else { + // turn the only possible direction + target = new Target(adjacentTiles.get(0)); + } + } else { + // n-way intersection, pick random direction + int rand = state.random.nextInt(adjacentTiles.size()); + target = new Target(adjacentTiles.get(rand)); + } + return target; + } + + } + } diff --git a/core/src/com/me/pacman/entity/Pacman.java b/core/src/com/me/pacman/entity/Pacman.java index e8ed2e0..4042ed8 100644 --- a/core/src/com/me/pacman/entity/Pacman.java +++ b/core/src/com/me/pacman/entity/Pacman.java @@ -46,11 +46,11 @@ public class Pacman extends MovableEntity { super.update(dt); - if (!state.paused && canMove && age % 4 == 0) { + if (canMove && age % 4 == 0) { counter += 1; } - if (age % 8 == 0 && !alive) { + if (!alive && age % 8 == 0) { deathFrame++; } diff --git a/core/src/com/me/pacman/entity/ai/Target.java b/core/src/com/me/pacman/entity/ai/Target.java index 1bb1465..9ae06dd 100644 --- a/core/src/com/me/pacman/entity/ai/Target.java +++ b/core/src/com/me/pacman/entity/ai/Target.java @@ -32,4 +32,8 @@ public class Target { return this.x == (int) x && this.y == (int) y; } + public boolean targetReached(Vector2 vec) { + return targetReached(vec.x, vec.y); + } + } diff --git a/core/src/com/me/pacman/state/PlayState.java b/core/src/com/me/pacman/state/PlayState.java index a656d40..978e418 100644 --- a/core/src/com/me/pacman/state/PlayState.java +++ b/core/src/com/me/pacman/state/PlayState.java @@ -15,17 +15,21 @@ import com.me.pacman.entity.ai.BlinkyChaseBehaviour; import com.me.pacman.level.Level; import com.me.pacman.level.LevelTile; +import java.util.Random; + public class PlayState extends LevelState { private Texture levelBackground; private BitmapFont font; + private TextureRegion lifeSprite; + private int pelletCount; private int pelletEatenCount; private int score; private int lives; private int round; - public boolean paused = false; + private boolean paused = false; private long sirenId; @@ -36,7 +40,7 @@ public class PlayState extends LevelState { private boolean pacmanCaught; - private TextureRegion lifeSprite; + public Random random; public Pacman pacman; public Ghost[] ghosts; @@ -90,7 +94,6 @@ public class PlayState extends LevelState { if (paused) { game.assets.getFont().setColor(Color.YELLOW); game.assets.getFont().draw(game.batch, "paused", 90, 151); - return; } } @@ -127,6 +130,8 @@ public class PlayState extends LevelState { } } + dt = 1/60f; + if (!pacmanCaught) { for (Ghost ghost : ghosts) { if (ghost == null) { @@ -184,7 +189,7 @@ public class PlayState extends LevelState { level = new Level(game,"level"); pacman = new Pacman(this, false); - ghosts[0] = new Ghost(this, 14, 19.5f, Direction.LEFT, 0, new BlinkyChaseBehaviour(this), null, null); + ghosts[0] = new Ghost(this, 14, 19.5f, Direction.LEFT, 0, new BlinkyChaseBehaviour(this), null); ghosts[0].currentBehaviour = ghosts[0].chaseBehaviour; game.assets.siren.stop(sirenId); @@ -205,8 +210,10 @@ public class PlayState extends LevelState { lives--; pacmanCaught = false; + random = new Random(897198256012865L); + pacman = new Pacman(this, false); - ghosts[0] = new Ghost(this, 14, 19.5f, Direction.LEFT, 0, new BlinkyChaseBehaviour(this), null, null); + ghosts[0] = new Ghost(this, 14, 19.5f, Direction.LEFT, 0, new BlinkyChaseBehaviour(this), null); ghosts[0].currentBehaviour = ghosts[0].chaseBehaviour; }