diff --git a/src/main/java/eu/midnightdust/yaytris/Tetris.java b/src/main/java/eu/midnightdust/yaytris/Tetris.java index 93c4d99..9f2b9e5 100644 --- a/src/main/java/eu/midnightdust/yaytris/Tetris.java +++ b/src/main/java/eu/midnightdust/yaytris/Tetris.java @@ -3,7 +3,8 @@ package eu.midnightdust.yaytris; import eu.midnightdust.yaytris.game.Space; import eu.midnightdust.yaytris.ui.ScoreMenu; import eu.midnightdust.yaytris.ui.TetrisUI; -import eu.midnightdust.yaytris.util.SoundUtil; +import eu.midnightdust.yaytris.util.GravityTimerTask; +import eu.midnightdust.yaytris.util.sound.SoundUtil; import javax.swing.*; import java.time.LocalTime; @@ -48,6 +49,15 @@ public class Tetris { return space; } + /** + * Get the ui instance + * + * @see TetrisUI + */ + public static TetrisUI getUi() { + return ui; + } + /** * Resets the game space, preparing it for a new game. * @@ -127,17 +137,4 @@ public class Tetris { } } - /** - * Defines our custom timer task that handles falling pieces. - */ - public static class GravityTimerTask extends TimerTask { - @Override - public void run() { - if (space.getCurrentTetromino() != null) { - updateTime(); - space.getCurrentTetromino().fall(); - ui.getGamePanel().repaint(); - } - } - } } diff --git a/src/main/java/eu/midnightdust/yaytris/util/GravityTimerTask.java b/src/main/java/eu/midnightdust/yaytris/util/GravityTimerTask.java new file mode 100644 index 0000000..2aed805 --- /dev/null +++ b/src/main/java/eu/midnightdust/yaytris/util/GravityTimerTask.java @@ -0,0 +1,19 @@ +package eu.midnightdust.yaytris.util; + +import eu.midnightdust.yaytris.Tetris; + +import java.util.TimerTask; + +/** + * Defines our custom timer task that handles falling pieces. + */ +public class GravityTimerTask extends TimerTask { + @Override + public void run() { + if (Tetris.getSpace().getCurrentTetromino() != null) { + Tetris.updateTime(); + Tetris.getSpace().getCurrentTetromino().fall(); + Tetris.getUi().getGamePanel().repaint(); + } + } +} diff --git a/src/main/java/eu/midnightdust/yaytris/util/SoundEffect.java b/src/main/java/eu/midnightdust/yaytris/util/SoundEffect.java index 63a987e..425cc40 100644 --- a/src/main/java/eu/midnightdust/yaytris/util/SoundEffect.java +++ b/src/main/java/eu/midnightdust/yaytris/util/SoundEffect.java @@ -1,5 +1,7 @@ package eu.midnightdust.yaytris.util; +import eu.midnightdust.yaytris.util.sound.SoundUtil; + public enum SoundEffect { BOOP("/sounds/boop.wav"), LINE_COMPLETED("/sounds/line-completed.wav"); diff --git a/src/main/java/eu/midnightdust/yaytris/util/sound/LineUpdateListener.java b/src/main/java/eu/midnightdust/yaytris/util/sound/LineUpdateListener.java new file mode 100644 index 0000000..eea3738 --- /dev/null +++ b/src/main/java/eu/midnightdust/yaytris/util/sound/LineUpdateListener.java @@ -0,0 +1,13 @@ +package eu.midnightdust.yaytris.util.sound; + +import javax.sound.sampled.LineEvent; +import javax.sound.sampled.LineListener; + +public class LineUpdateListener implements LineListener { + @Override + public void update(LineEvent event) { + if (LineEvent.Type.STOP == event.getType()) { + event.getLine().close(); + } + } +} diff --git a/src/main/java/eu/midnightdust/yaytris/util/sound/MusicThread.java b/src/main/java/eu/midnightdust/yaytris/util/sound/MusicThread.java new file mode 100644 index 0000000..31b8ae4 --- /dev/null +++ b/src/main/java/eu/midnightdust/yaytris/util/sound/MusicThread.java @@ -0,0 +1,70 @@ +package eu.midnightdust.yaytris.util.sound; + +import eu.midnightdust.yaytris.Settings; + +import javax.sound.sampled.*; +import java.io.IOException; + +/** + * Handle music in separate threads to not interrupt the main game + */ +public class MusicThread extends Thread { + private static final int BUFFER_SIZE = 8192; + private final boolean looped; + private final String fileLocation; + private boolean playing; + + public MusicThread(String fileLocation, boolean looped) { + this.fileLocation = fileLocation; + this.looped = looped; + this.playing = true; + } + + public void stopMusic() { + this.playing = false; + } + + @Override + public void run() { + do { + playMusic(fileLocation); + } while (looped && playing); + } + + /** + * INTERNAL! + * Play the long audio file found at the specified location. + * Fades out after calling {@link #stopMusic()}. + * Adapted from: Baeldung + * + * @see SoundUtil#playMusic(String, boolean) + */ + private void playMusic(String fileLocation) { + try (AudioInputStream stream = AudioSystem.getAudioInputStream(SoundUtil.getResource(fileLocation))) { + AudioFormat format = stream.getFormat(); + DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); + + SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(info); + sourceDataLine.open(format); + sourceDataLine.start(); + SoundUtil.setVolume(sourceDataLine, Settings.musicVolume); + float fadeOut = 1.0f; + + byte[] bufferBytes = new byte[BUFFER_SIZE]; + int readBytes; + while ((readBytes = stream.read(bufferBytes)) != -1) { + if (!playing) { + fadeOut = (float) Math.sin(fadeOut - 0.01f); // Sinus fade-out + SoundUtil.setVolume(sourceDataLine, (int) (fadeOut * Settings.musicVolume)); + if (fadeOut <= 0) break; + } + sourceDataLine.write(bufferBytes, 0, readBytes); + } + + sourceDataLine.drain(); + sourceDataLine.close(); + } catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/eu/midnightdust/yaytris/util/SoundUtil.java b/src/main/java/eu/midnightdust/yaytris/util/sound/SoundUtil.java similarity index 51% rename from src/main/java/eu/midnightdust/yaytris/util/SoundUtil.java rename to src/main/java/eu/midnightdust/yaytris/util/sound/SoundUtil.java index 3f9013f..ad8f066 100644 --- a/src/main/java/eu/midnightdust/yaytris/util/SoundUtil.java +++ b/src/main/java/eu/midnightdust/yaytris/util/sound/SoundUtil.java @@ -1,4 +1,4 @@ -package eu.midnightdust.yaytris.util; +package eu.midnightdust.yaytris.util.sound; import eu.midnightdust.yaytris.Settings; @@ -55,7 +55,7 @@ public class SoundUtil { } } - private static URL getResource(String fileLocation) { + protected static URL getResource(String fileLocation) { return SoundUtil.class.getResource(fileLocation); } @@ -66,80 +66,10 @@ public class SoundUtil { * @param line the DataLine responsible for audio playback * @param volume the requested volume in percent (0-100%) */ - private static void setVolume(Line line, int volume) { + protected static void setVolume(Line line, int volume) { if (volume < 0 || volume > 100) throw new IllegalArgumentException("Volume not valid: " + volume); FloatControl gainControl = (FloatControl) line.getControl(FloatControl.Type.MASTER_GAIN); gainControl.setValue(20f * (float) Math.log10(volume/100f)); } - - /** - * Handle music in separate threads to not interrupt the main game - */ - public static class MusicThread extends Thread { - private static final int BUFFER_SIZE = 8192; - private final boolean looped; - private final String fileLocation; - private boolean playing; - - MusicThread(String fileLocation, boolean looped) { - this.fileLocation = fileLocation; - this.looped = looped; - this.playing = true; - } - - public void stopMusic() { - this.playing = false; - } - - @Override - public void run() { - do {playMusic(fileLocation);} while (looped && playing); - } - - /** - * INTERNAL! - * Play the long audio file found at the specified location. - * Fades out after calling {@link #stopMusic()}. - * Adapted from: Baeldung - * @see SoundUtil#playMusic(String, boolean) - */ - private void playMusic(String fileLocation) { - try (AudioInputStream stream = AudioSystem.getAudioInputStream(getResource(fileLocation))) { - AudioFormat format = stream.getFormat(); - DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); - - SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(info); - sourceDataLine.open(format); - sourceDataLine.start(); - setVolume(sourceDataLine, Settings.musicVolume); - float fadeOut = 1.0f; - - byte[] bufferBytes = new byte[BUFFER_SIZE]; - int readBytes; - while ((readBytes = stream.read(bufferBytes)) != -1) { - if (!playing) { - fadeOut = (float) Math.sin(fadeOut-0.01f); // Sinus fade-out - setVolume(sourceDataLine, (int) (fadeOut * Settings.musicVolume)); - if (fadeOut <= 0) break; - } - sourceDataLine.write(bufferBytes, 0, readBytes); - } - - sourceDataLine.drain(); - sourceDataLine.close(); - } catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) { - throw new RuntimeException(e); - } - } - } - - public static class LineUpdateListener implements LineListener { - @Override - public void update(LineEvent event) { - if (LineEvent.Type.STOP == event.getType()) { - event.getLine().close(); - } - } - } }