Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
c:jogo_grafico [2023/08/01 19:14] – criada maziero | c:jogo_grafico [2023/08/01 19:21] (atual) – edição externa 127.0.0.1 | ||
---|---|---|---|
Linha 1: | Linha 1: | ||
+ | ====== Jogo gráfico ====== | ||
+ | |||
+ | {{ pong.gif|Pong}} | ||
+ | |||
+ | O objetivo deste projeto é construir um jogo monousuário com interface gráfica 2D. O aluno deve escolher um destes jogos ((Diversos outros jogos foram desconsiderados porque existem muitas implementações prontas usando C e Allegro.)): | ||
+ | |||
+ | Clássicos: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[http:// | ||
+ | * [[https:// | ||
+ | |||
+ | Recentes: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | |||
+ | Você pode propor outros jogos ao professor para análise. | ||
+ | |||
+ | /* | ||
+ | Muito batidos ou muito fáceis: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | */ | ||
+ | |||
+ | ===== Requisitos ===== | ||
+ | |||
+ | Requisitos do jogo: | ||
+ | |||
+ | * Executar no Linux, em uma janela gráfica | ||
+ | * Interagir com o usuário através do teclado e/ou mouse | ||
+ | * Usar imagens coloridas (// | ||
+ | * Tocar sons nos principais eventos (pode usar sons prontos da Internet) | ||
+ | * Suportar ao menos **três níveis** com mapas, ações e/ou objetos diferentes | ||
+ | * Calcular a pontuação do jogador e manter um //score// persistente (salvo em disco) das melhores pontuações obtidas, apresentado ao usuário ao finalizar o jogo | ||
+ | * As teclas '' | ||
+ | * Ter um // | ||
+ | * Executar a 60 FPS (//frames per second//) | ||
+ | |||
+ | /* | ||
+ | :NEW: Requisitos solicitados pelo prof. Menotti (2021/2): | ||
+ | |||
+ | * Suportar ao menos 10 níveis com mapas, ações e/ou objetos diferentes | ||
+ | * Permitir que o usuário avance entre todos os mapas/ | ||
+ | * //Easter egg// - um arquivo '' | ||
+ | */ | ||
+ | Requisitos do código: | ||
+ | |||
+ | * Ser desenvolvido em C padrão C99 ('' | ||
+ | * Usar a biblioteca gráfica **Allegro 5** ((Não é a mais poderosa, mas tem um bom compromisso entre funcionalidades e facilidade de uso.)) | ||
+ | * Separar o código em vários arquivos '' | ||
+ | * Usar [[alocação de memória]] dinâmica | ||
+ | * Usar [[estruturas]] | ||
+ | * Compilar com o flag '' | ||
+ | * Usar [[o sistema Make]] para compilação, | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * Todos os arquivos que não forem código-fonte (imagens, sons, fontes, mapas, ...) devem ser colocados em um subdiretório '' | ||
+ | |||
+ | Critérios de avaliação | ||
+ | |||
+ | * cumprimento dos requisitos acima | ||
+ | * fidelidade ao jogo original | ||
+ | * qualidade do código (estrutura, clareza, comentários, | ||
+ | |||
+ | ===== A biblioteca Allegro ===== | ||
+ | |||
+ | A biblioteca gráfica [[http:// | ||
+ | |||
+ | Algumas de suas características: | ||
+ | |||
+ | * multiplataforma: | ||
+ | * pode ser usada em C e outras linguagens | ||
+ | * usa aceleração gráfica (através de OpenGL ou DirectX) | ||
+ | * manipulação de áudio e vídeo | ||
+ | * leitura de mouse, teclado e joystick | ||
+ | |||
+ | Instalação da biblioteca Allegro 5 em Linux (Ubuntu, Mint, Debian): | ||
+ | |||
+ | < | ||
+ | sudo apt-get install liballegro5-dev | ||
+ | </ | ||
+ | |||
+ | Uso: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | |||
+ | Bibliotecas gráficas como a Allegro e SDL operam usando um esquema interno de **buffer duplo**, ou seja, dois //buffers// gráficos distintos que são usados em conjunto: | ||
+ | |||
+ | * buffer< | ||
+ | * buffer< | ||
+ | |||
+ | Esses //buffers// devem ser periodicamente alternados pelo programador (pseudocódigo): | ||
+ | |||
+ | < | ||
+ | fill_color (black) ; // operações feitas no buffer 1, não são visíveis | ||
+ | draw (...) ; // na tela neste momento. | ||
+ | draw (...) ; | ||
+ | ... | ||
+ | flip_buffers () ; // troca buffer 1 com 2, mostrando o novo conteúdo | ||
+ | </ | ||
+ | |||
+ | As técnicas des [[https:// | ||
+ | |||
+ | ===== Estrutura básica de um jogo ===== | ||
+ | |||
+ | A maioria dos jogos segue uma estrutura de código similar. O funcionamento do jogo segue uma " | ||
+ | |||
+ | ==== Estado das entidades ==== | ||
+ | |||
+ | Cada entidade do jogo (jogador, bola, etc) tem um conjunto de atributos que a representam, | ||
+ | |||
+ | <code c> | ||
+ | // estrutura de uma bola | ||
+ | typedef struct | ||
+ | { | ||
+ | short x, y ; // posição atual | ||
+ | short sx, sy ; // velocidade atual | ||
+ | short w, h ; // dimensões | ||
+ | color_t color ; // cor atual | ||
+ | } | ||
+ | ball_t ; | ||
+ | |||
+ | // cria uma bola | ||
+ | ball_t ball ; | ||
+ | </ | ||
+ | |||
+ | Estruturas como essa devem ser construídas para cada entidade ativa do jogo. | ||
+ | |||
+ | ==== Máquina de estados ==== | ||
+ | |||
+ | O funcionamento do jogo é gerenciado através de uma //máquina de estados//. Cada estado do jogo define o que deve ser feito naquele momento, as transições possíveis entre estados e os eventos que levam de um estado a outro. Por exemplo, a máquina de estados do jogo [[https:// | ||
+ | |||
+ | * **inicio**: desenha a tela inicial do jogo e aguarda 5 segundos. | ||
+ | * **servindo**: | ||
+ | * **jogando**: | ||
+ | * **fim partida**: um dos jogadores atingiu a pontuação máxima. | ||
+ | * **fim jogo**: o jogo encerra. | ||
+ | |||
+ | O relacionamento entre esses estados pode ser representado graficamente: | ||
+ | |||
+ | {{ game-state-machine.png |}} | ||
+ | |||
+ | Essa máquina de estados pode ser facilmente implementada em C: | ||
+ | |||
+ | <code c> | ||
+ | // estados possíveis do jogo Pong | ||
+ | enum {INICIO, SERVINDO, JOGANDO, FIMPART, FIMJOGO} state ; | ||
+ | |||
+ | // programa principal do jogo | ||
+ | int main () | ||
+ | { | ||
+ | state = INICIO ; | ||
+ | for (;;) | ||
+ | switch (state) | ||
+ | { | ||
+ | case INICIO | ||
+ | case SERVINDO: state_serve () ; break ; | ||
+ | case JOGANDO : state_play () ; break ; | ||
+ | case FIMPART : state_over () ; break ; | ||
+ | case FIMJOGO : state_close () ; break ; | ||
+ | default: break ; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Dessa forma, as funções '' | ||
+ | |||
+ | ==== O laço principal ==== | ||
+ | |||
+ | Durante o jogo propriamente dito, o programa deve continuamente ler as entradas de dados (teclado, mouse, ...), atualizar o estado dos jogadores e demais entidades do jogo de acordo com essas entradas e desenhar a tela. Esse comportamento é chamado o **laço principal** do jogo. | ||
+ | |||
+ | O pseudocódigo a seguir dá um exemplo do laço principal do jogo Pong (simplificado): | ||
+ | |||
+ | < | ||
+ | // define estado inicial das entidades | ||
+ | inicia_jogadores () | ||
+ | inicia_bola () | ||
+ | |||
+ | // laço principal | ||
+ | faça | ||
+ | ler_entrada (teclado, mouse, ...) | ||
+ | atualiza_estado_jogadores () | ||
+ | atualiza_estado_bola () | ||
+ | desenha_tela () | ||
+ | até fim da partida | ||
+ | </ | ||
+ | |||
+ | Esse ciclo deve ser repetido rapidamente (dezenas de vezes por segundo) para dar a impressão de fluidez do jogo. | ||
+ | |||
+ | O [[https:// | ||
+ | |||
+ | ==== Controle da taxa de quadros ==== | ||
+ | |||
+ | A tela do jogo deve ser atualizada com velocidade suficiente para dar fluidez ao jogo. De preferência, | ||
+ | |||
+ | Em um jogo simples, a quantidade de cálculo a efetuar antes de cada atualização de estado e de tela é geralmente pequena, se comparada à capacidade de processamento do computador. Por isso, é interessante **pausar a execução** por alguns milissegundos a cada ciclo, para garantir uma taxa de quadros constante (e também diminuir o consumo de CPU). | ||
+ | |||
+ | Uma forma de controlar a taxa de quadros é através de pausas (pseudocódigo): | ||
+ | |||
+ | < | ||
+ | // taxa de quadros por segundo | ||
+ | frame_rate = 60 | ||
+ | |||
+ | // duração de cada quadro, em ms | ||
+ | t_quadro = 1000 / frame_rate | ||
+ | |||
+ | // laço principal do jogo | ||
+ | repita | ||
+ | |||
+ | | ||
+ | |||
+ | // processamento do jogo | ||
+ | ... | ||
+ | |||
+ | // espera um tempo para completar o quadro | ||
+ | t_final = relogio_ms () | ||
+ | t_pausa = t_quadro - (t_final - t_inicio) | ||
+ | pausa_ms (t_pausa) | ||
+ | |||
+ | até o fim da partida | ||
+ | </ | ||
+ | |||
+ | Outra forma, que é usada frequentemente na Allegro 5, é a **programação por eventos**. Neste caso específico, | ||
+ | |||
+ | < | ||
+ | // taxa de quadros por segundo | ||
+ | frame_rate = 60 | ||
+ | |||
+ | // duração de cada quadro, em ms | ||
+ | t_quadro = 1000 / frame_rate | ||
+ | |||
+ | // define timer (um evento a cada X ms) | ||
+ | define_timer (t_quadro) | ||
+ | |||
+ | // laço principal do jogo | ||
+ | repita | ||
+ | |||
+ | // espera o próximo evento do timer | ||
+ | | ||
+ | |||
+ | // processamento do jogo | ||
+ | ... | ||
+ | |||
+ | até o fim da partida | ||
+ | </ | ||
+ | |||
+ | ==== Links ==== | ||
+ | |||
+ | Desenvolvimento de jogos: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * Canal [[https:// | ||
+ | |||
+ | Sprites e sons: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[http:// | ||