You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多关卡Pong游戏:切换关卡时如何停止上一关卡背景音乐?

多关卡Pong游戏音频切换问题解决方案

我正在制作一款带多关卡的Pong游戏,每个关卡会切换背景图和音频。当前通过分数触发关卡切换逻辑,代码如下:

//仅在分数为0且上一分数不为0时运行图片文件转换,避免每帧重复转换和设置背景,
//同时避免媒体播放器每帧更新
//还会检查显示当前关卡的文本是否可见,若可见则淡出
if (Integer.parseInt(playerScore.getText()) == 0 && Integer.parseInt(aiScore.getText()) == 0 &&
    (previousPlayerScore != 0 || previousAiScore != 0)) {
        if (levelBackground.isVisible()) {
            levelBackground.setVisible(true);
            fadeOut.playFromStart();
        }
            
        convertImageFiles();
        convertAudioFiles();
}

这段逻辑会在动画计时器的每一次脉冲中检查,游戏初期运行正常,但切换到第二关卡后,第一关卡的音乐不会停止,和第二关卡音乐叠加播放,后续关卡都存在这个问题。音频转换的代码如下:

MediaPlayer playMusic;
private void convertAudioFiles() {
    //获取当前游戏关卡
    int currentLevel = Integer.parseInt(level.getText());
    //遍历音频文件数组
    for(int i = 0; i < audioArrayLength; i++) {
        //若索引+1等于当前关卡
        if((i + 1) == currentLevel) {
            //将当前歌曲设置为对应索引的音频
            String currentSong = audioList[i];
            System.out.println(currentSong);
            //将歌曲转换为文件
            File musicFile = new File(currentSong);
            //转换为媒体资源
            Media musicMedia = new Media(musicFile.toURI().toString());
            //传入媒体播放器
            playMusic = new MediaPlayer(musicMedia);
            //设置播放结束后重复
            playMusic.setOnEndOfMedia(new Runnable() {
                public void run() {
                    playMusic.seek(Duration.ZERO);
                }
            });
            //开始播放
            playMusic.play();
        }
         }
}

解决方案

方案一:创建新播放器前停止并释放旧实例

在初始化新的playMusic实例前,先检查旧实例是否存在,停止播放并释放资源,确保旧音频彻底停止:

MediaPlayer playMusic;
private void convertAudioFiles() {
    // 获取当前游戏关卡
    int currentLevel = Integer.parseInt(level.getText());
    
    // 停止并释放之前的媒体播放器
    if (playMusic != null) {
        playMusic.stop();
        playMusic.dispose(); // 彻底释放资源,避免旧播放器后台运行
    }
    
    // 遍历音频文件数组
    for(int i = 0; i < audioArrayLength; i++) {
        if((i + 1) == currentLevel) {
            String currentSong = audioList[i];
            System.out.println(currentSong);
            File musicFile = new File(currentSong);
            Media musicMedia = new Media(musicFile.toURI().toString());
            playMusic = new MediaPlayer(musicMedia);
            playMusic.setOnEndOfMedia(() -> playMusic.seek(Duration.ZERO));
            playMusic.play();
            break; // 找到对应音频后跳出循环,提升效率
        }
    }
}

之前仅调用stop()无效,是因为旧的MediaPlayer实例仍占用资源在后台运行,dispose()会彻底销毁该实例,确保旧音频停止。

方案二:提前初始化所有关卡播放器

如果关卡数量固定,可以提前初始化所有关卡的MediaPlayer实例,切换时直接切换播放的实例,避免重复创建:

// 全局变量,存储各关卡对应的MediaPlayer
private Map<Integer, MediaPlayer> levelMusicPlayers = new HashMap<>();
private MediaPlayer currentPlayingMusic;

// 初始化阶段创建所有播放器
private void initMusicPlayers() {
    for(int i = 0; i < audioArrayLength; i++) {
        String songPath = audioList[i];
        File musicFile = new File(songPath);
        Media musicMedia = new Media(musicFile.toURI().toString());
        MediaPlayer player = new MediaPlayer(musicMedia);
        player.setOnEndOfMedia(() -> player.seek(Duration.ZERO));
        levelMusicPlayers.put(i + 1, player); // 用关卡号作为键
    }
}

// 切换关卡音频的方法
private void switchLevelMusic(int currentLevel) {
    // 停止当前播放的音频
    if (currentPlayingMusic != null) {
        currentPlayingMusic.stop();
    }
    // 启动对应关卡的音频
    currentPlayingMusic = levelMusicPlayers.get(currentLevel);
    if (currentPlayingMusic != null) {
        currentPlayingMusic.play();
    }
}

之后在关卡切换时调用switchLevelMusic(currentLevel)即可,这种方式更高效,适合关卡数量不多的场景。

内容的提问来源于stack exchange,提问作者River Lockhart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 16:14:55