Como fazer um jogo em JavaScript com a tag canvas

[download id=”396″]

Esse tutorial apresenta uma maneira de desenvolver o jogo pong. Um jogo básico e simples.
Vamos começar criando um arquivo em branco chamado jogo.htm. Nesse arquivo vamos digitar o código:

<!doctype html>
<html>
    <body>
        Daqui vai surgir o jogo
    </body>
</html>

Vamos apagar a frase e colocar o elemento canvas

<canvas></canvas>

Se você salvar o arquivo e clicar duas vezes sobre ele, o navegador irá exibir uma página em branco.
Mas o canvas está lá…
Para deixar ele visível vamos colocar uma borda:

<canvas style="border:1px solid #4a4a4a;"></canvas>

Para o jogo ficar de um jeito legal vamos colocar o canvas no meio da tela e dar o tamanho 400x450px
O motivo que me levou a usar o elemento canvas é que ele possibilita desenhar na tela codificando… escrever ‘desenhe uma linha azul;’ ou ‘desenhe um quadrado no canto’
Os primeiros jogos eletrônicos eram em modo texto. Em seguida eram em blocos quadrados. Depois eram desenhados através de codificação… Depois vieram os bmp os gif os jpg… os 3d…
Mas esse jogo é da época do quadrado
E usa o canvas que é um elemento que ‘emula’ um recurso inventado na época do ‘desenhar com código’

Quando fiz esse jogo no canvas pela primeira vez em 2010 eu estava acompanhando o surgimento do html5 e li sobre o canvas e sobre como era possível desenhar nele. O jogo foi resultado de testes que começaram com a pergunta: ‘Como eu desenho uma bola nesse canvas?’
Eu pesquisei… em vários sites e tutoriais… inclusive no site do w3c e w3schools

Para desenhar no canvas eu preciso de um ‘context’
Para isso eu dou um id pro canvas que criei… e uso JavaScript

<html>
<body>
    <center><canvas id=canvas width=400 height=450 style='border:1px solid #4a4a4a;'></canvas></center>
    <script>
        canvas=document.getElementById('canvas').getContext('2d');
    </script>
</body>
</html>

Para desenhar o círculo em vermelho dentro do canvas em preciso de algumas propriedades do ‘context’… alguns métodos e atributos:
fillStyle
beginPath();
arc();
fill();

canvas.fillStyle='#ff0000'; 
canvas.beginPath(); 
canvas.arc(50,125,16,0,Math.PI*2,false); 
canvas.fill();

Recomendo que vc entenda esses parâmetros.

Vamos usar a função setTimeout();
Pegar esse código que desenha a bolinha e fazer ele ser executado a cada 10 milissegundos.
E mudar os dois primeiros parâmetros da função arc para variáveis x e y, e incrementar essas variáveis cada vez para a bolinha se mover.

x=30;
y=15;
function anda()
{	
    x+=2;
    y+=2;
    canvas.fillStyle='#ff0000';
    canvas.beginPath();
    canvas.arc(x,y,16,0,Math.PI*2,false);
    canvas.fill();
    setTimeout('anda();',10);
}
anda();
canvas.fillStyle='#ffffff'; 
canvas.fillRect(0,0,400,450);

Para isso vamos precisar de novas variáveis dx e dy que vão armazenar quanto a bolinha avança (ou retrocede) no eixos x e y
Vamos mudar o valor de dx e de dy quando a bolinha pingar na parede… quando ela chegar no chão o dx vai mudar de +2 para -2

<script>
canvas=document.getElementById('canvas').getContext('2d');
x=20;
y=200;
tamanho=10;
dx=2;
dy=2;
function anda()
{	
    x+=dx;
    y+=dy;
    if(x<tamanho)dx*=-1;
    if(y<tamanho)dy*=-1;
    if(x>400-tamanho)dx*=-1;
    if(y>450-tamanho)dy*=-1;
    canvas.fillStyle='#ffffff';
    canvas.fillRect(0,0,400,450);
    canvas.fillStyle='#ff0000';
    canvas.beginPath();
    canvas.arc(x,y,tamanho,0,Math.PI*2,false);
    canvas.fill();
    setTimeout('anda();',10);
}
anda();
</script>
barrax=150;
canvas.fillStyle='#000000'; 
canvas.fillRect(barrax,430,100,20);

Para fazer a barra se mover vamos usar o atributo onKeyDown da tag body

<body onkeyDown='movebarra(event.which);'>

E vamos escrever a função movebarra
Inicialmente vamos por um alert para identificar o código de cada tecla

function movebarra(tecla)
{	
    alert(tecla);
}

E agora vamos fazer a barra se mover

function movebarra(tecla)
{	
    /*alert(tecla);*/
    if(tecla==37)barrax-=40;
    if(tecla==39)barrax+=40;
}

Quando a bola acertar a barra a bola deve voltar a subir… E dependendo de que parte da barra a bola acertar a bola deve voltar em um certo ângulo
Vamos modificar a função anda

if(y <450-tamanho)setTimeout( 'anda();',10);
else alert('Fim de jogo');
 if(y>430-tamanho)
{	
    var dif=x-barrax;
    if(dif>-10&&dif<110)
    {	
        dy*=-1;
        if(dif>-10&&dif<15)dx=-3;
        if(dif>=15&&dif<50)dx=-2;
        if(dif>=50&&dif<85)dx=2;
        if(dif>=85&&dif<110)dx=3;
        y=430-tamanho;
    }
}

O código até aqui fica:

<!doctype html>
<html>
<body onkeyDown='movebarra(event.which);'>
<center><canvas id=canvas width=400 height=450 style='border:1px solid #4a4a4a;'></canvas></center>
<script>
canvas=document.getElementById('canvas').getContext('2d');
x=20;
y=200;
tamanho=10;
dx=2;
dy=2;
barrax=150;
function anda()
{	
    x+=dx;
    y+=dy;
    if(x<tamanho)dx*=-1;
    if(y<tamanho)dy*=-1;
    if(x>400-tamanho)dx*=-1;
    if(y>450-tamanho)dy*=-1;
    canvas.fillStyle='#ffffff';
    canvas.fillRect(0,0,400,450);
    canvas.fillStyle='#000000';
    canvas.fillRect(barrax,430,100,20);
    canvas.fillStyle='#ff0000';
    canvas.beginPath();
    canvas.arc(x,y,tamanho,0,Math.PI*2,false);
    canvas.fill();
    if(y>430-tamanho)
    {	
        var dif=x-barrax;
        if(dif>-10&&dif<110)
        {	dy*=-1;
            if(dif>-10&&dif<15)dx=-3;
            if(dif>=15&&dif<50)dx=-2;
            if(dif>=50&&dif<85)dx=2;
            if(dif>=85&&dif<110)dx=3;
            y=430-tamanho;
        }
    }
    if(y<450-tamanho)setTimeout('anda();',10);
    else alert('Fim de jogo');
}
anda();
function movebarra(tecla)
{	
    /*alert(tecla);*/
    if(tecla==37)barrax-=40;
    if(tecla==39)barrax+=40;
}
</script>
</body>
</html>

Para começar vamos apenas desenhar um bloquinho.
Vamos criar uma variável bloco que será um array com três índices:

 

  • A posição x do bloco
  • A posição y
  • Se o bloco deve ser exibido (começa com true e fica false assim que a bola atingir)
bloco=[10,20,true];
if(bloco[2])
{	
    canvas.fillStyle='#0000ff';
    canvas.fillRect(bloco[0],bloco[1],50,20);
}
if(bloco[2])
{	
    var dif=y-bloco[1]-tamanho;
    if((dy<0&&(dif>0&&dif<20))||(dy>0&&(dif<0&&dif>-20)))
    {	if(x>bloco[0]&&x<bloco[0]+50)
        {	dy*=-1;
            bloco[2]=false;
        }
    }
}

Por enquanto fizemos o jogo funcionar com um bloco
Vamos transformar em um array de blocos
Vários blocos
Vamos colocar antes da declaração do x=20 e y=200 esse trecho de código que inicializa o array de blocos:

blocos=[]; 
for(x=0;x<8;x++)for(y=0;y<5;y++)blocos.push([x*50,y*20,true]);

E vamos ‘refatorar’ o código… transformar todas a ocorrencias de bloco em blocos[indice]:

for(c=0;c<blocos.length;c++)if(blocos[c][2])
{	
    var dif=y-blocos[c][1]-tamanho;
    if((dy<0&&(dif>0&&dif<20))||(dy>0&&(dif<0&&dif>-20)))
    {	if(x>blocos[c][0]&&x<blocos[c][0]+50)
        {	blocos[c][2]=false;
            dy*=-1;
        }
    }
}
for(c=0;c<blocos.length;c++)if(blocos[c][2])
{	
    canvas.fillStyle='#0000ff';
    canvas.fillRect(blocos[c][0],blocos[c][1],50,20);
}

O código completo fica:

<!doctype html>
<html>
<body onkeyDown='movebarra(event.which);'>
<center><canvas id=canvas width=400 height=450 style='border:1px solid #4a4a4a;'></canvas></center>
<script>
canvas=document.getElementById('canvas').getContext('2d');
blocos=[];
for(x=0;x<8;x++)for(y=0;y<5;y++)blocos.push([x*50,y*20,true]);
x=20;
y=200;
tamanho=10;
dx=2;
dy=2;
barrax=150;
function anda()
{	
    x+=dx;
    y+=dy;
    if(x<tamanho)dx*=-1;
    if(y<tamanho)dy*=-1;
    if(x>400-tamanho)dx*=-1;
    if(y>450-tamanho)dy*=-1;
    canvas.fillStyle='#ffffff';
    canvas.fillRect(0,0,400,450);
    canvas.fillStyle='#000000';
    canvas.fillRect(barrax,430,100,20);
    canvas.fillStyle='#ff0000';
    canvas.beginPath();
    canvas.arc(x,y,tamanho,0,Math.PI*2,false);
    canvas.fill();
    for(c=0;c<blocos.length;c++)if(blocos[c][2])
    {	
        canvas.fillStyle='#0000ff';
        canvas.fillRect(blocos[c][0],blocos[c][1],50,20);
    }
    for(c=0;c<blocos.length;c++)if(blocos[c][2])
    {	
        var dif=y-blocos[c][1]-tamanho;
        if((dy<0&&(dif>0&&dif<20))||(dy>0&&(dif<0&&dif>-20)))
        {	
            if(x>blocos[c][0]&&x<blocos[c][0]+50)
            {	blocos[c][2]=false;
                dy*=-1;
            }
        }
    }
    if(y>430-tamanho)
    {	
        var dif=x-barrax;
        if(dif>-10&&dif<110)
        {	
            dy*=-1;
            if(dif>-10&&dif<15)dx=-3;
            if(dif>=15&&dif<50)dx=-2;
            if(dif>=50&&dif<85)dx=2;
            if(dif>=85&&dif<110)dx=3;
            y=430-tamanho;
        }
    }
    if(y<450-tamanho)setTimeout('anda();',10);
    else alert('Fim de jogo');
}
anda();
function movebarra(tecla)
{	
    /*alert(tecla);*/
    if(tecla==37)barrax-=40;
    if(tecla==39)barrax+=40;
}
</script>
</body>
</html>

Deixe um comentário