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:
parent
2a65084363
commit
cd2b968631
@ -15,6 +15,8 @@ public class PacDude extends Game {
|
|||||||
public static final String TITLE = "Pac-Dude";
|
public static final String TITLE = "Pac-Dude";
|
||||||
public static final String VERSION = "v0.0.1";
|
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_WIDTH = 224;
|
||||||
public static final int LEVEL_HEIGHT = 288;
|
public static final int LEVEL_HEIGHT = 288;
|
||||||
|
|
||||||
|
@ -4,42 +4,51 @@ import com.badlogic.gdx.math.Vector2;
|
|||||||
|
|
||||||
public enum Direction {
|
public enum Direction {
|
||||||
|
|
||||||
UP,
|
UP(new Vector2(0f, 1f)),
|
||||||
DOWN,
|
DOWN(new Vector2(0f, -1f)),
|
||||||
LEFT,
|
LEFT(new Vector2(-1f, 0f)),
|
||||||
RIGHT,
|
RIGHT(new Vector2(1f, 0f)),
|
||||||
;
|
;
|
||||||
|
|
||||||
public boolean isOpposite(Direction dir) {
|
private Vector2 vector;
|
||||||
|
|
||||||
|
Direction(Vector2 vector) {
|
||||||
|
this.vector = vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Direction getOpposite() {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case UP:
|
case UP:
|
||||||
return dir == DOWN;
|
return DOWN;
|
||||||
case DOWN:
|
case DOWN:
|
||||||
return dir == UP;
|
return UP;
|
||||||
case LEFT:
|
case LEFT:
|
||||||
return dir == RIGHT;
|
return RIGHT;
|
||||||
case 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) {
|
public Vector2 getVector(float scale) {
|
||||||
switch (this) {
|
return new Vector2(this.vector).scl(scale);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 getVector() {
|
public Vector2 getVector() {
|
||||||
return this.getVector(1f);
|
return this.getVector(1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Direction fromVector(Vector2 vector) {
|
||||||
|
for (Direction dir : values()) {
|
||||||
|
if (dir.vector.hasSameDirection(vector)) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import com.badlogic.gdx.math.Vector2;
|
|||||||
import com.me.pacman.entity.ai.Behaviour;
|
import com.me.pacman.entity.ai.Behaviour;
|
||||||
import com.me.pacman.entity.ai.ReturnToBase;
|
import com.me.pacman.entity.ai.ReturnToBase;
|
||||||
import com.me.pacman.entity.ai.Target;
|
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.level.LevelTile;
|
||||||
import com.me.pacman.state.PlayState;
|
import com.me.pacman.state.PlayState;
|
||||||
|
|
||||||
@ -13,6 +15,10 @@ import java.util.ArrayList;
|
|||||||
|
|
||||||
public class Ghost extends MovableEntity {
|
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 };
|
public static final Direction[] GHOST_ORDER = { Direction.UP, Direction.LEFT, Direction.DOWN, Direction.RIGHT };
|
||||||
|
|
||||||
private PlayState state;
|
private PlayState state;
|
||||||
@ -32,7 +38,7 @@ public class Ghost extends MovableEntity {
|
|||||||
|
|
||||||
public Ghost(PlayState state, float x, float y, Direction direction, int spriteIndex,
|
public Ghost(PlayState state, float x, float y, Direction direction, int spriteIndex,
|
||||||
Behaviour chaseBehaviour, Behaviour scatterBehaviour) {
|
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.state = state;
|
||||||
this.spriteIndex = spriteIndex;
|
this.spriteIndex = spriteIndex;
|
||||||
this.chaseBehaviour = chaseBehaviour;
|
this.chaseBehaviour = chaseBehaviour;
|
||||||
@ -45,7 +51,7 @@ public class Ghost extends MovableEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TextureRegion getSprite() {
|
public TextureRegion getSprite() {
|
||||||
if (caught) {
|
if (caught && !returned) {
|
||||||
return null;
|
return null;
|
||||||
} else if (state.frightTimer > 0 && !returned) {
|
} else if (state.frightTimer > 0 && !returned) {
|
||||||
return sprite[0][counter % 2];
|
return sprite[0][counter % 2];
|
||||||
@ -71,6 +77,23 @@ public class Ghost extends MovableEntity {
|
|||||||
counter++;
|
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) {
|
if (currentBehaviour == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -86,9 +109,8 @@ public class Ghost extends MovableEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentBehaviour instanceof ReturnToBase && target.targetReached(pos)) {
|
if (currentBehaviour instanceof ReturnToBase && target.targetReached(pos)) {
|
||||||
caught = false;
|
currentPath = new EnterGhostHousePath(pos);
|
||||||
returned = true;
|
return;
|
||||||
currentBehaviour = chaseBehaviour;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 ahead = new Vector2((int) pos.x, (int) pos.y).add(currDirection.getVector());
|
Vector2 ahead = new Vector2((int) pos.x, (int) pos.y).add(currDirection.getVector());
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.me.pacman.entity;
|
package com.me.pacman.entity;
|
||||||
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
import com.me.pacman.entity.path.Path;
|
||||||
import com.me.pacman.level.LevelTile;
|
import com.me.pacman.level.LevelTile;
|
||||||
import com.me.pacman.state.LevelState;
|
import com.me.pacman.state.LevelState;
|
||||||
|
|
||||||
@ -15,6 +16,8 @@ public abstract class MovableEntity extends Entity {
|
|||||||
private Direction nextDirection = null;
|
private Direction nextDirection = null;
|
||||||
public boolean canMove = true;
|
public boolean canMove = true;
|
||||||
|
|
||||||
|
public Path currentPath = null;
|
||||||
|
|
||||||
public MovableEntity(LevelState state, float x, float y, float speed, boolean moving, Direction currDirection, float turnTolerance) {
|
public MovableEntity(LevelState state, float x, float y, float speed, boolean moving, Direction currDirection, float turnTolerance) {
|
||||||
super(state, x, y);
|
super(state, x, y);
|
||||||
this.speed = speed;
|
this.speed = speed;
|
||||||
@ -30,6 +33,12 @@ public abstract class MovableEntity extends Entity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentPath != null) {
|
||||||
|
currentPath.update(dt);
|
||||||
|
currentPath.updateEntity(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LevelTile nextTile = null;
|
LevelTile nextTile = null;
|
||||||
|
|
||||||
if (nextDirection != null) {
|
if (nextDirection != null) {
|
||||||
@ -89,8 +98,6 @@ public abstract class MovableEntity extends Entity {
|
|||||||
float dist = speed * dt;
|
float dist = speed * dt;
|
||||||
|
|
||||||
LevelTile currentTile = state.level.getTile(pos.x, pos.y);
|
LevelTile currentTile = state.level.getTile(pos.x, pos.y);
|
||||||
nextTile = null;
|
|
||||||
|
|
||||||
Vector2 new_pos = new Vector2(pos);
|
Vector2 new_pos = new Vector2(pos);
|
||||||
|
|
||||||
switch (currDirection) {
|
switch (currDirection) {
|
||||||
|
@ -4,7 +4,6 @@ import com.me.pacman.state.PlayState;
|
|||||||
|
|
||||||
public class ReturnToBase extends Behaviour {
|
public class ReturnToBase extends Behaviour {
|
||||||
|
|
||||||
// final Target home = new Target(14, 16);
|
|
||||||
final Target home = new Target(14, 19);
|
final Target home = new Target(14, 19);
|
||||||
|
|
||||||
public ReturnToBase(PlayState state) {
|
public ReturnToBase(PlayState state) {
|
||||||
|
20
core/src/com/me/pacman/entity/path/EnterGhostHousePath.java
Normal file
20
core/src/com/me/pacman/entity/path/EnterGhostHousePath.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
core/src/com/me/pacman/entity/path/ExitGhostHousePath.java
Normal file
20
core/src/com/me/pacman/entity/path/ExitGhostHousePath.java
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
89
core/src/com/me/pacman/entity/path/Path.java
Normal file
89
core/src/com/me/pacman/entity/path/Path.java
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -106,6 +106,11 @@ public class PlayState extends LevelState {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PacDude.DEBUG) {
|
||||||
|
// Fixed time step for debugger
|
||||||
|
dt = 1/60f;
|
||||||
|
}
|
||||||
|
|
||||||
if (gameOverTimer > 0) {
|
if (gameOverTimer > 0) {
|
||||||
gameOverTimer -= dt;
|
gameOverTimer -= dt;
|
||||||
if (gameOverTimer <= 0) {
|
if (gameOverTimer <= 0) {
|
||||||
@ -137,7 +142,8 @@ public class PlayState extends LevelState {
|
|||||||
frightTimer -= dt;
|
frightTimer -= dt;
|
||||||
if (frightTimer < 0) {
|
if (frightTimer < 0) {
|
||||||
for (Ghost ghost : ghosts) {
|
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;
|
ghost.currentBehaviour = ghost.chaseBehaviour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +157,7 @@ public class PlayState extends LevelState {
|
|||||||
ghost.update(dt);
|
ghost.update(dt);
|
||||||
|
|
||||||
if (ghost.onSameTile(pacman)) {
|
if (ghost.onSameTile(pacman)) {
|
||||||
if (frightTimer > 0) {
|
if (frightTimer > 0 && !ghost.returned) {
|
||||||
if (!ghost.caught) ghostCaught(ghost);
|
if (!ghost.caught) ghostCaught(ghost);
|
||||||
} else {
|
} else {
|
||||||
pacmanCaught();
|
pacmanCaught();
|
||||||
@ -268,6 +274,7 @@ public class PlayState extends LevelState {
|
|||||||
if (ghost == null || ghost.caught) continue;
|
if (ghost == null || ghost.caught) continue;
|
||||||
ghost.currentBehaviour = ghost.frightBehaviour;
|
ghost.currentBehaviour = ghost.frightBehaviour;
|
||||||
ghost.returned = false;
|
ghost.returned = false;
|
||||||
|
ghost.currDirection = ghost.currDirection.getOpposite();
|
||||||
}
|
}
|
||||||
frightTimer = 6f;
|
frightTimer = 6f;
|
||||||
score += 50;
|
score += 50;
|
||||||
@ -284,6 +291,7 @@ public class PlayState extends LevelState {
|
|||||||
ghost.caught = true;
|
ghost.caught = true;
|
||||||
ghost.returned = false;
|
ghost.returned = false;
|
||||||
ghost.currentBehaviour = new ReturnToBase(this);
|
ghost.currentBehaviour = new ReturnToBase(this);
|
||||||
|
ghost.speed = Ghost.EYES_SPEED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user