Javascript episódio 3

Continuando nos desenhos no canvas com javascript, vamos desenhar algo com significado agora, vamos desenhar o pacman.
Todo mundo deve conhecer o pacman, ele basicamente é um círculo incompleto.

Algumas coisas são importantes para a gente lembrar aqui, sobre o círculo, primeiro que ele tem 2\pi de perímetro, mas o de 0 a 2\pi corre no sentido horário, isso é importante para lembrar onde começa e termina o círculo .

Então baseado na imagem acima, basta usar a função arc de desenho no canvas.
continuando daquele script básico de tínhamos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Pacman no canvas html</title>
    <link rel="stylesheet" href="java02.css">
    <script src="biblioteca.js"></script>
 
  </head>
  <body>
 
    <h1>Pacman</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
 
    <script>
      var canvas = document.getElementById("asteroids");
      var context = canvas.getContext("2d");
 
      desenha_grid(context);
 
    </script>
 
  </body>
</html>

Vamos desenhar o pacman usando a função arc, então abaixo da chamada de função desenha_grid(), usamos o seguinte código

1
2
3
4
5
      context.beginPath();
      context.arc(200, 200, 150, 0.2 * Math.PI, 1.8 * Math.PI);
      context.lineTo(200, 200);
      context.fillStyle = "yellow";
      context.fill();

Que vai dar:

Bem o que é legal notar, fomos do 0.2 ao 1.8 pi, e no final temos que voltar para o centro, caso contrário teremos um círculo cortado no cantinho, já que o desenho começa no 0.2 pi, lembre-se que o fill termina de fechar a figura, não usamos o stroke, porque as linhas não fariam a forma direito, diferente do fill.

Tudo bem, agora podemos então criar uma função para desenhar o pacman na tela, basicamente precisamos de todos os argumentos do arc, além o contexto que é para ser desenhado, então fazemos uma função com x, y e a abertura da boca, agora veja porque é importante saber em qual sentido o círculo é desenhado, para abrir e fechar a boca, precisamos somar o quanto queremos abrir a boca de uma lado, e diminuir o quanto queremos fechar do outro.

1
2
3
4
5
6
7
8
function desenha_pacman(ctx,x,y,raio,boca) {
    var abertura = boca*0.2
    ctx.beginPath();
    ctx.arc(x, y, raio, (0.2-abertura) * Math.PI, (1.8+abertura) * Math.PI);
    ctx.lineTo(x, y);
    ctx.fillStyle = "yellow";
    ctx.fill();
}

Podemos deixar essa função na biblioteca a parte, junto com a função do grid, e apenas usar no nosso html, para deixar mais fácil a leitura do código.

1
desenha_pacman(context,200,200,150,Math.random());

E isso nos da:

Cada vez que atualizamos o navegador teremos uma abertura diferente na boca, legal né. Bem algo importante quando estamos mexendo com o javascript, principalmente quando separamos em uma biblioteca, separamos em mais arquivos, é que o navegar jaz cache de arquivos js, então as vezes mudamos no servidor os arquivos js, mas eles não mudam no navegador, o que pode ser bem chato quanto se ta testando scripts, eu tenho usado o modo incognito para evitar esse cache.

Bem ai para testar melhor a nossa função, podemos desenhar alguns pacman aleatórios na página, com vários tamanhos , aberturas de bocas e desenhos variados

1
2
3
4
5
6
7
8
      var min_radius = 5;
      var max_radius = 50;
      do {
          let x = context.canvas.width * Math.random();
          let y = context.canvas.height * Math.random();
          let radius = min_radius + (max_radius - min_radius) * Math.random();
          desenha_pacman(context, x, y, radius, Math.random());
      } while(Math.random() < 0.9);

E usando um “do while”, temos:

E cada vez que damos refresh no navegador a imagem fica diferente.

Ai a título de curiosidade eu me pergunto, quantos pacmen devem aparecer na tela dados esse código. Veja que Sempre haverá pelo menos 1, que o código roda uma vez e depois testa se um número aleatório de uma distribuição uniforme é menor que 0.9.

Podemos simular isso no R com o seguinte código

1
2
3
4
5
6
7
8
9
10
11
12
amostras <- list()
 
for(i in 1:1000) {
 
    numero <- runif(1)
    amostras[[i]] <- c(numero)
 
    while(numero<0.9){
        numero <- runif(1)
        amostras[[i]] <- c(amostras[[i]],numero)
        }
}

Depois contamos quantos números tem em cada amostra, e temos:

Acontece que nem precisamos simular, pois isso é uma distribuição binomial negativa, o nome é imponente, mas é uma distribuição binomial ao contrário, não queremos saber quantos sucessos, mas quantos fracassos teremos até ter um sucesso. O número que sai é irrelevante, o que interessa é quantas vezes ele é menor que 0.9, como a distribuição é uniforme, sabemos que todos os números tem a mesma chance, então ser menor que 0.9, a chance é de 90%, ou seja temos 10% de chance de sucesso, dele ser maior, so ai, 0 e 1, ja sabemos que tem que ter algo binomial na jogada, mas queremos saber dos fracassos, então é negative binomial.

Ela é assim:

dnbinom(Sucessos,Fracassos,Probabilidade)

Ou seja, qual a chance de Tantos sucessos, antes de tantos fracassos, dada uma probabilidade de sucesso tal, é meio confuso , mas um plot ajuda a digerir isso.

Ou seja a chance de 1 sucesso com 1 jogada, é 90%, a chance de 1 sucesso com duas jogadas é menor, porque? Porque tem 90% de chance de logo de primeira ja ter sucesso, veja que a chance sempre diminui, porque para três jogadas, eu tenho uma chance alta na primeira, tenho uma chance alta na segunda, então com três jogadas já é para ter saído esse sucesso, e assim ela vai só diminuindo nesse caso.

Veja como isso encaixa certinho no nosso histograma

Lembrando que o primeiro pacman é garantido, a gente so tem o teste a partir do segundo, se ele vai existir ou não.

Bem é isso ai, já da para entender mais alguma coisinha de Javascript agora, ainda demos uma lembrada em distribuição binomial negativa, tudo ficando mais organizado sempre, o script vai estar la no repositório de javascript, e se eu escrevi alguma bobeira, algo errado, deixe um comentário corrigindo ou mande um e-mail.

Referência:
Graeme Stuart 2017 – Introducing JavaScript Game Development Build a 2D Game from the Ground Up. Apress 221pp

Javascript episódio 2

Continuando no Javascript, vamos olhar como funciona as coordenadas, o sistema de coordenadas no canvas. Lembro que vi isso pela primeira vez no livro de java do Robert Sedgewick, porque ele fazia o próprio sistema de gráficos dele, bem simples, para fazer histogramas e gráficos de pontos, mas la a gente ve que diferente de como a gente pensa, o monitor desenha da parte superior esquerda, para baixo e para direta, então é como se fosse tudo uma mega matriz de pixels, e o (0,0) esta no canso superior esquerdo, pra quem esta olhando a tela. Com arduino, tem um projetinho que você projeta a hora na tv, via cabo coaxial, e você tem que fazer umas contas nesses sentido, mas uma coisa é pintar meia duzia de pixel para fazer um número, controlar uma matriz de led, outra é fazer uma imagem, mas chega de divagar, vamos continuar aquele exemplo, vamos olhar algumas partes agora.

No post anterior, a gente colocou tudo no arquivo html, e ele ficou grande, colocamos o elemento style e os scripts de javascript tudo junto, mas isso começa a complicar, então o que vamos fazer é separar tudo em arquivos diferentes, para web, a gente pode fazer mais de um arquivo na mesma pasta, para facilitar, e usamos arquivos .css para o código do estilo da página e os arquivos .js para scripts de javascript.

Ai como você faz para separar, eu vou ter dois arquivos, o java02.css e o java02.html, o tudo que estava dentro da tag style, eu vou colocar dentro do java02.css, que fica assim:

$ cat java02.css body { text-align: center; font-family: sans-serif; } canvas { background-color: black; }

E no arquivo java02.html, vamos adicionar uma linha no para chamar esse arquivo assim:

1
<link rel="stylesheet" href="java02.css">

E pronto, ja diminuímos um pouco o tamanho de tudo. E agora, vamos continuar com aquela mesma estrutura de html, com um canvas. Então o java02.html vai ser:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Desenhando no canvas html</title>
    <link rel="stylesheet" href="java02.css">
 
  </head>
  <body>
 
    <h1>Desenhando no canvas html</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
 
    <script>
    //Meu script
    </script>
 
 
  </body>
</html>

E vamos fazer um script, primeiro para entender como funciona esse grid.

Precisamos sempre a referência do elemento para trabalhar

1
2
var canvas = document.getElementById("asteroids");
var context = canvas.getContext("2d");

Mas para desenhar, vamos fazer uma função, colocando em outro arquivo, para depois utilizar, então vamos criar um arquivo chamado biblioteca.js, vamos referenciar ele, parecido com o que fizemos com o arquivo css, na linha depois dela dentro do

1
<script src="biblioteca.js"></script>

Agora dentro desse aquivos, vamos criar uma função de javascript da seguinte forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function desenha_grid(ctx, minor, major, stroke, fill) {
 
    minor = minor || 10;
    major = major || minor * 5;
    stroke = stroke || "#00FF00";
    fill = fill || "#009900";
    ctx.save();
    ctx.strokeStyle = stroke;
    ctx.fillStyle = fill;
 
    let width = ctx.canvas.width, height = ctx.canvas.height
 
    for(var x = 0; x < width; x += minor) {
	ctx.beginPath();
        ctx.moveTo(x, 0);
        ctx.lineTo(x, height);
        if(x % 50 == 0){
            ctx.lineWidth = (0.5);
	}else{
           ctx.lineWidth = (0.25);
        }
        ctx.stroke();
        if(x % major == 0 ) {ctx.fillText(x, x, 10);}
    }
    for(var y = 0; y < height; y += minor) {
        ctx.beginPath();
        ctx.moveTo(0, y);
        ctx.lineTo(width, y);
        ctx.lineWidth = (y % major == 0) ? 0.5 : 0.25;
        ctx.stroke();
        if(y % major == 0 ) {ctx.fillText(y, 0, y + 10);}
    }
    ctx.restore();
}

Então essa é uma função, chamada desenha_grid, que aceita cinco argumentos, o primeiro é o contexto, o canvas que a gente quer desenhar, e o outros são de quanto em quanto pixels a gente quer desenhar linhas, assim como num papel milimetrados, temos linhas pequenas e linhas mais grossas, esses são os tamanhos em pixel, e o stroke e fill são as cores de preenchimento.

O jeito mais simples de usar é apenas falar qual o contexto, que temos argumentos de tamanhos e cores pré-definidos, então o seguinte arquivo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Desenhando no canvas html</title>
    <link rel="stylesheet" href="java02.css">
    <script src="biblioteca.js"></script>
 
  </head>
  <body>
 
    <h1>Desenhando no canvas html</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
 
    <script>
      var canvas = document.getElementById("asteroids");
      var context = canvas.getContext("2d");
      // Desenhando no Canvas
 
      desenha_grid(context);
 
    </script>
 
  </body>
</html>

Vai produzir isso:

Legal, veja que podemos chamar a função com outras cores para produzir outras coisas. Por exemplo

1
desenha_grid(context, 15, 45, 'red', 'yellow');

Vai produzir

Ok, agora que a gente já viu o que a função faz vamos entender como ela funciona.

A estrutura geral para definir uma função no javascript é assim:

1
2
3
function desenha_grid(ctx, minor, major, stroke, fill) {
Seu código
}

Não precisamos definir o tipo dos argumentos, so dar nomes, ai o código da função é o seguinte

1
2
3
4
    minor = minor || 10;
    major = major || minor * 5;
    stroke = stroke || "#00FF00";
    fill = fill || "#009900";

Com exceção do contexto, de onde desenhar, que não tem como ser padrão, precisamos de um canvas para desenhar, todos os outros argumentos, se não forem definidos na função, definimos eles aqui, veja que eles são pegos na ordem que são fornecidos na função.

Depois, antes de alterar o contexto, salvamos todos os parâmetros deles

1
    ctx.save();

Depois que temos salvo os parâmetros, começamos a mexer neles,

1
2
    ctx.strokeStyle = stroke;
    ctx.fillStyle = fill;

Definimos duas váriaveis, altura e largura, que vamos usar para fazer o grid

1
    let width = ctx.canvas.width, height = ctx.canvas.height

E então vamos fazer dois loops

1
2
3
4
5
6
7
8
9
10
11
12
    for(var x = 0; x < width; x += minor) {
	ctx.beginPath();
        ctx.moveTo(x, 0);
        ctx.lineTo(x, height);
        if(x % major == 0){
            ctx.lineWidth = (0.5);
	}else{
           ctx.lineWidth = (0.25);
        }
        ctx.stroke();
        if(x % major == 0 ) {ctx.fillText(x, x, 10);}
    }

Aqui para a altura, vamos fazer linhas, então começamos a linhas no (0,0), vamos com ela até la em baixo, já que height foi definido ali em cima como o tamanho da tela, e definimos o lineWidth fina para cada linha minor, e mais grossa para o major, que são argumentos para o grid, usando um if, depois o ctx.stroke() desenha a linha e para cada vez que chegamos no major, escrevemos em que pixel estamos com o fillText. Depois repetimos o mesmo esquema para as linhas horizontais

1
2
3
4
5
6
7
8
    for(var y = 0; y < height; y += minor) {
        ctx.beginPath();
        ctx.moveTo(0, y);
        ctx.lineTo(width, y);
        ctx.lineWidth = (y % major == 0) ? 0.5 : 0.25;
        ctx.stroke();
        if(y % major == 0 ) {ctx.fillText(y, 0, y + 10);}
    }

So dando um destaque aqui, para essa forma mais resumida de usar if e else, acho que é o mesmo esquema que da pra usar no c++ e no c, mas que a gente não vê em R e python, se bem que python tem maneiras bem sintéticas de escrever as coisas, mas a primeira vez que a gente vê pode ser confuso, mas tem a mesma coisa usando if else ali em cima só para facilitar o entendimento.

Bem, feito isso, como mudamos os parâmetros do contexto, e la em cima salvamos como estava antes, voltamos eles com o restore()

1
    ctx.restore();

E agora é como se nem tivéssemos mexidos. Esse grid vai ajudar muito a entender melhor as coordenadas, da para entender melhor como são feitas as retas e o preenchimento agora.

Vamos fazer algumas retas

1
2
3
4
5
6
7
8
9
10
11
      context.beginPath();
      context.strokeStyle = "#FFFFFF";
      context.fillStyle = "#00FF00";
      context.lineWidth = 2;
      context.moveTo(50, 50);
      context.lineTo(150, 250);
      context.lineTo(250, 170);
      context.stroke();
      context.fillText("(50, 50)", 30, 40);
      context.fillText("(150, 250)", 130, 260);
      context.fillText("(250, 170)", 255, 175);

Começamos um caminho, fomos para o ponto (50, 50) dai fazemos uma reta para (150, 250) e depois (250, 170), e vamos escrever esses pontos, um pouco deslocado do local sendo desenhado com fillText, para se ligar no que estamos fazendo, lembrando que só o lineTo não desenha nada, so depois do stroke o desenho aparece na tela.

Agora diferente do texto, Stroke desenha a linha, mas podemos preencher essa linha, que como não é uma forma fechada, fica assim.

1
2
3
4
5
6
7
8
9
10
11
12
13
      //Reta inicial
      context.beginPath();
      context.strokeStyle = "#FFFFFF";
      context.fillStyle = "#00FF00";
      context.lineWidth = 2;
      context.moveTo(50, 50);
      context.lineTo(150, 250);
      context.lineTo(250, 170);
      context.stroke();
      context.fillText("(50, 50)", 30, 40);
      context.fillText("(150, 250)", 130, 260);
      context.fillText("(250, 170)", 255, 175);
      context.fill();

Que fica assim:

Então o que acontece, é que a forma sempre é fechada na origem e preenchida, caso ela não esteja fechada, por exemplo se expandirmos as linhas assim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
      //Reta inicial
      context.beginPath();
      context.strokeStyle = "#FFFFFF";
      context.fillStyle = "#00FF00";
      context.lineWidth = 2;
      context.moveTo(50, 50);
      context.lineTo(150, 250);
      context.lineTo(250, 170);
      context.lineTo(320, 280);
      context.stroke();
      context.fillText("(50, 50)", 30, 40);
      context.fillText("(150, 250)", 130, 260);
      context.fillText("(250, 170)", 255, 175);
      //context.fill();

quando preenchemos com o fill temos

Mas para fecharmos nossas forma, e fazer um triângulo por exemplo, podemos usar o closePath

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Triângulos
      context.beginPath()
      context.moveTo(50, 250);
      context.lineTo(50, 350);
      context.lineTo(150, 350);
      context.closePath();
      context.moveTo(230, 360);
      context.lineTo(270, 360);
      context.lineTo(270, 310);
      context.closePath();
      context.moveTo(250, 50);
      context.lineTo(370, 50);
      context.lineTo(370, 100);
      context.closePath();
      context.strokeStyle = "#FFFF00";
      context.fillStyle = "#000000";
      context.fill();
      context.stroke();

Que da.

Mas estrada sem curvas da sono não é verdade, existe algumas formar de curvarmos um poucos as formas, uma é usando o quadraticCurveTo, que é uma equação de segundo grau, basicamente, então o ponto inicial e final são as duas raizes e temos os outros termos da equação.

Nesse caso, a gente fornece mais dois pontos,

context.quadraticCurveTo(cpx,cpy,x,y);

cpx e cpy são um ponto de controle, e o x e y são a outra raiz, dessa forma

É equivalente a

1
2
moveTo(20,20)
quadraticCurveTo(20,100,200,20)

Então esse código

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
      //Curvas Quadráticas
      context.beginPath()
      context.moveTo(50, 250);
      context.quadraticCurveTo(25, 300, 50, 350);
      context.quadraticCurveTo(100, 375, 150, 350);
      context.closePath();
      context.moveTo(230, 360);
      context.quadraticCurveTo(255, 340, 270, 360);
      context.quadraticCurveTo(255, 340, 270, 310);
      context.closePath();
      context.moveTo(250, 50);
      context.quadraticCurveTo(310, 60, 370, 50);
      context.quadraticCurveTo(400, 75, 370, 100);
      context.closePath();
      context.strokeStyle = "#FFFF00";
      context.fillStyle = "#000000";
      context.fill();
      context.stroke();

da isso.

Legal, mas no manual do w3schools para quadraticCurveTo a gente já vê sobre o bezierCurveTo(), que é parecido, mas usamos dois pontos de referencia, para entortar diferente as curvas.

a sintaxe vai pedir dois pontos de controle

context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);

E o codigo

1
2
moveTo(20,20)
bezierCurveTo(20,100,200,100,200,20)

Vai produzir o seguinte

Então podemos modificar aquelas primeiras retas e usar o closePath

1
2
3
4
5
6
7
8
9
10
11
//Curvas Bezier
      context.beginPath();
      context.strokeStyle = "red";
      context.fillStyle = "#00FF00";
      context.lineWidth = 2;
      context.moveTo(50, 50);
      context.bezierCurveTo(0, 0, 80, 250, 150, 250);
      context.bezierCurveTo(250, 250, 250, 250, 250, 170);
      context.bezierCurveTo(250, 50, 400, 350, 320, 280);
      context.closePath();
      context.stroke();

Para produzir

Sendo que o closePath continua sendo uma reta.

Bem é isso ai, já da para entender mais alguma coisinha de Javascript agora, tudo ficando mais organizado, o script vai estar la no repositório de javascript, e se eu escrevi alguma bobeira, algo errado, deixe um comentário corrigindo ou mande um e-mail.

Referência:
Graeme Stuart 2017 – Introducing JavaScript Game Development Build a 2D Game from the Ground Up. Apress 221pp

Javascript episódio 1

Como quase tudo, eu tenho tentado aprender javascript na tentativa e erro, mas acho que já esta na hora de começar a ler e entender melhor o que estou fazendo, melhor que tentativa e erro para progredir mais um pouco, e acabei que achei um livro que achei tanto simples como legal. Essa foi a lição do capítulo 1.

Bem aqui a gente vai apenas fazer um canvas com javascript do zero, para começar, vamos fazer somente um arquivo html, e ele vai ter um elemento no corpo que vai ser um canvas.

1
2
3
4
5
6
7
8
9
10
11
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Isto é um canvas html</title>
  </head>
  <body>
    <h1>Isto é um canvas html</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
  </body>
</html>

Isso gera o seguinte no navegador.

Então temos um canvas de 400 por 400, mas na verdade a gente não vê nada, porque tudo, tanto a página quanto o canvas tem tudo a mesma cor, mas ele está ali, abaixo do texto. Agora vamos desenhar algo nele, com um script de javascript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!doctype html>                                                                                                                                                                                             
<html>                                                                                                                                                                                                      
  <head>                                                                                                                                                                                                    
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">                                                                                                                                
    <title>Isto é um canvas html</title>                                                                                                                                                                    
  </head>                                                                                                                                                                                                   
  <body>                                                                                                                                                                                                    
 
    <h1>Isto é um canvas html</h1>                                                                                                                                                                          
    <canvas id="asteroids" width="400" height="400"></canvas>                                                                                                                                               
 
    <script>                                                                                                                                                                                                
      var canvas = document.getElementById("asteroids");                                                                                                                                                    
      var context = canvas.getContext("2d");                                                                                                                                                                
      context.strokeStyle = 'dimgrey';                                                                                                                                                                      
      context.lineWidth = 5;                                                                                                                                                                                
      context.rect(75, 75, 250, 250);                                                                                                                                                                       
      context.stroke();                                                                                                                                                                                     
      // Comentário                                                                                                                                                                                         
    </script>                                                                                                                                                                                               
 
  </body>                                                                                                                                                                                                   
</html>

E vemos o seguinte.

Bem, primeiro a gente tem que se ligar que javascript é uma linguagem scriptada, então assim como o R, ele vai rodando linha por linha, e so para se a gente fizer algo errado, até la ele roda, e ele roda na ordem, por isso o script esta depois do elemento canvas no html, porque se tiver antes, ele vai tentar rodar num elemento de html que ainda não existe.
Outra coisa, é que ele é orientado a objetos, então a primeira linha

1
      var canvas = document.getElementById("asteroids");

Apenas instancia um objeto, que esta ligado ao elemento asteroids, que é o id que demos no nosso canvas ali no html

1
<canvas id="asteroids" width="400" height="400"></canvas>

Depois disso criamos um contexto. Apesar do elemento canvas ser usado para desenhar, plotar, etc, através de scripts, ele não tem métodos de desenho, então quando a gente usa o método getContext(), ele retorna o objeto que tem os métodos para desenho, no caso o “2d” é para desenhos em 2d, como retas, formas, texto entre outras coisas.

Agora podemos mexer no contexto, que é o que realmente desenha, o strokeStyle seta a cor, lineWidth qual a espessura da linha a ser desenhada em pixels, rect faz um retangulo, que no nosso caso é um quadrado, os dois primeiros valores são o ponto onde ele vai começar, onde vai ser ancorado essa forma, e depois temos o tamanho dele, 250 de largura e altura.

Até essa linha, nada foi desenhado, so depois que rodamos o método stroke, que tudo realmente é desenhado. Mas não da para ver onde é o canvas, porque precisamos mexer no estilo da página, para colocar outra cor no canvas, no nosso elemento, para diferencias ele, então precisamos de um pouco de CSS, que podemos colocar direto aqui.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Isto é um canvas html</title>
 
    <style media="screen">
      body {
      text-align: center;
      font-family: sans-serif;
      }
      canvas {
      background-color: black;
      }
    </style>
 
  </head>
  <body>
 
    <h1>Isto é um canvas html</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
 
    <script>
      var canvas = document.getElementById("asteroids");
      var context = canvas.getContext("2d");
      context.strokeStyle = 'dimgrey';
      context.lineWidth = 5;
      context.rect(75, 75, 250, 250);
      context.stroke();
      // Comentário
    </script>
 
  </body>
</html>

Essa modificação no estilo, também direto dentro do html, colocamos o elemento style la no cabeçalho, no head, e mudamos o plano de fundo dos elementos, e centralizamos na página também.

Agora da pra ver melhor o canvas, vamos mexer no nosso desenho melhor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Isto é um canvas html</title>
 
    <style media="screen">
      body {
      text-align: center;
      font-family: sans-serif;
      }
      canvas {
      background-color: black;
      }
    </style>
 
  </head>
  <body>
 
    <h1>Isto é um canvas html</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
 
    <script>
      var canvas = document.getElementById("asteroids");
      var context = canvas.getContext("2d");
      context.strokeStyle = 'lightgrey';
      context.fillStyle = 'dimgrey';
      context.lineWidth = 5;
      context.rect(75, 50,canvas.width - 150, canvas.height - 100);
      context.stroke();
      context.fill();
      // Comentário
    </script>
 
  </body>
</html>

Isso vira o seguinte.

O que a gente fez aqui, primeiro veja que temos agora uma cor para a borda do elemento e uma cor de preenchimento, que é o fillStyle, outra coisa, veja que mudamos agora as medidas e o ponto de referencia do retângulo que fazemos com rect, estamos fazendo ele baseado nas medidas do canvas, veja que podemos acessar esses valores a partir do objeto canvas que criamos, ele tem esses atributos, e agora usamos o stroke para desenhar o e fill para preencher, antes de fazer isso, nada acontece, podemos comentar essas linhas para ir testando o comportamento dos métodos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Isto é um canvas html</title>
 
    <style media="screen">
      body {
      text-align: center;
      font-family: sans-serif;
      }
      canvas {
      background-color: black;
      }
    </style>
 
  </head>
  <body>
 
    <h1>Isto é um canvas html</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
 
    <script>
      var canvas = document.getElementById("asteroids");
 
      //Retângulo
      var context = canvas.getContext("2d");
      context.strokeStyle = 'lightgrey';
      context.fillStyle = 'dimgrey';
      context.lineWidth = 5;
      context.rect(75, 50,canvas.width - 150, canvas.height - 100);
      context.stroke();
      context.fill();
 
      // Texto
      context.font = "34px Arial";
      context.strokeStyle = '#FF2222';
      context.fillStyle = '#FFAAAA';
      context.lineWidth = 0.75;
      context.textAlign="center";
      let msg = "Desenhando 2d"
      context.fillText(msg, canvas.width / 2, 100);
      context.strokeText(msg, canvas.width / 2, 100);
    </script>
 
  </body>
</html>

Agora adicionando o elemento de texto.

Bem, os comentários são como no c++, com duas barras, podemos usar eles para dar uma organizada no texto, bem agora vamos mexer no contexto, veja que a cor e o preenchimento são uma propriedade, no caso nos mudamos ela de novo depois que fizemos o retângulo, pegamos cores novas, mudamos a grossura da linha de desenho com lineWidth e vamos desenhar texto, alinhando ele centralizado a partir do ponto onde desejamos escrever, declaramos um string com let, a diferença de let e var é sutil, os dois declaram variáveis, mas tem diferentes escopo e eu não sei explicar isso direito ainda, mas tudo bem. Ai assim como o retângulo, usamos o fillText para preencher as letras, e o strokeText para o contorno, veja que mandamos para ele o texto e o ponto onde ele deve ser ancorado, sendo o meio do canvas, na altura 100 pixel, lembrando que é um desenho numa tela, então não contamos os eixos como num gráfico, mas ao contrario, o canto superior esquerdo é onde começa a tela.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!doctype html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Isto é um canvas html</title>
 
    <style media="screen">
      body {
      text-align: center;
      font-family: sans-serif;
      }
      canvas {
      background-color: black;
      }
    </style>
 
  </head>
  <body>
 
    <h1>Isto é um canvas html</h1>
    <canvas id="asteroids" width="400" height="400"></canvas>
 
    <script>
      var canvas = document.getElementById("asteroids");
 
      //Retângulo
      var context = canvas.getContext("2d");
      context.strokeStyle = 'lightgrey';
      context.fillStyle = 'dimgrey';
      context.lineWidth = 5;
      context.rect(75, 50,canvas.width - 150, canvas.height - 100);
      context.stroke();
      context.fill();
 
      // Texto
      context.font = "34px Arial";
      context.strokeStyle = '#FF2222';
      context.fillStyle = '#FFAAAA';
      context.lineWidth = 0.75;
      context.textAlign="center";
      let msg = "Desenhando 2d"
      context.fillText(msg, canvas.width / 2, 100);
      context.strokeText(msg, canvas.width / 2, 100);
 
      // Bonequinho
      context.strokeStyle = '#FFFFFF';
      context.lineWidth = 2;
      context.beginPath();
      context.arc(200, 140, 20, 0, Math.PI * 2);
      context.moveTo(200, 160);
      context.lineTo(200, 220);
      context.moveTo(180, 300);
      context.lineTo(185, 260);
      context.lineTo(200, 220);
      context.lineTo(215, 260);
      context.lineTo(220, 300);
      context.moveTo(240, 130);
      context.lineTo(225, 170);
      context.lineTo(200, 170);
      context.lineTo(175, 180);
      context.lineTo(170, 220);
      context.stroke();
 
      // Mais texto
      let msg2 = "bem simples!!!";
      context.font = "24px Arial";
      context.strokeStyle = '#FF2222';
      context.lineWidth = 0.75;
      context.fillText(msg2, canvas.width / 2, 330);
      context.strokeText(msg2, canvas.width / 2, 330);
    </script>
 
  </body>
</html>

Agora basicamente é isso, com mais algumas funções, fazemos um bonequinho usando path, funciona assim, a gente começa um path com beginPath, veja que ele usa os parâmetros de cor, tamanho ja determinados, ai usamos outra função que é fazer um arco, para fazer a cabeça, um arco é um circulo, então temos que ter um ponto onde ele começa, onde ele ancora, depois o tamanho do raio e onde ele começa e onde termina, no caso 2 \pi é uma volta completa, dai temos um circulo, o moveTo move para onde queremos começar a desenhar, e lineTo para da onde está o último moveTo até o ponto que indicamos, e antes de terminar, temos que desenhar o que queremos, bem vamos fazer mais uma mensagem, e sempre lembrando que precisamos tomar cuidado pois mudamos as cores, as propriedades do texto.

Bem é isso ai, estava olhando javascript hoje e resolvi posta o que fiz, o script vai estar la no repositório de javascript, e se eu escrevi alguma bobeira, algo errado, deixe um comentário corrigindo ou mande um e-mail.

Referência:
Graeme Stuart 2017 – Introducing JavaScript Game Development Build a 2D Game from the Ground Up. Apress 221pp