clean code: extract inner classes

This commit is contained in:
Martin Prokoph
2025-09-03 14:17:47 +02:00
parent 6d03702ada
commit f6a94e6cd8
6 changed files with 118 additions and 87 deletions

View File

@@ -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();
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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");

View File

@@ -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();
}
}
}

View File

@@ -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: <a href="https://www.baeldung.com/java-play-sound">Baeldung</a>
*
* @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);
}
}
}

View File

@@ -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: <a href="https://www.baeldung.com/java-play-sound">Baeldung</a>
* @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();
}
}
}
}