Pré-requisitos:
- Assistir o vídeo promocional do framework de jogos LibGDX
- Conhecimento de Java
- Um ambiente de desenvolvimento:
- NetBeans com plugin Gradle Support
Objetivos:
- Familiarizar-se com o funcionamento da LibGDX
- Conhecer técnicas comuns de renderização em 2D - Sprites, Animações etc.
- Praticar conceitos de renderização em 2D na LibGDX
- Uso de texturas
- Sprites
- Animações
- Entender a importância de se reduzir o número de "chamadas de desenho" (draw calls)
Você deve começar usando o código do professor como ponto de partida para a atividade. Você deve fazer 3 exercícios:
Desenhar o cenário como duas texturas (Texture), uma em cima da outra,
carregando map-level-1.png e map-level-2.png (dentro do método
void create()) e mandando desenhar (dentro do render()) na posição (0, 0) -
canto inferior esquerdo.
-
map-level-1.png(nível 1: o chão - já está lá) -
map-level-2.png: (nível 2: as cerquinhas) -
Nota: tipicamente, um cenário em um jogo bidimensional é formado por um grid de tiles, como no RPG Maker/Boss. Contudo, neste exercício, vamos simplesmente desenhar uma imagem "inteira" em cima da outra.
Criar uma Sprite para o Goomba usando goomba.png (sem animação ainda) que
pode ser controlada pelo teclado (via setinhas):
- Defina membros na classe
Gamepara aSpritee para aTexturee as instancie devidamente.- Assim que instanciar a sprite, defina sua posição para (30, 10).
- Desenhe a sprite entre os níveis 1 e 2 do cenário
Agora você deve possibilitar o jogador a controlar a posição do Goomba.
- Na função
update(), quando o jogador pressionar alguma das setas do teclado, altere a posição da sprite de acordo.- Como exemplo, veja como o pressionar da tecla Esc está encerrando o jogo
- Faça uma verificação da nova coordenada da sprite para que o
personagem não saia da tela
- Basta garantir que sua posição
xestá entre [0,LARGURA_DA_TELA - LARGURA_GOOMBA] e o análogo paray- Para pegar a largura e altura da janela podemos usar
Gdx.graphics.getWidth()eGdx.graphics.getHeight() - Esta não é uma solução boa (redimensione a janela e veja o que acontece), mas por ora está ok.
- Para pegar a largura e altura da janela podemos usar
- Basta garantir que sua posição
A esta altura, o código de Game está um pouco bagunçado e, então, você deve
organizá-lo. A ideia é criar uma classe Goomba que vai conter o código
relacionado ao personagem, e a Game vai conter uma instância dela e vai
passar a chamar seus métodos.
- Crie uma classe
Goomba, com um construtor que recebe apenas a textura do Goomba. - Crie métodos
update()erender(batch), com seus respectivos códigos. - Mova o código de
update()erender()relativo ao Goomba deGameparaGoombae, então, chame os métodos doGoombaemGame.
Nesta parte, você deve colocar uma animação de movimentação do Goomba. Na
LibGDX existe a classe Animation que representa "algo que vai trocando
ao longo do tempo" - é basicamente um array de quadros com um índice de
qual é o quadro corrente, que vai trocando ao longo do tempo.
Ao usar Animation, não será mais possível usar a Sprite, porque elas são
incompatíveis (na LibGDX - um erro de projeto do framework, na opinião
do professor). Portanto, vamos comentar o código da Sprite dentro de Goomba
e precisar gerenciar a posição do Goomba nós mesmos.
- Configuração da spritesheet:
- Largura do quadro:
21px - Altura do quadro:
24px
- Largura do quadro:
Sugestão de passos:
- Comente todo o código relativo à
SpriteemGoomba - Em
Gamecreate(), instancie a textura da spritesheet e passe-a para oGoombapelo construtor - Nele, divida a textura em vários quadros usando
TextureRegion.split(textura, larguraDoQuadro, alturaDoQuadro)- Uma
TextureRegioné um pedaço retangular de uma textura, i.e., um quadro
- Uma
- Defina um membro do
Goombae instancie uma animação (no construtor) com os 5 quadros da primeira linha da spritesheet, com um intervalo de tempo de 0.1f segundo- Configure a animação para ficar em loop e em modo de ping-pong (vai da
esquerda para a direita, depois volta para a esquerda):
andarParaFrente.setPlayMode(PlayMode....);
- Configure a animação para ficar em loop e em modo de ping-pong (vai da
esquerda para a direita, depois volta para a esquerda):
- Crie um membro em
Goombaque receberá o tempo que o Goomba está em animação (i.e.,private float tempoDaAnimacao;).- Em
update(delta), some nela o tempo passado desde o último quadro. - Durante o
render(), em vez de desenhar aSprite(que agora está comentada), desenhe o quadro corrente da animação- Repare que não sabemos mais qual é a posição (x,y) do Goomba, visto que
não podemos usar a
Spritejunto com animações. - Sendo assim, você deve criar um membro
private Vector2 positione "gerenciar" a posição do Goomba você mesmo.
- Repare que não sabemos mais qual é a posição (x,y) do Goomba, visto que
não podemos usar a
- Em
Em vez de ter apenas uma animação, faça com que o Goomba tenha a animação relativa à direção para onde ele está andando. Além disso, faça ele parar a animação quando estiver parado.
Dica: será necessário ter 4 Animations diferentes, uma para cada
direção. Além disso, você pode ter mais uma Animation que é um ponteiro
para qual das 4 é a animação corrente.
Este trabalho deve ser entregue via Moodle. Mas caso o Moodle ainda
não esteja funcionando de vento em polpa, considere o parágrafo a seguir.
Os exercícios desta aula prática serão corrigidos ao final do nosso horário. Assim que estiver pronto, chame o professor para que possa ver seu trabalho.
- Como desenho uma textura na LibGDX?
- É necessário (1) carregar a textura para depois (2) desenhá-la:
- Carregando a textura dentro do
create():@Override public void create() { batch = new SpriteBatch(); algumaTextura = new Texture("nome-do-arquivo"); }
- Desenhando no
render(), em alguma posição:@Override public void render() { // ... batch.begin(); batch.draw(algumaTextura, x, y); batch.end(); }
- Carregando a textura dentro do
- É necessário (1) carregar a textura para depois (2) desenhá-la:
- Qual a diferença entre uma
Texturee umaSpritena LibGDX?- Uma
Textureé apenas uma imagem que foi carregada pela placa de vídeo. É possível desenhar uma textura, em determinada posição, usando um SpriteBatch, e.g.:batch.begin(); batch.draw(algumaTextura, 25, 0); batch.end();
- Uma
Spriteé um objeto que possui uma textura e uma posição no mundo. Diferentemente da textura, a sprite "sabe se desenhar" porque ela sabe onde está posicionada:// dentro de update() algumaSprite.setPosition(100, 25); // ... // ... // dentro de render() batch.begin(); algumaSprite.draw(batch); batch.end();
- Uma
- Como funciona essa
Animationmesmo?- Veja os slides da aula, ou então este breve tutorial sobre animação na LibGDX.
- Não existe uma classe
AnimatedSpritena LibGDX?- Na LibGDX não, mas você pode criar a sua, que herde da
Spriteda LibGDX. Na verdade, um membro da comunidade já fez isso e disponibilizou tal classe juntamente com outros utilitários do projetogdx-utils(veja como "instalar"). - A
AnimatedSpritedagdx-utils, no entanto, contém apenas 1 animação. Mas, no nosso caso, temos 4 animações. Para não precisar de criar 4xAnimatedSprite, você pode criar umaMultiAnimatedSprite, que herde deAnimatedSpritemas possa trabalhar com várias animações diferentes.- Na verdade, o professor já criou uma
classe
MultiAnimatedSprite, que você pode usar, se quiser.
- Na verdade, o professor já criou uma
classe
- Na LibGDX não, mas você pode criar a sua, que herde da



