Game design - Movimentando o personagem
Postado: na M.Cassab
Estado: falta muito para as 17h30 ?
Escutando: Van Halen - Not Enough
Estado: falta muito para as 17h30 ?
Escutando: Van Halen - Not Enough
Atribuição: Uso Não-Comercial
O conteúdo desta página foi baseado nos tutoriais contidos no site Tile based games, autorizado sob a licença Creative Commons e não pode ser utilizado para fins comerciais.
A tradução e adaptação dos textos, códigos ActionScripts e todas as outras obras originais criadas por Tonypa foram autorizada é são de propriedade dele.
Attribution: Noncommercial
The content on this page was based tutorials in the site Tile based games, licensed under a Creative Commons License and you may not use this work for commercial purposes.
The translation and adaptation of text, ActionScripts codes and all other original works created by Tonypa were authorized is are his property.
Agora que você viu como inserir um personagem no cenário (vamos chamar simplesmente como PC), chegou o momento de dar vida a ele.
Entenda, a maior diferença de um jogo para uma animação é unicamente a interatividade do que você criou com o jogador. A partir de agora, tenha isso sempre em mente.
Sendo assim, vamos criar o primeiro canal de interatividade: a interface do jogo com o jogador por meio dos controles. Vamos começar com o básico, utilizando os quatro direcionais do teclado.
No final do processo, você deverá ter algo parecido com esse exemplo que o Tony publicou o site Tile based games:
Esse SFW foi criado pelo Tony para o site Tile based games e está sendo utilizado sob sua autorização.
Note que o PC está passando por cima de
tudo. Não se preocupe com isso. Vamos nos concentrar apenas com a movimentação primeiro.
1º passo: Criar um movieClip para o PC
Como você deve ter lido sobre os sprites no capítulo passado (eu espero), vamos direto para a prática.
Para facilitar ainda mais a nossa vida, vamos utilizar o exemplo do Tony: um triângulo vermelho que apontará a direção do movimento. Além disso, vamos simular o movimento dos passos para deixar as coisas mais interativas, logo, interessantes aos olhos.
A primeira coisa que fará é criar um movieClip para cada posição do PC. No nosso caso, de frente, de costas e de lado.
Não se preocupe com detalhes, vamos apenas criar uma movimentação simples para você entender como funciona o conceito.
Lembre-se de que todos os movieClips tem que ter o mesmo tamanho (menores do que 30px) e o registro tem que está no centro.
O Tomy, para simplificar, fez o seguinte, criou um movieClip com três keys frames, sendo:
- o primeiro key frame com o desenho está centralizado;
- o segundo key frame com o desenho levemente deslocado;
- o terceiro key frame com o desenho levemente deslocado para o lado oposto;
Cada key frame possui dois quadros (frames) de intervalo apenas para controlar a velocidade da animação. Veja a ilustração de como ficou a timeline do movieClips dele.
Se fez tudo corretamente, você terá para o PC, além do movieClips antigo que criou no capítulo anterior, mais três movieClips, um para cada posição do personagem (frente, costas e lado), no mínimo.
Claro, isso é para este caso. Para um jogo de verdade, você teria que criar um movieClips para cada estado do PC, sendo que cada um teria uma imagem em cada quadro da animação do movimento específico.
Voltando ao assunto, lembra do nosso movieClip char ? Vamos aproveitá-lo para agrupar os sprites do PC.
Exclua o que tiver no primeiro quadro e adicione os movieClips com as movimentações criadas. Cada movieClip de animação deverá ficar em um key frame.
Agora, nomeie a instância de cada movieClip como char. Essa é uma gambiarra é necessária para forçar o código a localizar o objeto quando trocar de quadro. Terminando, clique no primeiro quadro e insira a action stop() no frame.
O exemplo do Tony tem um movieClip com cinco quadros, sendo que o segundo tem dois quadros de duração.
Esse segundo quadro é (mais) uma gambiarra que entenderá melhor quando for programar as funções.
Depois de criar os key frames, crie uma nova camada, nomeie de Action e insira um stop() no primeiro quadro para travar a timeline de dentro desse movieClip e volte para o palco principal.
2º passo: declarar as propriedades do PC
Antes de começar a digitar o código, é preciso ter em mente o que deverá ser feito. Vamos inserir uma série de comandos que fará o personagem andar pelo cenário.
Se o PC vai se movimentar, precisamos declarar a velocidade do movimento. Como já havíamos declarado uma posição inicial no início do código, vamos aproveitar e declarar mais um parâmetro nessa linha.
char={xtile:2, ytile:1, speed:4};
Relembrando o capítulo anterior, nessa linha é declarada a posição inicial do nosso PC. Agora, incluímos mais um parâmetro, que indicará que ele terá a velocidade de 4px.
4º passo: verificar se houve alguma entrada nos controles
Não, não digitei errado. Mas por questões didáticas, achei melhor abordar esse assunto primeiro.
Vamos dar interatividade ao PC, criando uma interface com os controles do jogador, utilizando os direcionais do teclado. A primeira coisa a fazer é criar uma função para verificar se houve alguma entrada nos controles.
function detectKeys() {
Depois, deve declarar um objeto para receber o movieClip com os sprites do PC. Além disso, vamos delcarar tamébm uma variável para informar se houve uma entrada de comando (true) ou não (false).
var ob = _root.char;
var keyPressed = false;
Agora vem a interação com as entradas do controle. Devemos verificar qual botão foi pressionado pelo jogador e indicar o que acontecerá quando isso acontecer.
if (Key.isDown(Key.RIGHT)) {
keyPressed=_root.moveChar(ob, 1, 0);
} else if (Key.isDown(Key.LEFT)) {
keyPressed=_root.moveChar(ob, -1, 0);
} else if (Key.isDown(Key.UP)) {
keyPressed=_root.moveChar(ob, 0, -1);
} else if (Key.isDown(Key.DOWN)) {
keyPressed=_root.moveChar(ob, 0, 1);
}
Parece bem complicado, mas na verdade é até simples... só não imagino como o Tony chegou a essa conclusão. Mas faz sentido.
Na primeira linha é feita uma verificação se uma tecla é pressionada. Se for, é declarada uma função dentro de uma variável e passados alguns argumentos (objeto com o movieClip, coeficiente para o eixo X e coeficiente para o eixo Y).
Traduzindo: se essa tecla for pressionada, "pegue" o objeto indicado e mova-o para o sentido apontado pelo botão. Vou parar a explicação por aqui para retomamos esse ponto logo mais.
É feita a verificação se foi pressionada uma determinada tecla. Se não foi, é verificado se foi pressionada outra, seguindo assim consecutivamente até verificar todas.
Essa é uma função que deverá verificar todas as direções, ou seja, os sentidos relacionados aos botões disponibilizados no teclado (direita, esquerda, acima e abaixo). Se nenhum desses botões foi pressionado, não acontece nada e o PC fica parado (keyPressed = false).
Caso exista uma entrada, a variável keyPressed deixará de ser false e passará a ter a função que orientará a movimentação. Se a variável passa a ter um valor, então ela deixa de ser false e passa a ser true, permitindo verificar o conteúdo dessa variável para acionar um evento.
if (!keyPressed) {
ob.clip.char.gotoAndStop(1);
} else {
ob.clip.char.play();
}
A verificação acima está "questionando" se há um valor na variável keyPressed, ou seja, se ela é igual de false. Se for, o movieClip indicado ficará parado no primeiro quadro (gotoAndStop(1)). Se não, será iniciada a animação da movimentação (play()).
3º passo: movimentando o PC
Tudo isso foi a função para verificar se houve uma entrada de comando. Agora, vamos voltar para a função de movimentação.
Testamos a entrada de comando e declaramos na variável keyPressed uma função com os argumentos para movimentar o PC (_root.moveChar(ob, 1, 0);), indicando o sentido da movimentação. Para isso, vamos criar uma função para gerar a movimentação.
function moveChar(ob, dirx, diry) {
Note que são informados três argumentos junto com a função (objeto com o movieClip, coeficiente para o eixo X e coeficiente para o eixo Y).
Esses coeficientes serão responsáveis por informar em qual eixo o PC deverá ser deslocado. Logo, se o eixo X (dirx) for igual a 1, o personagem será deslocado na horizontal. Caso seja o eixo Y (diry), o personagem será deslocado na vertical.
Tendo isso em mente, somaremos os argumentos com as propriedades do PC para verificar o sentido do movimento (X ou Y) e sua velocidade (speed).
ob.x += dirx*ob.speed;
ob.y += diry*ob.speed;
Aqui é que está o segredo. Digamos que seja pressionada a tecla para cima. A função verificará o eixo utilizado (diry = 1) e multiplicará pela velocidade do PC. Resumindo, diry*ob.speed = 1 x 4 = 4, ou seja, o PC deverá se deslocar 4px, como ele está no ponto 0, 4px é um ponto acima dele, logo, ele subirá.
Como X é igual a 0, o calculo retornará 0: dirx*ob.speed = 0 x 4 = 0, ou seja, o PC deverá se deslocar 0px, que não quer dizer nada e ele não se moverá na horizontal.
O valor negativo (-1) ou positivo (1) servirá para indicar qual é o sentido da movimentação. Se o PC está parado, seu eixo X e Y é igual a 0.
O padrão é que o eixo positivo seja direcionado para cima ou para a direita. Se inverter, o eixo negativo seja direcionado para baixo ou para a esquerda... entendeu ?
Depois que informamos o sentido da movimentação, é preciso indicar quais sprite serão utilizados para a animação.
ob.clip.gotoAndStop(dirx+diry*2+3);
Respire fundo, "muitas horas nessa calma". Essa nem eu entendi. Só depois que fiz um teste de mesa é que percebi a lógica de tudo.
Antes disso, é preciso lembrar as regras da matemática, onde primeiro efetua a multiplicação e a divisão e só depois a soma e a subtração... tinha esquecido disso né ?
Logo, a forma real de efetuar esse cálculo não é (dirx + diry * 2 + 3). O correto seria (dirx + (diry * 2) + 3). Faça o teste de mesa.
- cima = 0 + (1 x 2) + 3 = quadro 5
- desce = 0 + ((-1) x 2) + 3 = quadro 1
- direita = 1 + (0 x 2) + 3 = quadro 4
- esquerda = (-1) + (0 x 2) + 3 = quadro 2
Depois dessa loucura toda, basta declarar o resultado na propriedade do objeto e indicar que há uma movimentação (true).
ob.clip._x = ob.x;
ob.clip._y = ob.y;
return (true);
Porém, para tudo isso dar certo, essa função tem que ser declarada antes da função que verifica se há uma entrada de comando. Se não for declarado antes, não tem como incluir o resultado na variável keyPressed.
5º passo: executar o evento de verificação de comando
Depois de informar todas as funções, basta acionar um evento para executá-las.
O Tony programou um evento em um movieClip para acionar o evento. Sinceramente, acho mais prático fazer isso diretamente no frame, deixando todo o código em um único lugar, o que facilitará futuras correções.
_root.onEnterFrame = function(){
_root.detectKeys();
}
Conclusão
Até agora, para fazer tudo isso, foi preciso:
Fase de Planejamento
- Definir os tipos de cenários
- Definir o comportamento para cada elemento do cenário
- Definir o PC, seu comportamento e movimentação
Fase de Elaboração
- Preparar as imagens do cenário
- Criar um movieClip para agrupar o jogo (empty)
- Criar um movieClip para agrupar as imagens do cenário (tiles)
- Preparar as imagens do PC
- Criar um movieClip para cada movimentação do PC
- Criar um movieClip agrupar os sprite do PC (char)
Fase de Programação
- Declarar a matriz do cenário
- Declarar o tamanho de cada imagem do cenário
- Declarar um objeto padrão para os elementos do cenário
- Declarar os elementos de cenário e suas propriedades
- Declarar as propriedades do PC
- Declarar a função construtora
- Declarar a função de movimentação
- Declarar a função de entrada de comando
- Montar o cenário do jogo
- Acionar um evento de verificação
Seu FLA deverá ter apenas um frame vazio, contendo o seguinte ActionScript:
myMap = [
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1]
];
game = {tileW:30, tileH:30};
game.TileClass = function () {};
game.TileClass.prototype.walkable=false;
game.TileClass.prototype.frame=2;
game.Tile0 = function () {};
game.Tile0.prototype.__proto__ = game.TileClass.prototype;
game.Tile0.prototype.walkable=true;
game.Tile0.prototype.frame=1;
game.Tile1 = function () {};
game.Tile1.prototype.__proto__ = game.TileClass.prototype;
char = {xtile:2, ytile:1, speed:4};
function buildMap (map) {
_root.attachMovie("empty", "tiles", ++d);
game.clip=_root.tiles;
var mapWidth = map[0].length;
var mapHeight = map.length;
for (var i = 0; i < mapHeight; ++i) {
for (var j = 0; j < mapWidth; ++j) {
var name = "t_"+i+"_"+j;
game[name]= new game["Tile"+map[i][j]];
game.clip.attachMovie("tile", name, i*100+j*2);
game.clip[name]._x = (j*game.tileW);
game.clip[name]._y = (i*game.tileH);
game.clip[name].gotoAndStop(game[name].frame);
}
}
game.clip.attachMovie("char", "char", 10000);
char.clip = game.clip.char;
char.x = (char.xtile*game.tileW)+game.tileW/2;
char.y = (char.ytile*game.tileH)+game.tileH/2;
char.width = char.clip._width/2;
char.height = char.clip._height/2;
char.clip._x = char.x;
char.clip._y = char.y;
}
function moveChar(ob, dirx, diry) {
ob.x += dirx*ob.speed;
ob.y += diry*ob.speed;
ob.clip.gotoAndStop(dirx+diry*2+3);
ob.clip._x = ob.x;
ob.clip._y = ob.y;
return (true);
}
function detectKeys() {
var ob = _root.char;
var keyPressed = false;
if (Key.isDown(Key.RIGHT)) {
keyPressed=_root.moveChar(ob, 1, 0);
} else if (Key.isDown(Key.LEFT)) {
keyPressed=_root.moveChar(ob, -1, 0);
} else if (Key.isDown(Key.UP)) {
keyPressed=_root.moveChar(ob, 0, -1);
} else if (Key.isDown(Key.DOWN)) {
keyPressed=_root.moveChar(ob, 0, 1);
}
if (!keyPressed) {
ob.clip.char.gotoAndStop(1);
} else {
ob.clip.char.play();
}
}
buildMap(myMap);
_root.onEnterFrame = function(){
_root.detectKeys();
}
Se estiver tudo certo, o resultado final ao publicar o SWF será esse:
Esse SFW foi criado pelo Tony para o site Tile based games e está sendo utilizado sob sua autorização.
Considerações
A partir de agora, a coisa vai começar a ficar "punk".
Já deve ter notado que não basta saber desenhar e programar para criar um jogo, também é preciso conhecer bem os conceitos de matemática e física, além de lógica e até algoritmo. Daqui para frente, a tendência é piorar.
Por este motivo, acho que aqui cabe uma revisão de tudo o que fiz para não ficar com nenhuma duvida.
Se quiser, volte ao índice para ver a lista completa do conteúdo.
Próximo assunto:
Delimitando a movimentação do personagem
Post a Comment