多关卡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
相关产品推荐
相关产品推荐

