O Jogo do Ano é: Ben 10 Battle Ready.




um original do bob esponja: Jellyfish shuffleboard.


Ping-Pong 3D


um clássico: o joguinho de uma fase só



um clássico original: pac-man



um jogo viciante: Splitter 2

(Clique na foto para jogar!)

splitter2

quarta-feira, 2 de dezembro de 2009

Como fazer um jogo com Html.

1. Visão Geral do Jogo

O objetivo do jogo que iremos montar é fazer desaparecer todos os monstros que andam pela tela; para isso, basta clicá-los com o ponteiro do mouse.

Como os monstros têm velocidades diferentes, a pontuação deve variar de acordo com a velocidade (quanto maior, mais pontos). Ao errar o clique (não clicar em nenhum monstro), o jogador perde pontos. Ao final da partida, depois que todos os monstros desaparecerem, é descontado do total de pontos um valor proporcional ao tempo transcorrido desde o início da partida.

barra horizontal azul

2. Definições e Outras Funções

O cenário do jogo consistirá de duas partes: a parte esquerda da tela é onde os monstros se movimentam, e a parte direita é onde está o placar, o contador de monstros e o tempo transcorrido. Definiremos que, do total de 800x600 da tela, 600x600 sejam da parte esquerda, e o resto, naturalmente, da direita. Para isso, escrevemos

    #define ESP_PONTOS 200
    #define ARENA_X (MAX_X) - (ESP_PONTOS)
    #define ARENA_Y (MAX_Y)

Devemos definir, também, o número de monstros que aparecerão inicialmente, bem como os tamanhos horizontal e vertical de seu bitmap e os máximos deslocamentos horizontal e veritcal possíveis. Para tanto, fazemos

    #define MAX_MONSTRO 30
    #define MONSTRO_X 32
    #define MONSTRO_Y 32
    #define MAX_DX 5
    #define MAX_DY 5

Utilizaremos um sprite denominado MONSTRO, definido da seguinte maneira:

    typedef struct _MONSTRO
    {
      int x, y;
      int dx, dy;
      int show;
    } MONSTRO;

Além dos #define's, precisamos escrever a função que será chamada pelo temporizador para incrementar o tempo. Note que, devido ao uso que se faz desta função (temporizador), é necessário o uso da macro que se encontra no final daquela.

    void aumenta_tempo (void)
    {
      tempo++;
    }
    END_OF_FUNCTION(aumenta_tempo);

Precisamos, ainda, incluir algum código na função inicia do esqueleto do programa, para que seja inicializado o arquivo de recordes

    set_config_file("jogo.rec");
e as macros do temporizador
    LOCK_VARIABLE(tempo);
    LOCK_FUNCTION(aumenta_tempo);

barra horizontal azul

3. As Inicializações

Devemos, primeiramente, declarar as variáveis que vamos utilizar no jogo. Para tal, dentro da função principal, escrevemos

    MONSTRO monstro[MAX_MONSTRO];
    BITMAP *bmp_monstro;
    BITMAP *tela;
    PALETTE pal;
    SAMPLE *certo, *errado;
    MIDI *musica;
    int mx, my;
    int num_monstros;
    int pontos, maior;
    int acertou;
    int i;
Há, ainda, uma variável a ser declarada como global
    volatile int tempo;
e que será utilizada no contador de tempo.

Podemos, então, fazer as inicializações necessárias. Primeiro, criamos o bitmap de double buffering, declarado como a variável tela,

    tela = create_bitmap(MAX_X, MAX_Y);
Depois, carregamos o bitmap monstro.bmp na memória
    bmp_monstro = load_bitmap("monstro.bmp", pal);
e os waves (certo.wav e errado.wav) e midi (caverns.mid) que serão utilizados
    certo = load_sample("certo.wav");
    errado = load_sample("errado.wav");
    musica = load_midi("caverns.mid");

Após isso, inicializamos com valores aleatórios o vetor de elementos do tipo MONSTRO, da seguinte forma:

    srand(time(0));
    for (i = 0; i < MAX_MONSTRO; i++)
    {
      monstro[i].x = rand() % (ARENA_X - MONSTRO_X);
      monstro[i].y = rand() % (ARENA_Y - MONSTRO_Y);
      do
      {
        monstro[i].dx = (rand() % (MAX_DX * 2)) - MAX_DX;
      } while (monstro[i].dx == 0);
      do
      {
        monstro[i].dy = (rand() % (MAX_DY * 2)) - MAX_DY;
      } while (monstro[i].dy == 0);
      monstro[i].show = TRUE;
    }
e inicializamos o número de monstros
    num_monstros = MAX_MONSTRO;

Para terminar, inicializamos as variáveis mx e my, que guardarão os valores da última posição do mouse

    mx = my = -1;
e inicializamos, também, as variáveis pontos e maior
    pontos = 0;
    maior = get_config_int(NULL, "HighScore", 0);

Devemos, também, adicionar algumas linhas ao final da função inicia (antes do último return) para que possamos utilizar algumas outras funções.

    set_config_file("jogo.rec");

    LOCK_VARIABLE(tempo);
    LOCK_FUNCTION(aumenta_tempo);
barra horizontal azul

4. O Loop Principal

Antes de iniciarmos o loop principal do jogo, fazemos algumas chamadas de inicialização que, por certos motivos, foram preferencialmente deixadas para esta parte. Assim, podemos chamar uma função de fade

    fade_in(pal, 4);
a função para iniciar a música
    play_midi(musica, TRUE);
zerar o tempo e iniciar o temporizador da função aumenta_tempo
    tempo = 0;
    install_int(aumenta_tempo, 1000);

Após isso, vamos, finalmente, ao loop principal. A parte do-while consiste de

    clear_keybuf();
    do
    {

      /* Loop Principal */

    } while ((!key[KEY_ESC]) && (num_monstros > 0));

Então, dentro do loop principal, inserimos o restante do código. Primeiro, as rotinas que irão gerenciar o clique com o botão do mouse

    if ((mouse_b & 1) && ((mouse_x != mx) || (mouse_y != my)))
    {
      mx = mouse_x;
      my = mouse_y;
      for (i = 0, acertou = FALSE; i < MAX_MONSTRO; i++)
      {
        if ((mouse_x >= monstro[i].x) && (mouse_x <= (monstro[i].x + MONSTRO_X)) &&
        (mouse_y >= monstro[i].y) && (mouse_y <= (monstro[i].y + MONSTRO_Y)) &&
        (monstro[i].show))
        {
          monstro[i].show = FALSE;
          acertou = TRUE;
          pontos += (abs(monstro[i].dx) + abs(monstro[i].dy)) * 50;
          num_monstros--;
        }
      }
      if (acertou)
      {
        play_sample(certo, 255, 128, 1000, FALSE);
      }
      else
      {
        play_sample(errado, 255, 128, 1000, FALSE);
        pontos -= 100;
      }
    }
e, depois, as rotinas de double buffering
    show_mouse(NULL);
    clear(tela);
    for (i = 0; i < MAX_MONSTRO; i++)
    {
      if (monstro[i].show)
      {
        monstro[i].x += monstro[i].dx;
        monstro[i].y += monstro[i].dy;
        if ((monstro[i].x <> (ARENA_X - MONSTRO_X)))
        {
          monstro[i].dx = -monstro[i].dx;
        }
        if ((monstro[i].y <> (ARENA_Y - MONSTRO_Y)))
        {
          monstro[i].dy = -monstro[i].dy;
        }
        draw_sprite(tela, bmp_monstro, monstro[i].x, monstro[i].y);
      }
    }
    imprime_placar(tela, pontos, maior, num_monstros);
    show_mouse(tela);
    blit(tela, screen, 0, 0, 0, 0, MAX_X, MAX_Y);

Com isso, terminamos o loop principal do jogo.

barra horizontal azul

5. As Finalizações

Quando saímos do loop principal, não podemos apenas terminar o programa. É necessário fazer uma série de chamadas, tais como a de parar a música

    stop_midi();
e a de remover o temporizador
    remove_int(aumenta_tempo);

Além disso, precisamos calcular os pontos do jogador e, se for o caso, armazenar essa pontuação como a maior até o momento. Qualquer que seja a situação, devemos, também, imprimir esta pontuação final obtida. Para isso,

    pontos -= num_monstros * 50;
    pontos -= (tempo - 30) * 5 / 3;
    if (pontos > maior)
    {
      maior = pontos;
      set_config_int(NULL, "HighScore", pontos);
    }
    clear(tela);
    imprime_placar(tela, pontos, maior, num_monstros);
    blit(tela, screen, 0, 0, 0, 0, MAX_X, MAX_Y);
Para que o jogador possa ver o seu placar, devemos, ainda, fazer um loop de espera por uma tecla. Assim,
    while (key[KEY_ESC]);
    clear_keybuf();
    textout_centre(screen, font, "Pressione qualquer tecla para continuar", (ARENA_X) / 2,
    (ARENA_Y) / 2 - 8, 8);
    while (!keypressed());

Apenas para finalizar de uma boa forma, utilizamos uma função de fade

    fade_out(4);

barra horizontal azul

Nenhum comentário:

Postar um comentário