Iae galera, tudo tranquilo?
Bem... dessa vez eu vou criar um super tutorial de como criar seu jogo de
Top-Down de aventura e batalha em tempo real. Para quem não sabe, Top-Down é quando você olha o personagem por cima e tem a liberdade de se movimentar para todas as direções (diferente de um jogo de plataforma, onde a gravidade é aplicada ao jogo).
Nesse projetos, vamos explorar muitas possibilidades, o que fará o tutorial ser bem extenso. Mas depois que completarmos, você irá me agradecer. Pode ter certeza x3 Só cuidado para não se perder no fluxo do tutorial. Se não entendeu uma parte, vá tentando até conseguir, não pule partes e leia atentamente ou tudo vai dar errado no final.
Para isso, vocês devem ter o
GameMaker 8.0 ou o
8.1 Standard(
não usem o 8.1 Lite/grátis pois ela coloca uma watermark da Yoyo games no seu jogo).
Antes de começarmos, não se esqueca de ir no
Menu e checar se a opção
Advanced Mode está ativa.
0. Objetivo do tutorial
1. Iniciando
2. O Jogador
2.1 Primeiros passos
2.2 Movimentação
2.3 Ataque
2.3 Energia, Vidas e Game over
2.4 Vida Extra
3. Nossa primeira room e a câmera
4. Obstáculos
5. Itens
6. Inimigos e sistema de batalha
7. Objetivo do jogo
8. Interface
9. Considerações finais
0. Objetivo do tutorial:
Criar um jogo Top-Down em que o jogador necessita pegar o diamante no final das fases, atacando os inimigos com socos e flechas se necessário. O jogo deverá apresentar uma interface básica também.
1. Iniciando:
Bom galera, primeiro vamos criar os objetos do jogo. Para os sprites, recomendo que por hora usem alguns básicos como quadrados de diferentes cores. Vamos criar alguns sprites e objetos vazios por hora para usarmos mais tarde:
Sprites: (Faça todos eles 32x32 de preferência)
- jogador_esquerda
- jogador_direita
- jogador_cima
- jogador_baixo
- jogador_ataque_esquerda
- jogador_ataque_direita
- jogador_ataque_cima
- jogador_ataque_baixo
- parede_sprite
- flecha_sprite
- tesouro_sprite
- mask_32_32 (Deve ser um quadrado cheio que ocupe toda a imagem, sem sobras)
- item_energia_sprite
- item_vida_sprite
- diamante_sprite
- vida_barra_sprite
- bola_de_fogo_sprite
Objetos:
-
jogador
-
ataque_principal
-
ataque_1
-
flecha
-
inimigo_principal
- inimigo_1
- inimigo_2
- inimigo_3
-
obstaculo_principal
-
obstaculo_alto
-
obstaculo_raso
-
tesouro
-
inimigo
- item_energia
- item_vida
- diamante
- jogador_posicao_inicial
- interface
- bola_de_fogo
Criem esses objetos com os mesmos nomes. Todos eles ficarão vazios, se quiser, você já pode especificar as sprites deles.
Já, já, iremos usar GML (Game Maker Language) para programas nossos jogos, então, copie e cole os códigos em
verde e coloque-os nos eventos que eu irei especificar.
Mas colar onde? Cole nas páginas do
Execute Code.
2. O Jogador
Bem, aqui está o nosso herói da vez. Ele vai carregar em sí o foco principal da câmera do jogo e várias variáveis importantes, por isso, ele nunca poderá deixar de existir.
2.1 Primeiros passos:
Assim sendo, vamos deixá-lo
Persistent. Assim, basta colocar ele apenas na primeira room do jogo que ele passará adiante em todas as outras Rooms.
Também deixaremos ele
Sólid. Pois assim, os inimigos não vão passar por cima dele futuramente e interpretarão ele como um obstáculo em potêncial.
Para evitarmos bugs na colisão com obstáculos, adicionaremos uma
Mask para o jogador. A
Mask dele será a
mask_32_32 que criamos anteriormente.
Agora no
Create event, vamos dar ao nosso personagem algumas funções importantes. Coloque uma peça de código e vamos carregá-lo com algumas informações necessárias.
atacando =false
face =0
pontos =0
energia =100
energia_maximo =energia
vidas =3
2.2 Movimentação:
Agora vamos lhe dar movimentação, que é a parte mais importante. Para isso, vamos usar um código que checa se na direção não existe objetos sólidos, se o botão está sendo pressionado e, enquanto as duas estiverem satisfeitas, o jogador vai andar. Veja um exemplo:
if keyboard_check(vk_up) //Checa se o botão 'Direcional para Cima' está pressionado
{face = 90 //A direção do jogador, em graus. Não é obrigatório, mas será muito útil.
sprite_index = jogador_cima //Caso for verdade, o jogador mudará sua sprite.
if place_free(x,y-4){y -=4} //Agora, se quatro pixels acima estiver livres de obstáculos sólidos, o jogador andará quatro pixels acima. Se não, ele não anda nada.
}
Se você entendeu como funciona este código, será fácil programar as outras direções do personagem. Vamos colocar este código no
step event do objeto
jogador. Assim, usaremos as setas de direção para movermos nosso personagem.
//Movimentação para a direita
if keyboard_check(vk_right)
{face =0
sprite_index = jogador_direita
if place_free(x+4,y){x +=4}
}
//Movimentação para a esquerda
if keyboard_check(vk_left)
{face =180
sprite_index = jogador_esquerda
if place_free(x-4,y){x -=4}
}
//Movimentação para cima
if keyboard_check(vk_up)
{face =90
sprite_index = jogador_cima
if place_free(x,y-4){y -=4}
}
//Movimentação para baixo
if keyboard_check(vk_down)
{face =270
sprite_index = jogador_baixo
if place_free(x,y+4){y +=4}
}
Depois disso, vamos arrumar a
velocidade visual de movimentação do personagem.
Mas como assim? Bem, você provavelmente quer ver o seu personagem ''andando'' apenas quando ele tem certa velocidade, e não mechendo as pernas enquanto estiver parado.
Para isso, vamos utilizar o seguinte código, também no
step event, e deve ser após o código anterior:
if keyboard_check (vk_down) or keyboard_check (vk_up) or keyboard_check (vk_right) or keyboard_check (vk_left) = true //Checa se algum direcional está sendo pressionado
{
image_speed=0.5 //A imagem do personagem se movimentará junto com ele
}
else //Se não...
{
image_speed =0 //O desenho do personagem ficará parado
image_index =0 //e voltará para a primeira imagem
}
Agora, a movimentação de nosso personagem está completa.
2.3 Ataque
Bom, agora vamos trabalhar no ataque do nosso personagem. Para inovar, vamos fazer duas possibilidades: o ataque de curto alcance e atirar flechas. ''Atirar flechas'' pode ser facilmente substituido por tiros, então fique ligado!
Antes disso, vamos alterar um pouco os nossos objetos ataque_principal, ataque_1 e flecha. Faça o ataque_1 e a flecha ficarem
Parent do ataque_principal.
O
ataque_1 representará o ataque de curta distância do personagem, seja um soco ou coisa do tipo. Coloque qualquer sprite, de preferência 32x32 e de apenas uma subimagem. Você provavelmente vai querer que ele exista mais fique invisível aos olhos do jogador, então, vamos
desmarcar a caixa de
Visible dele. Agora, vá em
Other events >
Animation End e coloque apenas a função
instance_destroy(). Isso fará com que ele se destrua quase instantaneamente.
Mas porque isso é necessário? Simples, para ele ser destruído (o ataque) assim que acertar ou não acertar o inimigo.
Agora a
flecha. Coloque no objeto uma sprite com 4 subimagens, cada uma com a flecha apontando para uma direção diferente. A primeira subimagem deve ser da flecha apontando para a direita (a segunda, para cima, a terceira para a esquerda e a ultima para baixo). Agora, coloque no
create event o seguinte código:
direction = jogador.face //Faz com que ela vá na direção do jogador no momento que ela foi criada
speed =8 //Velocidade da flecha
image_speed =0
image_index=direction*image_number/360 //Este código faz com que a flecha escolha automáticamente a subimagem certa conforme sua direção.
Ainda no
Create Event, coloque o
alarm[0] para 150, e no evento do alarm[0], coloque
instance_destroy(). Isso fará com que, em 5 segundos, a flecha se auto-destrua, para impedir que ela vá muito longe.
Agora coloque um
evento de colisão com o objeto
obstaculo_alto,
instance_destroy() também, para ela ser destruida assim que bater em alguma parede ou coisa do gênero.
Agora que nós programamos os dois tipos de ataque, vamos programar para o jogador em criar ambos. O botão para o jogador atacar de perto será a letra
A, e para o jogador atirar uma flecha, será a letra
S.
Primeiro vamos programar o ataque curto/soco no
jogador. Adicione o seguinte código na letra correspondente (neste caso, a letra
A).
if atacando =false //Se ele ainda não estiver atacando no momento...
{atacando =true //Agora ele está.
if face = 0
instance_create(x+16,y,ataque_1)
if face =90
instance_create(y-16,y,ataque_1)
if face =180
instance_create(x-16,y,ataque_1)
if face = 270
instance_create(y+16,y,ataque_1)
}
Agora faça o mesmo com a flecha, só que em outra tecla (no nosso caso,
S). Use o mesmo código acima, trocando apenas o ataque_1 por flecha. Se você preferir, troque também todos os 16 por 8, assim, evitará alguns bugs de colisão nas paredes e etc.
Muito bem! Agora nosso personagem ataca! Mas perái... ele pode até criar o ataque e a flecha, mas ele ainda não aparece atacando... Bom, para isso, vamos utilizar um código simples como o de andar, e de quebra, impediremos o jogador de andar enquanto ataca.
Coloque este código no step event, na mesma página do código do movimento, porém primeiro. Assim:
if atacando =true //Se o personagem estiver atacando...
{
image_speed =0.5
if face =0
sprite_index = jogador_atacando_direita
if face =90
sprite_index = jogador_atacando_cima
if face =180
sprite_index = jogador_atacando_esquerda
if face =270
sprite_index = jogador_atacando_baixo
}
else //Ou então... apartir daqui, ficará o código do movimento do personagem, assim, se ele NÃO estiver atacando, ele ficará livre para andar.
{Coloque o código de movimento aqui dentro e apague esta mensagem, ou seu jogo vai dar erro}
Agora, coloque isto no evento
Other >
Animation end:
atacando =false //Assim, o jogador vai parar de atacar assim que a animação de ataque dele terminar.
Ufa! Sei que essa parte foi extremamente cansativa e trabalhosa, mas posso lhe dizer: o pior já foi. Agora respire fundo e vamos continuar.
2.4 Energia, Vidas e Game over:
Agora vamos programar a parte da energia, vida e para nosso personagem morrer. O Próprio GameMaker oferece esse sistema, mas é, na verdade, bem limitado, fora isso, se você conseguir entender como funciona, você terá infinitas possibilidades!
No Create event do nosso personagem, vamos
relembrar algumas coisas que nós especificamos:
energia =100
energia_maximo =energia
vidas =3
Assim sendo, vamos fazer o seguinte: Quando a energia chegar em 0, o personagem perde uma vida. Se as vidas chegarem ao 0, o jogo acaba. Faça o seguinte, numa folha de código separada no
step event do jogador:
if energia < 0 {energia =0} // Impede que a energia fique menos que 0
if energia > energia_maximo {energia = energia_maximo} //Impede que a energia fique mais que o limite que especificamos.
if energia =0 //Agora, se a energia chegar à 0...
{
show_message("Você morreu! Tente novamente!") //Mensagem de morte
vidas -=1 // Retira uma vida
room_restart() // Futuramente faremos com que isso faça o jogador voltar para a posição inicial
}
Muito bem, agora a nossa energia está programada e irá funcionar corretamente. Agora vamos programar as vidas. Você pode colocar este código na mesma folha da energia, depois ou antes:
if vidas <=0 {
show_message("Fim de Jogo!!") // Mensagem de Game over
game_restart() // Reinicia o jogo
}
Muito bem! Agora o nosso Game over também está programado.
2.5: Vida extra:
Nós ainda temos que pensar no que fazer com os pontos que o personagem vai pegar durante o jogo. Por que não colocamos, por exemplo, para cada 1000 pontos que ele obter, ele ganha uma nova vida?
Para isso, coloque outra folha de código no step event:
if pontos >=1000 // Se o jogador tiver mil ou mais pontos
{
vidas +=1 // Ele ganha mais uma vida
pontos -=1000 // Não se esqueça de descontar os mil pontos, ou ele ficará ganhando vidas infinitas toda hora
}
Ótimo! Agora nosso jogador está definitivamente completo! Agora que temos metade do jogo em nossas mãos, vamos aos outros aspectos necessário para o jogo rodar.
3. Nossa primeira room e a câmera:
Bom, agora, crie uma sala de cerca de 960x960 e coloque uma instância de jogador no centro dela.Você pode colocar um background legal.
Agora, vá na aba
Views e marque a caixa
Enable use of views e no View[0], marque a caixa
Visible when room starts. Agora você pode alterar livremente os valores, mas considere muitas coisas antes:
View in room: Altera o tamanho da câmera da room. O padrão é 640x480 e é um bom tamanho, quase ideal. Não precisa alterar o X e Y pois não será uma câmera fixa, ela vai seguir o
jogador.
Port on Screen: Altera o tamanha da tela do jogo no computador da pessoa. Se você colocar maior que o View in room, ele vai esticar os gráficos do seu jogo, e se for menor, vai comprimir. O ideal é deixar do mesmo tamanho que o view.
Object following: Coloque jogador. O Hsp (Horizontal Speed) e Vsp (Vertical Speed) é a velocidade da câmera ao seguir o jogador. De preferência deixe -1 como está. Já o Hbor e Vbor, coloque valores como 128/96, para centralizar um pouco o jogador na câmera.
4. Obstáculos:
Agora vamos criar os obstáculos do jogo. Eu pedi a vocês para criarem os objetos
obstaculo_principal,
obstaculo_raso e
obstaculo_alto.
Mas por quê isso?
Bem, a explicação é muito simples: o
obstaculo_alto não permitirá a passagem de flechas e coisas do gênero enquanto o
obstaculo_raso sim, mas ambos não permitirão o jogador nem os inimigos passarem. Legal, né? Assim, você poderá fazer paredes não deixar flechas passarem, mas ao mesmo tempo possibilitar do jogador atirar flechas nos inimigos do outro lado de um rio ou por grades, por exemplo.
Bom, se você acompanhou o tutorial, já programamos a flecha para ser destruída no contato com o obstáculo_alto.
Agora, faça o
obstaculo_alto e
obstaculo_raso ficaram no
Parent com o
obstaculo_principal. Isso não terá uma utilidade definida, mas é somente por conveniência. Coloque também
todos os três como
Solid por motivos óbvios.
Agora, você pode criar todos os obstáculos que imaginar: árvores, pedras, rios e etc. Mas lembre-se sempre de ligar os obstáculos no
Parent com o
obstaculo_alto ou o
obstaculo_raso, dependendo se ele deixa ou não flechas passarem por ele. Lembre-se: nenhum objeto além do
obstáculo_raso e
obstáculo_alto devem ser ligados diretamente no
obstáculo_principal.
Lembre-se também de colocar a
mask_32_32 como
mask dos obstáculos para impedir bugs de colisão.
Então, coloque os obstáculos na sua room e faça um rápido teste. Atire flechas e tente andar sobre eles. Se nenhum deles deixar o jogador passar, e os rasos (provalmente rios, por exemplo) não destruirem as flechas, ótimo! Deu tudo certo!
Se você quiser colocar a room como
Persistent, fique a vontade.
Mas lembre-se: Se ela NÃO for Persistent, sempre que você voltar nela um novo jogador será criado, então, você pode:
- Deixar a room persistent
- Impedir do jogador voltar nessa room depois que sair dela
5. Itens:
Agora vamos criar nossos itens. Eu pedi para vocês criarem três itens: item_energia, item_vida e tesouro. São muito simples de serem programados, e todas suas funções eles serão especificadas via
Collision event com o
jogador.
item_energia:
jogador.energia +=25
instance_destroy()
item_vida:
jogador.vida +=1
instance_destroy()
item_tesouro:
jogador.pontos +=100
instance_destroy()
Se os itens tiverem uma animação básica em seus sprites, coloque um
image_speed =0.5 no
Create event para que ela não fique muito rápida.
Agora nós temos os itens para espalhar pelo nosso jogo. Agora vamos continuar que estamos quase acabando!
6. Inimigos e sistema de batalhas:
Bom, agora chegou a hora de colocar ameaças e desafios no nosso jogo. Existe infinitas possibilidades para programar uma IA de inimigos. Não vamos entrar em detalhes perfeccionistas nem uma IA tão inteligente, vamos apenas fazer um molde básico de inimigo.
Como o nosso jogo permite o personagem atacar, vamos ter que fazer inimigos mais agressivos e que saibam atacar o jogador também.
Eu pedi para vocês criarem quatro objetos:
inimigo_principal,
inimigo_1,
inimigo_2,
inimigo_3. Assim como nos obstáculos, o inimigo_1,2 e 3 serão ligados no
inimigo_principal, e assim como os obstáculos, o
inimigo_principal não fará parte do jogo diretamente, é apenas o molde que dará as informações mais necessárias para seus afiliados, por isso, faremos o principal nele, e para diferenciar um inimigo do outro, faremos pequenas alterações, como velocidade, sprite e etc. Se ficou difícil de entender, vamos por a mão na massa que se aprende mesmo é fazendo.
Vamos primeiro fazer o ataque deles, que será representado pelo objeto bola_de_fogo que já foi criado. No
Create event da
bola_de_fogo, coloque:
move_towards_point(jogador.x,jogador.y,4)
Na
colisão com o
jogador, coloque:
jogador.energia -10
instance_destroy()
E na
colisão com o
obstaculo_alto, coloque apenas:
instance_destroy()
No
Create event do
inimigo_principal, coloque:
velocidade =0
energia =0
delay =0
Então, no
step event, vamos fazer uma IA básica:
if distance_to_object(jogador) <=160 //Se ele estiver a menos de 160 pixels de distância do jogador...
{
if distance_to_object(jogador) <=64 //Agora, se ele estiver ainda mais perto do jogador...
{
if delay <=0{
delay =100
instance_create(x,y,bola_de_fogo) //Ele ataca
}
}
else //Se não...
mp_potential_step(jogador.x,jogador.y,velocidade,0) //Ele continua andando em direção ao jogador
}
else //Se não...
speed =0 //Para de andar
if delay >0{delay -=1}
if energia <=0 {instance_destroy()} //Se a energia acabar, ele é destruido.
Agora vamos fazer o inimigo perder energia quando é atacado. Para isso, crie um
Collision event com o objeto ataque_principal:
energia -=irandom_range(10,25) //Faremos ele perder entre 10 e 25 pontos de energia quando atacado.
other.destroy_instance() //Destruir o ataque
Só para finalizar, vamos fazer com que os inimigos parem de andar no contato com a parede. Coloque um evento de
colisão com o
obstáculo_principal.
speed =0 //Apenas por conveniência, já que a IA dele impede que ele tente atravessar obstáculos
Agora, nosso
inimigo_principal já está totalmente pronto. Agora, vamos fazer pequenas alterações no
inimigo_1,
inimigo_2 e
inimigo_3.
No
Create event do
inimigo_1:
velocidade =1
energia =50
delay =0
No
Create event do
inimigo_2:
velocidade =4
energia =20
delay =0
No
Create event do
inimigo_3:
velocidade =2
energia =70
delay =0
Todo os outros eventos não precisam ser alterados, pois estão puxando informação da programação do
inimigo_principal, já que estão de
Parent nele. Agora que os inimigos estão totalmente programados, você nós podemos partir para o penúltimo passo do nosso mega tutorial.
7. Objetivo do jogo
Claro que todo jogo deve ter um objetivo. Então, vamos colocar como objetivo o jogador pegar o
diamante. Você provavelmente deve ter colocado várias instâncias na sua primeira room, então, agora coloque alguns inimigos, faça um pequeno "labirinto" (mas não leve ao pé da letra, pois isso não é um jogo de maze) e coloque o diamante no fim dele. Agora vamos programar o diamante.
Coloque um
Collision event do
diamante com o
Jogador.
if (room != room_last) //Se não for a última room do jogo
{
show_message("Você conseguiu! Vamos para a próxima fase!") //Mensagem de sucesso
room_goto_next() //Próxima fase
}
else //Mas se for...
{
show_message("Parabéns! Você conseguiu vencer a última fase! Obrigado por jogar!!") //Mensagem final
game_end() //O jogo fecha
}
Agora o diamante está programado para passar as fases e terminar o jogo. Mas quando você passa a fase, provavelmente perceberá que o seu
jogador, que é
Persistent, inicia a próxima no mesmo lugar que ele terminou a anterior. É aí que encontra nosso objeto especial:
jogador_posicao_inicial.
Coloque o
jogador_posicao_inicial no lugar que você quer que o
jogador comece a fase. Então coloque no
other >
room_start do
jogador_posicao_inicial e coloque o seguinte código:
jogador.x = x
jogador y =y
Agora sempre que o jogador entrar numa room ou morrer (lembra que programamos para a room reiniciar quando o personagem morrer?), ele é transportado automáticamente para o
jogador_posicao_inicial. Não se esqueça de colocar um
sprite qualquer nele e deixar o
Visible dele
desligado. E claro, lembre-se de colocar o
jogador_posicao_inicial em todas as rooms do jogo.
8. Interface:
Agora que nosso jogo está praticamente completo, por que não deixá-lo mais bonito e com algumas informações? Para isso, criamos o sprite
vida_barra_sprite. Faça dele um sprite cerca de 100x25 com cerca de 20 subimagens, cada uma menos cheia que a outra.
 |
| Salve esta imagem se desejar. |
Agora, precisamos de um objeto para colocar nossa interface na tela. Para isso criamos o objeto
interface. Deixe ele sempre
Visible e
Persistent, e coloque ele na mesma sala que o
jogador. Além disso, coloque o
Depth dela como
-1000 (isso fará ela ficar acima de qualquer objeto).
Agora, acrescente o
Draw Event e vamos fazer a interface básica do nosso joguinho.
draw_sprite(vida_barra_sprite,(jogador.energia*20/jogador.energia_maximo),view_xview[0]+4,view_yview[0]+4)
Este código colocará sua barra de energia no canto superior esquerdo da tela como mágica. Agora vamos adicionar algumas informações, como vidas restantes e a pontuação.
Coloque uma cor legal no draw event da interface (uma que não seja tão escura nem tão clara) e crie uma fonte legal, nem muito pequena nem muito grande e coloque-a também (ambos acima da folha de código).
Agora adicione o código na mesma folha da barra de vida.
draw_text(view_xview[0]+4,view_yview[0]+30,"Vidas: "+string(jogador.vidas))
draw_text(view_xview[0]+4,view_yview[0]+50,"Pontos: "+string(jogador.pontos))
Pronto! Agora sua interface está completa!
9. Considerações finais:
Pronto! Agora criamos todos os básicos que um jogo deve ter usando GML. Teste seu jogo e veja se funciona. Se algo no tutorial está dando errado, favor avisar!!
Logo, criarei uma engine com tudo pronto e disponibilizarei o Download para vocês verem como é nosso jogo pronto.
Copie, mas cite a fonte!!!
Até a próxima!