Mostrando postagens com marcador Game Maker. Mostrar todas as postagens
Mostrando postagens com marcador Game Maker. Mostrar todas as postagens

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!

domingo, 22 de março de 2015

[Gamer Maker] Aula 0: aprendendo a lidar com GML!

Neste prefácio da Apostila de manuais de GML, eu irei passar um apanhadão sobre como funciona a GML e entregar á vocês noções básicas importantes que irão adiantar a sua vida.

A GML, ou Game Maker Language, é na verdade muito simples de primeira instância. Ela foi planejada para facilitar a vida de novos programadores, ao mesmo passado que adianta o trabalho de programadores experientes e da á eles liberdade ilimitada quando o assunto é 2D. O Game Maker na verdade foi foi para ser usado principalmente em seu sistema fácil de Drag'n'Drop, ou seja, você cria um jogo somente pegando e puxando ícones que executam determinadas funções e altera os valores de acordo com a sua vontade. É possível fazer um jogo perfeito e extremamente funcional sem ter a mínima noção sobre escrever códigos ou coisas do tipo, porém, é muito importante você se acostumar a criar seus jogos diretamente da GML, pois assim você não se limita e acelera em muito o seu trabalho.

Índice:
1. Termos comuns
2. Lógica e operações matemáticas
3. Constantes e variáveis pré-definidas
4. Finalização

1. Termos comuns:
O executável do GML funciona na base de objetos, rooms e scripts. O jogo só lê as instâncias que estão contidas na room atual, e as instâncias funcionam á base dos scripts. Aliás, você sabe o que é room e instância e quaisquer seja esses termos?

Vamos com calma então. Primeiro, deixe-me dar um pequeno "dicionário" de termos muito utilizados.

Instância: nome dado ao representante do objeto dentro da room, enquanto o jogo roda. Por exemplo, existe o objeto obj_inimigo_dragao. Dentro de uma room, chama rm_ninho_do_dragao, existem 10 instâncias do obj_inimigo_dragao. Você programa uma vez, e depois espalha pelas rooms.

Room: sala, ambiente, local. Pode ser um ambiente jogável, uma sala de menu, uma sala de cinemática, uma sala de opções do jogo, etc.

Views: são câmeras. Podem ser fixadas em algum lugar para manter o jogador com a tela fixa, ou podem ser atribuídas á um objeto, como o jogador, por exemplo, para fazer com que ela o siga durante a room.

Eventos: ocasiões em que os códigos são executados nos objetos. Exemplo: você atribui um código para quando o inimigo é criado, para definir as variáveis necessárias para o seu funcionamento, um outro código para ser executado constantemente enquanto ele existir para tornar sua I.A funcional, e um outro código para quando sua instância for destruída, para criar uma pilha de moedas.
Visible: torne o objeto visível ou invisível. Um objeto invisível ainda é completamente existente e possui funções de colisão. É muito útil para criar switches invisíveis e acionamento de armadilhas, por exemplo.

Mask: Área de colisão do objeto, independente do seu Sprite.

Parent: "Pai" do objeto, no qual ele irá copiar todos os eventos dos quais ele não tem nenhum código adicionado. Extremamente útil, pois com este recurso você pode, por exemplo, configurar apenas três tipos de inimigos e depois criar centenas de outros inimigos ligados apenas aos três iniciais, apenas com modificações em sua vida, dano, experiência, velocidade, sprites, habilidades... evitando assim ter que fazer as mesmas coisas diversas vezes. Isso é útil também para criar uma classe inteira de eventos em comuns, como por exemplo os "itens", os "npcs", os "obstáculos", nos quais todos se comportarão quase da mesma maneira, modificando uma coisa ou outra entre cada um.

Solid: variável pré-definida que interfere em ações de colisões. Um objeto solido é tratado pelo jogo como algo que não deve permitir a passagem de outros objetos no qual ele possui algum evento ou relação de colisão, porém isso não significa que ele seja impenetrável e que outros objetos que não possuem relação com ele passem por cima, ignorando-o.

Depth: profundidade visual do objeto. Quanto mais Depth, mais abaixo o objeto fica. Por exemplo: um objeto de depth 1 fica sempre, independente da situação, visualmente abaixo de qualquer objeto de depth 0 ou maior. Um objeto com depth -10000 fica sempre acima visualmente de qualquer objeto de depth -9999 ou menos. Isso é muito útil principalmente de criar enfeites que devem sempre permanecer abaixo de tudo, como flores, para impedir que itens fiquem encima das personagens ou que a interface do jogo fique com coisas atrapalhando.

Persistent: um objeto persistent é transferido de room em room, mantendo sua posição (X,Y). Você pode usar isso para transportar controladores invisíveis importantes ao seu jogo (como um objeto que segura dados de pontuação e desempenho do jogador) ou para transportar certos objetos á uma room específica e depois "desligar" seu Persistent, deixando-o lá. Com isso, me vem à mente trabalhar com personagens que Quests, por exemplo, que geralmente o seguem até o local designado e depois não aparecem mais. Uma room também por ser persistent, ou seja, ela se mantém da mesma maneira que foi deixada quando o jogador reentra, útil para salvar, por exemplo, uma casa pessoal personalizada do jogador ou coisas do tipo.

2. Lógica e operações matemáticas
A lógica da GML também é bem simplificada, não é a toa que é uma boa porta para a entrada de novos programadores. Ela utiliza-se da linguagem matemática simples para fazer suas atribuições, como > (maior), < (menor), == (igualdade comparativa), = (atribuição de um valor)... segue abaixo uma lista destas igualdades lógicas e operações matemáticas:

Comparações lógicas:Significado e uso:
Maior
<Menor
>=Maior ou Igual
<=Menor ou Igual
==Igualdade comparativa
=Atribuição de um valor (nova igualdade)
+=Soma
-=Subtração
*Multiplicação
/Divisão
|| (ou or)"ou"
&& (ou and)"e"
!Inversão. Transforma true em false e vice-versa, e igualdades em desigualdades.
sqrt(x)Raíz quadrada de X
sqr(x)X ao quadrado (X²)
random(x)Valor real aleatório entre 0 e X.
random(x,y)Valor real aleatório entre X e Y.
irandom(x)Valor real inteiro entre 0 e X.
irandom_range(x,y)Valor real inteiro entre X e Y.
round(x)Arredondamento para mais ou para menos.
ceil(x)Arredondamento para mais.
floor(x)Arredondamento para menos.
mean(x,y,z,w...)Moda entre os valores.
median(x,y,z,w...)Mediana entre os valores.
min(x,y,z,w...)Retorna o menor valor.
max(x,y,z,w...)Retorna o maior valor.
choose(x,y,z,w...)Retorna um valor aleatório dentre os especificados.
Entre outros mais, como sin, cos, tg, log...

3. Constantes e variáveis pré-definidas:
Já na parte das variáveis, saiba que todos os objetos do Game Maker são criados já com um pacote de variáveis pré-definidas (claro que o programador pode adicionar infinitas mais, quando quiser). Isso tem um lado bom e um ruim. O lado bom é que pode poupar ao programador de executar ações básicas desnecessárias, como atribuir uma variável de velocidade á um objeto toda vez que quiser que ele se mova, ou atribuir uma nova variável toda vez que o programador quiser que ele torne-se invisível ao jogador. O lado ruim é o custo de memória usada muitas vezes para nada, pois cada instância vem com um pacote de variáveis nas quais o programador sequer irá mexer alguma vez. 

Segue um listão então das variáveis e constantes pré-definidas:

Constante ou variável pré-definida:Significado e uso:
ifCondição"se".
Exemplo: if speed > 0 {image_speed = 1}
Se a velocidade for maior que 0, a velocidade da animação será de 1:1 ao framerate da room.
elseCondição "ou", "se não".
Exemplo: if speed < 0 {image_speed = 0} else {image_speed = 1}
Se a velocidade for menor que 0, a velocidade da animação será nula, se não, ela será de 1:1 ao framerate.
while e doCondição "enquanto... for... faça..."
Exemplos: while image_speed > 1 do {image_speed -= 0.1}
Enquanto a velocidade de imagem for maior que 1, faça ela diminuir 0.1.
switchConjunto compacto e de rápida execução de vários "if" e um "else" para uma única variável.
Exemplos: switch(var_nota)
{
case 8: var_message="Melhore um pouco!"; break;
case 9: var_message="Quase lá!"; break;
case 10: var_message="Excelente!"; break;
default: var_message="Estude mais!"; break;
}
trueEquivale á 1.
Exemplo: (var_teste = 1) é o mesmo que (var_teste = true)
falseEquivale á 0.
Exemplo: (var_ligado = 0) é o mesmo que (var_ligado = false)
repeat(x)Repete a próxima ação ou bloco X número de vezes.
Exemplos: repeat(3) instance_create(x,y,obj_enfeite);

repeat(global.var_numero_de_pontos)
{
obj_jogador.var_recurso_energia += 1;
obj_jogador.var_recurso_forca += 1;
obj_jogador.var_fome -= 10;
}
globalAlgo que engloba o próprio jogo, e não uma instância ou room específica.
Exemplos: global.var_numero_de_pontos += 100;
global.var_numero_da_fase = 3;
global.var_nome_do_jogador = "Felipe";
allTodas as instâncias da sala.
xCoordenada X (horizontal).
yCoordenada Y (vertical)
xstartValor inicial X da instância no momento que foi criado na room. Não pode ser alterado.
ystartValor inicial Y da instância no momento que foi criado na room. Não pode ser alterado.
selfA própria instância, retorna em forma do id dela.
Exemplo: uuu = instance_create(x, y, obj_magia_de_cura)
uuu.var_alvo_para_curar = (self);
idO número da instância. Funciona como "RG" dela. Nenhuma instância, nunca, tem o mesmo id igual, ou seja, é uma boa forma de acrescentar funções únicas á uma instância específica.
Use sempre entre ( ) parênteses. (id).
nooneNada e Ninguém. Normalmente usado para zerar uma variável, completamente.
Exemplo: var_meu_alvo = noone;
if var_tesouro_do_bau != noone {instance_create(x, y, var_tesouro_do_bau) }
otherUsado só em eventos de colisões, refere-se ao objeto em que você colidiu.
Exemplos: with other do instance_destroy();
other.var_recurso_vida -= 1;
orEquivale á ||, "ou".
andEquivale á &&, "e".
livesVariável global de "vida" pré-definido.
Exemplos: if lives == 0 {room = rm_gameover;}
lives += 4;
lives -= 1;
healthVariável global de "energia" pré-definido. Mínimo de 0 e máximo de 100.
Exemplos: if health == 0 {room_restart(); lives -=1; sound_play(snd_morte)}
scoreVariável global de "pontuação" pré-definido.
Exemplos: 
score += 50;
score += irandom(80);
score += irandom_range(20, 200);
mouse_xCoordenada X do mouse. 
mouse_yCoordenada Y do mouse. 
sprite_indexSprite no qual o objeto está usando no momento. Pode ser usado para definir um novo sprite existente naturalmente.
Exemplos: if sprite_index == spr_super_personagem {var_poder = 90;}
sprite_index = spr_item_poder;
sprite_index = 68;
mask_indexMask no qual o objeto está usando como área de colisão. Assim como o sprite, pode ser normalmente trocada.
Exemplos: if sprite_index = spr_objeto_grande {mask_index = spr_mask_grande;}
mask_index = spr_mask_circulo32x32;
image_indexNúmero da subimagem do sprite atual. Pode ser alterada normalmente.
Exemplos: if speed == 0 {image_speed = 0; image_index = 0;}
if image_index == 0 {var_velocidade += 1;}
image_speedNúmero que é constantemente adicionado ao image_index para ocorrer a animação.
Exemplos: image_speed = 0.25;
if image_speed <= 0 && speed > 0 {image_speed = 0.5;}
image_numberNúmero de subimagens total do sprite utilizado no momento. Embora uma "variável", não pode ser alterada durante o jogo.
image_angleÂngulo, em graus, da imagem. Lembre-se que 360º = volta completa = 0º.
Exemplos: image_angle += 10;
image_angle -= 36;
image_angle = 75;
image_angle = direction;
image_alphaTransparência da imagem, entre 0 (totalmente invisível) e 1 (totalmente opaco).
Exemplos: if var_morto == true 
{
image_alpha -= 0.1; 
if image_alpha <= 0 {instance_destroy();}
}

image_alpha = 0.5;
directionDireção, em graus, do objeto. Ou seja, para onde está virada a "cara" dele.
image_xscaleProporção de tamanho de imagem:tamanho original, horizontalmente.
Exemplos: image_xscale = 2;
image_xscale += 1;
image_yscaleProporção de tamanho de imagem:tamanho original, verticalmente.
Exemplos: image_yscale = 2;
image_yscale += 1;
solidVariável que interfere em eventos de colisão e de movimentação. Um objeto sólido é tratado diferentemente nessas ocasiões, mas não necessariamente é impenetrável.
alarm[0,1,2,3...11]Aciona o alarme selecionado, depois de um momento especificado.
Exemplos: alarm[0] = 30;
alarm[3] = 45;
alarm[7] = 300;
alarm[4] = 900;
alarm[11] = 5;
sleep(x)Congela o jogo totalmente por x milissegundos.
Existem centenas de outras variáveis pré-estabelecidas. Eu só listeis as mais importantes, as mais básicas e as mais utilizadas normalmente.

4. Finalização: 
Existem também algumas convenções matemáticas que são importantes lembrar. O valor de 30 unidades em alarms significa 1 segundo real, 60 unidades em alarms, 2 segundos, 450 unidades em alarms, 15 segundos reais para o alarm ativar.

Tudo (ou 99,9999%) pode ser alterado via código. Enfim... muita coisa ainda deve ser explicada! Use esta postagem como referência fácil enquanto você acompanha o restante da apostila. Espero que eu tenha ajudado em algo! Até a próxima!

sábado, 21 de março de 2015

[Game Maker] Introdução de como criar seu jogo!


Oi! Meu nome é Felipe, estive mexendo no Game Maker por mais de quatro ou cinco anos e este será uma breve introdução de como criar seu primeiro jogo utilizando GML (Game Maker Language). Para isso, nós teremos que pacientemente estudar cada recurso que o Game Maker disponibiliza (que são muitos, por sinal) à nosso favor para que tornemos isso possível. De início, vamos utilizar técnicas simples e macetes básicos para um jogo funcional, livre de bugs e agradável ao olhar. Embora eu tenha feito outros guias anteriores à esse, eu acho que vale à pena recomeçar de uma forma melhor.


Nesta introdução, eu irei apenas dar ênfase aos detalhes mais importantes e básicos do Game Maker. Será uma passada geral pela interface do programa, principalmente para aqueles que não estão familiarizados com ele. 

Índice:
1. Recursos do Game Maker 8.0
2. Aprendendo e mantendo a organização
3. Primeiros passos no Game Maker
4. Trabalhando com códigos

1. Recursos do Game Maker 8.0:

O Game Maker trabalha com os seguintes tipos de recursos: Sprites, Objects, Paths, Sounds, Scripts, Rooms e TimeLines (GM versão 8.0 e 8.1). Dois deles, Paths e TimeLines, particulamento não são tão utilizados, pois são usados apenas como uma forma "fácil" de realizar certas ações. Eu pessoalmente não os utilizo e não tenho interesse em usá-los.

Os 'Sprites' são todas as animações que você irá utilizar no seu jogo. Geralmente, os utilizadores sempre preferem sprites do tamanho 32x32 para menos, pois isso poupa bastante trabalho, deixa o jogo mais leve e ao mesmo tempo fácil de torná-lo agradável ao jogador. Você pode utilizar de programas externos para fazer suas Sprites e depois importá-las para o Game Maker entretanto. Eu costumo utilizar bastante do Pixel Art, então utilizar sprites do tamanho 16x16 ou 8x8 é bastante comum em meus jogos.

Os 'Objects' são todos os elementos do jogo. Isto é, tudo que você irá colocar no jogo. Eles podem ser utilizados da forma que você imaginar. Por exemplo: uma parede é um objeto, o jogador é um objeto, um baú é um objeto, e até mesmo um "controlador" invisível que controla a interface do jogo e marca os pontos e nem sequer aparece no jogo para o jogador, é um objeto também. Á um objeto pode ser atribuído variáveis, ações, scripts, Sprites, e também outras configurações do próprio Game Maker como Solid, Visible e até mesmo Persistent. Calma que chegaremos lá.

Os 'Scripts' são folhas de códigos que você atribui um nome, por exemplo, Script_Jogador_Movimento ou Script_Inimigo_Atacar. Quanto mais folhas de Scripts para cada função você cria, mais organizado fica seu projeto, pois assim você sempre irá saber aonde você exatamente deve ir para alterar alguma coisa que não ficou muito bom, ou acabou por não funcionar.

Os 'Sounds' são, nada mais que, os efeitos sonoros que você irá utilizar em seu jogo, seja eles um simples *clic* ou uma trilha sonora.

Por fim, as 'Rooms', elas são os ambientes do seu jogo. Um ambiente não é necessariamente um local que o seu personagem anda livremente, mas também pode ser uma Room de Menu Principal, uma Room de uma animação ou uma Room exibindo uma tela de Game Over. São utilizados também Rooms que agregam apenas alguns Objetos de inicialização do jogo, no qual passa tão depressa que o jogador nem sequer nota a sua transição.

2. Aprendendo e mantendo a organização:

A seguir eu irei passar algumas dicas sobre a criação de jogos e o início de um projeto.

Um projeto mal organizado nunca será terminado. Ou, pelo menos, nunca terá um resultado bom. Nunca. Claro que, você que está começando não precisa se preocupar tanto em organizar seus primeiros projetos. Na verdade, para dominar qualquer forma de programação, o programador iniciante terá que se submeter à muito, muito tempo de "tentativa e erro". Assim, ele irá chegar sempre em novos resultados, irá compreender como funciona cada função e assim, poderá distinguir qual a melhor, mais simples e mais eficiente forma de se programar qualquer coisa que ele desejar. Para criar um jogo, isso não vai ser diferente.

Antes de criar um projeto sério, onde o principal objetivo é criar um jogo real e funcional, é importante manter a qualidade dentro da programação. Posso garantir para você que a qualidade do código vai refletir, e muito, na jogabilidade à seguir. Criar códigos gigantescos com milhares de funções e chamar variáveis sempre que você quiser fazer alguma coisa é uma péssima ideia. Se você me perguntar qual é o melhor código para fazer 'x' coisa, eu logo irei responder: "o código mais simples, lógico e limpo que você conseguir criar". Isso serve para qualquer tipo de jogo, códigos simples são os mais fáceis de se trabalhar, são os menos propensos a causar bugs inexplicáveis e, as vezes, incorrigíveis.

O nome que você dá recursos também deve ter uma atenção especial. Algumas regras básicas à serem seguidas é: 1) nunca utilizar acentuação, símbolos ou espaços (o GM não reconhece esses caracteres), 2) utilizar de nomes simples, descritivos e claros, criando padrões (exemplos: sprite_jogador_direcao_direita, objeto_inimigo_dragao, objeto_item_arma_00, som_tiro) e 3) tomar cuidado para não repetir nomes entre nenhum recurso (por exemplo, uma Sprite e um Objeto que ambos se chamam 'item_cura'). Criar pastas para subdividir seus recursos também é essencial para uma boa organização.

Outro ponto que você deve dar atenção é à própria jogabilidade. Primeiro, deve-se pensar na ideia geral do jogo, trabalhando sempre os pontos mais importantes como Movimentação e Inteligência Artificial. Após fazer a base do jogo, só então é recomendável você criar coisas adicionais, como itens de bônus, novas naves ou então asinhas para o seu personagem. Deixe sempre o mais trabalhoso e complicado primeiro, pois assim você pode criar novas coisas a partir do padrão que foi utilizado, e não ao contrário.

Outra dica é sempre procurar criar uma história para o seu jogo. Se o seu jogo é de um rato atrás de uma fatia de queijo, então imagine algo tão simples quanto o próprio jogo para resumir a situação ao jogador. História em um jogo é um ponto importantíssimo, pois ajuda o jogador à se localizar no universo que você está tentando criar e deixa mais claro o objetivo principal do jogo, além de ajudar o próprio programador a compreender no que deve ser trabalhado.

No mais, guarde sempre estas dicas. Ninguém é obrigado à fazer tudo isso nas primeiras tentativas, mas trabalhe encima disso. Como eu disse, o modo "tentativa e erro" de início é, disparado, a melhor forma de você tentar entender as coisas. Nenhum guia, por melhor que seja, vai ser tão eficaz quanto a experiência que você obter tentando criar as coisas por si só. É uma tarefa difícil, mas em pouco tempo você irá conseguir filtrar muitas coisas e com elas, ir se aprofundando cada vez mais.

De início, fazer um bonequinho andar corretamente e parando ao topar com obstáculos já é um grande progresso. Apenas nessa brincadeira, você está trabalhando com o sistema de movimentação, colisão de obstáculos e o sistema de condições (o personagem parar SE ele bater em um obstáculo).

3. Primeiros passos no Game Maker:

O Game Maker já possui um tutorial bem simples explicando todos os passos para a criação de um jogo de "point and click" na sua inicialização.

Para iniciar o seu primeiro projeto, eu indico que você não se preocupe com a parte gráfica. Crie diversos sprites limpos, como quadrados de uma só cor de diversos tamanhos para representar as paredes, diversos quadrados de outra cor representando os inimigos e assim sucessivamente. A parte da mecânica inicial do jogo é sempre o momento mais crucial de qualquer projeto pois é daí que o jogo irá se desenvolver.

Antes de prosseguir desta parte, tenta certeza que o jogo flui bem e que nada fique travando em paredes ou parando de funcionar por alguma razão.

4. Trabalhando com códigos:

Trabalhar usando códigos é essencial. De início, o programador pode fazer coisas utilizando o sistema Drag'n Drop, mas cedo ou tarde ele terá que  se acostumar a programar utilizando a GML pois a partir de certo ponto, é impossível trabalhar sem ela.

Para começar, devo lhe dar dicas para manter seu código bem organizado:

- Crie o bom costume de nomear suas variáveis sempre com um início padrão, como por exemplo "var_" (var_jogador_vidas, var_inimigo_dano, var_inimigo_velocidade, var_dinheiro_quantidade) ou algo do gênero, o que for melhor para você.

- Sempre que você abrir {chaves}, procure sempre deixar o conteúdo interno em um nível de texto superior ao anterior (utilizando a tecla TAB), para deixar claro quando as condições são abertas e quando são fechadas, e também se aquelas condições estão dentro de outras condições. Por exemplo:

{
if var_condicao_01 == true
      {
       sprite_index = 0;
       image_index = 0;

       if var_condicao_02 == false
              {
               var_dano = 2;
               var_energia -= 1;
               
               image_index = (image_number - 1);
               }
       else
               var_morto = true;

       if var_condicao_03 == false
               var_velocidade = 4;

       }
}

Outro conselho é sempre trabalhar por partes em qualquer situação. Por exemplo, você quer fazer um inimigo. Crie diversas folhas de scripts para cada ação que o inimigo pode executar, como por exemplo, script_inimigo_andar, script_inimigo_atacar, script_inimigo_morrer, script_inimigo_sprites, e por aí vai, interligando-os internamente sempre que necessário. Como eu disse anteriormente, isso vai ajudar você á descobrir exatamente onde ir sempre que alguma coisa estiver saindo errado. Para ligar um script ao outro através de código, você pode usar a função script_execute(nome_do_script). Por exemplo:

{
//Script geral do inimigo comum

if var_recurso_energia > 0
      {
       
       if distance_to_object(obj_jogador) <= var_visao || var_seguir_jogador > 0
              {

              var_seguir_jogador = 90;
              //90 = 3 segundos! Portanto: 30 = 1 segundo!

              script_execute(script_inimigo_seguir_jogador);

              if place_meeting(x,  y,  obj_jogador) && var_ataque_delay <= 0
                     {
                     
                     var_ataque_delay = 60;
                     //60 = 2 segundos!

                     obj_jogador.var_recurso_energia -= var_dano;

                     sound_play(snd_mordida);
                     
                     }
              
              }
       else
              {
              
              var_seguir_jogador <= 0
                     script_execute(script_andar_aleatoriamente)
              
              }

       if var_seguir_jogador > 0
              var_seguir_jogador -= 1;

       if var_ataque_delay > 0
              var_ataque_delay -= 1;
       
       }
else
       {
       
       script_execute(script_inimigo_deixar_item);
       instance_destroy();
       
       }

}

Vale lembrar de declarar todas as variáveis no Crate Event para não ocorrer nenhum erro. Lembre-se: você ensina a GML!

Nos próximos posts eu irei abordar dicas valiosas para a programação para iniciantes e para avançados que também querem aprimorar suas técnicas. Vou deixar claro que algumas coisas eu não costumo usar, portanto não posso lhe tirar todas as dúvidas. Mas farei o melhor! Procure pela TAG "Game Maker" para mais guias, ou clique abaixo para ver a próxima aula!


Aula anterior - Próxima aula

quarta-feira, 10 de outubro de 2012

[GameMaker] Manual: criando seu primeiro RPG!

Fala galera, beleza?
Este guia está em construção e pode ainda haver possíveis pequenos erros e constantes atualizações.

Neste manual eu irei ensinar, passo-à-passo, como criar seu primeiro RPG utilizando o GameMaker. Lembre-se que um jogo é algo difícil de se fazer, e é necessário muito empenho e dedicação encima disso. Mesmo que você siga este guia à risca, seu jogo faltará muitas coisas importantes, como efeitos sonoros (links úteis à respeito disso no final do guia) e principalmente originalidade.

Por último, tenha em mente que este guia é realmente extenso, e o resultado ainda sim será bastante simples. Pode demorar até dias para você digerir todas as informações dele. Claro que você pode simplesmente sair copiando os códigos e fazendo o que eu digo. Depois você sequer vai saber utilizar a ferramenta em suas mãos, e a sua primeira alteração resultará num Erro que fechará o seu jogo. Eu não vou disponibilizar um Download do Tutorial pronto para evitar que isso aconteça. Se você vai só copiar tudo, aí já não é comigo. Não se esqueça que o real objetivo deste guia é ensinar como as coisas funcionam, assim você poderá começar a criar a partir do que aprender aqui. Pegue um tempo livre, abra seu Game Maker e venha comigo. Depois de acabado, pratique e personalize. 

Lembre-se que neste guia não usarei nenhum recurso exclusivo do Game Maker PRO.

Índice:
1. Preparativos
2. Criando os personagem
3. Obstáculos
4. Ataques e Habilidades 
5. Itens, equipamentos e PowerUps
6. Fazendo funcionar os atributos do personagem 
7. Configurando os Inimigos 
8. Npcs, negociantes e sistema básico de missões
9. Criando as rooms
10. Interface do jogo
11. Menu
12. Toques finais e Utilidades

1. Preparativos:

Primeiro de tudo, vamos organizar nossos recursos, seguindo algumas regras básicas:

1. Todos os Objetos terão o nome começando com "obj_" (como "obj_jogador", por exemplo), assim como todos os Sprites vão começar com "spr_", todas as Rooms como "rm_", todos os efeitos sonoros como "snd_" e todos os Scripts como "script_", nossos Backgrounds como "bg_" e todas as nossas variáveis vão começar com "var_". Nós não vamos utilizar Paths nem Time Lines, pois são recursos opcionais e facilmente substituídos.

2. Crie pastas para cada tipo de recurso na seção dos Objetos e dos Sprites, como, por exemplo, "jogador", "inimigos", "itens"... Futuramente você irá criar mais pastas conforme a necessidade.

3. Em todos os Sprites, aperte em "Center" para centralizar as coordenadas inciais das sprites, isso vai fazer diferença ao utilizar perseguição inimiga e ajudar a prevenir certos bugs de movimentação.

4. Crie um Sprite chamado spr_mask do mesmo tamanho padrão de todas as suas outras Sprites (8x8 nesse caso), mude a Mask dela para um padrão que você deverá estabelecer. Recomendo você usar o padrão "Full image + rectangle/disk". Não se esqueça de aplicar o passo acima neste sprite.
5. Crie o Objeto obj_persistent, e coloque ele como Parent TUDO que for de fato persistent. Não precisa ser diretamente. Isso vai ajudar a manter o controle nesses objetos, caso, por exemplo, você queira destruí-los numa room de Game Over sem precisar ser um à um.

Pode não parecer, mas estas simples regras farão uma IMENSA diferença no projeto, tanto na parte de organização como pode também evitar centenas de bugs futuramente (acontece quando um Objeto e uma Sprite possuem o mesmo nome, por exemplo).

Abaixo existe uma imagem com tudo pré-criado, desde Objetos até Sprites, pronto para ser trabalhado. Se quiser, tire um tempo agora para fazer o mesmo, isso vai agilizar o processo futuro.

Lembre-se: você pode usar as suas próprias Sprites ou não, porém eu irei ensinar utilizando como base Sprites do tamanho padrão de 8x8. Tente utilizar este mesmo tamanho, ou alguns códigos que utilizam coordenadas podem não funcionar corretamente.
2. Criando o personagem:

Conceito: 
Bom, como todo RPG possui diversos personagens, nós vamos ter que trabalhar muito nos personagens deste jogo. Nós vamos criar três personagens: um mago, um guerreiro e um arqueiro. Cada um terá três formas de ataque, mas isso será visto em breve.

Preparação:

Para fazermos tudo isso, temos que criar nossos recursos que serão utilizados. Devo avisar que muita coisa deve ser criada desde início, pois os personagens são de fato o objeto mais importante do jogo.

Crie as seguintes Sprites: spr_mago_0, spr_mago_90, spr_mago_180, spr_mago_270, spr_mago_morto, spr_arqueiro_0, spr_arqueiro_90, spr_arqueiro_180, spr_arqueiro_270, spr_arqueiro_morto, spr_guerreiro_0, spr_guerreiro_90, spr_guerreiro_180, spr_guerreiro_270, spr_guerreiro_morto.
Crie os seguintes Objetos: obj_personagem, obj_personagem_guerreiro, obj_personagem_arqueiro, obj_personagem_mago.
Crie os seguintes Scripts: script_jogador_setup_geral, script_jogador_setup_mago, script_jogador_setup_guerreiro, script_jogador_setup_arqueiro, script_jogador_movimento, script_jogador_sprite, script_jogador_arrumador.

AJUDANDO A ENTENDER: "O que significa o '0', '90', '180' e '270'??" - Bem, a visão do nosso personagem é medida em graus. Ou seja, 0 (graus) significa que ele está olhando para a direita, 90 (graus) significa que ele está olhando para cima, 180 (graus) para a esquerda, e 270 (graus) para baixo. Sim, você terá que desenhar todos os personagens olhando para as quatro direções.

Criando:

Agora que temos os nossos recursos necessários para este passo criados, vamos começar a trabalhar com alguns objetos e códigos. Esta parte é bastante simples e eu farei de tudo para explicar de uma forma que até o menos familiarizado com o Game Maker possa entender.

Vamos começar trocando algumas coisas nos objetos obj_personagem_guerreiro, obj_personagem_arqueiro e obj_personagem_mago. Clique em qualquer um dos três e siga as instruções abaixo:

- Coloque apenas o obj_personagem com Parent no obj_persistent (criado em 1. Preparativos).
- Coloque em todos os três seus Parent como obj_personagem.
- Coloque os três como Solid.
- Coloque os três como Persistent.
- Coloque os três com a Mask como spr_mask (criado em 1. Preparativos).

AJUDANDO A ENTENDER: "Qual a diferença de um objeto Solido e um não Sólido??" -  Inicialmente nenhuma... acontece que algumas funções do Game Maker tratam diferente objetos sólidos e não-sólidos, portanto marque sólido em tudo que seja um possível obstáculo, inclusive o próprio jogador, já que você não quer ver inimigos passando por você como se fosse um fantasma.
AJUDANDO A ENTENDER: "O que é Parent??" - Quando você marca um objeto como parente, todos os eventos do objeto apadrinhado que não foram alterados vão funcionar para o objeto afiliado, e o objeto afiliado também vai responder quando nos referirmos ao apadrinhado. Confuso? Deixe-me dar dois exemplos: 1) Supomos que no Create Event do obj_personagem tenha 2 scripts. Caso o obj_personagem_guerreiro, afiliado do obj_personagem, não tenha nada em seu Create Event ou tenha, mas tenha usado o "Call event", tudo o que está no Create Event do obj_personagem também acontecerá no obj_jogador_guerreiro. Isso evita fazer duas coisas iguais, e nos poupa de um imenso trabalho. 2) Agora vamos supor que o obj_inimigo queira atacar o personagem. Nós não vamos mandar ele atacar o obj_personagem_guerreiro, obj_personagem_mago e obj_personagem_arqueiro um por um. Imagina quanto trabalho fazer três coisas iguais desnecessáriamente. Ao invés disso, mandamos o inimigo atacar apenas o obj_personagem, pois os outros três, afiliados do obj_personagem, vão responder igualmente.
AJUDANDO A ENTENDER: "O que é Persistent??" - Quando o objeto é Persistent, basta colocar ele na primeira room, e ele será passado automáticamente para as próximas rooms mantendo todas as variáveis sem a necessidade de colocar ele novamente. Já quando a Room é Persistent, tudo o que acontece nela não é resetado, ou seja, ao retornar nela, tudo vai estar exatamante como você deixou antes de trocar de room.
AJUDANDO A ENTENDER: "O que é Mask??" - Mask é o sistema de colisão do Game Maker. Incialmente ela é exatamente igual ao Sprite. Supomos que o seu personagem seja um pequeno dragão e tenha uma calda irregular. Você não vai querer que esta calda atrapalhe o seu movimento, enroscando em obstáculos. Por isso, utilizamos uma Mask redonda, assim o personagem, mesmo não sendo redondo, vai ter uma forma redonda invisível. Mas por quê não usamos uma mask quadrada? Bem... você quem sabe, mas as pontas invisíveis do quadrado podem atrapalhar um pouco a sua movimentação.

Agora vá no script_jogador_setup_geral, e vamos criar as estatísticas dos nossos personagens desta maneira:

//Código de iniciação do personagem
{
    var_dano = 0;//Logo faremos o dano ser calculado de acordo com os atributos, estamos apenas criando a variável para usar mais tarde.
    var_energia = 1;
    var_energia_max = var_energia;//Limite máximo de energia, obs: colocado automáticamente, mas pode ser configurado manualmente
    var_mana = 1;
    var_mana_max =var_mana;//Limite máximo de mana, obs: colocado automáticamente, mas pode ser configurado manualmente
    var_municao =0;
    var_municao_max = var_municao;//Limite máximo de munição, obs: colocado automáticamente, mas pode ser configurado manualmente.
    var_especial =0;
    var_velocidade = 1 //Velocidade de movimento do personagem. Tome como base o tamanho dos sprites. Como usaremos 8x8, 1 de velocidade já é o suficiente.
    var_face =0 //A direção do personagem, ou seja, onde está a face dele.
    var_ataque_tempo =0;//Delay do ataque do personagem. Usaremos mais tarde.

    var_nivel = 1;
    var_experiencia =0;

    var_sprite_0 = 0;//Utilizaremos em cada personagem separadamente
    var_sprite_90 = 0;//Utilizaremos em cada personagem separadamente
    var_sprite_180 = 0;//Utilizaremos em cada personagem separadamente
    var_sprite_270 = 0;//Utilizaremos em cada personagem separadamente
    var_sprite_morto = 0;//Utilizaremos em cada personagem separadamente

    var_atributo_forca =0;
    var_atributo_inteligencia =0;
    var_atributo_vitalidade =0;
    var_atributo_destreza =0;

    var_equipamento_arma_nome ="Nenhuma"
    var_equipamento_arma =0; 
    var_equipamento_armadura_nome ="Nenhuma"
    var_equipamento_armadura =0;
}

Isso já é o suficiente. Como você pode ver, estamos preste à configurar a energia, mana, atributos e equipamentos dos nossos personagens. Isso é apenas uma base. Agora copie este mesmo código no script_jogador_setup_mago, script_jogador_setup_guerreiro, script_jogador_setup_arqueiro e faça as alterações necessárias para personalizar cada personagem, como por exemplo:

- No script_jogador_setup_arqueiro:
//Código de iniciação do personagem arqueiro
{
    var_energia = 10;
    var_energia_max = var_energia;
    var_mana = 10;
    var_mana_max =var_mana;
    var_municao =50;
    var_municao_max = var_municao;

    var_sprite_0 = spr_arqueiro_0;

    var_sprite_90 = spr_arqueiro_90;
    var_sprite_180 = spr_arqueiro_180;
    var_sprite_270 = spr_arqueiro_270;
    var_sprite_morto = spr_arqueiro_morto;

    var_atributo_forca =1;
    var_atributo_inteligencia =5;
    var_atributo_vitalidade =5;
    var_atributo_destreza =10;

    var_equipamento_arma_nome ="Arco comum"
    var_equipamento_arma =1; 
    var_equipamento_armadura_nome ="Armadura de couro"
    var_equipamento_armadura =1;
}

- No script_jogador_setup_guerreiro
//Código de iniciação do personagem guerreiro
{
    var_energia = 20;
    var_energia_max = var_energia;
    var_mana = 5;
    var_mana_max = var_mana;

    var_sprite_0 = spr_guerreiro_0;

    var_sprite_90 = spr_guerreiro_90;
    var_sprite_180 = spr_guerreiro_180;
    var_sprite_270 = spr_guerreiro_270;
    var_sprite_morto = spr_guerreiro_morto;

    var_atributo_forca =10;
    var_atributo_inteligencia =1;
    var_atributo_vitalidade =10;
    var_atributo_destreza =5;

    var_equipamento_arma_nome ="Espada comum"
    var_equipamento_arma =1; 
    var_equipamento_armadura_nome ="Armadura de ferro"
    var_equipamento_armadura =2;
}

- No script_jogador_setup_mago
//Código de iniciação do personagem mago
{
    var_energia = 10;
    var_energia_max = var_energia;
    var_mana = 20;
    var_mana_max =var_mana;
    var_municao =99;
    var_municao_max = var_municao;

    var_sprite_0 = spr_mago_0;

    var_sprite_90 = spr_mago_90;
    var_sprite_180 = spr_mago_180;
    var_sprite_270 = spr_mago_270;
    var_sprite_morto = spr_mago_morto;
    var_atributo_forca =5;
    var_atributo_inteligencia =15;
    var_atributo_vitalidade =5;
    var_atributo_destreza =1;

    var_equipamento_arma_nome ="Cajado comum"
    var_equipamento_arma =1; 
    var_equipamento_armadura_nome ="Armadura de couro"
    var_equipamento_armadura =1;
}

Lembre-se: Variáveis que não foram alteradas nos personagens não precisam ser repetidas. Note que a var_especial, var_velocidade, var_face, var_nivel, var_experiencia e var_ataque_tempo deverá permanecer igual, logo ela só está presente no script_personagem_setup_geral e já é o suficiente, e não precisa ser repetido.

Pronto. Scripts de criação prontos. Agora vamos colocar os scripts no Create Event de cada um dos personagens, sempre se lembrando de antes colocar um "Call Event". Deverá ficar parecido com isso:

AJUDANDO A ENTENDER: "O que é 'Call Event'?" - Esta função "chama" tudo que colocamos no mesmo evento do nosso obj no Parent. Por exemplo, colocamos um Script no Create Event do obj_personagem. O obj_personagem_guerreiro, tendo o obj_personagem como Parent, ao dar um 'Call Event' no Create Event o script que colocamos no obj_personagem se aplicará no Create Event dele também. Isso geralmente ocorre de forma automática, desde que não coloquemos nada nos Eventos do objeto afiliado. Concluindo: como colocamos o script_jogador_setup_guerreiro no Create Event do obj_personagem_guerreiro, logo temos que dar um 'Call Event' pois ele não vai mais ocorrer de forma automática.

Agora vamos trabalhar na movimentação e utilização correta das Sprites dos personagens. Vamos utilizar as teclas "A", "W", "S" e "D" para movimentar o personagem. Vá no script_personagem_movimento e vamos fazer um esquema básico de movimentação, utilizando o seguinte código:

//Movimento do personagem
{
    if keyboard_check(ord("W")) and place_free(x,y-var_velocidade) //Se a tecla "W" estiver sendo pressionada e nenhum obstáculo sólido se encontra na posição indicada, ou seja, encima do personagem...
        {
        y-= var_velocidade//Movimenta verticalmente para cima (pois está negativo) na velocidade do personagem
        var_face = 90//Como o personagem se movimentará para cima, a face dele ficará em 90º
        }
    if keyboard_check(ord("S")) and place_free(x,y+var_velocidade) //Se a tecla "S" estiver sendo pressionada e nenhum obstáculo sólido se encontra na posição indicada, ou seja, abaixo do personagem...
        {
        y+= var_velocidade//Movimenta verticalmente para baixo (pois está positivo) na velocidade do personagem
        var_face = 270//Como o personagem se movimentará para baixo, a face dele ficará em 270º
        }
    if keyboard_check(ord("A")) and place_free(x-var_velocidade,y) //Se a tecla "A" estiver sendo pressionada e nenhum obstáculo sólido se encontra na posição indicada, ou seja, à direita do personagem...
        {
        x-= var_velocidade//Movimenta verticalmente para direita (pois está negativo) na velocidade do personagem
        var_face = 180//Como o personagem se movimentará para a direita, a face dele ficará em 180º
        }
    if keyboard_check(ord("D")) and place_free(x+var_velocidade,y) //Se a tecla "D" estiver sendo pressionada e nenhum obstáculo sólido se encontra na posição indicada, ou seja, à esquerda do personagem...
        {
        x+= var_velocidade//Movimenta verticalmente para esquerda (pois está positivo) na velocidade do personagem
        var_face = 0//Como o personagem se movimentará para a esquerda, a face dele ficará em 0º
        }
}

Coloque este Script no Step Event do obj_personagem.

Agora vamos configurar o script_personagem_sprite para que ele troque a imagem do nosso personagem automáticamente conforme a necessidade, sem precisarmos trocarmos toda hora manualmente. Lembre-se que quando o personagem começar a atacar, nós vamos fazer uma pequena modificação neste Script, para que as Sprites deles atacando funcionem também. Por enquanto, o script_personagem_sprite deverá ficar assim:

//Configuração dos sprites do personagem. Por enquanto, nada precisa ser alterado.
{
var_andando =0;
switch(keyboard_key)//Checa se o personagem está andando ou não
    {
    case ord("A"):
    case ord("W"):
    case ord("S"):
    case ord("D"):
        var_andando =1; //Se alguma destas teclas (W,S,A ou D) foi pressionada, então ele está andando...
        break;
    }
   
    //Velocidade visual da sprite
    if var_ataque_tempo <=0 and var_andando=0//Se o personagem não está atacando e nem andando
        {
        image_speed =0; //Velocidade da sprite é zerado
        image_index =0; //Subimagem da sprite volta para a primeira e permanece nela
        }
    else
        {
        image_speed =0.2; //Velocidade da sprite vai para 0.2 (se for 1, vai ficar muito rápido)
        }

//=============================
//Configurar a sprite correta de acordo com a direção, ou seja, a face do personagem
switch(var_face)// Lembre-se que configuramos as sprites do personagem no script do setup de cada um, logo NADA precisa ser alterado por enquanto.
    {
    case 0: sprite_index=var_sprite_0; break;
    case 90: sprite_index=var_sprite_90; break;
    case 180: sprite_index=var_sprite_180; break;
    case 270: sprite_index=var_sprite_270; break;
    }
//=============================
}

AJUDANDO A ENTENDER: "O que seria um 'Switch'?" - Switch é um versão compacta e mais rápida de ser executada de vários 'If's'. Ao invés de você fazer if face =0 {}, if face =90 {} ... você resume tudo em um único switch, trocando os 'if's' pelo 'case' e não esquecendo de colocar um 'break' no final de cada resultado, ou não vai funcionar.


Agora coloque este Script junto com o script_jogador_movimento no Step Event do obj_personagem.

Agora crie uma Room chamada "rm_teste", coloque qualquer um dos três personagens (o obj_personagem NÃO é um personagem, ele é um representante que nunca vai ser colocado diretamente em nenhuma das rooms). Logo a seguir vamos criar muitos outros objetos como este), se quiser crie uma view (com cerca de 180x140 caso você esteja usando sprites 8x8) rápida apenas para focar melhor no personagem e veja se tudo está funcionando corretamente até agora.

Caso positivo, antes de iniciarmos os ataques e habilidades de nossos personagens, vamos fazer a primeira parte do script_jogador_arrumador. Este pequeno script cuidará automáticamente de variáveis para nós, como por exemplo, não deixar a var_energia ultrpassar a var_energia_max, que é o limite. Faça assim:

//Arrumador automático do personagem
{
    if var_energia > var_energia_max //Se nossa energia é maior que o máximo de energia permitido...
        var_energia = var_energia_max //A energia irá automáticamente se igualar ao máximo permitido, impedindo assim, a ultrapassagem.

    if var_mana > var_mana_max //Mesma coisa ao de cima, porém com a var_mana.
        var_mana = var_mana_max

    if var_especial >100//Esse "100" é um valor aleatório... é um bom número de golpe especial. 
    var_especial =100
}

Coloque-o no Step Event do obj_personagem, junto com os outros dois Scripts.

Logo mais vamos editar também este script para suprir futuras necessidades. Agora, guarde-o e vamos ao nosso próximo passo.

3. Obstáculos:

Conceito:

Antes de terminarmos os nossos personagens por completo, vamos terminar a movimentação dele. Pois para uma movimentação fazer sentido, temos que ter obstáculos, como pedras, paredes, grades, lagos. Nosso personagem não consegue passar por nenhum destes obtáculos... mas e uma flecha? A flecha não conseguirá passar por uma pedra, nem uma parede... mas por uma grade e um lago, obviamente ela consegue. É isso que vamos criar.

Preparação:

Crie os seguintes Sprites: spr_obstaculo_alto, spr_obstaculo_raso.
Crie os seguintes Objetos: obj_obstaculo_geral, obj_obstaculo_raso, obj_obstaculo_alto
Crie o seguinte Background: bg_obstaculos

Criando:

Com os nossos recursos que acabamos de criar, você deve estar no mínimo confuso. "Onde estão as árvores, os lagos, as paredes, as rochas?" você me pergunta. Bem, é importante saber que quanto menos objetos criarmos, mais leve será nosso jogo e conseqüentemente melhor desempenho teremos. Logo teremos apenas dois obstáculos: obj_obstaculo_raso (no qual permitirá a passagem de projéteis) e obj_obstaculo_alto (não permitirá a passagem de projéteis).

Você não precisa criar nenhum código. Apenas faça algumas configurações básicas:

- O Parent do obj_obstaculo_alto e obj_obstaculo_raso devem ser o obj_obstaculo_geral.
- As Sprites spr_obstaculo_raso e spr_obstculo_alto devem ser, de preferência, quadrados ocos (para não atrapalhar a sua visão) e de cores distintas, como vermelho e amarelo. Isso vai ajudar a diferenciá-los.
- Marque a opção Solid em ambos.
- Desmarque a opção Visible em ambos.
- Coloque a Mask de ambos como spr_mask como de costume.

AJUDANDO A ENTENDER: "O que 'Visible'?" - Visible, como o nome já implica, configura para o objeto estar vísivel ou invisível durante o jogo. Ambos os casos, ele ainda estará lá, existindo, e a sua colisão também. Isso é útil para criar armadilhas (com botões invisíveis no chão) e coisas do tipo.

Agora vamos à parte estética. No bg_obstaculos, crie uma folha de cerca de 64x64 e configure a Grid para se dividir em 8x8 (ou do tamanho padrão de suas Sprites).
Desenhe cada obstáculo em cada quadradinho separado. Se precisar, dê um zoom.
Você não precisa fazer tudo agora, desenhe apenas quatro para testes e dê OK. Na tela de configuração do background, selecione a opção "Use as Tileset" e coloque 8x8 (ou o tamanho que você usou) e dê OK.
Pronto. Agora nós temos nossos obstáculos. Entre na rm_teste, e distribua os obstáculos corretamente, colocando os tilesets um à um desejado e depois colocando um obj_obstáculo_alto ou obj_obstáculo_raso somente sobre cada um que possa ser um possível obstáculo para o jogador (somente o das bordas, não sobrecarregue o jogo colocando instâncias desnecessárias), combinando assim o obstáculo visual com o obtáculo real. Se quiser, crie um bg_teste para colocar como plano de fundo na sua rm_teste. Veja na foto um exemplo:
Apenas os Tilesets do bg_obstaculos, sem instâncias de objetos.
Com os obj_obstaculo_alto e obj_obstaculo_raso já colocados em seus respectivos lugares.
Lembre-se: o obj_obstaculo_alto não vai permitir que projéteis (como flechas e habilidades) passem por ele, e nem a visão inimiga, então coloque-o sobre árvores, pedras e coisas do gênero. O obj_obstáculo_raso vai permitir a passagem de projéteis, então coloque-os sobre rios, grades e coisas do gênero.

Por enquanto, não se preocupe em fazer muitas rooms. Nós ainda temos que criar todo o resto do jogo, como inimigos, itens e npcs. Deixe para criar os "mapas" quando dispor de todos os recursos. Agora vamos voltar aos nossos personagens.
4. Ataques e Habilidades:

Conceito:

Agora nós temos um mago, um guerreiro e um arqueiro. Cada um terá três formas de ataque: básico, à distância e especial. O ataque básico será de curta distância, danificando os inimigos à frente. O ataque à distância gastará algum tipo de munição, como flechas ou espírito. O especial vai utilizar uma espécie de energia que se acumula com o tempo ou quanto o personagem derrota inimigos. Para trocar de ataque, utilizaremos as teclas 1,2 e 3, respectivamente. 

Nós também criaremos Power Ups, itens que oferecerão temporáriamente super ataques para nossos pequenos soldados, só que mais à frente... um passo de cada vez.

Preparação:

Lembre-se que estes ataques são só um exemplo. Você pode trocar o obj_ataque_meteoro por obj_ataque_chuvadetrovoes, por exemplo. Fique tranquilo, depois que você entender como funciona esta mecânica, poderá criar quantos ataques você precisar.

Crie as seguintes Sprites: spr_flecha, spr_ataque_basico, spr_bola_de_fogo, spr_super_flecha, spr_super_golpe, spr_meteoro, spr_enfeite_splash, spr_enfeite_sanguejorrando, obj_enfeite_geral, spr_escudo, spr_arqueiro_ataque_0, spr_arqueiro_ataque_90, spr_arqueiro_ataque_180, spr_arqueiro_ataque_270, spr_guerreiro_ataque_0, spr_guerreiro_ataque_90, spr_guerreiro_ataque_180, spr_guerreiro_ataque_270, spr_mago_ataque_0, spr_mago_ataque_90, spr_mago_ataque_180, spr_mago_ataque_270.
Crie os seguintes Objetos: obj_ataque_geral, obj_projetil_geral, obj_ataque_flecha, obj_ataque_boladefogo, obj_ataque_superflecha, obj_ataque_meteoro, obj_ataque_basico, obj_ataque_supergolpe, obj_inimigo, obj_enfeite_splash, obj_enfeite_sanguejorrando, obj_escudo.
Crie os seguintes Scripts: script_ataque_setup, script_projetil_setup, script_ataque_geral, script_projetil_geral, script_ataque_geral, script_personagem_ataque, script_personagem_escolhadeataque, script_escudo, script_golpeespecial_guerreiro, script_golpeespecial_arqueiro, script_golpeespecial_mago.

Criando:

Agora temos tudo que precisamos para criar nossos ataques. Assim como os personagens, nós vamos criar um padrão utilizando o obj_ataque_geral e obj_projetil_geral e depois vamos distribuir atributos personalizados nos ataques, para que cada um reaja de forma diferente.

Novamente, vamos criar as variáveis iniciais dos nossos ataques utilizando o script_ataque_setup (para ataques corpo-à-corpo) e o script_projetil_setup (para ataque à longa distância), que deverão ficar assim:

- No script_ataque_setup:

//Setup básico dos ataques
{
    var_dano = obj_personagem.var_dano;
    image_speed =0.5;
}

- No script_projetil_setup:

// Setup básico de projéteis:
{
   direction = obj_personagem.var_face; //A direção da flecha vai ser a mesma da face do obj_personagem
   speed = var_velocidade;
   var_distancia = 90//Com uma duração de 90, o projetil durará 3 segundos. Aumente se quiser.
}

Agora coloque estes pequenos Scripts no Create Event do obj_ataque_geral e obj_projetil_geral, respectivamente. No Parent do obj_projetil_geral, coloque o obj_ataque_geral e coloque também um "Call event" no Create Event dele, afinal, ele também é um tipo de ataque. Ambos deverão ficar assim:
Pronto. Agora temos o setup dos nossos ataques. Agora vamos fazer os ataques funcionarem. Abra o script_ataque_geral e coloque o seguinte código:

//Ataque geral
{
    if place_meeting(x,y,obj_inimigo_geral)//Se um inimigo está sobre o ataque...
        {
         var_meu_alvo = instance_nearest(x,y,obj_inimigo_geral); //O alvo do ataque será o inimigo mais próximo, ou seja, o que está sob o ataque neste exato momento
     var_meu_alvo.energia -= var_dano; //Reduz a energia do inimigo mais próximo na mesma quantidade do dano. Lembre-se que não criamos essa variável no obj_inimigo ainda, portanto se rodar o jogo agora, ocorrerá um erro.
          
         instance_change(obj_enfeite_sanguejorrando, 1); //O ataque vira seu efeito de sangue jorrando.
        }
}

Coloque este script no Step Event do obj_ataque_geral.

Vamos trabalhar no obj_inimigo_geral mais à frente. Por enquanto deixe-o como está. Já o obj_enfeite_sanguejorrando, tente colocar uma Sprite com cerca de 5 subimagens representando um sangue progressivamente sumindo para dar um efeito de sangue sendo jorrado pelo inimigo. Agora coloque o Parent dele o obj_enfeite_geral. Já obj_enfeite_geral, crie um evento de Animation End ("other" > "animation end") e coloque uma folha de código normal apenas escrita instance_destroy(). Agora nossos efeitos visuais serão criados e automáticamente destruídos quando a animação deles acabarem.

Agora vamos programar o script_projetil_geral. Basicamente, os projeteis também vão levar o script_ataque_geral consigo (afinal, eles também são um tipo de ataque). No script_projetil_geral, vamos apenas fazer com que eles se destruam com o tempo (para não irem muito longe) e se destruam ao bater num obstáculo. Ficará o seguinte:

//Projétil geral
{
    var_distancia -=1; //Começa uma contagem regressiva da duração

  image_index = direction * image_number/360; //Esse código muda automáticamente para a subimagem correta de acordo com a direção do escudo.
//NOTA: SE VOCÊ TIVER O GM PRO, TROQUE O "IMAGE_INDEX" POR "IMAGE_ANGLE".
    if var_distancia <=0; //Quando a duração do projétil acabar...
        {
        speed =0; //Zera a velocidade
        instance_change(obj_enfeite_splash, 1); //Ele é destruído, virando um efeio visual básico
        }

    if place_meeting(x,y,obj_obstaculo_alto)//Se acontecer um choque com o obj_obstáculo_alto
          var_distancia =0;//A var_distancia é zerada, assim destruindo o projétil.
}

Para a seleção automática de subimagem funcionar corretamente de acordo com a direção do projétil, as Sprites de todos os projéteis devem ser um pouco diferente: você deverá fazer elas com 4 subimagens, cada uma com o projétil virado para uma direção diferente, começando para a direita (0º). Por exemplo:

Nota: Se você tiver o GM PRO, basta apenas fazer a primeira subimagem e usamos a função "image_angle".

Agora nós temos a base de nossos ataques. Logo faremos o nosso personagem atacar, mas antes precisamos criar os ataques que eles realmente vão ultilizar, como o obj_ataque_flecha e obj_ataque_boladefogo. Isso vai ser bem fácil, só precisamos dar uma pequena personalizada em cada um.

- Coloque as respectivas Sprites no obj_ataque_boladefogo, obj_ataque_flecha, obj_ataque_basico, obj_ataque_meteoro, obj_ataque_supergolpe, obj_ataque_superflecha.
- O Parent de obj_ataque_superflecha, obj_ataque_meteoro, obj_ataque_boladefogo, obj_ataque_flecha devem estar no obj_projetil_geral.
- O obj_ataque_basico e obj_ataque_supergolpe devem ter o Parent diretamente ligados ao obj_ataque_geral.

AJUDANDO A ENTENDER: "O obj_projetil_geral tem o Parent como obj_ataque_geral, logo todos não vão ser a mesma coisa?" - Na realidade, os nossos projéteis são, de fato, ataques. Logo nós queremos que os nossos projéteis se comportem como ataques, porém não queremos que todos os nossos ataques se comportem como projéteis. Por isso o obj_ataque_basico e obj_ataque_supergolpe são diretamente ligados ao obj_ataque_geral e não por meio do obj_projetil_geral.

Para dar as pequenas personalizadas que eu tanto digo, você pode fazer o seguinte: no Create Event de cada um dos super ataques, ou seja, o obj_ataque_supergolpe, obj_ataque_meteoro, obj_ataque_superflecha, coloque uma folha de código simples apenas escrito {dano = dano*2;}, obviamente não esquecendo do "Call Event" antes. Isso fará os nossos super ataques terem o dano dobrado.

Terminamos os nossos ataques. Vamos deixar os especiais para mais tarde. Agora vamos fazer com que o nosso personagem ataque, usando a tecla "K" (ou qualquer outra que você desejar). Como eu disse, nossos personagens terão três ataques: um corpo-à-corpo, outro à distância (no qual gasta munição no guerreiro/arqueiro e mana no mago) e outro especial (que gasta a barra de especial). Nós vamos trocar os ataques usando as teclas "1", "2" e "3".

Porém, antes de fazermos o nosso personagem atacar, vamos criar a variável "var_meu_ataque =0" (na qual vai indicar qual tipo de ataque está selecionado no momento). Coloque esta variável junto com as otras no script_jogador_setup_geral. Essa variável vai seguir a seguinte lógica:

Se var_meu_ataque for 0, estamos usando o ataque corpo-à-corpo.
Se var_meu_ataque for 1, estamos usando o ataque à distância.
Se var_meu_ataque for 2, estamos usando o golpe especial.

Agora alterando um à um os script_jogador_setup_guerreiro, script_jogador_setup_mago e script_jogador_setup_arqueiro, vamos criar as variaveis "var_meu_golpe", "var_meu_projetil" e "var_meu_script_especial".

- Para todos os três personagens coloque "var_meu_golpe = obj_ataque_basico". Isso quer dizer que, por padrão, os três personagens atacarão com o obj_ataque_basico futuramente.

- Agora a "var_meu_projetil" é um caso à parte. No script_setup_personagem_arqueiro, coloque "var_meu_projetil = obj_ataque_flecha" e no script_setup_personagem_mago coloque "var_meu_projetil = obj_ataque_boladefogo. O script_setup_personagem_guerreiro não deve atacar à distância, como a sua classe impõe, mas logo vamos criar um escudo para ele, que vai substituir essa função. Por enquanto, deixe "var_meu_projetil = obj_ataque_flecha" para evitar erros. Como nós deixamos ele sem munição no setup, nada vai acontecer.

- O "var_meu_script_especial" também são casos separados, porém facilmente distintos. No script_setup_personagem_guerreiro, coloque "var_meu_script_especial = script_golpeespecial_guerreiro", no script_setup_personagem_arqueiro, coloque "var_meu_script_especial = script_golpeespecial_arqueiro" e por fim, no script_setup_personagem_mago, coloque "var_meu_script_especial = script_golpeespecial_mago".

Agora vamos realmente fazer nossos personagens atacarem. No script_personagem_ataque, vamos fazer o seguinte código:

if keyboard_check(ord("K")) and var_ataque_tempo <=0 //Se a tecla "K" está sendo pressionada e não acabamos de efetuar um ataque ainda...
   {
    if var_meu_ataque =0//Se o nosso ataque selecionado é o corpo-à-corpo
       {
        var_ataque_tempo = 30//Vai mostrar que acabamos de atacar e não poderemos atacar novamente por 1 segundo.
       switch(var_face)//Vamos criar nosso ataque de acordo com a direção do personagem
               {
                case 0: instance_create(x+8,y,var_meu_golpe); break;
                case 90: instance_create(x,y-8,var_meu_golpe); break;
                case 180: instance_create(x-8,y,var_meu_golpe); break;
                case 270: instance_create(x,y+8,var_meu_golpe); break;
                }
           }
     if var_meu_ataque =1 and var_municao >0//Se o nosso ataque selecionado é à distância e tivermos munição...
       {
        var_ataque_tempo = 30//Vai mostrar que acabamos de atacar e não poderemos atacar novamente por 1 segundo.
        var_municao -=1//Reduzimos uma munição do total que temos
        switch(var_face)//Vamos criar nosso projétil de acordo com a direção do personagem
               {
                case 0: instance_create(x+8,y,var_meu_projetil); break;
                case 90: instance_create(x,y-8,var_meu_projetil); break;
                case 180: instance_create(x-8,y,var_meu_projetil); break;
                case 270: instance_create(x,y+8,var_meu_projetil); break;
                }
           }
     if var_meu_ataque =2 and var_especial =100//Se nosso ataque selecionado é o golpe especial e temos pontos de especial o suficiente...
           {
        var_ataque_tempo = 30//Vai mostrar que acabamos de atacar e não poderemos atacar novamente por 1 segundo.
           var_especial =0//Reduz o contador de pontos de especial que temos.
           script_execute(var_meu_script_especial);//Executa o script especial que colocamos em cada personagem.
           }
}

Nosso script de ataque está pronto. Novamente, coloque-o no Step Event do obj_personagem junto aos outros scripts. Agora vamos habilitar a troca de ataques (utilizando as teclas "1", "2" e "3" como já dito) usando o script_personagem_escolhadeataque. Basta colocar este código:

{
if keyboard_check(ord("1"))//Se a tecla 1 foi pressionada
    {
    var_meu_ataque =0//Troca para o ataque corpo à corpo.
    }
if keyboard_check(ord("2")) and var_municao >0//Se a tecla 2 foi pressionada e temos munição sobrando...
    {
    var_meu_ataque =1//Troca para o ataque à distância.
    }
if keyboard_check(ord("3")) and var_especial =100//Se a tecla 3 foi pressionada e temos pontos de especial maximizados no momento...
    {
    var_meu_ataque =2//Troca para o ataque especial.
    }
}

Agora coloque o script_personagem_escolhadeataque no Step Event do obj_personagem também junto aos outros scripts. Resta ainda trabalhar no especial dos três personagens, nos quais vamos fazer novos ataques com um pouco de criatividade.

Vamos trabalhar primeiro no obj_escudo do obj_personagem_guerreiro. Este, por sua vez, não terá nenhum Parent pois não se deve comportar nem como ataque, muito menos como um projétil, apesar de utilizar o mesmo código. A Sprite dele também deve seguir o padrão dos projéteis:
Nota: mais uma vez, se você tiver o GM PRO, faça apenas a primeira subimagem e já será o suficiente!

Seguindo, vamos trabalhar no script_escudo. Temos milhares de possibilidades, mas a que eu acho mais interessante é a seguinte:

//Script do obj_escudo, no qual substituirá o ataque à distância do obj_personagem_guerreiro.
{
obj_personagem.var_ataque_tempo =15;//Coloca constantemente um Delay no jogador, no qual impede que ele ataque enquanto o escudo está ativo. Como essa variável sempre será renovada, quando o obj_escudo ser destruído o obj_personagem_guerreiro ainda ficará 0,5 segundo sem poder atacar nem criar um novo escudo.

direction = obj_personagem.var_face; //A direção do escudo será a mesma da face do jogador.

image_index = direction * image_number/360; //Esse código muda automáticamente para a subimagem correta de acordo com a direção do escudo.
//NOTA: SE VOCÊ TIVER O GM PRO, TROQUE O "IMAGE_INDEX" POR "IMAGE_ANGLE". 

switch(direction)//Agora vamos fazer o escudo ficar sempre na frente do personagem corretamente...
   {
    case 0:
              x = obj_personagem.x+4;
              y = obj_personagem.y;
              break; 
    case 90:
              x = obj_personagem.x;
              y = obj_personagem.y-4;
              break;
    case 180:
              x = obj_personagem.x-4;
              y = obj_personagem.y;
              break;
    case 270:
              x = obj_personagem.x;
              y = obj_personagem.y+4;
              break;    
    default:
              x = obj_personagem.x;
              y = obj_personagem.y;
              break;   
   }

if place_meeting(x,y,obj_inimigo)//Se existir um inimigo colidindo com o escudo...
    {
     obj_personagem.var_municao -=1; //Retira uma munição, ou seja, uma carga do escudo do personagem
     var_meu_alvo = instance_nearest(x,y,obj_inimigo); //Marca o alvo, ou seja, o inimigo colidindo...

     var_meu_alvo.speed = 2; //Adiciona uma velocidade no inimigo, para empurrar ele
     var_meu_alvo.direction = direction; //O inimigo é empurrado na mesma direção do escudo
     var_meu_alvo.friction = 0.2; //Isso faz com que o inimigo pare lentamente, criando assim um efeito de empurrão mais realista e sólido.
    }

if !keyboard_check(ord("K")) or obj_personagem.var_municao <=0 or !obj_personagem.var_meu_ataque =1//Se a tecla "K" deixa de ser pressionada ou a munição, ou seja, a carga do escudo do jogador acabar ou outro ataque for selecionado...
    {
     instance_destroy();
    }
}

AJUDANDO A ENTENDER: "O que é 'Default' no switch?" - "Default" é o que acontece quando nenhuma condição do Switch foi saciada. Tomando como exemplo o switch acima, supomos que por algum motivo a 'direction' do escudo ficasse 45(º). Nesse caso, o Default vai acontecer. Claro que, nesse caso em específico, è quase impossível disso acontecer, mas colocamos apenas para evitar grandes bugs.

Coloque este código no Step Event do obj_escudo. O escudo deverá funcionar corretamente, sendo destruído quando as suas cargas acabarem ou a tecla "K" for liberada ou quando o jogador seleciona outro ataque. Agora não se esqueça de colocar a "var_meu_projetil = obj_escudo" no script_personagem_setup_guerreiro e não se esqueça de alterar a "var_municao" de 0 para algum valor razoável, como 40.

Agora vamos trabalhar nos três especiais dos personagens, utilizando os recursos que já criamos de uma forma diferente. Eu farei os três especiais da forma que eu achar melhor, mas você pode tentar usar o conhecimento que você obteve até agora para tentar algo novo.

- No script_golpeespecial_arqueiro:
//Golpe especial do personagem arqueiro, "Círculo de flechas". O arqueiro vai atacar flechas em oito direções diferentes em volta dele.
{
var_direcao = 0
repeat(8)//Repetir 7 vezes o seguinte script, ou seja, criando 8 flechas...
    {
     var_ataque = instance_create(x,y,obj_ataque_superflecha)
     var_ataque.direction = var_direcao
     var_ataque.speed = 4

    var_direcao +=45//A próxima flecha será num ângulo de 45º à mais que a anterior
    }
}

- No script_golpeespecial_mago:
//Golpe especial do personagem mago, "Onda de meteoros". O mago vai lançar quatro meteoros rápidos em formato de cruz e quatro meteoros lentos em forma de X. Nesse processo, ele ainda vai curar uma parcela da sua energia.
{
   var_energia +=round(var_energia_max/3)//Cura energia de acordo com a energia máxima do mago, nesse caso, 33% da energia total.
  
var_direcao = 0
var_ataque_velocidade =4
repeat(8)//Repetir 7 vezes o seguinte script, ou seja, criando 8 meteoros...
    {
     var_ataque = instance_create(x,y,obj_ataque_meteoro)
     var_ataque.direction = var_direcao
     var_ataque.speed =var_ataque_velocidade

     if var_ataque_velocidade =4//Se a velocidade do último tiro foi 4...
         var_ataque_velocidade =2;//Altera para 2
     else
         var_ataque_velocidade =4;//Se não, agora é 4.
     var_direcao +=45//O próximo meteoro será num ângulo de 45º à mais que o anterior
    }
}

- No script_golpeespecial_guerreiro:
//Golpe especial do personagem guerreiro, "Ataque mega-ofensivo". O guerreiro vai se teleportar ao inimigo mais próximo atacando-o pesadamente. Isso só vai acontecer quando não ouver nenhum obstáculos entre os dois.
{
var_meu_alvo = instance_nearest(x,y,obj_inimigo);
var_especial = 100;//Reseta o valor do especial, para impedir de gastá-los caso o especial não dê certo.

if distance_to_object(var_meu_alvo) <=64//Estabelece um limite de distância entre o alvo, para impedir que a àrea do efeito do especial seja infinito.
if !collision_line(var_meu_alvo.x,var_meu_alvo.y, obj_personagem.x, obj_personagem.y, obj_parede_geral, 0, 1)//Se não ouver nenhum obstáulo no caminho entre o jogador e o inimigo mais próximo...
    {
     instance_create(x,y,obj_enfeite_splash);//Cria um pequeno efeito visual antes de teleportar-se
     x = var_meu_alvo.x;
     y = var_meu_alvo.y;
     
     repeat(5)
        instance_create(var_meu_alvo.x,var_meu_alvo.y,obj_ataque_supergolpe);//Cria 5 super-ataques no inimigo, ou seja, 10x mais dano.
        
     var_meu_alvo.speed =4//Cria um sistema
     var_meu_alvo.friction = 0.2//de empurrão
     var_meu_alvo.direction = var_face//no inimigo..
     
     var_especial = 0;//O especial deu certo, então zeramos os pontos de especial.
    }
}
Agora todos os nossos especiais estão prontos. Assim que obtermos 100 pontos de especial com nossos personagens, poderemos selecionar o ataque da tecla "3" e pressionarmos "K" para utilizá-los. Ainda temos que encontrar um meio de fazermos o nosso personagem ganhar tais "pontos de especial", mas isso faremos mais à frente quando criarmos de fato nossos inimigos.
Mas espere um pouco... nosso personagem pode até estar atacando corretamente, mas ainda como vamos fazer para que ele ataque visualmente, usando as Sprites corretas? Bem, primeiro, vamos "ensinar" ao jogo quais são as Sprites de nossos personagens atacando.

- No script_personagem_setup_guerreiro, adicione:
    var_sprite_0_atacando = spr_guerreiro_ataque_0;
    var_sprite_90 = spr_guerreiro_ataque_90;
    var_sprite_180 = spr_guerreiro_ataque_180;
    var_sprite_270 = spr_guerreiro_ataque_270;

Faça o mesmo script_personagem_setup_arqueiro e no script_personagem_setup_mago, trocando apenas a parte do "guerreiro" por "arqueiro/mago".

Agora lembra-se que já temos um script que muda automáticamente as sprites do personagem? Pois bem, vamos ter que fazer algumas alterações nele. Abra novamente o script_personagem_sprite e troque a última parte marcada do script para a seguinte:

//Configurar a sprite correta de acordo com a direção, ou seja, a face do personagem
if var_ataque_tempo>0 //Se ele está atacando... 
switch(var_face)
    {
    case 0: sprite_index=var_sprite_0_ataque; break;
    case 90: sprite_index=var_sprite_90_ataque; break;
    case 180: sprite_index=var_sprite_180_ataque; break;
    case 270: sprite_index=var_sprite_270_ataque; break;
    }
else//Se não...
switch(var_face)
    {
    case 0: sprite_index=var_sprite_0; break;
    case 90: sprite_index=var_sprite_90; break;
    case 180: sprite_index=var_sprite_180; break;
    case 270: sprite_index=var_sprite_270; break;
    }

Pronto. Novamente, abra a rm_teste e tente efetuar alguns ataques dos três tipos (o especial pode não dar certo, pois o var_especial começa em 0 e não 100, então não se esqueça de alterar isso se quiser testá-lo também). Caso tudo deu certo até agora, vamos ao passo seguinte.
5. Itens, Equipamentos e PowerUps:

Conceito:

Chegou a hora de criarmos nossos equipamentos, itens, tesouros, poções e coisas desse tipo. Junto com o sistema de atributos, nossos equipamentos vão interferir na Energia máxima, Mana máxima e Dano do nosso personagem. Com nosso dinheiro, iremos interagir com NPCs para comprar equipamentos e outros itens. Lembra-se que no setup dos personagens já criamos um "sistema" de equipamentos? Também é hora de fazer ele funcionar corretamente. Além do mais, temos que fazer funcionar o sistema de super-ataques de nossos personagens utilizando Power Ups temporários. Com um passo de cada vez, iremos cumprir todos esses objetivos!

Preparação:

Crie as seguintes Sprites: spr_item_moeda, spr_item_tesouro, spr_item_diamante, spr_item_pocaodeenergia, spr_item_pocaodemana, spr_power_up, spr_equip_espadacomum, spr_equip_espadadourada, spr_equip_espadadecristal, spr_equip_arcocomum, spr_equip_arcodourado, spr_equip_arcodecristal, spr_equip_cajadocomum, spr_equip_cajadodourado, spr_equip_cajadodecristal, spr_equip_armaduradepano, spr_equip_armaduradeferro, spr_equip_armaduradourada.
Crie os seguintes Objetos: obj_item, obj_item_auto, obj_item_press, obj_equip_arma, obj_equip_armadura, obj_item_pocaodeenergia, obj_item_pocaodemana, obj_arma_comum, obj_arma_dourada, obj_arma_cristal, obj_armadura_pano, obj_armadura_ferro, obj_armadura_dourada, obj_power_up, obj_item_moeda, obj_item_tesouro, obj_item_diamante, obj_enfeite_mostradordeponto.
Crie os seguintes Scripts: script_item_auto, script_item_press, script_mostradordeponto, script_power_up
Crie os seguintes efeitos sonoros: snd_power_up

Criando:

Nós vamos criar dois tipos de itens. Um no qual é coletado automáticamente quando o jogador passa por cima, e outros que são coletados somente ao pressionar uma tecla específica.
Primeiro, vamos adicionar os Parents corretamente:
- obj_item_auto e obj_item_press com Parent no obj_item.
- obj_item_arma, obj_item_armadura, obj_item_pocaodeenergia, obj_item_pocaodemana com Parent no obj_item_press.
- obj_item_moeda, obj_item_tesouro e obj_item_diamante com Parent obj_item_auto.
- obj_arma_comum, obj_arma_dourada, obj_arma_cristal com Parent no obj_equip_arma.
- obj_armadura_pano, obj_armadura_ferro, obj_armadura_dourada com Parent no obj_equip_armadura.

Pronto. Agora vamos trabalhar nos scripts. O primeiro deles será o obj_item_auto, que é um dos mais simples. Deverá ficar assim:

{
if distance_to_object(obj_personagem) <=2
   {
   move_towards_point(obj_personagem.x, obj_personagem.y, 2);//Cria um efeito simples porém interessante em que o item vai na direção do jogador quando ele se aproxima demais, dando a impressão que ele atrai o item.
   }

if place_meeting(x,y, obj_personagem)
   {
    alarm[0] =1;//Como nós teremos diversos itens variados e seus efeitos não serão os mesmos, precisamos colocá-los separadamente. Nesse caso, o sistema de alarmes vai nos ajudar.

   instance_destroy();
   }
}

Coloque este script naturalmente no Step Event do obj_item_auto. O próximo script será o script_item_press, que deverá ficar parecido com o script acima, além de ser um pouco menor:

{
if place_meeting(x,y,obj_personagem) and keyboard_key_press(ord("L"))//Usarei a tecla "L" como tecla de ação secundária. Você pode trocar por outra se desejar.
    {
     alarm[0] =1;
    
     instance_destroy();
    }
}

Agora coloque no Step Event do obj_item_press.

AJUDANDO A ENTENDER: "O que é e como e funciona um Alarm?" - O evento Alarm acontece quando o tempo que você determina nele acaba. Por exemplo, se eu colocar alarm[0]=60, tudo que está no evento do Alarm 0 irá ocorrer ao passar 2 segundos (60 steps). Vale lembrar que isso não é igual ao Step Event. As ações do Alarm só ocorrem uma vez, e você deverá colocar o contador novamente se quiser que aconteçam novamente. Caso você precise de uma ação instantânea, coloque Alarm["x"]=1, por exemplo. Você também pode usar os alarm para que uma ação ocorra, por exemplo, sempre à cada 3 segundos. Basta apenas colocar Alarm[0]=90 no próprio Alarm 0, e o ciclo vai se repetir infinitamente.

Para configurar as Armas e as Armaduras, não usaremos nenhum script, porém uma folha de código simples no lugar. O motivo disso é que será algo simples demais. No alarm[0] ("create event" > "alarm" > "alarm 0") coloque uma folha de código em ambos com os seguintes códigos:

- No obj_equip_arma:
{
    obj_jogador.var_equipamento_arma_nome =var_nome;
    obj_jogador.var_equipamento_arma =var_ataque;
}

- No obj_equip_armadura:
{
    obj_jogador.var_equipamento_armadura_nome =var_nome;
    obj_jogador.var_equipamento_armadura =var_defesa;
}
Assim como nos ataques, nós vamos dar as pequenas personalizadas em cada armadura e arma separadamente, colocando uma folha de código simples no Create Event de cada uma e editando os seus valores, lembrando que vamos criar um pequeno sistema para o Sprite da arma mudar automáticamente de acordo com o personagem:

- No obj_arma_comum:
//Arma comum setup
if instance_exists(obj_personagem_guerreiro)
    {
    var_nome = "Espada comum";
    sprite_index = spr_arma_espadacomum;
    }
if instance_exists(obj_personagem_mago)
    {
    var_nome = "Cajado comum";
    sprite_index = spr_arma_cajadocomum;
    }
if instance_exists(obj_personagem_arqueiro)
    {
    var_nome = "Arco comum";
    sprite_index = spr_arma_arcocomum;
    }
    var_ataque =1;
}

- No obj_arma_dourada:
//Arma dourada setup
if instance_exists(obj_personagem_guerreiro)
    {
    var_nome = "Espada dourada";
    sprite_index = spr_arma_espadadourada;
    }
if instance_exists(obj_personagem_mago)
    {
    var_nome = "Cajado dourado";
    sprite_index = spr_arma_cajadocomum;
    }
if instance_exists(obj_personagem_arqueiro)
    {
    var_nome = "Arco dourado";
    sprite_index = spr_arma_arcocomum;
    }
    var_ataque =2;
}

- No obj_arma_cristal:
//Arma de cristal setup
if instance_exists(obj_personagem_guerreiro)
    {
    var_nome = "Espada de cristal";
    sprite_index = spr_arma_espadadecristal;
    }
if instance_exists(obj_personagem_mago)
    {
    var_nome = "Cajado de cristal";
    sprite_index = spr_arma_cajadodecristal;
    }
if instance_exists(obj_personagem_arqueiro)
    {
    var_nome = "Arco de cristal";
    sprite_index = spr_arma_arcodecristal;
    }
    var_ataque =3;
}

As armaduras vão seguir o mesmo padrão. Como nós não vamos diferenciar as armaduras de acordo com os personagens, será um pouco mais simples:

- No obj_armadura_pano:
//Armadura de pano setup
{
    var_nome = "Armadura de pano";
    var_defesa =1;
}

- No obj_armadura_ferro:
//Armadura de ferro setup
{
    var_nome = "Armadura de ferro";
    var_defesa =2;
}

- No obj_armadura_cristal:
//Armadura de cristal setup
{
    var_nome = "Armadura dourada";
    var_defesa =3;
}

Feito. Como você com certeza percebeu com o trabalho até agora, tudo se trata de ações em cadeia, onde tudo leva à outra coisa, sempre seguindo um mesmo padrão.

Antes de mais nada, vamos acrescentar um pequeno código no script_personagem_arrumador, no qual fará o nome da arma/armadura ser "Nenhuma" caso o personagem não tenha uma arma. Acrescente o seguinte:

if var_equipamento_arma =0
   var_equipamento_arma_nome ="Nenhuma";
if var_equipamento_armadura =0
   var_equipamento_armadura_nome ="Nenhuma";

Isso fará uma pequena mudança quando criarmos a interface do jogo, e afinal, uma correção automática é sempre bem-vindo (é uma coisa à menos para nos preocuparmos). Agora vamos fazer nosso dinheiro, tesouros, moedas e diamantes, que será extremamente simples. Na verdade, nós já fizemos parte disso, e o esquema será exatamente o mesmo. No alarm[0] do obj_item_auto, coloque:

//Setup de itens de dinheiro
{
    obj_personagem.var_moedas += var_quantidade;//Adiciona o dinheiro ao jogador
    var_enfeite = instance_create(x,y,obj_enfeite_mostradordeponto);//Cria um enfeite que será programado para mostrar quantos pontos o jogador obteve ao pegar o item.
    var_enfeite.var_quantidade = var_quantidade;//O obj_enfeite criado copia essa variável.
}

Agora vamos programar o obj_enfeite_mostradordeponto para que ele mostre quantos pontos o obj_personagem obteve ao pegar o item, de uma forma que os pontos mostrados subam lentamente na tela e desapareçam depois de alguns segundos. Ele será um pequeno fragmento da nossa interface, ou seja, ele utilizará o Draw Event. No script_mostradordeponto, faça o seguinte código:

//Mostra quantos pontos o jogador obteve
{
   draw_text(x,y,"+"+string(var_pontos))
}

Coloque este script no Draw Event do obj_enfeite_mostradordeponto. No Create Event, coloque {alarm[0] = 30;}. No Alarm[0], coloque {instance_destroy();}.Agora no Step Event, coloque uma folha de código simples apenas com {y+=1;}.

Vamos começar a trabalhar com os Power Ups. Basicamente eles serão itens especiais que almentam o poder do personagem por um certo período de, digamos, 30 segundos. No script_power_up, podemos colocar algo como:

if place_meeting(x,y,obj_jogador)
{
  obj_personagem.var_power_up = 900//30 steps por segundo x 30 segundos = 900
  sound_play(snd_power_up);//Efeito sonoro
  instance_destroy()//Destrói o item após o efeito.
}

Agora vamos ter que fazer pequenas alterações no obj_personagem, novamente, para que o Power Up funcione.

- No script_personagem_setup_geral, acrescente:
  var_power_up =0;

- No script_personagem_setup_guerreiro, acrescente:
  var_meu_supergolpe = obj_ataque_supergolpe;

- No script_personagem_setup_arqueiro, acrescente:
  var_meu_supergolpe = obj_ataque_superflecha;

- No script_personagem_setup_mago, acrescente:
  var_meu_supergolpe = obj_ataque_meteoro;

Agora faremos uma pequena mudança no script_personagem_ataque. Troquer a primeira parte do script (var_meu_ataque = 0) pela seguinte:

    if var_meu_ataque =0//Se o nosso ataque selecionado é o corpo-à-corpo
       {
        var_ataque_tempo = 30
        if  var_power_up <=0//Se o contador de super ataque está zerado.
        switch(var_face)//Vamos criar nosso ataque de acordo com a direção do personagem
               {
                case 0: instance_create(x+8,y,var_meu_golpe); break;
                case 90: instance_create(x,y-8,var_meu_golpe); break;
                case 180: instance_create(x-8,y,var_meu_golpe); break;
                case 270: instance_create(x,y+8,var_meu_golpe); break;
                }
        else
        switch(var_face)//Vamos criar nosso superataque de acordo com a direção do personagem
               {
                case 0: instance_create(x+8,y,var_meu_supergolpe); break;
                case 90: instance_create(x,y-8,var_meu_supergolpe); break;
                case 180: instance_create(x-8,y,var_meu_supergolpe); break;
                case 270: instance_create(x,y+8,var_meu_supergolpe); break;
                }
           }

No script_personagem_arrumador, vamos acrescentar o seguinte:

if var_power_up >0
   var_power_up -=1;

Pronto. Agora nosso personagem está apto à ter super-ataques por um curto período. Se quiser dar uma segunda olhada, vá no script_personagem_ataque e veja que o obj_personagem fará super-golpes quando a var_power_up está acima de 0, e no script_personagem_arrumador diminuirá constantemente em 1 o var_power_up até que ele se esgote. Tudo está se encaixando. Logo, quando programarmos os inimigos, faremos com que os mais poderosos tenham pequenas chances de deixar tal Power Up cair.

Vamos para o próximo passo, no qual vamos nos aprofundar mais nos atributos do personagem (dano, defesa, energia, mana) e também no nível e experiência, como qualquer outro RPG comum.
6. Fazendo funcionar os atributos do personagem:
Conceito:

Os atributos do personagem é um elemento presente em qualquer tipo de RPG. 'Força', 'Inteligencia', 'Vitalidade', 'Destreza', 'Sorte', e outros tantos que você pode acrescentar. Neste projeto vamos trabalhar com algo mais simples, utilizando apenas quatro atributos que irão interferir no combate: Força, Deztreza, Vitalidade e Inteligência.

No início do nosso projeto, nós já atribuímos estes recursos ao nossos personagens (nos script_jogador_setup_x), mas eles eram apenas representativos. Vamos fazê-los com que funcionem realmente e tenham sinergia com o nível e com o equipamento dos nossos personagens.

Futuramente vamos criar formas diferentes do personagem aprimorar seus atributos, como por exemplo completar algumas missões.

Preparação:

Crie os seguintes scripts: script_personagem_mago_atributos, script_personagem_guerreiro_atributos, script_personagem_arqueiro_atributos, script
Crie os seguintes efeitos sonoros: snd_levelup

Método:

Este será um passo muito simples. Lembre-se que cada personagem possui uma sinergia maior com um atributo diferente. Por exemplo, a força agirá melhor com o guerreiro assim como um mago ficará mais eficaz com a inteligência alta do que os outros personagens.

No script_personagem_mago_atributos, coloque:
{
    var_dano = (var_equipamento_arma*5 + var_inteligencia*2);//O mago tem seu dano baseado em inteligência
    var_mana_max = (var_inteligencia*7);//Demos ao mago um destaque maior à mana
    var_energia_max = (var_vitalidade*3);//Demos um mago uma fragilidade maior quanto aos outros personagens, para compensar dano em potencial maior
}

No script_personagem_guerreiro_atributos, coloque:
{
    var_dano = (var_equipamento_arma*5 + var_forca*2);//O guerreiro tem seu dano baseado em força
    var_mana_max = (var_inteligencia);//Demos ao guerreiro o pior potencial para mana
    var_energia_max = (var_vitalidade*10);//Demos ao guerreiro a melhor resistência possível
}

No script_personagem_arqueiro_atributos, coloque:
{
    var_dano = (var_equipamento_arma*5 + var_destreza*2);//O arqueiro tem seu dano baseado na destreza
    var_mana_max = (var_inteligencia*3);//Demos ao arqueiro uma mana mediana
    var_energia_max = (var_vitalidade*5);//Demos ao arqueiro uma resistência mediana
}

Agora que os atributos estão um pouco mais consistentes, coloque, como de costume, estes scripts no Step Event em seus respectivos personagens. Agora vamos mexer novamente no script_personagem_arrumador.

Vamos fazer com que o personagem evolua de nível ao atingir uma certa quantidade de pontos de experiência. Esses pontos serão obtidos ao abater inimigos, e toda vez que o personagem ganha um nível, ele ganha alguns pontos de atributos baseados em sua classe e o limite para evoluir ao próximo inimigo se torna maior.

A formula que iremos usar para indicar quantos pontos o jogador deve acumular para avançar ao próximo nível será (pode ser alterada de acordo com o seu gosto):
(var_nivel*var_nivel)*17

No script_personagem_arrumador, acrescente:
if var_experiencia >= (var_nivel*var_nivel)*17
{
    var_experiencia -=(var_nivel*var_nivel)*17;//Retira os pontos de experiência já ganhos
    var_nivel +=1;//Avança um nível

    //Adiciona um ponto para cada atributo do personagem. Lembre-se que as classes se comportam diferentemente perante cada atributo.
    var_atributo_forca +=1;
    var_atributo_destreza +=1;
    var_atributo_inteligencia +=1;
    var_atributo_vitalidade +=1;

    //Prêmios adicionais
    var_energia = var_energia_max;//Como premio adicional, o jogador é curado ao máximo
    var_mana = var_mana_max;//Como premio adicional, a mana do jogador é restaurada ao máximo
    var_especial = 100//Como último prêmio adicional, a barra do golpe especial do jogador é preenchida

    //Efeito sonoro
    sound_play(snd_levelup);//Toca um efeito sonoro para indicar ao jogador
}

Este foi um passo bem simples, porém importante. Ele terá uma função muito importante durente o combate do jogo. Para que isso aconteça, nós precisamos de inimigos para batalharmos. E eu acho que este é o melhor momento.

[EM CONSTRUÇÃO]