Skip to content
/ microgamr Public template

Um objeto de aprendizagem sobre desenvolvimento de jogos, base para um jogo de sequências de microgames

Notifications You must be signed in to change notification settings

fegemo/microgamr

Repository files navigation

Microgamr

Um jogo simples, descomprometido e maroto com vários microgames.

Instruções para Começar

O projeto deve ser entregue como um Pull Request (veja [1] e [2]) neste repositório. Ou seja, você deve fazer um fork e, no branch master, você deve criar os dois microjogos.

Siga os passos:

  1. (Um (01) integrante da dupla/grupo) faça um fork deste repositório pela interface do Github.com.
  2. Dê permissão de alteração no fork para o(s) colega(s).
  3. Clonem o (seu) repositório forked para seu computador.
  4. Criem um branch cujo nome é o primeiro nome do(s) integrante(s) do grupo, sem letras maiúsculas e com hífen separando o(s) nome(s).
    • Por exemplo, git branch -b sandy-junior.
  5. Trabalhem fazendo commits nesse branch.
  6. Quando estiver pronto, faça um Pull Request do seu branch (e.g., leandro-leonardo) para o branch master do professor.

Descrição da Implementação

Veja alguns detalhes sobre a implementação do jogo a seguir.

Telas

O jogo possui algumas telas, como de splash (inicial), menu principal e "de jogo", e o código referente a cada uma reside em uma classe que herda de BaseScreen.

Pacote "screens" com as classes referentes às telas do jogo

Pacotes

As classes do projeto estão modularizadas nos seguintes pacotes:

Todos os pacotes do projeto

  1. br.microgamr: classes de inicialização e configuração geral do jogo.
  2. br.microgamr.graphics: classes com utilitários gráficos.
  3. br.microgamr.logic: classes de utilidade para a lógica de jogo.
  4. br.microgamr.minigames: classes referentes aos microgames.
  5. br.microgamr.minigames.factories: classes referentes às fábricas abstratas que são responsáveis por instanciar os microgames.
  6. br.microgamr.minigames.util: classes utilitárias aos microgames.
  7. br.microgamr.screens: classes referentes às telas do jogo.

Assets

Os assets (recursos gráficos e de áudio) do jogo ficam na pasta core/assets:

Pasta assets dentro da pasta core

Os assets de cada microgame devem estar dentro de uma pasta cujo nome é o nome dele, sem maiúsculas e acentuação, com hífen separando as palavras, caso haja mais de uma (e.g., assets/shoot-the-monsters).

Para os microgames, estamos usando um gerenciador de assets para pré-carregá-los de forma que, quando da execução da sequência de microgames, o jogo não pára para carregar os recursos e isso proporciona uma experiência de jogo melhor.

Para usar o gerenciador, supondo que você está criando um SuperMicroJogo, cada microgame deve ser implementado em 2 passos:

  1. Declarar de quais assets ele precisa, na classe SuperMicroJogoFactory. Por exemplo:
    package br.microgamr.microgames.factories;
    
    public class SuperMicroJogoFactory implements MicroGameFactory {
        // ...
    
        @Override
        public Map<String, Class> getAssetsToPreload() {
            return new HashMap<String, Class>() {
                {
                    // texturas
                    put("super-micro-jogo/personagem.png", Texture.class);
                    // efeitos sonoros
                    put("super-micro-jogo/tiro.wav", Sound.class);
                    // música de fundo
                    put("super-micro-jogo/musica.mp3", Music.class);
                }
            };
        }
    }  
  2. Solicitar os assets já carregados ao gerenciador, na classe do microgame propriamente dito. Por exemplo:
    public class SuperMicroJogo extends MicroGame {
        private Texture texturaPersonagem;
        private Sound somTiro;
        private Music musicaFundo;
    
        public SuperMicroJogo(BaseScreen screen,
              GameStateObserver observer, float difficulty) {
            super(
                    screen,        // tela que está executando este microgame.
                    observer,      // alguém interessado no estado (eg, HUD).
                    difficulty,    // dificuldade [0,1] que este jogo deve ter.
                    10,            // duração em segundos deste microgame.
                    TimeoutBehavior.FAILS_WHEN_MINIGAME_ENDS   // o que acontece
                                                               // qdo o tempo
                                                               // acaba.
            );
        }
    
        @Override
        protected void onStart() {
            this.texturaPersonagem = assets.get(
                   "super-micro-jogo/personagem.png", Texture.class);
            this.somTiro = assets.get(
                   "super-micro-jogo/tiro.wav", Sound.class);
            this.musicaFundo = assets.get(
                   "super-micro-jogo/musica.mp3", Music.class);
            // ...
        }
        // ...
    }

Após criar classes que herdam de MicroGame e MicroGameFactory, você deve ir até MenuScreen e incluir a fábrica do seu microgame na lista de microgames disponíveis e passar para o construtor de GameSequencer:

/**
 * Navega para a tela de jogo.
 */
private void navigateToMicroGameScreen() {
    final float difficultyOfFirstMicrogame = 0;
    final float difficultyOfLastMicrogame = 1;
    final int numberOfGamesInSequence = 5;
    // cria um sequenciador com um número de jogos em sequência e a lista
    // de microgames disponíveis para serem sorteados, além de definir a
    // dificuldade do microgame inicial e a do final
    GameSequencer sequencer = new GameSequencer(numberOfGamesInSequence,
        new HashSet<MicroGameFactory>(
            Arrays.asList(
                    // microgames iniciais, de exemplo
                    // (*não devem ser removidos* ao commitar)
                    new ShootTheMonstersFactory(),
                    new ExpelTheMonstersFactory()
                    // microgames do grupo 1:

                    // microgames do grupo 2:

                    // microgames do grupo 3:
                    // ...
            )
        ),
        difficultyOfFirstMicrogame,
        difficultyOfLastMicrogame);
    game.setScreen(new GameScreen(game, this, sequencer));
}

Nota: para ver como o pré-carregamento está sendo feito, procure na classe GameSequencer.

Sistema de Coordenadas

Como muito bem lembramos da queridíssima aula de Computação Gráfica, uma aplicação em OpenGL possui pelo menos 2 sistemas de coordenadas extremamente importantes:

  • O sistema de coordenadas do mundo (arbitrário, definido por nós)
  • O sistema de coordenadas da janela (definido em pixels)

Em jogos digitais, qual deve ser o comportamento quando um usuário redimensiona a janela? Há pelo menos 3 possibilidades:

  1. A imagem que estamos renderizando fica espichada ou achatada (não queremos isso)
  2. Mantemos a razão de aspecto (a imagem não distorce) e fazemos com que toda a imagem renderizada caiba dentro do espaço disponível
    • Isso faz com que surjam barras laterais ou superioes-inferiores "em branco" quando a nova dimensão da janela tem uma razão de aspecto diferente daquela para a qual o jogo foi programado (veja a imagem a seguir)
  3. Mantemos a razão de aspecto e aumentamos o espaço do mundo que é visível ao jogador

É possível e bem simples fazer qualquer uma dessas formas na LibGDX. Optamos pela forma (2) porque ela permite que usemos valores virtuais para largura e altura da tela... como assim?

Podemos ver 3 constantes importantes em Config.java:

public class Config {

    /**
     * A largura do mundo de jogo.
     *
     * Todos os objetos (sprites, etc.) devem estar contidos em coordenadas x
     * que vão de 0 a WORLD_WIDTH para que apareçam na tela.
     */
    public static final int WORLD_WIDTH = 1280;

    /**
     * A altura do mundo de jogo.
     *
     * Todos os objetos (sprites, etc.) devem estar contidos em coordenadas y
     * que vão de 0 a WORLD_HEIGHT para que apareçam na tela.
     */
    public static final int WORLD_HEIGHT = 720;

    public static final float DESIRED_ASPECT_RATIO
            = (float) WORLD_WIDTH / (float) WORLD_HEIGHT;

    // ...
}

Repare na figura a seguir. Podendo considerar que o sistema de coordenadas do mundo é sempre x E [0,1280] e y E [0,720], fica fácil posicionar os elementos de forma que eles estarão aonde queremos independente da resolução atual da janela do jogo.

FAQ

  1. Pergunta: Por que o código está em inglês?
    • Resposta: as linguagens de programação e seus compiladores costumam ter problemas para identificar caracteres com acentuação nos códigos-fonte. Poderíamos escrever em Português sem usar a acentuação, porém se escrevermos em inglês, além de descartar essa possibilidade de problemas, tornamos o código-fonte acessível a leitores estrangeiros que saibam ler em Inglês.
  2. Pergunta: Fiz meu fork, mas o professor foi lá e fez mais commits... agora meu fork está desatualizado. Como faço para ressincronizá-lo do o do professor?

About

Um objeto de aprendizagem sobre desenvolvimento de jogos, base para um jogo de sequências de microgames

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages