Javascript, Programming

Criando um jogo em Javascript [2/5] – Personagem principal

Vamos continuar a nossa versão em JavaScript do Freeway, aquele jogo do Atari da galinha atravessando a rua.

No post anterior, fizemos a rua, calçadas e faixas que ficarão como pano de fundo.

Agora colocaremos a figura do personagem principal.

Inserindo uma imagem

No Freeway criado pelo Henrique Lobo Weissmann, a galinha foi criada a partir de uma matriz de cores (ou bitmap).

Aqui, vamos tomar uma abordagem mais simples: usaremos uma imagem já pronta. Apresento-lhes a Dilminha:

Dilminha, a personagem principal

Essa imagem pode ser baixada em:
http://a-dilminha.appspot.com/dilminha.png

Nota: quem tiver os direitos autorais dessa imagem, por favor entre em contato.

Criaremos um novo Image, com a URL da imagem no atributo src:

var imagem = new Image();
imagem.src = "../../dilminha.png";

Para inserir a imagem no fundo, usaremos o contexto 2D que foi criado a partir do canvas. Passaremos a imagem para a função drawImage do contexto, além das posições iniciais (x e y) e largura e altura da imagem:

var x = 320;
var y = 400;
contexto.drawImage(imagem, x, y, imagem.width, imagem.height);

Se tentarmos executar o código acima, veremos que a imagem não foi exibida. Porque será? É que só podemos colocá-la no contexto depois dela ter sido carregada. Para isso, devemos colocar uma função na propriedade onload da imagem que será executada depois do carregamento:

imagem.onload = function(){
    contexto.drawImage(imagem, x, y, imagem.width, imagem.height);
}

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/movendo/5-figura.html

Imagem da Dilminha sobre o fundo

Movendo o personagem

Com a imagem inserida sobre o fundo, precisamos movê-la ao pressionar as setas do teclado. Para isso, vamos passar para a propriedade onkeydown do document uma função que será chamada quando algo for digitado:

document.onkeydown = function(){
    //executado quando algo for digitado...
}

Nessa função, recebemos como parâmetro um objeto que representa o evento do pressionamento de teclas. Através da propriedade which desse evento, podemos saber qual tecla foi pressionada. A seta pra esquerda tem o código 37; pra cima, o código é 38; pra direita, 39; para baixo, 40.

Os eixos x e y são contados da esquerda pra direita e de baixo pra cima. Quanto maior o valor, mais para a direita e mais para baixo estará a imagem. Por isso, mover para a direita é aumentar o valor de x; pra esquerda é diminuir. Mover para cima, é diminuir o y; pra baixo, é aumentar.

Então, ficaríamos com o código:

document.onkeydown = function(event) {
    switch(event.which) {
        case 37: //pra esquerda
            x = x - 10;
        break;
        case 38: //pra cima
            y = y - 10;
        break;
        case 39: //pra direita
            x = x + 10;
        break;
        case 40: //pra baixo
            y = y + 10;
        break;
    }
}

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/movendo/6-move.html

Mas não moveu...

Por que não moveu?

Ao executarmos o código acima, vamos perceber que a imagem não foi movida. Será que esse código não funciona?

Bom… Quando o usuário pressiona as setas do teclado, o x e o y foram atualizados. O que precisamos fazer é redesenhar a imagem periodicamente, para que as novas posições sejam exibidas.

Para executar algo periodicamente no JavaScript, devemos usar a função setInterval. Precisam ser passados como parâmetros a função que será chamada e o número de milissegundos de espera entre as chamadas.

No nosso caso, a função terá o trecho de código que desenha a imagem no contexto 2D. Serão utilizados o x e o y calculados quando o usuário pressiona alguma seta do teclado. Nosso intervalo de espera será de 50 milissegundos:

setInterval(function(){
    contexto.drawImage(imagem, x, y, imagem.width, imagem.height);
}, 50);

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/movendo/7-recarrega.html

Redesenha a imagem a cada 50 milissegundos

Limpando o fundo

Perceba na imagem anterior que é deixado um rastro de todas as posições da nossa imagem. Isso acontece porque estamos redesenhando a imagem nas novas posições se limpar as imagens anteriores.

Uma maneira de fazer isso é desenhar o fundo novamente toda vez que formos atualizar a posição da imagem.

Para poder reaproveitar o código que desenha o fundo, vamos colocá-lo dentro de uma função chamada desenhaFundo. Essa função será invocada imediatamente, logo que a página for carregada, além de periodicamente, a cada 50 ms.

Vamos aproveitar e criar uma função desenhaImagem, que será responsável por desenhar a imagem no contexto 2D. Essa função também será invocada imediatamente e periodicamente.

O código reorganizado ficaria assim:

function desenhaFundo () {
    //preenche o fundo com cinza escuro
    contexto.fillStyle = "dimgray";
    contexto.fillRect(0, 0, canvas.width, canvas.height);

    //calcada superior
    contexto.fillStyle = "lightgray";
    contexto.fillRect(0, 0, canvas.width, 80);

    //calcada inferior
    contexto.fillStyle = "lightgray";
    contexto.fillRect(0, 380, canvas.width, 100);

    //faixas
    contexto.fillStyle = "white";
    for(var i = 0; i < 25; i++){
        contexto.fillRect(i*30-5, 185, 20, 4);
        contexto.fillRect(i*30-5, 280, 20, 4);
    }
}

function desenhaImagem(){
    contexto.drawImage(imagem, x, y, imagem.width, imagem.height);
};

var imagem = new Image();
imagem.src = "../../dilminha.png";
var x = 320;
var y = 400;
imagem.onload = desenhaImagem;

//código que trata teclas pressionadas omitido...

setInterval(function(){
    desenhaFundo();
    desenhaImagem();
},50);

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/movendo/8-limpando.html

Movendo imagem depois de limpar fundo

Impondo limites

Do jeito que foi feito o código que trata as teclas digitadas, os valores de x e y são adicionados ou subtraídos indefinidamente. Isso faz com que não existam limites e a imagem desapareça da tela. Por exemplo:

Imagem quase sumindo do canto inferior direito da tela

Seria interessante que limitássemos os valores possíveis de x e y. Por exemplo, podemos definir um limite superior e fazer com que, quando ultrapassado, a imagem aparece na parte debaixo da tela. Poderíamos criar também limites horizontais: quando a imagem ultrapassar o limite da direita, aparecerá a esquerda e vice-versa. O limite inferior será fixo, não fazendo com que seja tomado um atalho para o topo da tela.

Uma implementação desses limites, seguindo as regras acima, seria:

document.onkeydown = function(event) {
    switch(event.which) {
        case 37: //pra esquerda
            x = x -10;
            //passado o limite da esquerda, aparecerá à direita
            if(x < -imagem.width) {
                x = canvas.width;
            }
        break;
        case 38: //pra cima
            y = y - 10;
            //passado o limite superior, aparecerá embaixo
            if(y <= -5) {
                y = canvas.height - imagem.height;
            }
        break;
        case 39: //pra direita
            x = x + 10;
            //passado o limite da direita, aparecerá à esquerda
            if(x > canvas.width) {
                x = -imagem.width;
            }
        break;
        case 40: //pra baixo
            y = y + 10;
            //se o novo y passou o limite inferior, desfaz a soma
            if(y > canvas.height - imagem.height + 5) {
                y -= 10;
            }
        break;
    }
}

O resultado do código acima está disponível em:
http://a-dilminha.appspot.com/passo-a-passo/movendo/9-limites.html

Limite inferior

Tem mais

Semana que vem, teremos carros que se moverão sozinhos. E iremos organizar um pouco o código. Até mais!

Anúncios

10 comentários sobre “Criando um jogo em Javascript [2/5] – Personagem principal

  1. Então, eu estou desenvolvendo um game com os mesmos comandos que você utilizou para fazer o avatar se mover, porém. eu estou utilizando uma imagem ao invés de apenas cores no fundo, mas por utilizar imagem não estou conseguindo limpar os rastros do avatar, pode me ajudar?
    Agradeço desde já!

    1. Bruno,

      Para limpar os rastros, você precisa pintar a imagem por cima do que já existe!

      Fazer algo como: contexto.drawImage(imagem, 0, 0, larguraMaxima, alturaMaxima);

      1. Cara, deu certo, muito obrigado! Não só pela ajuda mas também pela velocidade com que respondeu.. Obrigado mesmo!

  2. Alexandre, aqui estou eu novamente procurando sua ajuda haha, eu consegui avançar bastante depois que eu arrumei o fundo, porém agora estou em um outro impasse, a movimentação que você mostrou é uma boa e simples, porém eu gostaria de uma mais suave, tipo, sem que se possa ver que ele está desenhando outra sabe? Que ele se movimentasse bem suave..
    Aí eu fiz isso:

    function keydownHandler(e){
    var key = e.keyCode;
    //Esquerda
    if(key === LEFT && key !== RIGHT){
    moveEsquerda = true;
    }
    //Direita
    if(key === RIGHT && key !== LEFT){
    moveDireita = true;
    }
    //Para Cima
    if(key === UP && key !== DOWN){
    moveCima = true;
    }
    //Para Baixo
    if(key === DOWN && key !== UP){
    moveBaixo = true;
    }

    function keyupHandler(e){
    var key = e.keyCode;
    //Esquerda
    if(key === LEFT && key !== RIGHT){
    moveEsquerda = false;
    }
    //Direita
    if(key === RIGHT && key !== LEFT){
    moveDireita = false;
    }
    //Para Cima
    if(key === UP && key !== DOWN){
    moveCima = false;
    }
    //Para Baixo
    if(key === DOWN && key !== UP){
    moveBaixo = false;
    }

    function move(){
    //Move para a esquerda
    if(moveEsquerda){
    p1.x–;
    }
    //Move para a direita
    if(moveDireita){
    p1.x++;
    }
    //Move para cima
    if(moveCima){
    p1.y–;
    }
    //Move para baixo
    if(moveBaixo){
    p1.y++;
    }
    }
    Ok, isso funcionou, porém o meu avatar ficou muito lento.. Alguma ideia de como posso aumentar a velocidade deles sem que perca a “suavidade”?

  3. Olá, estou tentando construir um jogo, mas minha imagem não carrega! Você poderia me ajudar? Estou fazendo baseado neste código, mas quando executo a tela fica em “Loading…”.

    Tirando a função preload e colocando o carregamento dentro da função draw, a imagem não aparece na tela! 😦

    var img;

    function preload() {
    img = loadImage(‘imagens/nave.png’);
    }

    function setup() {

    }

    function draw() {
    image(img, 10,20);

    }

  4. Oi @Larisse, tudo bem? Estava com o mesmo problema, provisoriamente coloquei a imagem direto na raiz e o endereço ficou só com o nome ( imagem.src = “dilminha.png”; ). Dê uma conferida no endereço da sua imagem, tente isto também: /../imagens/nave.png ou direto na raiz.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.