From cd2b968631076d75ac576189ecd8bdff5e274e9e Mon Sep 17 00:00:00 2001 From: Matt Low Date: Fri, 27 Dec 2019 14:32:22 +0400 Subject: [PATCH] Ghosts can get inside their house now Add Path object for defining apath an entity should take at a given speed. Fix some issues with ghost capturing logic --- core/src/com/me/pacman/PacDude.java | 2 + core/src/com/me/pacman/entity/Direction.java | 51 ++++++----- core/src/com/me/pacman/entity/Ghost.java | 32 +++++-- .../com/me/pacman/entity/MovableEntity.java | 11 ++- .../com/me/pacman/entity/ai/ReturnToBase.java | 1 - .../entity/path/EnterGhostHousePath.java | 20 +++++ .../entity/path/ExitGhostHousePath.java | 20 +++++ core/src/com/me/pacman/entity/path/Path.java | 89 +++++++++++++++++++ core/src/com/me/pacman/state/PlayState.java | 12 ++- 9 files changed, 207 insertions(+), 31 deletions(-) create mode 100644 core/src/com/me/pacman/entity/path/EnterGhostHousePath.java create mode 100644 core/src/com/me/pacman/entity/path/ExitGhostHousePath.java create mode 100644 core/src/com/me/pacman/entity/path/Path.java diff --git a/core/src/com/me/pacman/PacDude.java b/core/src/com/me/pacman/PacDude.java index 033b774..8326c70 100644 --- a/core/src/com/me/pacman/PacDude.java +++ b/core/src/com/me/pacman/PacDude.java @@ -15,6 +15,8 @@ public class PacDude extends Game { public static final String TITLE = "Pac-Dude"; public static final String VERSION = "v0.0.1"; + public static final boolean DEBUG = false; + public static final int LEVEL_WIDTH = 224; public static final int LEVEL_HEIGHT = 288; diff --git a/core/src/com/me/pacman/entity/Direction.java b/core/src/com/me/pacman/entity/Direction.java index c93b637..ae8f15f 100644 --- a/core/src/com/me/pacman/entity/Direction.java +++ b/core/src/com/me/pacman/entity/Direction.java @@ -4,42 +4,51 @@ import com.badlogic.gdx.math.Vector2; public enum Direction { - UP, - DOWN, - LEFT, - RIGHT, + UP(new Vector2(0f, 1f)), + DOWN(new Vector2(0f, -1f)), + LEFT(new Vector2(-1f, 0f)), + RIGHT(new Vector2(1f, 0f)), ; - public boolean isOpposite(Direction dir) { + private Vector2 vector; + + Direction(Vector2 vector) { + this.vector = vector; + } + + public Direction getOpposite() { switch (this) { case UP: - return dir == DOWN; + return DOWN; case DOWN: - return dir == UP; + return UP; case LEFT: - return dir == RIGHT; + return RIGHT; case RIGHT: - return dir == LEFT; + return LEFT; } - return false; + return null; + } + + public boolean isOpposite(Direction dir) { + return dir == getOpposite(); } public Vector2 getVector(float scale) { - switch (this) { - case UP: - return new Vector2(0f, 1f * scale); - case DOWN: - return new Vector2(0f, -1f * scale); - case LEFT: - return new Vector2(-1 * scale, 0f); - case RIGHT: - return new Vector2(1 * scale, 0f); - } - return null; + return new Vector2(this.vector).scl(scale); } public Vector2 getVector() { return this.getVector(1f); } + public static Direction fromVector(Vector2 vector) { + for (Direction dir : values()) { + if (dir.vector.hasSameDirection(vector)) { + return dir; + } + } + return null; + } + } diff --git a/core/src/com/me/pacman/entity/Ghost.java b/core/src/com/me/pacman/entity/Ghost.java index e1f9b17..6a02c90 100644 --- a/core/src/com/me/pacman/entity/Ghost.java +++ b/core/src/com/me/pacman/entity/Ghost.java @@ -6,6 +6,8 @@ import com.badlogic.gdx.math.Vector2; import com.me.pacman.entity.ai.Behaviour; import com.me.pacman.entity.ai.ReturnToBase; import com.me.pacman.entity.ai.Target; +import com.me.pacman.entity.path.EnterGhostHousePath; +import com.me.pacman.entity.path.ExitGhostHousePath; import com.me.pacman.level.LevelTile; import com.me.pacman.state.PlayState; @@ -13,6 +15,10 @@ import java.util.ArrayList; public class Ghost extends MovableEntity { + public static final float GHOST_SPEED = 7.03f; + public static final float GHOST_TUNNEL_SPEED = GHOST_SPEED / 2; + public static final float EYES_SPEED = 15f; + public static final Direction[] GHOST_ORDER = { Direction.UP, Direction.LEFT, Direction.DOWN, Direction.RIGHT }; private PlayState state; @@ -32,7 +38,7 @@ public class Ghost extends MovableEntity { public Ghost(PlayState state, float x, float y, Direction direction, int spriteIndex, Behaviour chaseBehaviour, Behaviour scatterBehaviour) { - super(state, x, y, 7.03f, true, direction, 0.1f); + super(state, x, y, GHOST_SPEED, true, direction, 0.1f); this.state = state; this.spriteIndex = spriteIndex; this.chaseBehaviour = chaseBehaviour; @@ -45,7 +51,7 @@ public class Ghost extends MovableEntity { @Override public TextureRegion getSprite() { - if (caught) { + if (caught && !returned) { return null; } else if (state.frightTimer > 0 && !returned) { return sprite[0][counter % 2]; @@ -71,6 +77,23 @@ public class Ghost extends MovableEntity { counter++; } + if (currentPath != null) { + if (currentPath instanceof EnterGhostHousePath) { + if (!currentPath.finished()) { + return; + } + currentPath = new ExitGhostHousePath(pos); + returned = true; + } else if (currentPath instanceof ExitGhostHousePath) { + if (!currentPath.finished()) { + return; + } + speed = GHOST_SPEED; + currentBehaviour = chaseBehaviour; + currentPath = null; + } + } + if (currentBehaviour == null) { return; } @@ -86,9 +109,8 @@ public class Ghost extends MovableEntity { } if (currentBehaviour instanceof ReturnToBase && target.targetReached(pos)) { - caught = false; - returned = true; - currentBehaviour = chaseBehaviour; + currentPath = new EnterGhostHousePath(pos); + return; } Vector2 ahead = new Vector2((int) pos.x, (int) pos.y).add(currDirection.getVector()); diff --git a/core/src/com/me/pacman/entity/MovableEntity.java b/core/src/com/me/pacman/entity/MovableEntity.java index 65f97ba..ff5b96f 100644 --- a/core/src/com/me/pacman/entity/MovableEntity.java +++ b/core/src/com/me/pacman/entity/MovableEntity.java @@ -1,6 +1,7 @@ package com.me.pacman.entity; import com.badlogic.gdx.math.Vector2; +import com.me.pacman.entity.path.Path; import com.me.pacman.level.LevelTile; import com.me.pacman.state.LevelState; @@ -15,6 +16,8 @@ public abstract class MovableEntity extends Entity { private Direction nextDirection = null; public boolean canMove = true; + public Path currentPath = null; + public MovableEntity(LevelState state, float x, float y, float speed, boolean moving, Direction currDirection, float turnTolerance) { super(state, x, y); this.speed = speed; @@ -30,6 +33,12 @@ public abstract class MovableEntity extends Entity { return; } + if (currentPath != null) { + currentPath.update(dt); + currentPath.updateEntity(this); + return; + } + LevelTile nextTile = null; if (nextDirection != null) { @@ -89,8 +98,6 @@ public abstract class MovableEntity extends Entity { float dist = speed * dt; LevelTile currentTile = state.level.getTile(pos.x, pos.y); - nextTile = null; - Vector2 new_pos = new Vector2(pos); switch (currDirection) { diff --git a/core/src/com/me/pacman/entity/ai/ReturnToBase.java b/core/src/com/me/pacman/entity/ai/ReturnToBase.java index e2e1a6d..88f29ea 100644 --- a/core/src/com/me/pacman/entity/ai/ReturnToBase.java +++ b/core/src/com/me/pacman/entity/ai/ReturnToBase.java @@ -4,7 +4,6 @@ import com.me.pacman.state.PlayState; public class ReturnToBase extends Behaviour { -// final Target home = new Target(14, 16); final Target home = new Target(14, 19); public ReturnToBase(PlayState state) { diff --git a/core/src/com/me/pacman/entity/path/EnterGhostHousePath.java b/core/src/com/me/pacman/entity/path/EnterGhostHousePath.java new file mode 100644 index 0000000..7eb2eae --- /dev/null +++ b/core/src/com/me/pacman/entity/path/EnterGhostHousePath.java @@ -0,0 +1,20 @@ +package com.me.pacman.entity.path; + +import com.badlogic.gdx.math.Vector2; +import com.me.pacman.entity.Ghost; + +import java.util.ArrayList; + +public class EnterGhostHousePath extends Path { + + private static final ArrayList points = new ArrayList() {{ + add(new Vector2(14, 19.5f)); + add(new Vector2(14, 16.5f)); + }}; + + public EnterGhostHousePath(Vector2 start) { + super(Ghost.EYES_SPEED, start); + addPoints(points); + } + +} diff --git a/core/src/com/me/pacman/entity/path/ExitGhostHousePath.java b/core/src/com/me/pacman/entity/path/ExitGhostHousePath.java new file mode 100644 index 0000000..2223eb1 --- /dev/null +++ b/core/src/com/me/pacman/entity/path/ExitGhostHousePath.java @@ -0,0 +1,20 @@ +package com.me.pacman.entity.path; + +import com.badlogic.gdx.math.Vector2; +import com.me.pacman.entity.Ghost; + +import java.util.ArrayList; + +public class ExitGhostHousePath extends Path { + + private static final ArrayList points = new ArrayList() {{ + add(new Vector2(14, 16.5f)); + add(new Vector2(14, 19.5f)); + }}; + + public ExitGhostHousePath(Vector2 start) { + super(Ghost.GHOST_TUNNEL_SPEED, start); + addPoints(points); + } + +} diff --git a/core/src/com/me/pacman/entity/path/Path.java b/core/src/com/me/pacman/entity/path/Path.java new file mode 100644 index 0000000..4fea18f --- /dev/null +++ b/core/src/com/me/pacman/entity/path/Path.java @@ -0,0 +1,89 @@ +package com.me.pacman.entity.path; + +import com.badlogic.gdx.math.Vector2; +import com.me.pacman.entity.Direction; +import com.me.pacman.entity.MovableEntity; + +import java.util.ArrayList; +import java.util.List; + +public class Path { + + private float speed; // speed in tiles/sec + private float elapsed; // seconds elapsed since beginning of path + + private List points; // points in the path + private List segmentLengths; + private int pathSegments; // total path segments + + private float pathLength; // total path length + private float progress; // distance along path + + public Path(float speed, Vector2 start) { + this.speed = speed; + this.elapsed = 0; + this.points = new ArrayList<>(); + this.segmentLengths = new ArrayList<>(); + addPoint(start); + } + + public void addPoints(List points) { + for (Vector2 point : points) { + addPoint(point); + } + } + + protected void addPoint(Vector2 point) { + points.add(point); + + if (points.size() == 1) { + return; + } + + pathSegments++; + Vector2 previous = points.get(points.size()-2); + float length = previous.dst(point); + segmentLengths.add(length); + pathLength += length; + } + + public void updateEntity(MovableEntity entity) { + if (finished()) { + return; + } + + float tmp = progress; + for (int i = 0; i < pathSegments; i++) { + float segmentLength = segmentLengths.get(i); + + if (tmp > segmentLength) { + tmp -= segmentLength; + continue; + } + + Vector2 a = new Vector2(points.get(i)); + Vector2 b = new Vector2(points.get(i+1)); + + Vector2 pathDir = b.sub(a).nor(); + + entity.currDirection = Direction.fromVector(pathDir); + entity.pos = a.add(pathDir.scl(tmp)); + break; + } + } + + public void reset() { + elapsed = 0; + progress = 0; + } + + public boolean finished() { + return progress >= pathLength; + } + + public void update(float dt) { + elapsed += dt; + progress = elapsed * speed; + } + +} \ No newline at end of file diff --git a/core/src/com/me/pacman/state/PlayState.java b/core/src/com/me/pacman/state/PlayState.java index 1b7ac45..15e3a30 100644 --- a/core/src/com/me/pacman/state/PlayState.java +++ b/core/src/com/me/pacman/state/PlayState.java @@ -106,6 +106,11 @@ public class PlayState extends LevelState { return; } + if (PacDude.DEBUG) { + // Fixed time step for debugger + dt = 1/60f; + } + if (gameOverTimer > 0) { gameOverTimer -= dt; if (gameOverTimer <= 0) { @@ -137,7 +142,8 @@ public class PlayState extends LevelState { frightTimer -= dt; if (frightTimer < 0) { for (Ghost ghost : ghosts) { - if (ghost == null || ghost.caught) continue; + if (ghost == null || (ghost.caught && !ghost.returned)) continue; + ghost.caught = false; ghost.currentBehaviour = ghost.chaseBehaviour; } } @@ -151,7 +157,7 @@ public class PlayState extends LevelState { ghost.update(dt); if (ghost.onSameTile(pacman)) { - if (frightTimer > 0) { + if (frightTimer > 0 && !ghost.returned) { if (!ghost.caught) ghostCaught(ghost); } else { pacmanCaught(); @@ -268,6 +274,7 @@ public class PlayState extends LevelState { if (ghost == null || ghost.caught) continue; ghost.currentBehaviour = ghost.frightBehaviour; ghost.returned = false; + ghost.currDirection = ghost.currDirection.getOpposite(); } frightTimer = 6f; score += 50; @@ -284,6 +291,7 @@ public class PlayState extends LevelState { ghost.caught = true; ghost.returned = false; ghost.currentBehaviour = new ReturnToBase(this); + ghost.speed = Ghost.EYES_SPEED; } @Override