Posts anteriores sobre esse assunto:
Salve pessoal!
E lá vamos nós, a todo vapor, para a quarta parte de nosso “mini-curso”. Nesse post vamos fazer um esboço do famoso jogo Pong! Dessa vez vou começar de forma diferente. Primeiro vou postar um vídeo do jogo rodando para em seguida explicar e analisar as linhas de código.
Agora que vocês já assistiram ao vídeo, vamos à algumas considerações:
O objetivo do post é demonstrar algumas técnicas e facilitar o aprendizado de quem está querendo se aventurar no AB. Não pretendo publicar o jogo completo. Seriam muitas linhas de código, tanto para eu programar, quanto para explicar, algo praticamente inviável. O importante é aprender o conceito, pegar as dicas e depois continuar com as próprias pernas, ou melhor, com as próprias mãos :-D.
Outro ponto que vale a pena mencionar é quanto a aparência dos exemplos que tenho postado. Mais uma vez não estou muito preocupado com isso. Repito, o importante é o conceito. E não pense que só dá pra fazer esses jogos com baixa resolução com o AB! É possível criar jogos em alta-resolução, AGA e até para placas RTG.
Sobre o jogo
O Pong dispensa apresentações. Nesse exemplo, algumas funcionalidades não estão implementadas, como a parte de pontuação, efeitos sonoros, níveis de dificuldade entre outros detalhes menores. Apenas a título de informação, para que fosse possível filmar com uma das mãos e mover os bastões com a outra, tive que diminuir a velocidade da bola, o que deixou o jogo consideravelmente menos divertido (mais do que já é) :-D.
Aprendendo a jogar, quer dizer, a programar…
Esse exemplo pode parecer simples, mas já inclui alguns conceitos interessantes, como o limite da área de jogo e um dos mais importantes: a colisão entre objetos! Colisões?! Sim! Toda vez que dois ou mais objetos da tela se sobrepõem ocorre uma colisão. No nosso exemplo, isso acontece principalmente quando a bola bate (colide) com os bastões. Veremos também como impedir que o bastão saia da tela e como fazer a bola rebater nas bordas superior e inferior da tela.
Vamos ao código!
Mesmo sem implementar o jogo por inteiro, já temos uma quantidade razoável de linhas e por esse motivo precisei dividir a imagem com as linhas de código em duas partes. As linhas que já estão com comentários no código ou com comandos que já vimos nos posts anteriores, eu não vou explicar, a menos que exista algo importante que mereça ser mencionado.
LoadPalette
Depois de criar os dois BitMaps, o próximo passo foi carregar as imagens que serão utilizadas no jogo, assim como o arquivo com as informações de cores, ou como são mais conhecidos: Palette. A maioria dos programas gráficos permite que você grave num arquivo as informações sobre as cores da imagem. E foi isso que eu fiz no PPaint depois de desenhar o “campo” de jogo do nosso Pong. Essa Palette (PongPalette.col) foi armazenada sob o índice 0 (zero).
Os arquivos de imagens utilizados no jogo
Usaremos dois arquivos com imagens no nosso jogo. O primeiro, Campo.IFF, é uma imagem de 320×240 para servir de background para o nosso jogo. O segundo arquivo, PongShapes.IFF, contém o desenho da bola e dos bastões. É desse aquivo que serão extraídos os Shapes que logo em seguida são convertidos em Sprites, tudo com uma Palette de apenas 4 cores.
Liberando memória
Depois de carregar as imagens e os Sprites, os arquivos “de origem” não tem mais utilidade. Então com o comando Free, retiramos esses objetos da memória. Em seguida, entramos no modo BLITZ, setamos o Slice e associamos a Palette 0 a ele com o comando Use. Dessa forma as cores, teoricamente (sim, existem ainda outros fatores que podem atrapalhar), serão exibidas corretamente durante a execução do programa.
A partir daí até o comando Show, não há qualquer novidade ou bicho de sete cabeças. Apenas atribuições com o devido comentário direto no código.
Laço principal
Na segunda parte do código ficaram as coisas mais interessantes. Pra começar, dentro do laço principal, são exibidos os três Sprites nas coordenadas setadas anteriormente. Na sequencia temos o tratamento de movimentação dos bastões. Eu mantive as teclas direcionais para movimentar ambos os bastões. Calma! Eu seu que você achou isso esquisito, mas foi uma forma que achei de conseguir movimentá-los com apenas uma das mãos e conseguir filmar ao mesmo tempo pra fazer o vídeo do início do post :-D. Numa versão “final”, as teclas de movimentação deveriam ser escolhidas com um pouquinho mais critério :-D, ou ainda, prever a utilização de joysticks. Um detalhe que eu esqueci de comentar no post passado, mas também ninguém reclamou ou questionou (será que alguém leu? :-() foi quanto as atribuições. Por exemplo: y1 -2. Esse tipo de comando equivale a: y1=y1-2. Só pra ficar registrado.
Mantendo os bastões dentro da tela
Os quatro IF´s que vêm a seguir, servem pra manter os bastões dentro da tela. Mas por quê y1 >= 210 e não y1 >= 240 (que é o limite da tela)? Se não informarmos nada diferente ao programa, o ponto de referência de um objeto é sempre o canto superior esquerdo do mesmo (existem formas de se alterar isso). No caso dos bastões, se olharmos a criação dos seus Shapes no início do código, eles tem 5 pixels de largura por 30 de altura. Então temos que levar essas medidas em conta sempre que formos comparar a colisão com o lado direito e a parte inferior dos objetos, somando a sua largura e altura respectivamente. Nesse caso especificamente, eu testei se y1 era maior ou igual a 210, que somados aos 30 pixels de altura do bastão, resultam nos 240 pixels da tela e faço o bastão parar de se mover. Já pra testar os limites na margem superior, eu não preciso somar nada, pois o ponto de referência já fica no ponto zero do objeto. O teste fica simples assim: y1 <=0. Por que <=0 e não =0? Por que se eu estiver usando um multiplicador pra mover o bastão mais rápido, pode acontecer dele passar do zero e a condição não será verdadeira e o bastão continuará subindo, o que não é o nosso desejo.
Movimento da bola
xb e yb, como descrito anteriormente, são as coordenadas da bola na tela. Pra saber pra onde a bola vai, temos as variáveis dxb (direção do eixo x: negativo pra esquerda e positivo pra direita) e dyb (direção do eixo y: negativo pra cima e positivo pra baixo). Pra dar uma incrementada, criei ainda as variáveis vxb e vyb, que representam a velocidade (ou o passo) com que a bola se movimentará.
O IF a seguir (if xb>=320 OR xb<=0), serve para verificar se a bola passou dos limites da tela, ou seja, não foi rebatida. Se isso acontecer, a bola é recolocada em jogo, a partir do centro da tela e na direção oposta que estava se movendo na hora do “gol”. Se alguém se animar a incrementar o código, aqui seria o local adequado para computar os pontos dos jogadores.
E tome IF…
Vamos analisar o próximo comando: If yb>=235 OR yb <=0 Then dyb*-1. O que ele faz é bem simples, “rebate” a bola toda vez que ela chega na borda superior ou inferior da tela. Isso é feito multiplicando dyb por -1, ou seja, inverto a direção da bola no eixo y sempre que qualquer uma dessas condições for verdadeira.
SpriteHit – rebatendo a bola!
Para implementar rebatida da bola pelo bastão, vamos usar um recurso diferente: SpriteHit. Esse comando verifica a cada ciclo do programa se houve uma colisão entre os Sprites especificados. Por exemplo: SpriteHit(0, xb, yb, 1, x1, y1) vai retornar TRUE, se o Sprite 0, de coordenadas xb, yb (que por um acaso é a bola), colidir com o Sprite 1, de coordenadas x1, y1 (que por um acaso é o bastão 1). Com esse comando (sensacional), tudo que eu preciso fazer é testar se a bola colidiu com um dos bastões e inverter as direções dos eixos x e y da mesma. Simples assim!
Vale ressaltar que SpriteHit só checa colisão de Sprite com Sprite. Existem outras formas de testar colisões de Shapes com Shapes e ainda entre Sprites e Shapes!
Mas isso fica para um próximo post…