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