Como criar uma tela de menu - LibGDX


  Como sabemos, em todos os jogos as telas de menu são muito importantes, pois ajudam na orientação e facilidade na hora de jogar ou escolher uma outra opção.
No nosso jogo(criado no tutorial anterior) não é diferente.
Neste tutorial iremos adicionar uma tela de menu ao nosso jogo, e para isso precisaremos do projeto do jogo criado no tutorial anterior.
Antes de começarmos, será preciso criar 2 interfaces dentro do package com.badlogic.drop com os nomes: MainMenuScreen, GameScreen.







Feito isso, vamos para o código.

A classe mais abstrata do jogo fornece uma implementação de AplicationListener juntamente com alguns outros métodos para lidar com o processamento de tela, sendo que tela e jogo são objetos que juntos formam uma estrutura simples mas precisa.Agora vamos começar com a criação d u jogo de objeto, que será o ponto de entrada para o nosso jogo.
O seguinte código deve ficar em Drop.java:
package com.badlogic.drop;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;


public class Drop extends Game {

    public SpriteBatch batch;
    public BitmapFont font;

    public void create() {
        batch = new SpriteBatch();
        //A fonte usada será Arial(padrão da LibGDX)
        font = new BitmapFont();

        this.setScreen(new MainMenuScreen(this));
    }

    public void render() {
        super.render();
}
    public void dispose() {
        batch.dispose();
        font.dispose();
    }

}
Um erro comum é esquecer de chamar super.render() com uma implementação do jogo. Sem esta chamada, a tela que você definir no método create() não será processada.

No código acima, a linha  
this.setScreen(new MainMenuScreen(this)); tem a função de chamar para dentro do corpo do código a interface MainMenuScreen que será vista a seguir.
O código a seguir deve ficar em MainMenuScreen.java:


package com.badlogic.drop;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;

public class MainMenuScreen implements Screen {

    final Drop game;

    OrthographicCamera camera;

    public MainMenuScreen(final Drop gam) {
        game = gam;

        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 480);

    }


        //...resto do código após explicação...

}
Neste trecho de código, nós fazemos o construtor para a classe MainMenuScreen, que implementa a interface de tela. A interface de tela não fornece nenhum tipo do método create(), por isso, criamos um construtor. O único parâmetro usado para o construtor neste jogo é a instância Drop, de modo que podemos invocar seus métodos e campos dentro do código do jogo em Drop.java como dito mais acima.
public class MainMenuScreen implements Screen {

        //public class MainMenuScreen....        

    @Override
    public void render(float delta) {
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        camera.update();
        game.batch.setProjectionMatrix(camera.combined);

        game.batch.begin();
        game.font.draw(game.batch, "Welcome to Drop!!! ", 100, 150);
        game.font.draw(game.batch, "Tap anywhere to begin!", 100, 100);
        game.batch.end();

        if (Gdx.input.isTouched()) {
            game.setScreen(new GameScreen(game));
            dispose();
        }
    }

        //código completo após a explicação...
}
Precisamos chamar instâncias SpriteBatch e BitmapFont, para que o texto seja inicializado e depois impresso na tela, onde game.font.draw(SpriteBatch, String, float,float), representa a forma como o texto é renderizado na tela. A LibGDX vem com uma fonte pré-fabricada(Arial), de modo que você pode utilizar o construtor padrão e ainda utilizar sua fonte.
OBS:
 if (Gdx.input.isTouched()) {
            game.setScreen(new GameScreen(game));
            dispose();
As linhas acima irão verificar se houve alguma ação do mouse sobre a tela do jogo e se houver, a interface GameScreen será chamada e iniciará o jogo.
Código completo MainMenuScreen.java:



package com.badlogic.drop;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;

public class MainMenuScreen implements Screen {
        final Drop game;
 OrthographicCamera camera;

 public MainMenuScreen(final Drop gam) {
  game = gam;

  camera = new OrthographicCamera();
  camera.setToOrtho(false, 800, 480);

 }

 @Override
 public void render(float delta) {
  Gdx.gl.glClearColor(0, 0, 0.2f, 1);
  Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

  camera.update();
  game.batch.setProjectionMatrix(camera.combined);

  game.batch.begin();
  game.font.draw(game.batch, "Welcome to Drop!!! ", 100, 150);
  game.font.draw(game.batch, "Tap anywhere to begin!", 100, 100);
  game.batch.end();

  if (Gdx.input.isTouched()) {
   game.setScreen(new GameScreen(game));
   dispose();
  }
 }

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

 @Override
 public void show() {
 }

 @Override
 public void hide() {
 }

 @Override
 public void pause() {
 }

 @Override
 public void resume() {
 }

 @Override
 public void dispose() {
 }
}

Agora vamos para a interface GameScreen.
Agora que temos o nosso menu principal já pronto, é hora de começar a fazer o jogo.  
Estaremos levantando a maior parte do código do jogo original , para evitar ter que pensar em uma ideia de jogo diferente para implementar.
O código abaixo deve ficar em GameScreen.java:


package com.badlogic.drop;

import java.util.Iterator;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;

public class GameScreen implements Screen {
    final Drop game;

    Texture dropImage;
    Texture bucketImage;
    Sound dropSound;
    Music rainMusic;
    OrthographicCamera camera;
    Rectangle bucket;
    Array<Rectangle> raindrops;
    long lastDropTime;
    int dropsGathered;

    public GameScreen(final Drop gam) {
        this.game = gam;

        //carregamento das imagens do balde e da gota 
        dropImage = new Texture(Gdx.files.internal("droplet.png"));
        bucketImage = new Texture(Gdx.files.internal("bucket.png"));

        //carregamento dos efeitos sonoros da chuva e dos pingos
        dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
        rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
        rainMusic.setLooping(true);

        //cria a camera de visão do jogador e o sprite batch
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 480);

        //aqui é criado o "retangulo" onde o sprite do balde ficará localizado
        bucket = new Rectangle();
        bucket.x = 800 / 2 - 64 / 2; //aqui o balde é colocado centralizado na horizontal
        bucket.y = 20; //aqui defini-se a posição do balde sendo no canto inferior
                        //da tela 20 pixels acima da borda.
        bucket.width = 64;
        bucket.height = 64;

        //aqui é criada a matriz que irá gerar os pingos de chuva 
        raindrops = new Array<Rectangle>();
        spawnRaindrop();

    }

    private void spawnRaindrop() {
        Rectangle raindrop = new Rectangle();
        raindrop.x = MathUtils.random(0, 800 - 64);
        raindrop.y = 480;
        raindrop.width = 64;
        raindrop.height = 64;
        raindrops.add(raindrop);
        lastDropTime = TimeUtils.nanoTime();
    }

    @Override
    public void render(float delta) {
        //Limpa a tela com um azul escuro.
        // Os argumentos para glClearColor sâo vermelho , verde
        // azul e o componente alpha na posição [0,1]
        // da cor a ser usada para limpar a tela.
        Gdx.gl.glClearColor(0, 0, 0.2f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // aqui o programa diz a camera para atualizar suas
        // matrizes.
        camera.update();

        //aqui o spritebatch recebe ordens para renderizar no 
        // sistema nas coordenadas definidas pela camera.
        game.batch.setProjectionMatrix(camera.combined);

        //aqui o balde e as gotas são desenhados novamente
        game.batch.begin();
        game.font.draw(game.batch, "Drops Collected: " + dropsGathered, 0, 480);
        game.batch.draw(bucketImage, bucket.x, bucket.y, bucket.width, bucket.height);
        for (Rectangle raindrop : raindrops) {
            game.batch.draw(dropImage, raindrop.x, raindrop.y);
        }
        game.batch.end();

        //processo de entrada por parte do usuário através
        // do mouse ou teclado(setas).
        if (Gdx.input.isTouched()) {
            Vector3 touchPos = new Vector3();
            touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
            camera.unproject(touchPos);
            bucket.x = touchPos.x - 64 / 2;
        }
        if (Gdx.input.isKeyPressed(Keys.LEFT))
            bucket.x -= 200 * Gdx.graphics.getDeltaTime();
        if (Gdx.input.isKeyPressed(Keys.RIGHT))
            bucket.x += 200 * Gdx.graphics.getDeltaTime();

        //aqui o programa se certifica de que o balde está 
        // dentro dos limites da tela.
        if (bucket.x < 0)
            bucket.x = 0;
        if (bucket.x > 800 - 64)
            bucket.x = 800 - 64;

        //aqui é verificado se é necessário criar novos pingos
        // de chuva.
        if (TimeUtils.nanoTime() - lastDropTime > 1000000000)
            spawnRaindrop();

        //aqui são movidas as gotas de chuva, removendo as que estão abaixo
        // da borda inferior da tela ou as que atingiram o balde, na qual 
        // será executado um efeito sonoro caso atinja o balde.
        Iterator<Rectangle> iter = raindrops.iterator();
        while (iter.hasNext()) {
            Rectangle raindrop = iter.next();
            raindrop.y -= 200 * Gdx.graphics.getDeltaTime();
            if (raindrop.y + 64 < 0)
                iter.remove();
            if (raindrop.overlaps(bucket)) {
                dropsGathered++;
                dropSound.play();
                iter.remove();
            }
        }
    }

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

    @Override
    public void show() {
        //iniciar a reprodução da música de 
        //fundo assim que a tela é mostrada
        rainMusic.play();
    }

    @Override
    public void hide() {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
        dropImage.dispose();
        bucketImage.dispose();
        dropSound.dispose();
        rainMusic.dispose();
    }// aqui todos os recursos usados serão descartados após 
     // seu uso.

}

O código acima é quase idêntico ao original, exceto pelo fato de que agora usamos um construtor em vez do método create() do ApplicationListener, e transformamos Drop em um 
objeto, como feito na MainMenuScreenNós também começamos a tocar a música assim que a tela é definida para GameScreen, além de colocar uma string para contar a quantidade de gotas coletadas, localizada no canto superior esquerdo da tela.
Após a conclusão, seu jogo deve ficar mais ou menos assim:






É isso, agora você tem o jogo completo terminado, e aqui acaba o tutorial .

Bom trabalho!



REFERÊNCIAS:
  • GITHUB: Extending the simple game. Extending the simple game. 2016. Disponível em: <https://github.com/libgdx/libgdx/wiki/Extending-the-simple-game>. Acesso em: 23 set. 2016.
  • GITHUB: A simple game. A simple game. 2016. Disponível em: <https://github.com/libgdx/libgdx/wiki/A-simple-game>. Acesso em: 23 set. 2016.
  • SANTOS, Bruno. Gpjecc: TUTORIAL MY SIMPLE GAME LIBGDX. 2016. Disponível em: <https://gpjecc.blogspot.com/b/post-preview?token=bRwgWlcBAAA.vOB-Xwz8MROwQNIgXAAmTwbhc0rti45PqyWik83FR-pjmdRW_6mH5D9-DtDwCfGzfp2FnEczOFRr8bdqoOmsXw.fdQx1bxA2q0vG1gUwM7IuA&postId=8945204288171025357&type=POST>. Acesso em: 23 set. 2016.
  • STACK Overflow: the import com.badlogic.gdx.graphics.gl10 cannot be resolved. the import com.badlogic.gdx.graphics.gl10 cannot be resolved. 2016. Disponível em: <http://stackoverflow.com/questions/23691868/the-import-com-badlogic-gdx-graphics-gl10-cannot-be-resolved>. Acesso em: 28 set. 2016.

Postar um comentário

1 Comentários

  1. Galera, se vocês quiserem aprender a utilizar fontes com efeitos no LibGDX vocês podem seguir este tutorial https://www.programandojogosandroid.top/como-mostrar-texto-limpo-sem-borroes-com-efeito-stroke-libgdx

    ResponderExcluir
Emoji
(y)
:)
:(
hihi
:-)
:D
=D
:-d
;(
;-(
@-)
:P
:o
:>)
(o)
:p
(p)
:-s
(m)
8-)
:-t
:-b
b-(
:-#
=p~
x-)
(k)