javaperformanceaudioinputstream

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


So I am making a game, and I noticed that when I attempted to play audio when the player levels up it lags the whole game for a split second. public void tick() is called 60 times in a second.

And I have already tested it and the only thing lagging my game is the audio part in this 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;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Solution

  • This is due to the disk being read on-thread each time you come to that section. The game thread needs to loop 60 times a second (every 16ms) to get a smooth display and reading this sound from disk is taking more than 16ms. As a result, your game is laggy.

    I think for small sound effects like this the best approach is definitely to pre-load the sound into memory, and play it as needed. You might have to take a different approach for heavier resources, like background music.

    Alternatively, if you must read it from disk on each play, you will want to do so concurrently (i.e. in another thread) so your game thread doesn't block waiting for the disk to read the data. A downside to this approach is the sound will probably play a little later than you would like (but at least the game doesn't stutter waiting for load).

    In general, you want to make sure your game loop is only doing very lightweight transactions on-thread. You should be constantly looking for ways to do heavy transactions ahead of time or off-thread.