segunda-feira, 23 de março de 2015

[Game Maker] Aula 1: Meu primeiro personagem!

Olá! Neste guia, eu irei focar em dar dicas preciosas para alguém que está iniciando agora na GML, para começar com o pé direito!

Ao iniciar o trabalho em qualquer programa novo, é normal ficar perdido. O que fazer primeiro? Como fazer as coisas? O que é importante? Devo me preocupar com isso agora? São essas e muitas outras perguntas que passa pelas nossas cabeças. Mas, não se preocupe. Este guia foi feito para lhe abrir o caminho principal, do início até o Boss da fase! Não deixaremos nenhum item importante para trás!

Caso você não esteja muito familiarizado com a interface do Game Maker, sugiro que dê uma olhada na seção Introdutória antes. Então, vamos lá. Neste guia eu abordarei criação de personagens, inimigos básicos, obstáculos básicos, armadilhas básicas e salas simples. Para os mais avançados, já aviso que não entrarei em detalhes como Views, 

Índice:
1. Preparações básicas
2. Faremos o primeiro personagem

1. Preparações básicas:
Para viajarmos no conteúdo desse módulo inicial, vou propor um desafio essencial em qualquer jogo: criar o personagem controlável pelo jogador. Vale lembrar que eu sou um adepto ao estilo RPG Top-Down, então é neste estilo que eu irei usar para exemplificar.

Padrões do jogo:
Todos os jogos precisam de um padrão, para que permaneçam no mesmo estilo do começo ao fim. Para isso, você deve estabelecer primeiro alguns pontos de referência para depois sair criando todas as coisas.

No meu caso, o padrão de jogo é o seguinte:
Estilo: Top-Down (vista de cima, sem gravidade, personagem move-se para qualquer direção)
Tamanho da máscara: 16x16 (explicarei o que é isso já já!)
Origem da máscara: X:8 Y:8
Tamanho dos sprites: aproximadamente 16x16

Primeiro passo: criar uma sprite. Estas sprite deverá ser de tamanho padrão, contendo apenas uma subimagem de um círculo perfeito (é importante que ele esteja perfeito, cobrindo a imagem toda! Se precisar, use a tecla Shift enquanto faz o círculo) de qualquer cor opaca. Nas opções de Origem da imagem (Origin, como visto na imagem abaixo), marque x:8 y:8 (pois é o centro de uma imagem 16x16) ou simplesmente aperte o botão "Center" uma única vez. Algo parecido com isso:
Este tipo de sprite é importante para todos os jogos 2D, pois ele funcionará como uma "máscara" para todas as outras coisas. Em outras palavras, este círculo vermelho vai funcionar nos bastidores do jogo como uma espécie de área de contato para o jogador, inimigos, paredes, armadilhas... todos são círculos, só que o jogador não vê isso (claro que é possível criar infinitos tipos de máscaras, como quadrados, triângulos, maiores, menores, irregulares, ou todas elas juntas. Mas não iremos complicar muito por agora)!

Deixar a origem da imagem no centro é importante, como já dito, para o nosso progresso funcionar corretamente. Eu particularmente não tinha este recurso quando comecei a usar o Game Maker, e me acostumei a trabalhar sempre sem ele, deixando as origens das minhas imagens x:0, y:0. Isso, na verdade, sempre me dá trabalho adicional, mas o ponto que eu quero chegar é que deixarmos o ponto de origem da imagem centralizado é uma ótima convenção. Recomendo você começar desde já com este costume.

Conclua e coloque o nome da nossa máscara exatamente assim: "sprite_mask_padrao16x16". Feito isso, crie uma pasta chamada "Sprites importantes" na seção dos sprites (Botão Direito sobre a pasta fixa dos Sprites > "Create Group"). Coloque nossa máscara padrão nesta pasta de sprites importantes. A razão dela estar ali é que será um recurso que usaremos durante todo o jogo.

Só com isso já podemos ir para o próximo passo!

2. Faremos a primeira personagem
É mais que claro que quando pegamos um jogo qualquer com a personagem principal que aparentemente consegue destruir tudo, matar hordas de inimigos, gigantes, dragões, e todos os tipos de criaturas utilizando um arsenal mitológico de armas mágicas e poderes proibidos no qual ele vem adquirindo por toda sua aventura, e tudo isso sozinho, nos sentimos impressionados.

Muito bem, não vamos fazer nada disso. Ainda.

A verdade é que para fazer todos esses tipo de coisa, não é necessário ser nenhum Expert em GML. Basta dominar o básico, ter muita imaginação e muita paciência para aplicar o que você quer dentro do seu jogo. Como o objetivo deste guia é deixar as coisas claras, e não complicar sua vida, faremos uma personagem que apenas anda, ataca e coleta itens, ok? Muito bem, criaremos o primeiro objeto do jogo... a personagem!

Crie um objeto chamado "objeto_jogador_geral". Faça as coisas mais básicas nele já, colo marcar o check-up de Solid e adicionarmos a mask dele (que fizermos anteriormente). Como já dito, a máscara transforma o personagem num eterno quadrado para o funcionamento do jogo, que ajuda a impedir muitas situações de travamento em paredes e em inimigos enquanto anda ou ataca. Deixe-o de lado um pouco.

Voltamos ás sprites. Agora é a hora que os seus dotes artísticos falam mais alto, mas como o objetivo é simplificar, vamos usar o sistema de preguiçoso: uma única sprite animada para cada ação da personagem, que gira de acordo com a sua direção com uma função chamada image_angle. Vale lembrar que isso só funciona na versão paga do GM, e caso você não tenha adquirido-a, não se preocupe, pois nos guias seguintes abandonaremos o método do preguiçoso e usaremos algo que todos possam usar, algo que dá significantemente mais trabalho e resulta em cerca de 21 animações diferentes para uma única personagem.

Crie uma sprite chamada "sprite_jogador_andar". Faça-o no mesmíssimo padrão que fizemos a mask: tamanho 16x16, origem centralizada (não se esqueça!). Desta vez você pode colocar várias subimagens na sprite para fazer uma animação do personagem andando. Uma animação básica leva cerca de 4 subimagens, animações complexas podem levar números altos. De qualquer forma, isso não vai alterar na jogabilidade do nosso jogo. Um exemplo de animação básica que quebra um galho:

Se quiser salvar essa imagem e usá-la você mesmo:

Feito isso, deixe-a de lado e faremos outra animação necessária, seguindo sempre a mesma idéia. A nova sprite deverá se chamar "sprite_jogador_atacar". Neste caso, apenas 4 subimagens é muito pouco. Tudo vai depender da sua técnica e da sua capacidade artística. Outro detalhe, neste caso eu não usei uma sprite 16x16, e sim uma 20x20, para ter mais espaço para fazer a animação de ataque. É importante notar isso pois neste caso, a origem da imagem não pode ser centrelizada, e nem igual ás anteriores! (ou a imagem ficará deslocada quando o personagem atacar!). Caso você use a minha animação, o ponto de origem para que ela se alinhe com as outras animações é x:8, y:10. Caso você use a sua própria, você terá de alinhar a imagem conforme o necessário.

Imagem para salvar:

Certo, já temos as duas animações mais importantes! Normalmente uma personagem teria dezenas de animações, como pular, usar cada habilidade, morrer, descer e subir escadas, enfim, uma infinidade de ações visuais, mas não vamos nos preocupar com nada nisso agora. Vamos deixar só por isso mesmo.

Voltemos ao nosso "objeto_jogador_geral". Coloque a sprite padrão dele como "sprite_jogador_andar", e vamos começar a trabalhar encima dele. Primeiramente, deixe-me dar uma rápida refrescada de como funciona os eventos dos objetos:

1) O Create Event, Game Start e Room Start são eventos de inicialização. Tudo que você colocar dentro deles será feito em primeiro lugar, útil para estabelecer as regras.
2) O step event padrão é onde todos os códigos que precisam ser executados o tempo todo, de novo e de novo, até que o objeto seja destruído ou passe para uma outra room, como por exemplo scripts para os inimigos andar.
3) Os eventos de Colisão ocorrem ao bater o objeto em que a colisão é especificada, isso é muito importante para impedir que o jogador adentre a parede, por exemplo.
4) Existem outras dezenas de tipos de eventos, dos quais são úteis em situações específicas. Logo você descobrirá quando usar cada um deles, mas agora não é importante.

Para adicionar qualquer evento, apenas clique no botão "Add Event" e selecione qual você quer atribuir ao objeto. Usaremos todos os eventos vistos na imagem abaixo: Create Event, Step Event, Cinco funções para o teclado, o Event Other Animation End e um evento de Colisão. Eventos que ficam vazios somem automaticamente ao concluir a edição do objeto, então não se preocupe se você adicionar o evento errado. Por este mesmo motivo, não se preocupe em criar todos os eventos agora, fique calmo, e eu direi quando você deverá fazê-los.

Certo! Agora, no Create Event do "objeto_jogador_geral", crie uma folha de código vazia. Escreva apenas isso:

{
//Setup do personagem
var_atacando = false;
}

Acabamos de criar uma regra para o objeto. Agora ele reconhece uma nova variável, a tal da "var_atacando". Ele não sabe o que é isso, ele não sabe o seu propósito, e ele não faz a menor idéia de sequer vai usá-la alguma vez, mas o importante é que ele já conhece, e para ela foi atribuído um valor: false. Isso é equivalente ao binário 0. Para o computador, 1 e 0 é como sim ou não: tudo depende da pergunta. E agora que ele conhece a sua nova variável "var_atacando" e sabe que é "false", nós podemos utilizá-la para algum propósito. Para nós, é um pouco óbvio do por quê ela vai servir mais á frente, mas para o computador não - lembre-se sempre disso.

Agora vamos ao Step Event do objeto jogador. Crie outra folha de código vazia e este provavelmente será o maior código, onde atribuiremos um monte de novas regras que o nosso personagem deverá seguir para o jogo funcionar como o esperado. Estas regras serão totalmente lógicas: com um pouco de conhecimento básico em inglês e matemática, não será muito difícil você entender o que está se passando.

Eu também adicionei uma série de comentários no meio do código para ajudá-lo á entender a lógica. Para facilitar ainda mais (uau!), vamos dividir este código em quatro etapas só para questões didáticas (as quatro partes podem estar numa mesma folha de código, sem problema nenhum, porém você deve se lembrar que não é permitido separá-los em quatro grupos de {} chaves diferentes sem mais nem menos, logo evite copiar o código com as { chaves iniciais e as chaves finais }), assim, você poderá estudá-las separadamente sem precisar criar conexões entre elas.

Primeira etapa do step event: configuração rápida visual do jogador:

{
//1. Vira a sprite do jogador na direção que ele está no momento
image_angle = direction;
}

Antes de continuarmos o código do step event, vamos fazer com que o jogador se movimente. Para isso, temos que ensiná-lo como, e quando se movimentar. Adicione agora quatro eventos de teclado: um para virar á esquerda, outro á direita, outro para se mover á frente e outro para recuar. Eu recomendo as setas do teclado: Keyboard Up, Keyboard Down, Keyboard Left e Keyboard Right (use a imagem acima para ajudar na identificação se necessário). Você também pode usar o padrão "WASD".

No evento do botão para virar á esquerda (left), adicione o seguinte código:
{
//Lembre-se que uma rotação circular completa é 360 graus. Isso explica o número abaixo.

if direction < 360
    direction += 9;
else
    direction = 0;
}

No evento do botão á direita (Right), o exato oposto do código acima:
{
if direction >= 0
    direction -= 9;
else
    direction = 360;
}

No evento do botão para mover-se á frente (Up):
{
//A velocidade deve ser proporcional ao tamanho dos sprites que você vai usar. Esse valor mostra quantos pixels o objeto se move por ação. Neste caso, como o jogo utiliza um padrão de tamanho 16x16, 3 pixels por movimento é uma velocidade agradável: nem muito lerdo, nem muito rápido.

speed = 3;
}

E por fim, no evento de recuar (mover-se para trás, Down).
{
//Velocidade negativa = move-se na direção contrária. É interessante sempre colocar uma velocidade menor neste caso, pois é comum a personagem andar mais lenta para trás.

speed = (-2);
}


Muito bem. Agora, que atribuímos ás teclas direcionais a função de dar direção e velocidade ao nosso personagem, precisamos colocar nele um freio. Não fazer isso seria igual fazer um carro que só possui o acelerador: ele não para mais. E não existe ar no nosso jogo, logo, é quase uma simulação de vácuo: o personagem nunca vai perder essa velocidade adquirida.

Isso, é claro, não está certo. Pelo menos não nesta ocasião, então, para concertarmos isso, voltaremos ao código do Step Event para completá-lo mais uma vez. Já aviso: acostume-se sempre em viajar por entre os diferentes eventos ao montar qualquer coisa: nenhum evento age completamente isolado, um está dependendo do outro.

Segunda etapa do step event: questões de movimentação e de animação de movimentação

{
//Vale lembrar que o Game Maker possui uma série de variáveis pré-estabelecidas, como por exemplo: speed, image_speed, image_index, direction, etc...

//2. Se a speed do jogador for maior ou menor que zero...
if (speed > 0 || speed < 0)
    {
    
    //Diminui a velocidade do personagem, como um carro: desacelera ele quando o jogador parar de acelerar
    if speed > 0
        speed -= 1;
        
    //Velocidade negativa: anda na direção oposta, ou seja, para trás.
    if speed < 0
        speed += 1;
    
    //Faz com que a animação de andar aconteça
    image_speed = 0.25;
    
    }
}

Se você analisar o código acima, perceberá diversas programações lógicas extremamente simples que, como já dito, com um conhecimento básico em inglês e matemática, mesmo sem os meus comentários, você é capaz de perceber o que cada parte do código faz. Vale lembrar que ao montar um código, a ordem da cadeia lógica pode ser importante.

Agora, vamos deixar novamente o Step Event de lado. Vamos adicionar uma nova habilidade ao nosso personagem. Aquela que estávamos planejando desde o início, no Create Event: permitir que o personagem possa atacar. Nós já trabalhamos na animação do ataque do personagem anteriormente, agora é hora de a implantarmos nele. Para fazermos isso, nós precisaremos criar um novo objeto: o "objeto_ataque_geral". Como o próprio nome já diz, ele será o que de fato irá machucar os inimigos, e os inimigos o usarão para nos machucar.

O objeto_ataque_geral deverá ter a Mask e a Sprite da nossa "sprite_mask_padrao16x16", e também aplicaremos um novo conceito: desmarcaremos a opção Visible, ou seja, em código, visible = false. Quando não é visible, ele ainda existe, ele ainda está lá, e ele ainda faz tudo o que deve fazer. A diferença que o jogador não pode vê-lo, e é isso que nós queremos que a área do nosso ataque seja: algo que exista, mas que não fique visível ao jogador.

No Create Event do objeto_ataque_geral também usaremos algo extremamente útil, os Alarms. Ao todo, existem 12 alarms diferentes. Alarms são eventos que são ativados depois de um período determinado, executam o código atribuído á eles e depois só são executados novamente se forem acionados novamente. É exatamente igual um despertador da vida real: a diferença que este daqui não serve para fazer barulho. Os alarms são acionados pelo seguinte código:

Padrão: alarm[numero do alarm, entre 0 e 11] = (segundos que o alarm demora para acionar*30)
Exemplos: alarm[0] = 45; alarm[3] = 180; alarm[2] = 30; alarm[11] = 300 (Demoram 1.5, 6, 1 e 10 segundos para serem acionados, respectivamente). Bem, só usaremos um único Alarm por agora. Pode ser qualquer um, mas por convenção usaremos o alarm[0].

O alarm[0] do objeto_ataque_geral o destruirá, para que o ataque não fique existindo para sempre. Neste caso, atribuiremos uma vida útil rápida de um ataque, neste caso, 1/6 de segundo é o suficiente. No Create Event do objeto_ataque_geral colocaremos então:

{
//Lembre-se: 30 = 1 segundos, 60 = 2 segundos, 150 = 5 segundos, 300 = 10 segundos...)
alarm[0] = 5;
}

Agora, criaremos o evento do Alarm 0 ainda no objeto_ataque_geral e colocaremos o seguinte nele:
{
instance_destroy();
}

Como ainda não temos nenhum inimigo, deixaremos o ataque por isso mesmo. A verdade é que só precisamos disso para terminarmos a nossa personagem, depois nos preocupamos com o resto. Deixe o objeto_ataque_geral de lado e voltemos ao objeto_jogador_geral.

Muito bem. Agora vamos criar um novo evento de teclado. Eu escolhi a tecla Barra de Espaço para funcionar como tecla de ataque, mas você pode escolher qualquer outra de sua preferência.

No evento da tecla de ataque, atribuiremos o seguinte código:

if var_atacando == false
    {
    //Avisamos ao jogo que o personagem iniciou um ataque.
    var_atacando = true;
    
    //Criaremos uma instância do objeto_ataque_geral. "aaa" é como queremos que o jogo interprete o ataque criado. Pode ser qualquer outro nome, como "i", "yy", "var_ataque", "ataquecriado", etc...
    aaa = instance_create(x, y, obj_ataque_geral);

    //Então atribuímos variáveis para o ataque criado, no qual o jogo aprendeu que é o tal do "aaa".
    aaa.speed = 4;
    aaa.direction = direction;
    
    }

Certo. Agora, o jogador efetivamente "ataca". Mas para que isso seja 100%, precisaremos retornar ao Step Event para concluirmos as últimas etapas que darão vida ao personagem. Adicione as últimas peças de códigos que concluem a lógica:

Terceira etapa do step event: alternar corretamente entre a animação de andar e atacar
{
//3. Se o jogador estiver atacando...
if var_atacando == true
    {
    //Animação de atacar...
    sprite_index = spr_jogador_atacar;
    image_speed = 0.25;
    }
else
    {
    //Se não... ele tem a animação de andar.
    sprite_index = spr_jogador_andar;
    }
}

Última etapa do step event: toques finais para sofisticar mais a animação do personagem e evitar erros
{
//4. Caso o jogador não esteja andando nem atacando, a velocidade da animação dele zera e a subimagem volta ao zero
if (speed == 0 && var_atacando == false)
    {
    image_speed = 0;
    image_index = 0;
    }
}

Ótimo! Antes de realizar um rápido teste, temos que fechar o círculo ainda para que não haja nenhum erro. Ainda falta uma coisa importante! Veja só, para nós, o circuito se fecha no momento que o jogador lança o ataque, e este é destruído, e o jogador volta á sua posição original, pronto para realizar outro golpe, certo? Certo! Mas para o computador, não é tão simples. Ele não compreende isso, e por isso precisamos ensiná-lo o momento certo em que o ataque do jogador é finalmente finalizado. Na etapa do botão de ataque, como fizemos acima, nós avisamos que o jogador iniciou um ataque. Agora, temos que avisar que o ataque é finalizado no exato momento que o jogador guarda o seu punhal no bolso. Para a nossa sorte, existe um Evento que demarca este exato momento: Animation End.

Adiciona o evento Animation End no objeto_jogador_geral e adicione o seguinte código:

{
if var_atacando == true
    var_atacando = false;
}

Pronto. Agora o círculo se fecha: temos uma história com começo, meio e fim. Quando isso acontece, é sinal de que algo já está em pleno funcionamento e pronto para ser testado. Então, o que está esperando?


Salve o seu progresso, coloque o objeto_ataque_geral como visible temporariamente para que você conseguia ver se realmente existe um ataque saindo na direção certa da personagem enquanto ela ataca. Crie uma room qualquer e dê o nome de rm_testroom. Durante o teste, observe se a animação da personagem volta à posição original após o ataque, observe se ela anda em todas as direções (inclusive para trás).

Caso tudo ocorra bem, parabéns! Você conseguiu, e o mérito foi todo seu! Caso algo tenha dado errado, analise o que não está dando certo, volte atrás no passo que corresponde ao erro e observe o que está faltando.

Acho que estamos mais que prontos para ir para o próximo passo!

2 comentários:

  1. Olá amigo! estou tentando fazer alguma coisa, mas tá dificil, o tutorial é muito bom (parabéns), sou eu que cometo muitos erros daí eu começo tudo de novo rsrsrsrsrsr.
    Más um dia eu chego lá!
    Valeu: Renato.

    ResponderExcluir
  2. Estou com esse erro no momento do ataque:

    FATAL ERROR in
    action number 1
    of Keyboard Event for Key
    for object object_jogador_geral:
    Push :: Execution Error - Variable Get -1.obj_ataque_geral(100001, -2147483648)
    at gml_Object_object_jogador_geral_Key_SPACE_1 (line 8) - aaa = instance_create(x, y, obj_ataque_geral);

    ResponderExcluir

Dúvidas? Pergunte!
Ajudou? Agradece!
:]