Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
IndieGamerBrasil.com
Tutorial bsico de games
(c) 2013 by Cleuton Sampaio
Lio 1: objetos, tempo e movimento
Atribuio Voc deve creditar a obra da forma especificada pelo autor ou licenciante
(mas no de maneira que sugira que estes concedem qualquer aval a voc ou ao seu uso da
obra).
Uso no comercial Voc no pode usar esta obra para fins comerciais.
Calma! Eu sei que decepcionante... Mas toda longa jornada tem que comear com um passo. E
este o nosso primeiro passo.
Os arquivos esto em anexo. A pasta imagens tem as imagens globais do tutorial, e a pasta
scripts tem os scripts, imagens e css desta lio. Para executar, abra o arquivo
scripts/index.html no seu navegador e clique no boto iniciar da pgina. Depois, clique nos
botes Frente, Trs, Direita e Esquerda, para movimentar o objeto (a bola vermelha no
centro da arena).
Imagens
Nosso game ter algumas imagens:
Carros diversos;
A pessoa.
Todas as imagens esto dentro de imagens/objetos.odg, que um arquivo gerado pelo LibreOffice
Draw (). Voc pode selecionar e exportar as imagens individuais como png:
www.indiegamerbrasil.com Tutorial bsico de games Pgina: 2 de: 13
pessoa.js: implementao da classe Pessoa, que vai gerar o objeto que representa a
pessoa que vai atravessar a rua;
O evento onload da pgina acontece quando ela completamente carregada no navegador, logo,
todos os seus elementos foram completamente carregados. Neste caso, estou invocando a funo
inicializa(), que fica no arquivo inicializacao.js:
// inicializacao.js
function inicializa() {
larguraJanela = window.innerWidth;
alturaJanela = window.innerHeight;
// Prepara a "canvas" do game:
conteudo = document.getElementById("conteudo");
// Calcula tamanhos e posiciona a canvas:
var textoCanvas = "<canvas id=\"tela\" " +
" width=\"" + larguraJanela * 0.98 + "\"" +
" height=\"" + alturaJanela * 0.83 + "\"" +
"></canvas>";
conteudo.innerHTML = textoCanvas;
retangulo = {altura : tela.clientHeight, largura : tela.clientWidth};
contexto = tela.getContext("2d");
// Calcula a proporcao metro-tela: 1 metro = 10% da tela
metroPixels = Math.round(tela.clientWidth * 0.10);
retanguloMetros = {altura : tela.clientHeight / metroPixels, largura :
tela.clientWidth / metroPixels};
A funo inicializa() no inicia o game! Isto feito pela funo iniciar(), que invocada ao
clicar no boto iniciar:
<button onclick="iniciar()">Iniciar</button>
Tamanho e proporo
Um dos maiores problemas de qualquer game a proporo... Um game tem que executar
independentemente do tamanho da janela. E tudo tem que ficar na mesma proporo. Ns aqui
vamos considerar a unidade metro, informando-a em todas as definies dos gameobjects (altura,
largura, velocidade, posio etc).
Porm, temos que saber quanto vale 1 metro em pixels, o que depende da largura da tela. Ns
consideramos 1 metro como 10% da largura da tela. Assim, se o navegador for maior ou menor, no
importa: a proporo do tamanho e do movimento dos objetos ser a mesma.
Por isto criamos a varivel global metroPixels, dentro da funo inicializar().
O Game loop
O gameloop uma parte importante de qualquer game. Ele responsvel por atualizar o status do
game em cada instante. Para isto, ele precisa:
Ele repetido de tempos em tempos e deve rodar em paralelo com a interface de usurio, pois, caso
contrrio, pode travar o jogo.
www.indiegamerbrasil.com Tutorial bsico de games Pgina: 5 de: 13
Existem recursos que permitem usar programao concorrente, como Threads, ou Web Workers,
no HTML 5, porm, no esto disponveis em todos os navegadores, logo, no vamos utiliz-los.
O nosso gameloop fica no arquivo gameloop.js, na funo gameLoop():
function gameLoop() {
// Atualiza o "mundo" do game:
// Tempo decorrido desde a ltima atualizao:
var agora = new Date();
var tempoDecorrido = timeDifference(agora, tempo);
for (var x=0; x < gameObjects.length; x++) {
if (gameObjects[x].ativa) {
updateGO(gameObjects[x], tempoDecorrido);
}
}
// Escala a funcao de desenho para execuo:
setTimeout("desenhar()", 5);
tempo = agora;
}
O que ele faz? Ele calcula quanto tempo se passou desde a sua ltima execuo (em fraes de
segundo), e atualiza todos os gameobjects que esto no vetor global gameObjects (veremos mais
adiante). Para cada gameobject ele invoca a funo updateGO.
Depois de atualizar todos os gameobjects, necessrio desenh-los. Ele coloca a funo
desenhar() para executar em 5 milissegundos, com a funo setTimeout. Por que isso? Bem,
para no travar o thread principal do navegador. Em 5 milissegundos ele vai invocar a funo
desenhar().
claro que este gameloop est incompleto, afinal, apenas a primeira lio...
Como o gameloop iniciado?
Ao clicar o boto iniciar, a funo iniciar(), do arquivo gameloop.js invocada. Veja no
HTML (scripts/index.html):
<button onclick="iniciar()">Iniciar</button>
O que esta funo faz? Ela deve carregar o cenrio do nvel corrente, se estamos falando em um
game multinveis (a maioria ).
No nosso caso, estamos criando uma Pessoa e colocando-a no centro da arena. Estamos criando
um objeto do tipo Pessoa na memria, e depois colocando uma referncia para ele dentro do
nosso vetor de gameObjects.
A definio da classe Pessoa feita no arquivo pessoa.js:
// pessoa.js
var templatePessoa = {
arqImagem : "images/pessoa.png",
imagem : null,
centroX : 0,
centroY : 0,
velocidadeX : 1.0,
velocidadeY : 1.0,
aceleracaoX : 0.0,
aceleracaoY : 0.0,
altura : 1,
largura : 1,
ativa : true};
function Pessoa() {
this.arqImagem = templatePessoa.arqImagem;
this.imagem = templatePessoa.imagem;
this.centroX = templatePessoa.centroX;
this.centroY = templatePessoa.centroY;
this.velocidadeX = templatePessoa.velocidadeX;
this.velocidadeY = templatePessoa.velocidadeY;
this.aceleracaoX = templatePessoa.aceleracaoX;
this.aceleracaoY = templatePessoa.aceleracaoY;
this.altura = templatePessoa.altura;
this.largura = templatePessoa.largura;
this.ativa = templatePessoa.ativa;
}
Ns estamos usando a varivel global contexto, que foi criada na funo inicializa():
// Calcula tamanhos e posiciona a canvas:
var textoCanvas = "<canvas id=\"tela\" " +
" width=\"" + larguraJanela * 0.98 + "\"" +
" height=\"" + alturaJanela * 0.83 + "\"" +
"></canvas>";
conteudo.innerHTML = textoCanvas;
retangulo = {altura : tela.clientHeight, largura : tela.clientWidth};
contexto = tela.getContext("2d");
Ns criamos um elemento tela dinamicamente, e pegamos o seu contexto grfico 2d, logo,
podemos usar este contexto para desenhar imagens.
Antes de continuarmos, necessrio explicar qual o sistema de coordenadas de um Canvas. A
origem no canto superior esquerdo, com os valores das ordenadas (eixo y) crescendo para
baixo. Os valores das abscissas normal, crescendo para a direita. meio diferente de um plano
cartesiano normal, onde a origem fica no centro e o valor das ordenadas cresce para cima.
Isto muito importante, pois todos os clculos devem considerar a diferena na ordem do eixo y.
Continuando, o mtodo drawImage(), do contexto, espera os seguintes argumentos (existem
outras opes):
Largura, Altura: largura e altura da imagem (isto faz com que seja esticada ou escalada);
Movimentao do gameobject
Inicialmente, o nosso nico gameobject est parado, pois os valores das variveis globais
velocidadeX e velocidadeY esto zerados.
Depois de clicar no boto iniciar, se o jogador clicar em qualquer um dos botes de movimento,
vamos mudar o valor das velocidades X e Y:
<button
<button
<button
<button
onclick="frente()">Frente</button>
onclick="tras()">Trás</button>
onclick="direita()">Direita</button>
onclick="esquerda()">Esquerda</button>