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
This commit is contained in:
Matt Low 2019-12-27 14:32:22 +04:00
parent 2a65084363
commit cd2b968631
9 changed files with 207 additions and 31 deletions

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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());

View File

@ -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) {

View File

@ -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) {

View File

@ -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<Vector2> points = new ArrayList<Vector2>() {{
add(new Vector2(14, 19.5f));
add(new Vector2(14, 16.5f));
}};
public EnterGhostHousePath(Vector2 start) {
super(Ghost.EYES_SPEED, start);
addPoints(points);
}
}

View File

@ -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<Vector2> points = new ArrayList<Vector2>() {{
add(new Vector2(14, 16.5f));
add(new Vector2(14, 19.5f));
}};
public ExitGhostHousePath(Vector2 start) {
super(Ghost.GHOST_TUNNEL_SPEED, start);
addPoints(points);
}
}

View File

@ -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<Vector2> points; // points in the path
private List<Float> 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<Vector2> 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;
}
}

View File

@ -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