Thursday, September 26, 2013

LibGDX Tutorial 11: Using Audio

Objectives
  • Using Table to organize the UI
  • Using Array to hold many items
  • Playing Sound and Music

Using sfxr
sfxr (http://drpetter.se/project_sfxr.html) is an audio tool that can be used to make simple game sounds. Starting this program gives





Using the left hand menu I generated 9 different sounds. I named them according to the menu name. The website describe how they generate the frequencies and envelopes and their basis: sine, square, triangle, sawtooth. After saving the files as .wav (lower right corner), I can put them in the assets folder. I also put in one mp3 file. The Sounds are of short duration (few seconds) and music could be in the several minutes range.

Program
The program uses Table to organize the buttons as you can see from the comments. I also use Array and the button code is moved to an external function. For the audio, I have a separate class. I can only only access its methods as they are public and additionally they are static since it would be useless to use a new operator for the Audio.

MyButtonStage2D.java
package com.tutorials.mybuttonstage2d;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.utils.Array;
import com.tutorials.mybuttonstage2d.Sounds.MySound;

public class MyButtonStage2D implements ApplicationListener {
    private OrthographicCamera camera;
    private SpriteBatch batch;
    private Stage stage; //** stage holds the buttons **//
    private BitmapFont font; //** same as that used in Tut 7 **//
    private TextureAtlas buttonsAtlas; //** image of buttons **//
    private Skin buttonSkin; //** images are used as skins of the button **//
    private Array<TextButton> buttons; //** will contain the 9 buttons **//
    private Table table; //** add table to layout UI **//
    float width, height;
   
    @Override
    public void create() {       
        width = Gdx.graphics.getWidth();
        height = Gdx.graphics.getHeight();
       
        camera = new OrthographicCamera();
        camera.setToOrtho(false, width, height);
       
        batch = new SpriteBatch();
       
        buttonsAtlas = new TextureAtlas("buttons.pack"); //** button atlas image **//
        buttonSkin = new Skin();
        buttonSkin.addRegions(buttonsAtlas); //** skins for on and off **//
        font = new BitmapFont(Gdx.files.internal("CustomFont.fnt"),false); //** font **//
       
        stage = new Stage(width, height, true);        //** window is stage **//
        stage.clear();
        Gdx.input.setInputProcessor(stage); //** stage is responsive **//
       
        table = new Table();
        table.setFillParent(true);
       
        buttons = new Array<TextButton>();
        SetButtons(); //** This method is responsible for creating the buttons and listeners **//
       
        for (int i=0; i<9; i++) {
            table.add(buttons.get(i)).space(50).width(250);
            if ((i==2) || (i==5)) table.row();
        }
       
        MySound.PlayMusic(0.5f); //** Volume passed in **//

        /* Above Loop will do these steps
        able.add(buttons.get(0)).space(50).width(250);
        table.add(buttons.get(1)).space(50).width(250);
        table.add(buttons.get(2)).space(50).width(250).row();
        table.add(buttons.get(3)).space(50).width(250);
        table.add(buttons.get(4)).space(50).width(250);
        table.add(buttons.get(5)).space(50).width(250).row();
        table.add(buttons.get(6)).space(50).width(250);
        table.add(buttons.get(7)).space(50).width(250);
        table.add(buttons.get(8)).space(50).width(250);
        */
       
        stage.addActor(table);
    }
   
    private void SetButtons() {
       
        TextButtonStyle style = new TextButtonStyle(); //** Button properties **//
        style.up = buttonSkin.getDrawable("ButtonOff");
        style.down = buttonSkin.getDrawable("ButtonOn");
        style.font = font;
        TextButton button1 = new TextButton("COIN",style);
        buttons.add(button1);
        TextButton button2 = new TextButton("EXPLOSION", style);
        buttons.add(button2);
        TextButton button3 = new TextButton("HIT",style);
        buttons.add(button3);
        TextButton button4 = new TextButton("JUMP",style);
        buttons.add(button4);
        TextButton button5 = new TextButton("POWERUP",style);
        buttons.add(button5);
        TextButton button6 = new TextButton("RANDOMIZE",style);
        buttons.add(button6);
        TextButton button7 = new TextButton("SELECT",style);
        buttons.add(button7);
        TextButton button8 = new TextButton("SHOOT", style);
        buttons.add(button8);
        TextButton button9 = new TextButton("MUTATE", style);
        buttons.add(button9);
        buttons.get(0).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Coin Pressed");
                    MySound.PlayCoin();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Coin Released");
            }
        });
        buttons.get(1).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Explosion Pressed");
                    MySound.PlayExplosion();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Explosion Released");
            }
        });
        buttons.get(2).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Hit Pressed");
                    MySound.PlayHit();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Hit Released");
            }
        });
       
        buttons.get(3).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Jump Pressed");
                    MySound.PlayJump();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Jump Released");
            }
        });
        buttons.get(4).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Power Up Pressed");
                    MySound.PlayPowerup();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Power Up Released");
            }
        });
        buttons.get(5).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Randomize Pressed");
                    MySound.PlayRandomize();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Randomize Released");
            }
        });
        buttons.get(6).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    MySound.PlaySelect();
                    Gdx.app.log("my app", "Select Pressed");
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Select Released");
            }
        });
        buttons.get(7).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Shoot Pressed");
                    MySound.PlayShoot();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Shoot Released");
            }
        });
        buttons.get(8).addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Mutate Pressed");
                    MySound.PlayMutate();
                    return true;
            }
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Mutate Released");
            }
        });
    }

    @Override
    public void dispose() {
        batch.dispose();
        buttonSkin.dispose();
        buttonsAtlas.dispose();
        font.dispose();
        stage.dispose();
        MySound.DestroyAudio();
    }

    @Override
    public void render() {       
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
       
        stage.act();
       
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        stage.draw();
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}


MySounds.java
package com.tutorials.mybuttonstage2d.Sounds;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;

public class MySound {
    private static Sound coin = Gdx.audio.newSound(Gdx.files.internal("sounds/coin.wav"));
    private static Sound explosion = Gdx.audio.newSound(Gdx.files.internal("sounds/explosion.wav"));
    private static Sound hit = Gdx.audio.newSound(Gdx.files.internal("sounds/hit.wav"));
    private static Sound jump = Gdx.audio.newSound(Gdx.files.internal("sounds/jump.wav"));
    private static Sound mutate = Gdx.audio.newSound(Gdx.files.internal("sounds/mutate.wav"));
    private static Sound powerup = Gdx.audio.newSound(Gdx.files.internal("sounds/powerup.wav"));
    private static Sound randomize = Gdx.audio.newSound(Gdx.files.internal("sounds/randomize.wav"));
    private static Sound select = Gdx.audio.newSound(Gdx.files.internal("sounds/select.wav"));
    private static Sound shoot = Gdx.audio.newSound(Gdx.files.internal("sounds/shoot.wav"));
    public static Music song = Gdx.audio.newMusic(Gdx.files.internal("sounds/DavidHasselhoff.mp3"));
   
    public static void PlayMusic(float volume){
        song.setLooping(true);
        song.setVolume(volume);
        song.play();
    }
   
    public static void PlayShoot(){
        shoot.play();
    }
   
    public static void PlayMutate(){
        mutate.play();
    }
   
    public static void PlaySelect(){
        select.play();
    }
   
    public static void PlayCoin(){
        coin.play();
    }
   
    public static void PlayExplosion(){
        explosion.play();
    }
   
    public static void PlayHit(){
        hit.play();
    }
   
    public static void PlayJump(){
        jump.play();
    }
   
    public static void PlayPowerup(){
        powerup.play();
    }
   
    public static void PlayRandomize(){
        randomize.play();
    }
   
    public static void DestroyAudio(){
        coin.dispose();
        explosion.dispose();
        hit.dispose();
        jump.dispose();
        mutate.dispose();
        powerup.dispose();
        randomize.dispose();
        select.dispose();
        shoot.dispose();
        song.stop();
        song.dispose();
    }

}


The output when the COIN button is selected:



Wednesday, September 25, 2013

LibGDX Tutorial 10: Button and Stage 2D

To use Buttons, you have to use Scene 2D UI.

I have two buttons, only different shades in a folder (say ImageButton)

Like Tutorial 9, I create 9-Patch images of the two buttons, and put them in the same folder:

After running Texture Packer(see Texture Packer Tutorial), and putting the resulting files in same folder these are the new contents
The file buttons.pack is a text file (which can be opened by any text software)
From the split fields, we can see that they are recognized as 9-patch,  and we note the names that we will call in program.

Now we can setup by the projects:

MyButtonStage2D.java

package com.tutorials.mybuttonstage2d;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;

public class MyButtonStage2D implements ApplicationListener {
    private OrthographicCamera camera;
    private SpriteBatch batch;
    private Stage stage; //** stage holds the Button **//
    private BitmapFont font; //** same as that used in Tut 7 **//
    private TextureAtlas buttonsAtlas; //** image of buttons **//
    private Skin buttonSkin; //** images are used as skins of the button **//
    private TextButton button; //** the button - the only actor in program **//
   
    @Override
    public void create() {       
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 480); //** w/h ratio = 1.66 **//
       
        batch = new SpriteBatch();
       
        buttonsAtlas = new TextureAtlas("buttons.pack"); //** button atlas image **//
        buttonSkin = new Skin();
        buttonSkin.addRegions(buttonsAtlas); //** skins for on and off **//
        font = new BitmapFont(Gdx.files.internal("CustomFont.fnt"),false); //** font **//
       
        stage = new Stage(800, 480, true);        //** window is stage **//
        stage.clear();
        Gdx.input.setInputProcessor(stage); //** stage is responsive **//
       
        TextButtonStyle style = new TextButtonStyle(); //** Button properties **//
        style.up = buttonSkin.getDrawable("ButtonOff");
        style.down = buttonSkin.getDrawable("ButtonOn");
        style.font = font;
       
        button = new TextButton("PRESS ME", style); //** Button text and style **//
        button.setPosition(100, 100); //** Button location **//
        button.setHeight(300); //** Button Height **//
        button.setWidth(600); //** Button Width **//
        button.addListener(new InputListener() {
            public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Pressed"); //** Usually used to start Game, etc. **//
                    return true;
            }
           
            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    Gdx.app.log("my app", "Released");
            }
        });
       
        stage.addActor(button);
    }

    @Override
    public void dispose() {
        batch.dispose();
        buttonSkin.dispose();
        buttonsAtlas.dispose();
        font.dispose();
        stage.dispose();
}

    @Override
    public void render() {       
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
       
        stage.act();
       
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        stage.draw();
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}


This is the output when button is pressed



And this the output when the button is released.


This also is the initial state.