1

我正在写一个视频游戏,我想在玩家输掉或退出(到主菜单)时停止音乐。

这是我的代码:

public class Music{
    private static Clip clip;
    private static AudioInputStream stream;

    private static void loadMusic(){
        if(clip != null) return;
        try {
            AudioFormat format;
            DataLine.Info info;
            stream = AudioSystem.getAudioInputStream(Music.class.getResource("/resources/music/music.wav"));
            format = stream.getFormat();
            info = new DataLine.Info(Clip.class, format);
            clip = (Clip) AudioSystem.getLine(info);
            clip.open(stream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void playMusic(boolean loop){
        loadMusic();
        if(clip == null) return;
        if(loop) clip.loop(Clip.LOOP_CONTINUOUSLY);
        else clip.start();
    }

    public static void stopMusic(){
        clip.stop();
        clip.setMicrosecondPosition(0);
    }
}

每当我调用 Music.stopMusic() 时,游戏都会挂起几秒钟然后继续。

4

1 回答 1

2

根据我从您的描述中收集的信息,您正在按下 GUI 上的停止按钮,这会调用Music.stopMusic()。结果是音频剪辑停止播放,但您仍在等待 3 秒,GUI 才会响应。

这是因为您在其中Music.stopMusic()进行的调用会对 I/O 资源进行本机调用,而这不应在 EDT 中调用。您应该考虑运行一个工作线程来执行此操作:

Thread t = new Thread(new Runnable() { 
     public void run() {
         Music.stop();
     }
});
t.start();

或者考虑使用SwingWorker

有趣的是,虽然我不确定Clip返回的是哪个实现,但快速浏览一下MixerClip显示了对本机库的调用,然后可能是你困境中的确凿证据——等待回调 3 秒!

// stop the sample.  this invalidates the sample voice id.
nStop(id);

// wait for the callback
synchronized(lock) {
    if (id!=0) {
    try {
        //long time=System.currentTimeMillis();
        lock.wait(3000);
        //if (System.currentTimeMillis()-time > 2500) {
        //System.out.println(" WAITING TIMED OUT!"); System.out.flush();
        //id=0;
        //}
    } catch (InterruptedException e) { }
    }
}
于 2012-08-20T23:37:36.023 回答