Heli sissejuhatus

Sound ja Music klassid

LibGDX pakub kahte erinevat klassi helide esitamiseks: Sound ja Music. Nende erinevuse mõistmine on oluline, et valida õige klass vastavalt vajadusele.

Sound

Sound klass on mõeldud lühikeste heliefektide jaoks, nagu tulistamine, hüppamine või muu sarnane lühike heli. Sound laetakse täielikult mällu, mis tähendab, et seda saab kiiresti ja korduvalt mängida ilma viivituseta. Seetõttu sobib Sound hästi kõikide lühikeste heliefektide jaoks mängus.

  • Kiire esitus

  • Sobib lühikestele efektidele

  • Saab mängida korraga mitut korda (nt kiire tulistamine)

Music

Music klass on mõeldud pikemate helifailide jaoks, nagu taustamuusika. Music ei laeta täielikult mällu korraga, vaid voogedastab (stream) faili kettalt, mis tähendab, et see kulutab vähem RAM-i, kuid ei sobi kiireks korduvaks esituseks.

  • Sobib pikkadele helidele (taustamuusika, ambient)

  • Toetab tsüklis mängimist (setLooping(true))

Toetatud heliformaadid

LibGDX toetab kolme peamist heliformaati: WAV, MP3 ja OGG. Tuleb arvestada, et mõned formaadid ei pruugi kõikidel platvormidel korrektselt töötada, mistõttu võib olla vaja erinevaid formaate proovida.

  • WAV – lossless formaat, kõrgeim helikvaliteet, failid on suured. Laadib kiiresti, kuna dekompresseerimist pole vaja. Sobib hästi lühikestele heliefektidele (Sound klass).

  • MP3 – kompresseeritud formaat, väiksemad failid. Sobib taustamuusikale, kui failimaht on oluline.

  • OGG (Ogg Vorbis) – avatud ja kompresseeritud formaat, hea kvaliteedi ja failimahu suhe. Laialdaselt soovitatav LibGDX projektides, eriti kui WAV ja MP3 probleeme tekitavad. Paljud arendajad on leidnud, et OGG toimib kõige stabiilsemalt.

Soovitus: kui WAV või MP3 ei tööta oodatult, proovi OGG formaati. Helifaile saab konvertida näiteks tasuta tarkvaraga Audacity.

Heli haldav klass

Audio lisamiseks oma mängu tuleks luua eraldi klass AudioManager, kuhu koondatakse kõik heliga seotud meetodid. Selle kasutamine on hea mitmel põhjusel:

  • Koondab kõik heliga seotud funktsioonid (laadimine, esitamine, peatamine) ühte kohta

  • Heliloogika kapseldamine parendab koodi loetavust ja hooldatavust.

  • Soodustab koodi korduvkasutatavust

  • Mängu keerukuse kasvades saab hõlpsasti meetodeid juurde lisada.

AudioManager näide

Allpool on AudioManager klass koos konstruktori, initsialiseerimise ja vabastamise meetoditega. AssetManager on siin jagatud üle kogu mängu (üks eksemplar), mis aitab vältida sama vara korduvat laadimist.

public class AudioManager {
    private AssetManager assetManager;
    private Music backgroundMusic;
    private Sound soundEffect;
    private float musicVolume = 0.8f;  // Vaikimisi volüüm 80%
    private float soundVolume = 1.0f;

    // Konstruktor – võtab jagatud AssetManageri parameetrina
    // (üks AssetManager kogu mängu jaoks, ei loo uut)
    public AudioManager(AssetManager assetManager) {
        this.assetManager = assetManager;
    }

    // Laeb kõik vajalikud helivarad AssetManageriga
    public void loadAssets() {
        // Music pikemate helide jaoks (taustamuusika)
        assetManager.load("audio/background.ogg", Music.class);
        // Sound lühikeste efektide jaoks
        assetManager.load("audio/shoot.wav", Sound.class);
        // Ootab kuni kõik varad on laetud
        assetManager.finishLoading();

        backgroundMusic = assetManager.get("audio/background.ogg", Music.class);
        soundEffect = assetManager.get("audio/shoot.wav", Sound.class);
    }

    // Mängib taustamuusikat tsüklis
    public void playBackgroundMusic() {
        backgroundMusic.setLooping(true);
        backgroundMusic.setVolume(musicVolume);
        backgroundMusic.play();
    }

    // Peatab taustamuusika (saab hiljem jätkata)
    public void pauseBackgroundMusic() {
        backgroundMusic.pause();
    }

    // Mängib lühikest heliefekti
    public void playSoundEffect() {
        soundEffect.play(soundVolume);
    }

    // Muudab muusika volüümi (0.0 - 1.0)
    public void setMusicVolume(float volume) {
        this.musicVolume = volume;
        if (backgroundMusic != null) {
            backgroundMusic.setVolume(volume);
        }
    }

    // Kutsu välja mängu sulgemisel
    public void dispose() {
        // AssetManager vabastab kõik laetud varad
        assetManager.unload("audio/background.ogg");
        assetManager.unload("audio/shoot.wav");
    }
}

Helide järjestikune mängimine

Mõnikord on vaja mängida mitu heli üksteise järel (dialoogid, sammud või animatsiooniga seotud helid). Seda saab teha heli lõpetamise kuulaja (completion listener) abil.

public class AudioManager {
    private Sound[] stepSounds;  // Sammude helide massiiv
    private int currentStepIndex = 0;

    // Laeb mitu sammu heli
    public void loadStepSounds() {
        assetManager.load("audio/step1.wav", Sound.class);
        assetManager.load("audio/step2.wav", Sound.class);
        assetManager.load("audio/step3.wav", Sound.class);
        assetManager.finishLoading();

        stepSounds = new Sound[] {
            assetManager.get("audio/step1.wav", Sound.class),
            assetManager.get("audio/step2.wav", Sound.class),
            assetManager.get("audio/step3.wav", Sound.class)
        };
    }

    // Mängib sammude helisid tsükliliselt
    public void playNextStep() {
        // Mängib järgmise heli massiivist
        stepSounds[currentStepIndex].play(soundVolume);
        // Liigub järgmise heli juurde (tsükkel)
        currentStepIndex = (currentStepIndex + 1) % stepSounds.length;
    }

    // Alternatiiv: kasuta Music klassi onCompletionListener
    // järjestikku mängimiseks (nt dialoog)
    public void playSequence(Music first, Music second) {
        first.setOnCompletionListener(music -> {
            // Esimene heli lõppes – mängi teist
            second.play();
        });
        first.play();
    }
}

Mängu integreerimine

AudioManager integreeritakse mängu läbi jagatud AssetManageri. See luuakse mängu peaklassis ja antakse edasi kõigile ekraanidele – nii välditakse sama vara korduvat laadimist.

public class MyGame extends Game {
    public AssetManager assetManager;
    public AudioManager audioManager;

    @Override
    public void create() {
        assetManager = new AssetManager();
        audioManager = new AudioManager(assetManager);
        audioManager.loadAssets();
        setScreen(new GameScreen(this));
    }

    @Override
    public void dispose() {
        audioManager.dispose();
        assetManager.dispose();
    }
}

public class GameScreen implements Screen {
    private AudioManager audioManager;

    public GameScreen(MyGame game) {
        // Saab AudioManageri peamängult
        this.audioManager = game.audioManager;
    }

    @Override
    public void show() {
        // Ekraan ilmub – käivita muusika
        audioManager.playBackgroundMusic();
    }

    @Override
    public void hide() {
        // Ekraan peidetakse – peata muusika
        audioManager.pauseBackgroundMusic();
    }
}

Volüüm

Volüümi muutmist saab implementeerida LibGDX poolt pakutud Slider klassiga. Slider võtab konstruktoris minimaalsed ja maksimaalsed väärtused, sammusuurus määrab kui palju volüüm korraga muutub.

public class VolumeSlider extends Slider {
    private AudioManager audioManager;

    // Parameetrid:
    //   min, max   – volüümi vahemik (0.0 kuni 1.0)
    //   stepSize   – muutuse suurus ühe sammu kohta (nt 0.1)
    //   vertical   – kas liugur on vertikaalne (false = horisontaalne)
    //   skin       – LibGDX Skin liuguri visuaalse stiili jaoks
    public VolumeSlider(float min, float max, float stepSize,
                        boolean vertical, Skin skin,
                        AudioManager audioManager) {
        super(min, max, stepSize, vertical, skin);
        this.audioManager = audioManager;

        // Kuulaja käivitub iga kord, kui kasutaja liugurit liigutab
        addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                float volume = getValue();  // 0.0 – 1.0
                audioManager.setMusicVolume(volume);
            }
        });
    }
}

Nüüd saab liuguri lisada oma helisätetega ekraanile:

public class AudioScreen implements Screen {
    private Stage stage;
    private Skin skin;
    private AudioManager audioManager;

    public AudioScreen(MyGame game) {
        this.audioManager = game.audioManager;
        stage = new Stage();
        skin = new Skin(Gdx.files.internal("ui/uiskin.json"));

        // Loo volüümi liugur: min=0, max=1, samm=0.1, horisontaalne
        VolumeSlider volumeSlider = new VolumeSlider(
            0f, 1f, 0.1f, false, skin, audioManager
        );
        // Aseta liugur ekraani keskele
        volumeSlider.setPosition(
            Gdx.graphics.getWidth() / 2f - 100,
            Gdx.graphics.getHeight() / 2f
        );
        volumeSlider.setWidth(200);
        stage.addActor(volumeSlider);
    }

    @Override
    public void render(float delta) {
        stage.act(delta);
        stage.draw();
    }

    @Override
    public void dispose() {
        stage.dispose();
        skin.dispose();
    }
}

Lisaks abistavaid materjale