Я пытаюсь остановить воспроизведение вступительной песни при нажатии кнопки запуска. Я попытался сделать это, используя этот код. Обратите внимание, что этот код не влечет за собой весь мой код. Графический интерфейс выглядит нормально, прослушиватели действий тоже работают нормально. Только музыка не перестает играть при нажатии на кнопку запуска.
File introPath = new File("src/BattleshipGUI/423499__soundflakes__epic-heroic-orchestral-
dramatic.wav");
File buttonPressedPath = new File("src/BattleshipGUI/sfx_patcher_button_launch.wav");
static Clip introWAV;
Menu() {
super("BattleBoard");
this.setContentPane(this.panelMain);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setLocationRelativeTo(null);
this.pack();
play(introPath); // playing when launching
// when the game starts, the sound should stop
ButtonStartGame.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
play(buttonPressedPath);
try {
if (random) {
currentCols = (Integer) spinnerColumns.getValue();
currentRows = (Integer) spinnerRows.getValue();
if (currentCols < 5 || currentRows < 5) {
throw (new IllegalArgumentException());
} else {
BoardFrame b = new BoardFrame(currentRows, currentCols);
b.SetFrame(currentRows, currentCols);
b.AddRandomShips(currentRows, currentCols);
b.ScoreMethod(adjustedScoreMethod);
introWAV.stop();
introWAV.flush();
introWAV.close();
dispose();
public static void SetIntroWAV(Clip clip){
introWAV=clip;
}
public static void play(File file) {
try {
Clip sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
SetIntroWAV(sound);
sound.start();
} catch (Exception e) {
System.out.println(e);
}
}
Я пробовал другие способы, такие как использование циклов while в классе Play, операторов if-else,... Кто-нибудь знает, как это исправить? Заранее спасибо!
Виновником является часть вашего play
метода.
Всякий раз, когда вы хотите воспроизвести какой-либо звук, вы также вызываете SetIntroWAV
внутренне. Это приводит к установке вашей переменной introWAV
.
Вот почему это проблема:
При первом вызове play
воспроизводится вступительный звук, а introWAV
имеет правильное значение.
Однако, как только вы запустите игру и воспроизведете другой звук (а именно, используя buttonPressedPath
), ваша переменная introWAV
будет установлена на другое значение: звук, который был запущен последним.
Затем, когда вы пытаетесь остановить воспроизведение своего звука, вы используете introWAV
, который на самом деле больше не содержит отсылки к вашему вступительному звуку. Вместо этого это приведет к остановке вашего последнего воспроизведенного звука, поскольку это то, что сейчас удерживает introWAV
.
Чтобы исправить это, просто задайте переменную introWAV
только один раз, а не каждый раз, когда вызывается play
. Есть несколько способов сделать это, включая следующие:
Вы можете позволить своему методу play
вернуть результирующий Clip
, который будет воспроизведен впоследствии:
public static Clip play(File file) {
Clip sound = null;
try {
sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
sound.start();
} catch (Exception e) {
System.out.println(e);
} finally {
return sound;
}
}
Затем вы можете использовать это возвращаемое значение для вызова SetIntroWAV
один раз: SetIntroWAV(play(introPath));
Вы также можете использовать это возвращаемое значение для других целей, таких как сохранение локальных ссылок на ваши звуки. Однако вам не нужно использовать его каждый раз, и вы все равно можете игнорировать его, когда вам не нужна эта ссылка.
Вы можете переписать свой метод play
, чтобы он также содержал параметр, сообщающий методу, является ли звук, который вы пытаетесь воспроизвести, звуком вступления:
public static void play(File file, boolean intro) {
try {
Clip sound = AudioSystem.getClip();
sound.open(AudioSystem.getAudioInputStream(file));
if (intro) {
SetIntroWAV(sound);
}
sound.start();
} catch (Exception e) {
System.out.println(e);
}
}
Это также приведет к тому, что SetIntroWAV
будет вызываться только один раз.
Я бы также рекомендовал вам использовать для этого более объектно-ориентированный стиль программирования, поскольку он может сделать подобные вещи более очевидными и их легче исправить. Например, вы можете создать отдельные классы для воспроизведения звука и вашего игрового процесса.
ИМХО, лучшая практика с переменными Clip
- загрузить и открыть, а затем удерживать их в памяти. Это можно сделать в классе, который управляет вашими звуковыми эффектами. В этом классе используйте Clip в качестве переменной экземпляра, предварительно загрузите и откройте его в конструкторе.
Этот класс также может иметь два метода, которые вызываются из вашей игры.
public void play() {
clip.setFramePosition(0); // ensures Clip will start from the beginning
clip.start();
}
public void stop() {
clip.stop();
}
С такой структурой также стало проще управлять несколькими звуками. Например, у вас может быть два экземпляра этого класса управления звуком, и каждый из них может быть назначен на другой источник звука. Затем вы можете легко остановить один и начать другой.