为什么我玩这个 .wav 文件时游戏会滞后?

Why is my game lagging when I play this .wav file?

所以我正在制作游戏,我注意到当我尝试在玩家升级时播放音频时,它会在一瞬间滞后整个游戏。 public void tick() 每秒被调用 60 次。

而且我已经测试过了,唯一落后于我的游戏的是这个 class

中的音频部分
public void tick() {
    if (Game.startPressed == true) {
        if (HUD.HEALTH != 0) {
            if (Game.gamePaused == false) {
                playerScoreKeep++;
                playerScoreKeepShield++;
                if (playerScoreKeepShield >= 3000) {
                    playerScoreKeepShield = 0;
                    handler.addObject(new BasicShield(r.nextInt(Game.WIDTH - 17), r.nextInt(Game.HEIGHT - 17), ID.BasicShield, handler));
                }
                if (playerScoreKeep >= 1000) {
                    try { //This is the part that's causing the game to lag spike really bad
                        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(this.getClass().getResource("/lvl_up.wav"));
                        Clip clip = AudioSystem.getClip();
                        clip.open(audioInputStream);
                        clip.start();
                    } catch(Exception ex) {
                        System.out.println("Error with playing sound.");
                        ex.printStackTrace();
                    }
                    playerScoreKeep = 0;
                    HUD.playerLevel++;
                    handler.addObject(new BasicHP(r.nextInt(Game.WIDTH - 17), r.nextInt(Game.HEIGHT - 17), ID.BasicHP, handler));
                    for (int g = 0; g < 2; g++) handler.addObject(new BasicEnemy(r.nextInt(Game.WIDTH - 17), r.nextInt(Game.HEIGHT - 17), ID.BasicEnemy, handler));
                    if (HUD.playerLevel >= 5) {
                        advRandomDir = r.nextInt(3);
                        if (advRandomDir == 1) { 
                            handler.addObject(new AdvancedEnemy(10, r.nextInt(Game.HEIGHT), ID.AdvancedEnemy, handler));
                        }
                        else if (advRandomDir == 2) {
                            handler.addObject(new AdvancedEnemy(r.nextInt(Game.WIDTH), 32, ID.Advancedenemy, handler));
                        } else {
                            handler.addObject(new AdvancedEnemy(r.nextInt(Game.WIDTH), 32, ID.AdvancedEnemy, handler));
                        }
                        handler.addObject(new BasicEnemy(r.nextInt(Game.WIDTH - 17), r.nextInt(Game.HEIGHT - 17), ID.BasicEnemy, handler));
                        if (HUD.playerLevel == 8) {
                            handler.addObject(new ChaoticEnemy(Game.WIDTH/2, Game.HEIGHT/2, ID.ChaoticEnemy, handler));
                        } else if (HUD.playerLevel == 9) {
                            ChaoticEnemy.ChaoticEnemy_Bullet_Speed = 25;
                            for (int i = 0; i < handler.object.size(); i++) {
                                GameObject tempObject = handler.object.get(i);
                                if (tempObject.getID() == ID.ChaoticEnemy) if (HUD.HEALTH != 0) {
                                    tempObject.velX = 2;
                                    tempObject.velY = 2;
                                }
                            }
                        } else if (HUD.playerLevel == 15) {
                            ChaoticEnemy.ChaoticEnemy_Bullet_Speed = 20;
                            for (int i = 0; i < handler.object.size(); i++) {
                                GameObject tempObject = handler.object.get(i);
                                if (tempObject.getID() == ID.ChaoticEnemy) if (HUD.HEALTH != 0) {
                                    tempObject.velX = 3;
                                    tempObject.velY = 3;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

这是因为每次访问该部分时都会在线程上读取磁盘。游戏线程需要每秒循环 60 次(每 16 毫秒)以获得流畅的显示,并且从磁盘读取此声音需要超过 16 毫秒。因此,您的游戏很慢。

我认为对于像这样的小音效,最好的方法肯定是将声音预加载到内存中,然后根据需要播放。对于背景音乐等较重的资源,您可能需要采用不同的方法。

或者,如果您必须在每次播放时都从磁盘读取数据,您将希望同时进行(即在另一个线程中),这样您的游戏线程就不会阻塞等待磁盘读取数据。这种方法的缺点是声音可能会比您想要的晚播放一点(但至少游戏不会因等待加载而卡顿)。

一般来说,您要确保您的游戏循环仅在线程上执行非常轻量级的事务。您应该不断寻找提前或离线进行繁重事务的方法。