Compare commits
2 Commits
fd85d8cd0f
...
5b2626ad5d
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b2626ad5d | |||
| c65787dfc9 |
5
src/main/java/se/urmo/game/sound/SoundEffect.java
Normal file
5
src/main/java/se/urmo/game/sound/SoundEffect.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package se.urmo.game.sound;
|
||||||
|
|
||||||
|
public enum SoundEffect {
|
||||||
|
START, SIREN, MUNCH1, MUNCH2, FRUIT, GHOST_EATEN, EXTRA_LIFE, DEATH
|
||||||
|
}
|
||||||
62
src/main/java/se/urmo/game/sound/SoundManager.java
Normal file
62
src/main/java/se/urmo/game/sound/SoundManager.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package se.urmo.game.sound;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioInputStream;
|
||||||
|
import javax.sound.sampled.AudioSystem;
|
||||||
|
import javax.sound.sampled.Clip;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SoundManager {
|
||||||
|
private final Map<SoundEffect, Clip> clips = new EnumMap<>(SoundEffect.class);
|
||||||
|
private SoundEffect lastMunch = SoundEffect.MUNCH1;
|
||||||
|
|
||||||
|
public SoundManager() {
|
||||||
|
load(SoundEffect.START, "/sounds/start.wav");
|
||||||
|
load(SoundEffect.SIREN, "/sounds/siren0.wav");
|
||||||
|
load(SoundEffect.MUNCH1, "/sounds/eat_dot_0_fast.wav");
|
||||||
|
load(SoundEffect.MUNCH2, "/sounds/eat_dot_1_fast.wav");
|
||||||
|
load(SoundEffect.FRUIT, "/sounds/eat_fruit.wav");
|
||||||
|
load(SoundEffect.GHOST_EATEN, "/sounds/eat_ghost.wav");
|
||||||
|
load(SoundEffect.EXTRA_LIFE, "/sounds/extend.wav");
|
||||||
|
load(SoundEffect.DEATH, "/sounds/death_0.wav");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void load(SoundEffect id, String path) {
|
||||||
|
try (AudioInputStream ais = AudioSystem.getAudioInputStream(getClass().getResource(path))) {
|
||||||
|
Clip clip = AudioSystem.getClip();
|
||||||
|
clip.open(ais);
|
||||||
|
clips.put(id, clip);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to load sound: " + path, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void play(SoundEffect id) {
|
||||||
|
Clip clip = clips.get(id);
|
||||||
|
if (clip == null) return;
|
||||||
|
if (clip.isRunning()) clip.stop();
|
||||||
|
clip.setFramePosition(0);
|
||||||
|
clip.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loop(SoundEffect id) {
|
||||||
|
Clip clip = clips.get(id);
|
||||||
|
if (clip == null) return;
|
||||||
|
if (!clip.isRunning()) {
|
||||||
|
clip.setFramePosition(0);
|
||||||
|
clip.loop(Clip.LOOP_CONTINUOUSLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop(SoundEffect id) {
|
||||||
|
Clip clip = clips.get(id);
|
||||||
|
if (clip != null && clip.isRunning()) clip.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For dot munch alternation
|
||||||
|
public void playMunch() {
|
||||||
|
lastMunch = (lastMunch == SoundEffect.MUNCH1 ? SoundEffect.MUNCH2 : SoundEffect.MUNCH1);
|
||||||
|
play(lastMunch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -16,6 +16,8 @@ import se.urmo.game.main.ScorePopupManager;
|
|||||||
import se.urmo.game.map.GameMap;
|
import se.urmo.game.map.GameMap;
|
||||||
import se.urmo.game.map.MapTile;
|
import se.urmo.game.map.MapTile;
|
||||||
import se.urmo.game.map.TileType;
|
import se.urmo.game.map.TileType;
|
||||||
|
import se.urmo.game.sound.SoundEffect;
|
||||||
|
import se.urmo.game.sound.SoundManager;
|
||||||
import se.urmo.game.util.Direction;
|
import se.urmo.game.util.Direction;
|
||||||
import se.urmo.game.util.GameFonts;
|
import se.urmo.game.util.GameFonts;
|
||||||
import se.urmo.game.util.GameStateType;
|
import se.urmo.game.util.GameStateType;
|
||||||
@ -36,12 +38,12 @@ public class PlayingState implements GameState {
|
|||||||
private final FruitManager fruitManager;
|
private final FruitManager fruitManager;
|
||||||
private final LevelManager levelManager;
|
private final LevelManager levelManager;
|
||||||
private final AnimationManager animationManager;
|
private final AnimationManager animationManager;
|
||||||
private PacMan pacman;
|
private final PacMan pacman;
|
||||||
@Getter
|
@Getter
|
||||||
private GameMap map;
|
private final GameMap map;
|
||||||
|
|
||||||
// Durations (tune to taste)
|
// Durations (tune to taste)
|
||||||
private static final int READY_MS = 1500;
|
private static final int READY_MS = 3000;
|
||||||
private static final int LEVEL_COMPLETE_MS = 1500;
|
private static final int LEVEL_COMPLETE_MS = 1500;
|
||||||
private static final int LIFE_LOST_MS = 2000;
|
private static final int LIFE_LOST_MS = 2000;
|
||||||
|
|
||||||
@ -51,13 +53,14 @@ public class PlayingState implements GameState {
|
|||||||
private int dotsEaten = 0;
|
private int dotsEaten = 0;
|
||||||
|
|
||||||
// Phase + timers
|
// Phase + timers
|
||||||
private RoundPhase phase = RoundPhase.PLAYING;
|
private RoundPhase phase = RoundPhase.READY;
|
||||||
private long phaseStartMs = System.currentTimeMillis();
|
private long phaseStartMs = System.currentTimeMillis();
|
||||||
private boolean deathInProgress;
|
private boolean deathInProgress;
|
||||||
private int frightMultiplier;
|
|
||||||
|
|
||||||
private final ScorePopupManager scorePopups = new ScorePopupManager();
|
private final ScorePopupManager scorePopups = new ScorePopupManager();
|
||||||
private final Font scorePopupFont = GameFonts.arcade(16F); // or your arcade font
|
private final Font scorePopupFont = GameFonts.arcade(16F);
|
||||||
|
|
||||||
|
private final SoundManager sound = new SoundManager();
|
||||||
|
|
||||||
public PlayingState(GameStateManager gameStateManager, GameOverState gameOverState) {
|
public PlayingState(GameStateManager gameStateManager, GameOverState gameOverState) {
|
||||||
this.gameStateManager = gameStateManager;
|
this.gameStateManager = gameStateManager;
|
||||||
@ -69,6 +72,7 @@ public class PlayingState implements GameState {
|
|||||||
this.animationManager.register(pacman);
|
this.animationManager.register(pacman);
|
||||||
this.ghostManager = new GhostManager(new GhostCollisionChecker(map), animationManager, levelManager);
|
this.ghostManager = new GhostManager(new GhostCollisionChecker(map), animationManager, levelManager);
|
||||||
this.fruitManager = new FruitManager(levelManager);
|
this.fruitManager = new FruitManager(levelManager);
|
||||||
|
sound.play(SoundEffect.START);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,6 +86,7 @@ public class PlayingState implements GameState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case PLAYING -> {
|
case PLAYING -> {
|
||||||
|
sound.loop(SoundEffect.SIREN);
|
||||||
animationManager.updateAll();
|
animationManager.updateAll();
|
||||||
pacman.update();
|
pacman.update();
|
||||||
ghostManager.update(pacman, map);
|
ghostManager.update(pacman, map);
|
||||||
@ -137,9 +142,9 @@ public class PlayingState implements GameState {
|
|||||||
boolean wasRemoved = map.removeTileImage(pacmanScreenPos);
|
boolean wasRemoved = map.removeTileImage(pacmanScreenPos);
|
||||||
if (wasRemoved && tile.getTileType() == TileType.LARGE_PELLET) {
|
if (wasRemoved && tile.getTileType() == TileType.LARGE_PELLET) {
|
||||||
ghostManager.setFrightMode();
|
ghostManager.setFrightMode();
|
||||||
frightMultiplier = 1;
|
|
||||||
}
|
}
|
||||||
if (wasRemoved) {
|
if (wasRemoved) {
|
||||||
|
sound.playMunch();
|
||||||
dotsEaten++;
|
dotsEaten++;
|
||||||
fruitManager.dotEaten(dotsEaten);
|
fruitManager.dotEaten(dotsEaten);
|
||||||
score += tile.getTileType().getScore();
|
score += tile.getTileType().getScore();
|
||||||
@ -228,12 +233,14 @@ public class PlayingState implements GameState {
|
|||||||
if (ghost.isEaten()) return;
|
if (ghost.isEaten()) return;
|
||||||
if (ghost.isFrightened()) {
|
if (ghost.isFrightened()) {
|
||||||
log.debug("Pacman eats ghost");
|
log.debug("Pacman eats ghost");
|
||||||
|
sound.play(SoundEffect.GHOST_EATEN);
|
||||||
int pts = 200 * (1 << (ghostManager.getGhosts().size() - ghostManager.isFrightened()));
|
int pts = 200 * (1 << (ghostManager.getGhosts().size() - ghostManager.isFrightened()));
|
||||||
score += pts;
|
score += pts;
|
||||||
scorePopups.spawn(pts);
|
scorePopups.spawn(pts);
|
||||||
ghost.setMode(GhostMode.EATEN);
|
ghost.setMode(GhostMode.EATEN);
|
||||||
} else {
|
} else {
|
||||||
log.debug("Pacman loses a life");
|
log.debug("Pacman loses a life");
|
||||||
|
sound.play(SoundEffect.DEATH);
|
||||||
ghostManager.setFrozen(true);
|
ghostManager.setFrozen(true);
|
||||||
pacman.setState(PacMan.PacmanState.DYING);
|
pacman.setState(PacMan.PacmanState.DYING);
|
||||||
deathInProgress = true;
|
deathInProgress = true;
|
||||||
|
|||||||
@ -5,7 +5,14 @@
|
|||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<root level="DEBUG">
|
<!--root level="DEBUG">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
</root>
|
</root -->
|
||||||
|
|
||||||
|
<root level="OFF"/>
|
||||||
|
|
||||||
|
<!-- Enable entire package -->
|
||||||
|
<logger name="se.urmo.myapp" level="DEBUG" additivity="false">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
</logger>
|
||||||
</configuration>
|
</configuration>
|
||||||
@ -25,6 +25,6 @@
|
|||||||
49,27,28, 0,26,28, 0,15,17, 0,26,27,27, 7, 8,27,27,28, 0,15,17, 0,26,28, 0,26,27,50
|
49,27,28, 0,26,28, 0,15,17, 0,26,27,27, 7, 8,27,27,28, 0,15,17, 0,26,28, 0,26,27,50
|
||||||
12, 0, 0, 0, 0, 0, 0,15,17, 0, 0, 0, 0,15,17, 0, 0, 0, 0,15,17, 0, 0, 0, 0, 0, 0,14
|
12, 0, 0, 0, 0, 0, 0,15,17, 0, 0, 0, 0,15,17, 0, 0, 0, 0,15,17, 0, 0, 0, 0, 0, 0,14
|
||||||
12, 0, 4, 5, 5, 5, 5,18,19, 5, 5, 6, 0,15,17, 0, 4, 5, 5,18,19, 5, 5, 5, 5, 6, 0,14
|
12, 0, 4, 5, 5, 5, 5,18,19, 5, 5, 6, 0,15,17, 0, 4, 5, 5,18,19, 5, 5, 5, 5, 6, 0,14
|
||||||
12, 0,26,27,27,27,27,27,27,27,27,28, 0,26,28, 0,26,27,27,27,27,27,27,27,27,28, 0,14
|
12,56,26,27,27,27,27,27,27,27,27,28, 0,26,28, 0,26,27,27,27,27,27,27,27,27,28,56,14
|
||||||
12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,14
|
12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,14
|
||||||
23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25
|
23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25
|
||||||
|
BIN
src/main/resources/sounds/credit.wav
Normal file
BIN
src/main/resources/sounds/credit.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/death_0.wav
Normal file
BIN
src/main/resources/sounds/death_0.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/death_1.wav
Normal file
BIN
src/main/resources/sounds/death_1.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eat_dot_0.wav
Normal file
BIN
src/main/resources/sounds/eat_dot_0.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eat_dot_0_fast.wav
Normal file
BIN
src/main/resources/sounds/eat_dot_0_fast.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eat_dot_1.wav
Normal file
BIN
src/main/resources/sounds/eat_dot_1.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eat_dot_1_fast.wav
Normal file
BIN
src/main/resources/sounds/eat_dot_1_fast.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eat_fruit.wav
Normal file
BIN
src/main/resources/sounds/eat_fruit.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eat_ghost.wav
Normal file
BIN
src/main/resources/sounds/eat_ghost.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/extend.wav
Normal file
BIN
src/main/resources/sounds/extend.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eyes.wav
Normal file
BIN
src/main/resources/sounds/eyes.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/eyes_firstloop.wav
Normal file
BIN
src/main/resources/sounds/eyes_firstloop.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/fright.wav
Normal file
BIN
src/main/resources/sounds/fright.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/fright_firstloop.wav
Normal file
BIN
src/main/resources/sounds/fright_firstloop.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/intermission.wav
Normal file
BIN
src/main/resources/sounds/intermission.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren0.wav
Normal file
BIN
src/main/resources/sounds/siren0.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren0_firstloop.wav
Normal file
BIN
src/main/resources/sounds/siren0_firstloop.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren1.wav
Normal file
BIN
src/main/resources/sounds/siren1.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren1_firstloop.wav
Normal file
BIN
src/main/resources/sounds/siren1_firstloop.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren2.wav
Normal file
BIN
src/main/resources/sounds/siren2.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren2_firstloop.wav
Normal file
BIN
src/main/resources/sounds/siren2_firstloop.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren3.wav
Normal file
BIN
src/main/resources/sounds/siren3.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren3_firstloop.wav
Normal file
BIN
src/main/resources/sounds/siren3_firstloop.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren4.wav
Normal file
BIN
src/main/resources/sounds/siren4.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/siren4_firstloop.wav
Normal file
BIN
src/main/resources/sounds/siren4_firstloop.wav
Normal file
Binary file not shown.
BIN
src/main/resources/sounds/start.wav
Normal file
BIN
src/main/resources/sounds/start.wav
Normal file
Binary file not shown.
Reference in New Issue
Block a user