Implement round progression mechanics and Elroy speeds

Closes #3
Closes #6
This commit is contained in:
Matt Low 2020-01-05 12:44:52 +04:00
parent 37944fccd9
commit 31a2657c13
6 changed files with 324 additions and 25 deletions

View File

@ -5,6 +5,7 @@ import com.me.pacman.PacDude;
import com.me.pacman.entity.ai.BlinkyChaseBehaviour; import com.me.pacman.entity.ai.BlinkyChaseBehaviour;
import com.me.pacman.entity.ai.StaticTargetBehaviour; import com.me.pacman.entity.ai.StaticTargetBehaviour;
import com.me.pacman.entity.ai.Target; import com.me.pacman.entity.ai.Target;
import com.me.pacman.level.Modifiers;
import com.me.pacman.state.PlayState; import com.me.pacman.state.PlayState;
public class Blinky extends Ghost { public class Blinky extends Ghost {
@ -15,6 +16,19 @@ public class Blinky extends Ghost {
super(state, pos, direction, 0, new BlinkyChaseBehaviour(state), new StaticTargetBehaviour(state, SCATTER_TARGET), false); super(state, pos, direction, 0, new BlinkyChaseBehaviour(state), new StaticTargetBehaviour(state, SCATTER_TARGET), false);
} }
@Override
protected float getNormalSpeed() {
int round = state.round;
if (!state.hasDied || !state.ghosts[3].inHouse) {
if (state.pelletsRemaining <= Modifiers.getElroy2DotsLeft(round)) {
return Modifiers.getElroy2Speed(round);
} else if (state.pelletsRemaining <= Modifiers.getElroy1DotsLeft(round)) {
return Modifiers.getElroy1Speed(round);
}
}
return super.getNormalSpeed();
}
@Override @Override
public void update(float dt) { public void update(float dt) {
if (inHouse) { if (inHouse) {

View File

@ -9,15 +9,15 @@ import com.me.pacman.entity.ai.Target;
import com.me.pacman.entity.path.EnterGhostHousePath; import com.me.pacman.entity.path.EnterGhostHousePath;
import com.me.pacman.entity.path.ExitGhostHousePath; import com.me.pacman.entity.path.ExitGhostHousePath;
import com.me.pacman.level.LevelTile; import com.me.pacman.level.LevelTile;
import com.me.pacman.level.Modifiers;
import com.me.pacman.state.PlayState; import com.me.pacman.state.PlayState;
import java.util.ArrayList; import java.util.ArrayList;
public class Ghost extends MovableEntity { public class Ghost extends MovableEntity {
public static final float GHOST_SPEED = PlayState.FULL_SPEED * 0.75f;
public static final float GHOST_TUNNEL_SPEED = PlayState.FULL_SPEED * 0.4f;
public static final float EYES_SPEED = 15f; public static final float EYES_SPEED = 15f;
public static final float HOUSE_SPEED = PlayState.FULL_SPEED * 0.5f;
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 };
@ -40,7 +40,7 @@ public class Ghost extends MovableEntity {
public Ghost(PlayState state, Vector2 pos, Direction direction, int spriteIndex, public Ghost(PlayState state, Vector2 pos, Direction direction, int spriteIndex,
Behaviour chaseBehaviour, Behaviour scatterBehaviour, boolean inHouse) { Behaviour chaseBehaviour, Behaviour scatterBehaviour, boolean inHouse) {
super(state, pos.x, pos.y, GHOST_SPEED, true, direction, 0.1f); super(state, pos.x, pos.y, Modifiers.getGhostSpeed(0), true, direction, 0.1f);
this.state = state; this.state = state;
this.spriteIndex = spriteIndex; this.spriteIndex = spriteIndex;
this.chaseBehaviour = chaseBehaviour; this.chaseBehaviour = chaseBehaviour;
@ -77,18 +77,24 @@ public class Ghost extends MovableEntity {
batch.draw(sprite[1][currDirection.ordinal()], (int) (pos.x * 8) + (offsetX - 8), (pos.y * 8) + (offsetY - 8)); batch.draw(sprite[1][currDirection.ordinal()], (int) (pos.x * 8) + (offsetX - 8), (pos.y * 8) + (offsetY - 8));
} }
protected float getNormalSpeed() {
return Modifiers.getGhostSpeed(state.round);
}
@Override @Override
public void update(float dt) { public void update(float dt) {
LevelTile currentTile = state.level.getTile(pos); LevelTile currentTile = state.level.getTile(pos);
if (currentBehaviour instanceof FrightenedBehaviour) { if (currentTile == null || currentTile == LevelTile.TUNNEL) {
speed = PlayState.FULL_SPEED * 0.5f; speed = Modifiers.getGhostTunnelSpeed(state.round);
} else if (currentBehaviour instanceof FrightenedBehaviour) {
speed = Modifiers.getGhostFrightSpeed(state.round);
} else if (currentBehaviour instanceof ReturnToBase) { } else if (currentBehaviour instanceof ReturnToBase) {
speed = EYES_SPEED; speed = EYES_SPEED;
} else if (currentTile == LevelTile.TUNNEL || inHouse) { } else if (inHouse) {
speed = GHOST_TUNNEL_SPEED; speed = HOUSE_SPEED;
} else { } else {
speed = GHOST_SPEED; speed = getNormalSpeed();
} }
super.update(dt); super.update(dt);

View File

@ -1,11 +1,15 @@
package com.me.pacman.entity; package com.me.pacman.entity;
import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
import com.me.pacman.level.LevelTile; import com.me.pacman.level.LevelTile;
import com.me.pacman.level.Modifiers;
import com.me.pacman.state.PlayState; import com.me.pacman.state.PlayState;
public class Pacman extends MovableEntity { public class Pacman extends MovableEntity {
public static final Vector2 HOME = new Vector2(14, 7.5f);
private TextureRegion[][] sprite; private TextureRegion[][] sprite;
private TextureRegion[][] death; private TextureRegion[][] death;
@ -18,7 +22,7 @@ public class Pacman extends MovableEntity {
public int deathFrame = 0; public int deathFrame = 0;
public Pacman(PlayState state, boolean moving) { public Pacman(PlayState state, boolean moving) {
super(state, 14, 7.5f, PlayState.FULL_SPEED * 0.8f, moving, Direction.LEFT, 0.3f); super(state, HOME.x, HOME.y, PlayState.FULL_SPEED * 0.8f, moving, Direction.LEFT, 0.3f);
this.state = state; this.state = state;
sprite = state.getGame().assets.pacman; sprite = state.getGame().assets.pacman;
death = state.getGame().assets.deathAnimation; death = state.getGame().assets.deathAnimation;
@ -45,9 +49,9 @@ public class Pacman extends MovableEntity {
} }
if (state.frightTimer > 0) { if (state.frightTimer > 0) {
speed = PlayState.FULL_SPEED * 0.9f; speed = Modifiers.getPacmanFrightSpeed(state.round);
} else { } else {
speed = PlayState.FULL_SPEED * 0.8f; speed = Modifiers.getPacmanSpeed(state.round);
} }
super.update(dt); super.update(dt);

View File

@ -13,7 +13,7 @@ public class ExitGhostHousePath extends Path {
}}; }};
public ExitGhostHousePath(Vector2 start) { public ExitGhostHousePath(Vector2 start) {
super(Ghost.GHOST_TUNNEL_SPEED, start); super(Ghost.HOUSE_SPEED, start);
addPoints(points); addPoints(points);
} }

View File

@ -0,0 +1,273 @@
package com.me.pacman.level;
import com.me.pacman.state.PlayState;
import java.util.Arrays;
public class Modifiers {
private static final Modifiers[] ROUND_MODIFIERS;
private float frightTime;
private float pacmanSpeed;
private float pacmanFrightSpeed;
private float ghostSpeed;
private float ghostFrightSpeed;
private float ghostTunnelSpeed;
private int elroy1DotsLeft;
private float elroy1Speed;
private int elroy2DotsLeft;
private float elroy2Speed;
private int forceLeaveSeconds;
private float[] scatterChaseSwitchTimings;
private static int cap(int round) {
return Math.min(round, 20);
}
public static float getFrightTime(int round) {
return ROUND_MODIFIERS[cap(round)].frightTime;
}
public static float getPacmanSpeed(int round) {
return PlayState.FULL_SPEED * ROUND_MODIFIERS[cap(round)].pacmanSpeed;
}
public static float getPacmanFrightSpeed(int round) {
return PlayState.FULL_SPEED * ROUND_MODIFIERS[cap(round)].pacmanFrightSpeed;
}
public static float getGhostSpeed(int round) {
return PlayState.FULL_SPEED * ROUND_MODIFIERS[cap(round)].ghostSpeed;
}
public static float getGhostFrightSpeed(int round) {
return PlayState.FULL_SPEED * ROUND_MODIFIERS[cap(round)].ghostFrightSpeed;
}
public static float getGhostTunnelSpeed(int round) {
return PlayState.FULL_SPEED * ROUND_MODIFIERS[cap(round)].ghostTunnelSpeed;
}
public static int getElroy1DotsLeft(int round) {
return ROUND_MODIFIERS[cap(round)].elroy1DotsLeft;
}
public static float getElroy1Speed(int round) {
return PlayState.FULL_SPEED * ROUND_MODIFIERS[cap(round)].elroy1Speed;
}
public static int getElroy2DotsLeft(int round) {
return ROUND_MODIFIERS[cap(round)].elroy2DotsLeft;
}
public static float getElroy2Speed(int round) {
return PlayState.FULL_SPEED * ROUND_MODIFIERS[cap(round)].elroy2Speed;
}
public static int getForceLeaveSeconds(int round) {
return ROUND_MODIFIERS[cap(round)].forceLeaveSeconds;
}
public static float getScatterChaseTimer(int round, int scatterChaseTransition) {
return ROUND_MODIFIERS[cap(round)].scatterChaseSwitchTimings[scatterChaseTransition];
}
public Modifiers clone() {
Modifiers mod = new Modifiers();
mod.frightTime = frightTime;
mod.pacmanSpeed = pacmanSpeed;
mod.pacmanFrightSpeed = pacmanFrightSpeed;
mod.ghostSpeed = ghostSpeed;
mod.ghostFrightSpeed = ghostFrightSpeed;
mod.ghostTunnelSpeed = ghostTunnelSpeed;
mod.elroy1DotsLeft = elroy1DotsLeft;
mod.elroy1Speed = elroy1Speed;
mod.elroy2DotsLeft = elroy2DotsLeft;
mod.elroy2Speed = elroy2Speed;
mod.forceLeaveSeconds = forceLeaveSeconds;
mod.scatterChaseSwitchTimings = Arrays.copyOf(scatterChaseSwitchTimings, scatterChaseSwitchTimings.length);
return mod;
}
static {
ROUND_MODIFIERS = new Modifiers[21];
int round = 0;
// Round 1
Modifiers mod = new Modifiers();
mod.frightTime = 6f;
mod.pacmanSpeed = 0.8f;
mod.pacmanFrightSpeed = 0.9f;
mod.ghostSpeed = 0.75f;
mod.ghostFrightSpeed = 0.5f;
mod.ghostTunnelSpeed = 0.4f;
mod.elroy1DotsLeft = 20;
mod.elroy1Speed = 0.8f;
mod.elroy2DotsLeft = 10;
mod.elroy2Speed = 0.85f;
mod.forceLeaveSeconds = 4;
mod.scatterChaseSwitchTimings = new float[] {7f, 20f, 7f, 20f, 5f, 20f, 5f};
ROUND_MODIFIERS[round++] = mod;
// Round 2
mod = mod.clone();
mod.frightTime = 5f;
mod.pacmanSpeed = 0.9f;
mod.pacmanFrightSpeed = 0.95f;
mod.ghostSpeed = 0.85f;
mod.ghostFrightSpeed = 0.55f;
mod.ghostTunnelSpeed = 0.45f;
mod.elroy1DotsLeft = 30;
mod.elroy1Speed = 0.9f;
mod.elroy2DotsLeft = 14;
mod.elroy2Speed = 0.95f;
mod.scatterChaseSwitchTimings = new float[] {7f, 20f, 7f, 20f, 5f, 1033f, 1/60f};
ROUND_MODIFIERS[round++] = mod;
// Round 3
mod = mod.clone();
mod.frightTime = 4f;
mod.elroy1DotsLeft = 40;
mod.elroy1Speed = 0.9f;
mod.elroy2DotsLeft = 20;
mod.elroy2Speed = 0.95f;
ROUND_MODIFIERS[round++] = mod;
// Round 4
mod = mod.clone();
mod.frightTime = 3f;
ROUND_MODIFIERS[round++] = mod;
// Round 5
mod = mod.clone();
mod.frightTime = 2f;
mod.pacmanSpeed = 1f;
mod.pacmanFrightSpeed = 1f;
mod.ghostSpeed = 0.95f;
mod.ghostFrightSpeed = 0.6f;
mod.ghostTunnelSpeed = 0.5f;
mod.elroy1Speed = 1f;
mod.elroy2Speed = 1.05f;
mod.forceLeaveSeconds = 3;
mod.scatterChaseSwitchTimings = new float[] {7f, 20f, 7f, 20f, 5f, 1037f, 1/60f};
ROUND_MODIFIERS[round++] = mod;
// Round 6
mod = mod.clone();
mod.frightTime = 5f;
mod.elroy1DotsLeft = 50;
mod.elroy2DotsLeft = 25;
ROUND_MODIFIERS[round++] = mod;
// Round 7 & 8
mod = mod.clone();
mod.frightTime = 2f;
ROUND_MODIFIERS[round++] = mod;
ROUND_MODIFIERS[round++] = mod;
// Round 9
mod = mod.clone();
mod.frightTime = 1f;
mod.elroy1DotsLeft = 60;
mod.elroy2DotsLeft = 30;
ROUND_MODIFIERS[round++] = mod;
// Round 10
mod = mod.clone();
mod.frightTime = 5f;
ROUND_MODIFIERS[round++] = mod;
// Round 11
mod = mod.clone();
mod.frightTime = 2f;
ROUND_MODIFIERS[round++] = mod;
// Round 12 & 13
mod = mod.clone();
mod.frightTime = 1f;
mod.elroy1DotsLeft = 80;
mod.elroy2DotsLeft = 40;
ROUND_MODIFIERS[round++] = mod;
ROUND_MODIFIERS[round++] = mod;
// Round 14
mod = mod.clone();
mod.frightTime = 3f;
ROUND_MODIFIERS[round++] = mod;
// Round 15 & 16
mod = mod.clone();
mod.frightTime = 1f;
mod.elroy1DotsLeft = 100;
mod.elroy2DotsLeft = 50;
ROUND_MODIFIERS[round++] = mod;
ROUND_MODIFIERS[round++] = mod;
// Round 17
mod = mod.clone();
mod.frightTime = 0f;
ROUND_MODIFIERS[round++] = mod;
// Round 18
mod = mod.clone();
mod.frightTime = 1f;
ROUND_MODIFIERS[round++] = mod;
// Round 19 & 20
mod = mod.clone();
mod.frightTime = 0f;
mod.elroy1DotsLeft = 120;
mod.elroy2DotsLeft = 60;
ROUND_MODIFIERS[round++] = mod;
ROUND_MODIFIERS[round++] = mod;
// Round 21+
mod = mod.clone();
mod.pacmanSpeed = 0.9f;
ROUND_MODIFIERS[round++] = mod;
}
}

View File

@ -14,6 +14,7 @@ import com.me.pacman.entity.*;
import com.me.pacman.entity.ai.ReturnToBase; import com.me.pacman.entity.ai.ReturnToBase;
import com.me.pacman.level.Level; import com.me.pacman.level.Level;
import com.me.pacman.level.LevelTile; import com.me.pacman.level.LevelTile;
import com.me.pacman.level.Modifiers;
import java.util.Random; import java.util.Random;
@ -43,21 +44,22 @@ public class PlayState extends LevelState {
private long sirenId; private long sirenId;
private int pelletsRemaining; public int pelletsRemaining;
private int pelletsEaten; private int pelletsEaten;
public int pelletsEatenSinceDeath; public int pelletsEatenSinceDeath;
public boolean pelletsEatenSinceDeathCounterEnabled; public boolean pelletsEatenSinceDeathCounterEnabled;
public boolean hasDied;
private int score; private int score;
private int lives; private int lives;
private int round; public int round;
private boolean paused = false; private boolean paused = false;
public float secondsSinceLastDot; public float secondsSinceLastDot;
public boolean scatter; public boolean scatter;
private int scatterCount; private int scatterChaseTransition;
private float scatterChaseTimer; private float scatterChaseTimer;
public float frightTimer; // remaining fright time public float frightTimer; // remaining fright time
@ -131,11 +133,12 @@ public class PlayState extends LevelState {
private void initializeRound() { private void initializeRound() {
scatter = true; scatter = true;
scatterCount = 1; scatterChaseTransition = 0;
pelletsEaten = 0; pelletsEaten = 0;
pelletsEatenSinceDeath = 0; pelletsEatenSinceDeath = 0;
pelletsEatenSinceDeathCounterEnabled = false; pelletsEatenSinceDeathCounterEnabled = false;
hasDied = false;
spawnGhosts(); spawnGhosts();
} }
@ -147,7 +150,7 @@ public class PlayState extends LevelState {
lastGhostCaptured = null; lastGhostCaptured = null;
secondsSinceLastDot = 0; secondsSinceLastDot = 0;
scatterChaseTimer = scatter? 7f : 20f; scatterChaseTimer = Modifiers.getScatterChaseTimer(round, scatterChaseTransition);
random = new Random(897198256012865L); random = new Random(897198256012865L);
@ -158,7 +161,7 @@ public class PlayState extends LevelState {
private void preNewGame() { private void preNewGame() {
score = 0; score = 0;
lives = 3; lives = 3;
round = 1; round = 0;
initializeLevel(); initializeLevel();
@ -276,7 +279,7 @@ public class PlayState extends LevelState {
ghost.currentBehaviour = ghost.frightBehaviour; ghost.currentBehaviour = ghost.frightBehaviour;
ghost.currDirection = ghost.currDirection.getOpposite(); ghost.currDirection = ghost.currDirection.getOpposite();
} }
frightTimer = 6f; frightTimer = Modifiers.getFrightTime(round);
ghostsCaught = 0; ghostsCaught = 0;
score += 50; score += 50;
} }
@ -286,6 +289,7 @@ public class PlayState extends LevelState {
pacman.moving = false; pacman.moving = false;
pelletsEatenSinceDeath = 0; pelletsEatenSinceDeath = 0;
pelletsEatenSinceDeathCounterEnabled = true; pelletsEatenSinceDeathCounterEnabled = true;
hasDied = true;
setGameState(GameState.PACMAN_CAUGHT_WAIT); setGameState(GameState.PACMAN_CAUGHT_WAIT);
} }
@ -361,15 +365,13 @@ public class PlayState extends LevelState {
} }
private void updateScatterTimer(float dt) { private void updateScatterTimer(float dt) {
if (scatter || scatterCount < 4) { if (scatterChaseTransition < 7) {
// only update scatter timer if we're currently in scatter or if we've yet to enter scatter 4 times // only update scatter timer if we're currently in scatter or if we've yet to enter scatter 4 times
scatterChaseTimer -= dt; scatterChaseTimer -= dt;
if (scatterChaseTimer <= 0) { if (scatterChaseTimer <= 0) {
scatter = !scatter; scatter = !scatter;
scatterChaseTimer = scatter ? 7f : 20f; scatterChaseTimer = Modifiers.getScatterChaseTimer(round, scatterChaseTransition);
if (scatter) { scatterChaseTransition++;
scatterCount++;
}
} }
} }
} }
@ -387,7 +389,7 @@ public class PlayState extends LevelState {
private void updateSecondsSinceLastDot(float dt) { private void updateSecondsSinceLastDot(float dt) {
secondsSinceLastDot += dt; secondsSinceLastDot += dt;
if (secondsSinceLastDot >= 4) { if (secondsSinceLastDot >= Modifiers.getForceLeaveSeconds(round)) {
// It's been 4 seconds since pacman last ate a dot, he's tryin' to avoid ghosts coming out! // It's been 4 seconds since pacman last ate a dot, he's tryin' to avoid ghosts coming out!
// We'll get him... // We'll get him...
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {