From 1153205ddd3837137dc3e2078b323104237edfb6 Mon Sep 17 00:00:00 2001 From: Matt Low Date: Thu, 26 Dec 2019 01:44:10 +0400 Subject: [PATCH] There's a ghost! And death. And a game over sequence. --- core/src/com/me/pacman/entity/Direction.java | 4 +- core/src/com/me/pacman/entity/Entity.java | 4 + core/src/com/me/pacman/entity/Ghost.java | 72 +++++++++ core/src/com/me/pacman/entity/Pacman.java | 30 ++-- .../com/me/pacman/entity/ai/Behaviour.java | 15 ++ core/src/com/me/pacman/entity/ai/Target.java | 22 +++ core/src/com/me/pacman/state/PlayState.java | 144 +++++++++++++++--- 7 files changed, 248 insertions(+), 43 deletions(-) create mode 100644 core/src/com/me/pacman/entity/Ghost.java create mode 100644 core/src/com/me/pacman/entity/ai/Behaviour.java create mode 100644 core/src/com/me/pacman/entity/ai/Target.java diff --git a/core/src/com/me/pacman/entity/Direction.java b/core/src/com/me/pacman/entity/Direction.java index 840294c..630ee34 100644 --- a/core/src/com/me/pacman/entity/Direction.java +++ b/core/src/com/me/pacman/entity/Direction.java @@ -2,7 +2,7 @@ package com.me.pacman.entity; public enum Direction { NORTH, - EAST, SOUTH, - WEST + WEST, + EAST, } diff --git a/core/src/com/me/pacman/entity/Entity.java b/core/src/com/me/pacman/entity/Entity.java index 6889b7f..8a85ab5 100644 --- a/core/src/com/me/pacman/entity/Entity.java +++ b/core/src/com/me/pacman/entity/Entity.java @@ -22,6 +22,10 @@ public abstract class Entity { batch.draw(getSprite(), (int) (x * 8) + (offsetX - 8), (y * 8) + (offsetY - 8)); } + public boolean onSameTile(Entity other) { + return (int) x == (int) other.x && (int) y == (int) other.y; + } + public abstract TextureRegion getSprite(); public void update(float dt) { diff --git a/core/src/com/me/pacman/entity/Ghost.java b/core/src/com/me/pacman/entity/Ghost.java new file mode 100644 index 0000000..425ee4e --- /dev/null +++ b/core/src/com/me/pacman/entity/Ghost.java @@ -0,0 +1,72 @@ +package com.me.pacman.entity; + +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.me.pacman.entity.ai.Behaviour; +import com.me.pacman.entity.ai.Target; +import com.me.pacman.state.PlayState; + +public class Ghost extends MovableEntity { + + private PlayState state; + + public Behaviour currentBehaviour; + + public Behaviour chaseBehaviour; + public Behaviour freightBehaviour; + public Behaviour scatterBehaviour; + + public TextureRegion[][] sprite; + + private int spriteIndex; + private int counter = 0; + + public Ghost(PlayState state, float x, float y, Direction direction, int spriteIndex, + Behaviour chaseBehaviour, Behaviour freightBehaviour, Behaviour scatterBehaviour) { + super(state, x, y, 7.33f, true, direction, 0.1f); + this.state = state; + this.spriteIndex = spriteIndex; + this.chaseBehaviour = chaseBehaviour; + this.freightBehaviour = freightBehaviour; + this.scatterBehaviour = scatterBehaviour; + sprite = state.getGame().assets.ghosts; + } + + @Override + public TextureRegion getSprite() { + return sprite[2 + (counter % 2)][spriteIndex]; + } + + @Override + public void render(SpriteBatch batch, int offsetX, int offsetY) { + super.render(batch, offsetX, offsetY); + + // draw eyes so the ghost can see + batch.draw(sprite[1][currDirection.ordinal()], (int) (x * 8) + (offsetX - 8), (y * 8) + (offsetY - 8)); + } + + @Override + public void update(float dt) { + super.update(dt); + + if (!state.paused && age % 20 == 0) { + counter++; + } + } + + private class ReturnToBase extends Behaviour { + + final Target home = new Target(14, 16); + + public ReturnToBase(PlayState state) { + super(state); + } + + @Override + public Target getTarget() { + return home; + } + + } + +} diff --git a/core/src/com/me/pacman/entity/Pacman.java b/core/src/com/me/pacman/entity/Pacman.java index bd50d15..7c621b9 100644 --- a/core/src/com/me/pacman/entity/Pacman.java +++ b/core/src/com/me/pacman/entity/Pacman.java @@ -7,40 +7,34 @@ import com.me.pacman.state.PlayState; public class Pacman extends MovableEntity { private TextureRegion[][] sprite; + private TextureRegion[][] death; private PlayState state; private int counter = 1; private int freezeFrames = 0; + public boolean alive = true; + public int deathFrame = 0; + public Pacman(PlayState state, boolean moving) { super(state, 14, 7.5f, 7.5f, moving, Direction.EAST, 0.3f); this.state = state; sprite = state.getGame().assets.pacman; + death = state.getGame().assets.deathAnimation; } @Override public TextureRegion getSprite() { + if (!alive) { + return death[deathFrame / 4][deathFrame % 4]; + } + if (!moving) { return sprite[2][0]; } - int spriteDir; - switch(currDirection) { - case NORTH: - spriteDir = 0; - break; - case SOUTH: - spriteDir = 1; - break; - case WEST: - spriteDir = 2; - break; - default: - spriteDir = 3; - break; - } - return sprite[spriteDir][canMove ? counter % 3 : 1]; + return sprite[currDirection.ordinal()][canMove ? counter % 3 : 1]; } @Override @@ -56,6 +50,10 @@ public class Pacman extends MovableEntity { counter += 1; } + if (age % 8 == 0 && !alive) { + deathFrame++; + } + LevelTile tile = state.level.getTile(x, y); if (tile == null) { return; diff --git a/core/src/com/me/pacman/entity/ai/Behaviour.java b/core/src/com/me/pacman/entity/ai/Behaviour.java new file mode 100644 index 0000000..cd8ba51 --- /dev/null +++ b/core/src/com/me/pacman/entity/ai/Behaviour.java @@ -0,0 +1,15 @@ +package com.me.pacman.entity.ai; + +import com.me.pacman.state.PlayState; + +public abstract class Behaviour { + + public PlayState state; + + public Behaviour(PlayState state) { + this.state = state; + } + + public abstract Target getTarget(); + +} diff --git a/core/src/com/me/pacman/entity/ai/Target.java b/core/src/com/me/pacman/entity/ai/Target.java new file mode 100644 index 0000000..35b27fc --- /dev/null +++ b/core/src/com/me/pacman/entity/ai/Target.java @@ -0,0 +1,22 @@ +package com.me.pacman.entity.ai; + +public class Target { + + public int x; + public int y; + + public Target(int x, int y) { + this.x = x; + this.y = y; + } + + public Target(float x, float y) { + this.x = (int) x; + this.y = (int) y; + } + + public boolean targetReached(float x, float y) { + return this.x == (int) x && this.y == (int) y; + } + +} diff --git a/core/src/com/me/pacman/state/PlayState.java b/core/src/com/me/pacman/state/PlayState.java index 2023608..546aedf 100644 --- a/core/src/com/me/pacman/state/PlayState.java +++ b/core/src/com/me/pacman/state/PlayState.java @@ -3,12 +3,14 @@ package com.me.pacman.state; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.InputAdapter; +import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.me.pacman.PacDude; import com.me.pacman.entity.Direction; +import com.me.pacman.entity.Ghost; import com.me.pacman.entity.Pacman; import com.me.pacman.level.Level; import com.me.pacman.level.LevelTile; @@ -27,11 +29,17 @@ public class PlayState extends LevelState { private long sirenId; - private float waitTimer; + private float readyTimer; + private float gameOverTimer; + private float newGameTimer; + private float deathTimer; + + private boolean pacmanCaught; private TextureRegion lifeSprite; - private Pacman pacman; + public Pacman pacman; + public Ghost[] ghosts; public PlayState(PacDude game) { super(game); @@ -44,12 +52,6 @@ public class PlayState extends LevelState { lifeSprite = game.assets.pacman[2][1]; Gdx.input.setInputProcessor(new Controller()); - pelletCount = 0; - pelletEatenCount = 0; - score = 0; - lives = 3; - round = 0; - newGame(); } @@ -66,9 +68,23 @@ public class PlayState extends LevelState { pacman.render(game.batch, 0, 16); - if (waitTimer > 0) { + if (pacman.alive) { + for (Ghost ghost : ghosts) { + if (ghost == null) { + continue; + } + ghost.render(game.batch, 0, 16); + } + } + + if (readyTimer > 0) { game.assets.getFont().setColor(Color.YELLOW); - game.assets.getFont().draw(game.batch, "ready!", 90, 127); + game.assets.getFont().draw(game.batch, "ready!", 92, 127); + } + + if (gameOverTimer > 0) { + game.assets.getFont().setColor(Color.RED); + game.assets.getFont().draw(game.batch, "game over", 78, 127); } if (paused) { @@ -84,45 +100,115 @@ public class PlayState extends LevelState { return; } - if (waitTimer > 0) { - waitTimer -= dt; - if (waitTimer <= 0) { - startGame(); + if (gameOverTimer > 0) { + gameOverTimer -= dt; + if (gameOverTimer <= 0) { + newGame(); } else { return; } } + if (readyTimer > 0) { + readyTimer -= dt; + if (readyTimer <= 0) { + startGame(); + } else if (newGameTimer <= 0) { + return; + } + } + + if (newGameTimer > 0) { + newGameTimer -= dt; + if (newGameTimer <= 0) { + setupGame(); + } else { + return; + } + } + + if (!pacmanCaught) { + for (Ghost ghost : ghosts) { + if (ghost == null) { + continue; + } + ghost.update(dt); + + if (ghost.onSameTile(pacman)) { + pacmanCaught(); + return; + } + } + } else if (deathTimer <= 0) { + if (pacman.alive) { + game.assets.deathSound.play(1f); + } + + pacman.alive = false; + + if (pacman.deathFrame == 13) { + if (lives > 0) { + setupGame(); + readyTimer = 3f; + } else { + gameOverTimer = 2f; + } + } + } else { + deathTimer -= dt; + } + pacman.update(dt); } public void newGame() { + pelletCount = 0; + pelletEatenCount = 0; + score = 0; + lives = 3; + round = 0; + + pacmanCaught = false; + deathTimer = 0f; + + newGameTimer = 2.3f; + + ghosts = new Ghost[4]; + pacman = new Pacman(this, false); + + newRound(); + } + + public void newRound() { round++; + level = new Level(game,"level"); + pacman = new Pacman(this, false); + game.assets.siren.stop(sirenId); - level = new Level(game,"level"); pelletCount = level.getTileCount(LevelTile.PELLET); pelletCount += level.getTileCount(LevelTile.POWER_PELLET); if (round == 1) { - waitTimer = 4.3f; - game.assets.beginning.play(1.0f); - } else { - waitTimer = 4.2f; + readyTimer = 4.2f; game.assets.beginning_alt.play(1.0f); + } else { + readyTimer = 4.3f; + game.assets.beginning.play(1.0f); } + } + + public void setupGame() { + lives--; + pacmanCaught = false; pacman = new Pacman(this, false); + ghosts[0] = new Ghost(this, 14, 19.5f, Direction.WEST, 0, null, null, null); } public void startGame() { pacman.moving = true; - game.assets.beginning.stop(); - game.assets.beginning_alt.stop(); sirenId = game.assets.siren.loop(1.0f); - if (round == 1) { - lives--; - } } private void pelletEaten(float x, float y) { @@ -136,7 +222,7 @@ public class PlayState extends LevelState { pelletCount--; if (pelletCount == 0) { - newGame(); + newRound(); } } @@ -151,6 +237,14 @@ public class PlayState extends LevelState { score += 50; } + private void pacmanCaught() { + game.assets.siren.stop(sirenId); + deathTimer = 1f; + pacmanCaught = true; + pacman.moving = false; + } + + @Override public void dispose() { Gdx.input.setInputProcessor(null);