Como fazer um jogo de plataforma - Parte 2

    Compartilhe

    jiraya
    Administrador
    Administrador

    Mensagens : 1299
    Credibilidade : 54

    Como fazer um jogo de plataforma - Parte 2

    Mensagem por jiraya em Ter Fev 08, 2011 5:37 pm

    [Autor: KJr ]
    Nessa segunda parte, faremos com que o herói ataque, de duas formas, curta e longa distância.
    Vamos continuar a trabalhar por cima do projeto da primeira parte do tutorial, onde o herói já se move e pula.


    Parte 2 - Ataques
    Abra o Game Maker e o projeto do primeiro tutorial. Baixe o arquivo com as imagens que serão usadas nessa parte do tutorial aqui.
    Primeiro o ataque à distância.
    Crie um novo sprite, que será o tiro. Use o arquivo spr_shot e dê esse nome ao sprite.
    Crie também o sprite spr_player_gun, que será usado quando o herói tiver a arma em punho.
    Vamos aos objetos.
    Crie um objeto shot, o tiro.
    Nesse momento, em que não vamos fazer inimigos ainda, bastaria escolher o sprite do tiro e dar OK.
    Para não sobrecarregar o processamento, vamos otimizar nosso jogo, um pequeno detalhe. Se o objeto shot sair de um room, e portanto ficar "fora do jogo", destruímos esse objeto.
    É simples: adicione no objeto shot o evento Other > Outside room, e coloque o código seguinte:
    Código:
    instance_destroy()
    O evento Outside room ocorre exatamente quando o objeto está fora da room. A função instance_destroy() destrói o objeto.
    O tiro está pronto, o resto faremos nos eventos do herói. Voltaremos ao tiro quando chegarmos na parte de inimigos.
    No objeto player, vá no evento Create, e crie uma variável atirando, que vai indicar se o herói está ou não atirando.
    Crie uma outra variável atacando que vai indicar se o herói está ou não atacando com a espada, vamos usar essa depois.
    Deve ficar assim no final:
    Código:
    direita = 1
    noChao = 0
    atirando = 0
    atacando = 0
    Repare que as variáveis criadas até agora refletem os estados do herói, através do valor delas você sabe exatamente o que ele está fazendo.
    Agora faremos algo semelhante ao que fizemos para mover o personagem.
    O que queremos é o seguinte: se o herói estiver no chão e o jogador pressionar <A>, o herói atira.
    Vá no evento Step, e abaixo do que já está lá, adicione este código (você pode adicionar outra ação Execute a piece of code, se preferir):
    Código:
    if noChao && keyboard_check_pressed(ord('A')) {
    }
    Isso satisfaz a nossa condição para atirar, mas a parte complicada é fazer o ato de atirar em si. Então, passo a passo:
    1 - Vamos alterar o estado do herói. Isso é, faremos com que a variável atirando seja verdadeiro. Poderíamos fazer simplesmente atirando = 1 e serviria, mas como qualquer valor positivo é verdadeiro (vide a [url=http://]primeira parte do tutorial[/url]), vamos aproveitar essa mesma variável para controlar o tempo que o herói fica atirando.
    Faremos atirando = 10, e a cada frame, diminuímos 1 dessa variável, assim ele vai ficar de arma em punho por 10 frames. No fim do tutorial, altere para atirando = 50 para ver a diferença.
    2 - Vamos criar um objeto de tiro, e fazer com que ele se mova na direção em que o herói estiver olhando na hora.
    A função instance_create(X,Y,objeto) cria um objeto na posição dada por X,Y, e retorna o ID desse objeto. O ID pode ser usado para lidar com esse objeto, alterá-lo.
    Vamos usar a variável direita para saber a direção do movimento do tiro. Trigonometria básica, 0º aponta para a direita e 180º, esquerda.
    Então, se direita for 1, direção do tiro é 0. Se direita for -1, direção é 180.
    Você pode fazer usando if/else, mas tem um jeito mais rápido, em uma linha só, que é o que eu vou usar. Fica como exercício entender o que eu fiz, e tentar fazer do outro jeito, usando if/else.

    Depois de definir a direção do tiro, definimos também a velocidade.
    Um outro jeito de fazer é definir apenas a variável hspeed, velocidade horizontal, mas aí não usaria a variável direction. Tente fazer, como exercício.
    Então, o código ficaria assim:
    Código:
    if noChao && keyboard_check_pressed(ord('A')) {
    atirando = 10
    var tiro;
    tiro = instance_create(x,y,shot)
    tiro.direction = 270 + direita * 90
    tiro.speed = 15
    }
    Usei o comando var para declarar uma variável "descartável", local. Eu só uso ela nesse momento, para guardar o ID do objeto que eu criei, para poder alterá-lo depois.
    Outro comando novo foi usado em tiro.direction e tiro.speed. Você usa a estrutura objeto.variável para acessar variáveis de um objeto através de outro.
    Nesse caso eu precisava alterar uma variável do objeto shot enquanto escrevia códigos do objeto player. O comando with() é outro jeito de fazer isso, veja o Help para mais detalhes.
    Quase pronto. Se você testar agora, verá que o sprite não muda na hora que ele atira.
    Você já deve imaginar como corrigir isso. Já criamos o sprite no início, basta editar o evento Draw.
    Código:
    if noChao {
    if atirando {
    draw_sprite_ext(spr_player_gun,image_index,x,y,direita,1,0,c_white,1)
    } else {
    draw_sprite_ext(spr_player,image_index,x,y,direita,1,0,c_white,1)
    }
    } else {
    draw_sprite_ext(spr_player_jump,image_index,x,y,direita,1,0,c_white,1)
    }
    Temos uma nova possibilidade quando o objeto está no chão. Se ele estiver atirando, desenhamos spr_player_gun, senão, o sprite normal.
    Teste novamente para notar dois problemas que se destacam.
    Um, uma vez que você atira, o sprite não volta ao normal.
    Dois, o tiro não parece sair da arma, e sim de "dentro do herói".
    Para o sprite voltar ao normal, basta lembrar de um detalhe que eu mencionei. Quando o jogador aperta <A> e atira, definimos atirando como 10, e não mexemos mais nisso.
    Do jeito que está, atirando vale 10 eternamente, e o sprite não volta ao normal, com razão (o Game Maker sempre tem razão, por mais absurdo que o erro pareça).
    No evento Step, abaixo do que já estiver lá, adicione isso:
    Código:
    if atirando {
    atirando -= 1
    }
    Assim, se estiver atirando, descontamos 1, e como planejamos, depois de 10 frames, ele volta ao normal.
    Teste de novo, só pra ver o resultado.
    Segundo problema, o tiro não sai da arma.
    Clique duas vezes para editar o sprite spr_player_gun.
    Veja onde estão as coordenadas de origem do sprite (no centro, se você lembrou de clicar em Center, 32;32).
    Veja onde estão as coordenadas da arma, de onde gostaríamos que o tiro saísse. Digamos, 60;35.
    Quando usamos, num objeto, as variáveis x e y para saber a posição atual, elas indicam exatamente as coordenadas de origem do sprite, porque é onde ele está sendo desenhado.
    Se quisermos saber as coordenadas de um "outro lugar" no sprite, basta adicionar a diferença.
    Nesse caso, lá onde colocamos instance_create(x,y,shot), no evento Step, vamos colocar instance_create(x+28,y+3,shot).
    Como a coordenada central é 32, 32 mais 28 dá o X valendo 60, que é onde queremos que o tiro saia. Mesma coisa pro Y (32 + 3= 35).

    Não esqueça de centralizar de novo a origem do sprite (clique em Center).
    Teste e descubra o último detalhe que está faltando.
    Exatamente, você acertou ... atirando para a direita funciona bem, mas quando ele olha para a esquerda ...
    Bem, se usamos x+28 para o tiro sair um pouco mais para a direita, usaremos x-28 para a esquerda.
    Mas notem, novamente, a possibilidade de uma otimização, um macete.
    A variável direita vale 1 ou -1. Se multiplicarmos 1 ou -1 por 28, temos como resultado 28 ou -28, exatamente o que precisamos, na ordem certa.
    Fica assim:
    Código:
    instance_create(x+direita*28,y+3,shot)
    Por isso eu fiz questão de explicar a questão do verdadeiro e falso no início, e definir direita como 1 ou -1. Facilita as coisas. Demais.
    Bom ... teste novamente, só pra se certificar.
    O ataque de longa distância está pronto. Voltaremos a ele na próxima parte, com os inimigos.
    Vamos só adicionar outra coisa. Você deve ter reparado que o tiro atravessa os blocos. Seria interessante se ele explodisse ao colidir.
    Façamos isso.
    Vá no objeto shot, evento Collision > block:
    Código:
    effect_create_above(ef_smoke,x,y,.2,c_gray)
    instance_destroy()
    A função effect_create_above cria um efeito, nesse caso de fumaça, mas pode ser de nuvens, explosões, chuva, neve, estrelas, faíscas, etc.
    Agora, o ataque de curta distância.
    Crie um novo sprite, spr_player_atk. Esse sprite será usado na animação de ataque do herói, que nesse caso vai usar um "espada" para atacar de perto.
    Vamos ao objeto player.
    No evento Step, adicionaremos um código para fazer algo parecido com o tiro. Alteraremos o estado do herói, fazendo com que ele esteja atacando.
    Depois altera-se o evento Draw, adicionando uma ramificação para o caso do herói estar atacando, quando desenharemos o spr_player_atk, que acabamos de criar.
    Evento Step:
    Usando a tecla <S>, se estiver no chão, e não estiver atirando, o jogador faz o herói atacar.
    Código:
    if noChao && keyboard_check_pressed(ord('S')) && !atirando {
    atacando = 20
    }
    if atacando {
    atacando -= 1
    }
    A segunda parte é para que, como no ataque de longa distância, o herói não fique atacando eternamente.
    Evento Draw:
    Código:
    if noChao {
    if atirando {
    draw_sprite_ext(spr_player_gun,image_index,x,y,direita,1,0,c_white,1)
    } else if atacando {
    draw_sprite_ext(spr_player_atk,image_index,x,y,direita,1,0,c_white,1)
    } else {
    draw_sprite_ext(spr_player,image_index,x,y,direita,1,0,c_white,1)
    }
    } else {
    draw_sprite_ext(spr_player_jump,image_index,x,y,direita,1,0,c_white,1)
    }
    Adicionei outra possibilidade, se estiver no chão e atacando, o sprite é o de ataque.
    Teste o jogo. Talvez você tenha notado um problema. A animação não acontece. Para que ela aconteça, temos que alterar o valor de image_speed que, para quem não se lembra, controla a velocidade de animação.
    Se ele estiver atacando, queremos image_speed valendo, digamos, 0.2. Vamos fazer uma mudança no nosso sistema, visando organização. Vamos tratar das variáveis image_speed/image_index separadamente.
    Para tal, vamos criar outra variável de estado. Vá no evento Create e adicione uma variável que indica se o herói está se movendo.
    Código:
    movendo = 0
    Agora, no evento Step, reveja a parte do código que move o herói:
    Código:
    if keyboard_check(vk_right) {
    direita = 1 //true
    x += 5
    image_speed = .3
    } else if keyboard_check(vk_left) {
    direita = -1 //false
    x -= 5
    image_speed = .3
    } else {
    image_index = 0
    image_speed = 0
    }
    Substitua por:
    Código:
    if keyboard_check(vk_right) {
    direita = 1 //true
    x += 5
    movendo = 1
    } else if keyboard_check(vk_left) {
    direita = -1 //false
    x -= 5
    movendo = 1
    } else {
    movendo = 0
    }
    Agora a variável representa o estado de movimento do herói.
    Ainda no evento Step, adicione mais esse código, no final:
    Código:
    if atacando {
    image_speed = .2
    } else if movendo {
    image_speed = .3
    } else {
    image_index = 0
    image_speed = 0
    }
    Pronto. Se estiver atacando, image_speed vale tal coisa, se estiver andando, vale outra coisa, senão, vale zero.
    Antes de terminarmos, vamos só alterar mais algumas coisas, detalhes.
    Vamos impedir que o herói se mova caso esteja atacando ou atirando. E vamos impedir que o herói atire quando estiver atacando.
    Para impedir que ele ande caso esteja atacando/atirando, no evento Step, o código de movimento deve ser assim:
    Código:
    if keyboard_check(vk_right) && !(atacando || atirando) {
    direita = 1 //true
    x += 5
    movendo = 1
    } else if keyboard_check(vk_left) && !(atacando || atirando) {
    direita = -1 //false
    x -= 5
    movendo = 1
    } else {
    movendo = 0
    }
    A condição adicionada: && !(atacando || atirando) , significa "e não (atacando ou atirando)", que é o mesmo que "não atacando e não atirando".
    Para impedir que ele atire enquanto ataca:
    Código:
    if noChao && keyboard_check_pressed(ord('A')) && !atacando {
    atirando = 10
    var tiro;
    tiro = instance_create(x+direita*28,y+3,shot)
    tiro.direction = 270 + direita * 90
    tiro.speed = 15
    }
    A condição && !atacando dá conta de fazer o que queremos.


    É só isso. Basicamente o que fizemos foi criar as bases para a criação (na verdade, destruição) de inimigos, no próximo capítulo.
    Até agora o efeito do que fizemos aqui é apenas visual. Só vai ser funcional quando houver inimigos para matar.
    Dúvidas, comentários, sugestões, elogios, críticas, opiniões ... postem aí, ou mandem PM, muito provavelmente vou responder.
    Até a próxima parte, com inimigos prontos para morrer.

    Lyou
    Membro
    Membro

    Mensagens : 1
    Credibilidade : 0

    Re: Como fazer um jogo de plataforma - Parte 2

    Mensagem por Lyou em Sab Nov 10, 2012 5:53 pm

    Quando chega a parte 3 Jiraya *----* ? Questâo
    Thank You! Confiante

      Data/hora atual: Qua Dez 07, 2016 7:24 am