Issuu on Google+

Games em ActionScript 3.0

Web Games Aprendendo a criar seus jogos para web.

Objetivo 1:

Um jogo de nave simples.

1

Games em ActionScript 3.0

Introdução: O Objetivo dessa apostila é indicar os primeiros passos para aspirantes a criador de jogos. Tentei colocar aqui as bases necessárias para criação de um jogo simples, que pode ser feito com apenas alguns dias de trabalho, mas que contém as principais coisas necessárias, como movimentação via teclado, criação de vários inimigos, colisão e sons. De maneira alguma tenho expertise no assunto, sou apenas um entusiasta apaixonado por jogos que quer ajudar outros entusiastas a seguirem um caminho. Estou apenas auxiliando no aprendizado de uma ferramenta onde os criadores poderão ver seus projetos se movimentando pela tela.

Espero que essa apostila lhe ajude tanto quanto me ajudou tê-la criado e que você se divirta tanto quanto eu.

Artur Guitelar - Killdragon 2

Games em ActionScript 3.0

Ok, porque ActionScript 3.0? Explicando de forma rápida e fácil, o ActionScript é uma linguagem de programação script desenvolvida pela Adobe e que pode ser encontrada no Flash ou no Flex, softwares da mesma empresa. Embora o software tenha um forte apelo para sites e animações web, o código é robusto e conciso o suficiente para permitir que sejam programados bons jogos, que podem tanto ser jogados online quanto no computador, principalmente se sua intenção for desenvolver jogos de pequeno e médio porte. Mas nada impede que um programador experiente possa desenvolver jogos de grande porte. Deixo como exemplo uma imagem do MMO Dofus (http://www.dofus.com/pt), para que os mais curiosos procurem informações sobre ele no site da Ankama e entendam do que eu estou falando.

Existe uma série de softwares para criação de games gratuitos pela web, como o RPG Maker, o The Games Factory e o Game Maker. E até mesmo Engines poderosíssimas como a Unreal e a Unity 3D. Mas, a meu ver, enquanto os primeiros exemplos limitam um pouco o aprendizado real de programação por serem softwares um pouco mais limitados, os dois últimos citados são direcionados a quem já tem certa experiência na área. Para mim o ActionScript 3.0 está entre estes dois estilos de software. Se for usado em conjunto com o Flash o aprendizado se torna uma experiência visual gratificante, pois os primeiros

3

Games em ActionScript 3.0 passos acontecem muito rapidamente, e logo é possível começar a programar jogos simples, desde que se entendam os conceitos corretamente. A linguagem também é muito popular na Web, e não é nada difícil encontrar bom material de estudo em livrarias e pela internet afora. A questão aqui é que a maioria do material voltado para jogos está disponível em inglês. Essa apostila visa clarear um pouco a mente de todos também neste sentido, pois é preciso mais material sobre o assunto em português.

E porque WebGames? Em sua maioria os WebGames possuem características únicas que ajudam muito a quem está iniciando no mundo do desenvolvimento de jogos.   

Fácil distribuição: Não é muito difícil encontrar sites gratuitos que hospedem seu jogo ou, se você já tiver experiência com sites, hospedar um WebGame em flash em seu próprio servidor; Feedback rápido: Aproveitando o poder de comunicação que a internet possui é possível obter rápidas respostas positivas ou negativas sobre o seu game; Há muito material de inspiração na Internet: Uma rápida olhadela em sites como o http://www.kongregate.com/ ou o http://armorgames.com/ e já é possível encontrar centenas de games à disposição para inspiração.

4

Games em ActionScript 3.0

Agora entendi. Vamos começar? Vamos com calma. Antes de começarmos a produzir nossos jogos é preciso entender alguns conceitos por trás da programação. Primeiramente vamos dar uma olhada na interface do Adobe Flash CS5:

Provavelmente essa é a primeira janela que o Flash irá apresentar quando for iniciado. É bom lembrar que o objetivo desta apostila não é ensinar sobre o software em si, e sim sobre a linguagem ActionScript 3.0 voltada para jogos, e algumas formas de usar o programa em prol disso. Mas fique tranquilo, mesmo que não tenha tido experiências antigas com o Flash, basta seguir os exercícios atenciosamente e tudo estará bem. Claro que conhecer o programa previamente irá facilitar um pouco as coisas, mas não é extremamente necessário dominá-lo por completo. De qualquer forma o site oficial da Adobe (http://www.adobe.com/pt/ ) possui diversos tutoriais e o próprio help do programa é bem amigável. Livrarias e Internet também possuem materiais de qualidade sobre o software. Para começar, basicamente iremos precisar clicar em “ActionScript 3.0”, que se encontra na coluna “Criar novo”. Isso irá abrir um documento novo já preparado para aceitar a linguagem. Duas coisas superimportantes:

5

Games em ActionScript 3.0  

Este tipo de arquivo no Flash recebe a extensão .fla quando é salvo, e é o principal documento do seu projeto; Não é possível unir de forma consistentes projetos que possuam códigos em ActionScript 2.0 e ActionScript 3.0. A linguagem ActionScript 2.0 está descontinuada pela Adobe, mas ainda possuem programadores que preferem utilizá-la.

Com o documento aberto iremos precisar basicamente de duas janelas (que não estão habilitadas por padrão) para iniciarmos os exercícios: Ações (F9) e Saída (F2).

Arraste a nova janela Ações que se abriu para a faixa de baixo onde está o painel Linha do tempo e, quando a cor da faixa estiver azul, solte.

6

Games em ActionScript 3.0

Deve ficar desta forma:

Existem outras formas de organizar as janelas, mas n達o iremos nos preocupar com isso agora.

7

Games em ActionScript 3.0

Salvando Arquivos É interessante sempre salvar os arquivos, mesmo antes de terminar de editar um documento. Isso impede que sejamos pegos de surpresa caso acabe a luz, ou algum evento estranho desligue o computador no meio daquele código complicado que acabamos de criar. Para salvar arquivos no Flash, basta clicarmos no menu Arquivo e escolhermos a opção Salvar.

Na primeira vez que salvamos, o programa nos dá a opção de escolhermos o local, o nome e o tipo do arquivo que iremos salvar.

Depois disso, basta ir clicando em salvar periodicamente, depois de fazer alterações. O arquivo sempre será salvo no mesmo lugar, com o mesmo nome. O nome do arquivo agora aparece na aba da parte superior da cena.

8

Games em ActionScript 3.0

Como já foi dito, o Flash salva os arquivos no disco com a extensão .fla. Caso queira salvar em outro local, ou com nomes diferentes, basta selecionar no menu arquivo, a opção Salvar como... A tecla de atalho para “salvar” é ctrl + s, lembre-se sempre de usar o ctrl + s periodicamente. A tecla de atalho para “salvar como...” é ctrl + shift + s. Não será sugerido o nome do arquivo até a hora que seja necessário. Mas é interessante salvar os exercícios em arquivos separados para uma melhor organização.

9

Games em ActionScript 3.0

Escrevendo as primeiras linhas de código O painel de Ações contém do lado esquerdo uma série de atalhos para os comandos e bibliotecas e do lado direito uma área em branco de entrada de texto, onde escreveremos (digitaremos) algum código. Toda vez que precisarmos testar o código, iremos utilizar o atalho Ctrl+Enter para visualizar o resultado. O primeiro comando que iremos conhecer é o trace. Ele imprime resultados no painel de saída de acordo com a solicitação do usuário. Digite no painel de Ações: trace(“Olá! Essa é a sua primeira linha de código.”); Agora utilize as teclas de atalho Ctrl+Enter e observe o resultado.

Note que a janela está em branco, mas o resultado do trace está no painel de Saída. Feche a nova janela que se abriu e clique no painel de Ações. Vamos observar como funciona o código: trace(“Olá! Essa é a sua primeira linha de código.”);   

Tudo o que estiver entre os parênteses do comando trace será exibido no painel de saída; O que está entre aspas é considerado como texto no compilador do Flash; A cor azul indica que trace é uma palavra reservada do ActionScript 3.0. Não utilize palavras reservadas para outras funções que não sejam próprias para elas. 10

Games em ActionScript 3.0  

A cor verde indica que tudo que está entre aspas é texto. Para uma melhor organização e compreensão, é interessante terminar as linhas de código com “;”. O ActionScript 3.0 aceita linhas sem “;” mas colocá-lo no final é uma boa prática de programação e irá prepará-lo para linguagens futuras.

Vamos exercitar isso mais um pouco. Apague a antiga linha de código e digite estas: trace(“COMEÇOU A LUTA!”); trace(“Os competidores na arena são poderosíssimos! A luta será emocionante!”); trace(“Jogador 1 dá um soco.”); trace(100-30); trace(“Jogador 2 dá um chute.”); trace(100-40); trace(“Jogador 1 aplica um golpe especial.”); trace(70-50); trace(“Jogador 2 aplica um golpe especial de nível 2!”); trace(60-60); trace(“Jogador 1 cai derrotado.”); trace(“FIM DA LUTA.”); Observe o resultado.

Observe que tudo o que estava escrito entre aspas foi duplicado no painel, mas os números foram calculados. Essa é a diferença básica entre dados do tipo String e dados do tipo Number. O interpretador faz os cálculos dos números se eles não estiverem entre as aspas. Experimente digitar: trace(10+10); trace(“10+10”); Você perceberá que a primeira linha mostrará o resultado e a segunda apenas repetirá o que está entre aspas. O padrão de leitura do código pelo interpretador é da esquerda para a direita e de cima para baixo, assim como lemos os livros e revistas.

11

Games em ActionScript 3.0

Fundamentos básicos da linguagem A luta passada foi bem emocionante, mas escrever uma luta mais extensa pode se tornar bem cansativo. Isso porque utilizamos um estilo Sequencial na linguagem, ou seja, escrevemos os comandos linha a linha e o interpretador vai “lendo” uma por uma e executando passo a passo até o fim. É importante entender que este tipo de programação não é viável quando se trata de games, pois torna o código muito extenso. Uma forma de contornar isso é utilizando variáveis, condicionais e funções.

Vamos começar com as variáveis Variáveis são espaços alocados na memória separados pelo programa para armazenar determinados dados. De uma forma mais simplista é como se fossem contêineres que podem ser preenchidos com informações que serão usadas depois. As variáveis no código precisam ser declaradas e recebem um nome. Boas práticas de programação sugerem algumas regras para a nomeação das variáveis.      

Não utilize nomes de variáveis do ActionScript (se o nome ficar azul então mude o nome da variável), elas são palavras-chave de scripts da linguagem; Procure começar com letras minúsculas. Números e caracteres só são aceitos em conjunto com letras e após a primeira letra do nome; Não devem começar com números ou caracteres especiais; Se a variável tiver um nome composto, não deve ter espaço entre as palavras. Uma boa prática é utilizar um “_” ou uma letra maiúscula para referenciar as palavras. Ex.: primeira_variavel ou primeiraVariavel; Não utilize nomes repetidos em variáveis globais em um mesmo código; Utilize nomes curtos (ou abreviados), de fácil reconhecimento e que indiquem o que a variável faz.

Experimente digitar isso: var testando = "testando"; trace(testando);

12

Games em ActionScript 3.0 O resultado:

A palavra var serve pra indicar que estamos começando uma variável, o nome da variável é “testando” e ela tem como valor o texto (String) “testando”; Significa que toda vez que utilizarmos a variável testando ela irá trazer este resultado. Como ela está entre aspas é fácil identificar que a variável é do tipo String (texto), mas por boa prática é melhor declará-la desta forma: var testando:String = “testando”; Utilize o trace e o resultado será o mesmo. Eis uma tabela com os tipos de dados disponíveis: Tipo de Variável Number int uint String Boolean Array Object

Exemplo 15.5 -20 3 “Olá!” true [1,2,3] umObjeto

Descrição Qualquer número, incluindo decimais Qualquer número inteiro Qualquer número inteiro sem sinal ou não-negativo Texto ou uma sequência de caracteres Verdadeiro ou falso Mais de um valor em uma única variável Estrutura básica de toda a estrutura do ActionScript, utilizada para armazenar vários valores como um Array

Vamos a um exemplo prático. Vamos criar duas variáveis para armazenar a quantidade de energia de um personagem, depois simulamos que ele levou uma pancada e perdeu uma quantia dessa energia. var energiaPersonagem:Number = 100; var pancada:Number = 50; trace(energiaPersonagem - pancada); Se o resultado for 50, está correto.

13

Games em ActionScript 3.0

As Condicionais Muitas vezes enfrentaremos situações em que é preciso fazer comparações. Por exemplo, um personagem ganhar um item especial após ganhar um level, ou mesmo dizer que um inimigo foi derrotado após sua energia estar abaixo de 0. Para estes casos existem as condicionais, que são estruturas de código que comparam os termos e trazem um resultado. É como se fizéssemos um teste e se a condição não é atendida nenhuma ação é realizada.

O if Essa é a forma mais comum de condição. Praticamente todas as linguagens utilizam o if de alguma forma. If em português significa “se”, e basicamente compara condições verdadeiras e falsas. Vamos à prática: var energiaPersonagem:Number = 100; var pancada:Number = 110; trace(energiaPersonagem - pancada); if(energiaPersonagem < pancada){ trace("Personagem Morreu!"); } O resultado:

Parece confuso agora? Vamos destrinchar um pouco este script. Essas são as variáveis da pancada e da energia do personagem: var energiaPersonagem:Number = 100; var pancada:Number = 110; Então “pedimos” o resultado com esta linha: trace(energiaPersonagem - pancada); E depois fizemos uma comparação: Se a energia do personagem for menor do que a pancada, então vai aparecer a frase “Personagem Morreu!” no painel de saída. if(energiaPersonagem < pancada){ trace("Personagem Morreu!"); 14

Games em ActionScript 3.0 } Iniciamos o comando if, entre parênteses fazemos as comparações e entre as chaves colocamos o código a executar caso a comparação dê certo. Experimente trocar o valor da pancada de 110 para 90 e veja o que acontece! Se não aconteceu nada, está correto. Não há condição para caso a energia seja maior do que a pancada. Neste caso, experimente adicionar ao script a linha abaixo: if(energiaPersonagem > pancada){ trace("Personagem continua vivo."); } Acredito que você já tenha entendido.

O Switch O switch (escolha) é uma condicional de escolhas. Damos “opções” para serem escolhidas dentro do switch. Basicamente é como se fosse um if, com uma estrutura mais simples, pois ele também testa condições verdadeiras e falsas. Vamos a um exemplo prático: var soco:String = "Soco"; var chute:String = "Chute"; var especial:String = "Golpe Especial"; var botaoApertado:String = "a"; switch(botaoApertado){ case "a": trace(soco); break; case "b": trace(chute); break; case "c": trace(especial); break; default: trace("nenhum golpe"); break; } Destrinchando o código. Temos agora 4 variáveis, todas do tipo String: var var var var

soco:String = "Soco"; chute:String = "Chute"; especial:String = "Golpe Especial"; botaoApertado:String = "a";

15

Games em ActionScript 3.0 O switch inicia levando em consideração a variável botaoApertado e irá usar este valor para conferir o que é verdadeiro. Case, significa “caso” em português, então ele irá verificar caso a caso, até encontrar o valor do botaoApertado (que é “a”). Quando o valor for encontrado, a próxima linha depois dos “:” (dois pontos) será executada, até a hora em que encontrar um comando break (quebrar). Então o switch retorna os resultados.

Experimente trocar o valor da variável botaoApertado por “b” e veja que o resultado será Chute, e assim por diante. Um pequeno detalhe: default: trace("nenhum golpe"); break; Este trecho indica que, se nenhum dos case (caso) funcionar, o valor default (padrão) será a frase “nenhum golpe”. Experimente colocar qualquer valor que não seja “a”, “b” ou “c” na variável e veja o resultado. Isso também seria possível de fazer com o if. Vejamos como o código ficaria: var soco:String = "Soco"; var chute:String = "Chute"; var especial:String = "Golpe Especial"; var botaoApertado:String = "a"; if(botaoApertado == "a"){ trace(soco); }else if(botaoApertado == "b"){ trace(chute); }else if(botaoApertado == "c"){ trace(especial); }else{ trace("nenhum golpe"); } O resultado é o mesmo. Você poderia escolher qualquer um dos dois neste caso, mas se tivéssemos 50 verificações, o código if já seria de difícil leitura. O if também é reservado para casos de comparações mais difíceis, como ifs dentro de ifs (veremos isso mais adiante). Também pode ser utilizado um if dentro de um switch e vice-versa. A novidade neste código fica por conta do else if (se não, se) e do else (senão). 16

Games em ActionScript 3.0 Utilizamos else if em um bloco de código que tem condições para serem checadas que são dependentes umas das outras. E este else no final teria o mesmo valor do default no switch, ou seja: estamos dizendo que “se não for nenhuma das opções, utilize esta que está neste último else.”.

Loops Antes de qualquer coisa é preciso saber que Loops (Ciclos, para este caso) são trechos de código condicional que serão repetidos até que consigam alcançar um determinado critério. Para que fique mais simples, vamos a um exemplo prático, começando pelo loop for: var soco:Number = 10; for(var i=0; i<3;i++){ trace(soco); } O resultado será este:

Agora vamos entender o que está acontecendo. O primeiro trecho do código é bem conhecido: var soco:Number = 10; Declaramos uma variável, demos o nome a ela de soco e ela será do tipo Number, contendo o valor 10. Agora o loop: for(var i=0; i<3;i++){ trace(soco); } Em um loop for (para), estamos especificando que, para cada vez que o código entre parênteses for verdadeiro, tudo o que está entre as chaves deve ser executado. Nós criamos outra variável com o nome de i dentro dos parênteses. Você poderia dar qualquer nome a ela, se desejasse. Por exemplo:

17

Games em ActionScript 3.0 for(var batata=0; batata<3;batata++){ trace(soco); } O resultado seria o mesmo. É uma boa prática utilizar o i em um loop for para indicar que vamos incrementar essa variável. Este é um costume bem antigo, que acompanha os programadores até hoje. Vamos destrinchar o que está dentro do parêntese: var i=0; Aqui indica que a variável i começa valendo 0. i<3; Enquanto a variável i valer menos que 3... i++; ... o código irá acrescentar mais 1 ao valor da variável. Nesse caso, a variável i, que antes valia 0, começará a fazer uma “contagem” e terá o valor aumentado para 1 e quando chegar no 2 ela irá parar, porque 2 é menor que 3. OPA! Mas os resultados foram 3 números 10! Como isso é possível? No começo a variável valia 0, e isso também é contado como valor de índice. Na verdade é como se o laço contasse: 0=1, 1=2, 2=3. Algo como isso: Índice Ordem do índice

0 1

1 2

2 3

Para ficar mais simples ainda, faça o exercício desta forma: for(var i=1; i<4;i++){ trace(soco); } E o resultado será o mesmo. Mas a grande maioria dos programadores preferem utilizar todos os índices, então começam do 0. No começo é um pouco confuso, mas logo você pega a prática e verá como isso faz sentido durante a programação. Para finalizar: na prática basicamente estamos “pedindo” ao código para repetir tudo o que estiver entre as chaves até 3 vezes. { trace(soco); } A variável soco vale 10, então o comando trace irá repetir o valor 10 até 3 vezes. Experimente trocar o 3 por 4, 20, 30, 50, e veja o que acontece. Existem mais alguns tipos de variáveis, condicionais e loops, mas estes são os mais utilizados. Outros tipos serão explicados no decorrer dos exercícios.

18

Games em ActionScript 3.0

As Funções Funções (ou métodos, ou procedimentos) são blocos de código que podem ser reaproveitados posteriormente. Isso evita que muitos trechos de código sejam repetidos e o ajuda para que o código não fique muito extenso. No Actionscript 3.0 todas as funções devem começar com a palavra function e precisam ter um nome, assim como as variáveis. Após o nome elas recebem “()” (parênteses), que podem, ou não, conter os parâmetros necessários para a reutilização de variáveis. Tudo o que precisa ser executado é colocado entre ”{}” (chaves). Não muito diferente do que já vimos nas condicionais. Confuso? Vamos à prática: function comportamentoInimigo(){ trace("Inimigo sempre persegue o player."); trace("Inimigo foge quando sua energia está abaixo de ", 30); trace("Os tiros do inimigo sempre tiram ", 10, " da energia do oponente."); } comportamentoInimigo(); Resultado:

Agora, sempre que precisarmos escrever novamente essas três linhas no painel de saída, basta chamar a função desta forma: comportamentoInimigo(); Experimente acrescentar este trecho logo abaixo do código: trace("O Player está andando pela tela e encontra um inimigo."); comportamentoInimigo(); trace("O Player se desvia dos tiros e mata o inimigo com uma magia poderosa!"); trace("O Player continua sua caminha e encontra outro inimigo!"); comportamentoInimigo(); trace("Novamente o Player lança uma magia poderosa e vence a batalha!");

O resultado:

19

Games em ActionScript 3.0

Acredito que agora esteja clara a função da Função (trocadilho infame).

E os tais dos parâmetros? Outra grande vantagem da função é poder modificar algo dentro delas através dos parâmetros. Os parâmetros nada mais são do que variáveis que são colocadas dentro dos parênteses de uma função. É como se adicionássemos propriedades modificáveis às nossas funções. Exemplo: function mudaNome(nome:String){ trace("O nome do personagem será: ", nome); } mudaNome("Marssupilami"); mudaNome("Ryu"); mudaNome("Chapeleiro Louco"); Resultado:

Além de reutilizarmos a função mudaNome, ainda modificamos os nomes através da variável nome, que está dentro da função e foi acessada como um parâmetro. Regras básicas de funções com parâmetros simples: 

A quantidade de parâmetros dentro dos parênteses e dentro das chaves deve ser a mesma sempre; 20

Games em ActionScript 3.0 

   

Se a função pede dois parâmetros, quando ela for reutilizada, precisará de dados que preencham os dois parâmetros. Ex. mudaNome(nome:String, sobrenome:String){...}, e quando for reutilizar: mudaNome(“Yori”, “Yagami”); Sempre especifique o tipo da variável que está sendo utilizada entre os parênteses. Ex. capacete(nomeDoCapacete:String, resistencia:Number){...}; As variáveis dentro dos parênteses devem ser separadas com vírgula; Não inicie nomes de funções com números ou caracteres especiais; Procure colocar nomes curtos, fáceis de entender e que lembrem o que ela faz.

Instanciando os primeiros sprites Em um game 2D, sprites são elementos que se movimentam na tela. Eles podem ser personagens, montanhas, partes do cenário, poderes mágicos... Basta se movimentarem (ou terem animações) e serem instanciados com algum código. O código dará propriedades a estes sprites e irá trata-los como um objeto. Mas o que são Objetos? ActionScript 3.0 é uma linguagem que trabalha massivamente com objetos. Um objeto pode possuir propriedades (que definem sua, altura, largura, cor...) e também pode possuir métodos (que definem seu comportamento, o que ele faz). Na prática um objeto no código é uma instância de código que possui propriedades como um objeto real. Por exemplo: var aeronave:Object = new Object(); aeronave.width = 350; aeronave.rotation = 30; aeronave.height = 60; trace(aeronave.width); trace(aeronave.rotation); trace(aeronave.height); Resultado:

Neste pequeno trecho definimos que nossa aeronave é uma variável do tipo Object. A classe Object é um método pronto dentro do ActionScript 3.0 e, para não termos de modificar o código original, utilizamos uma nova instância com o código new Object() . Dessa forma temos 21

Games em ActionScript 3.0 acesso à parte do código escrito na classe Object, que é a classe principal do ActionScript. Não se preocupe com classes agora, veremos isso mais adiante. Basicamente reutilizamos a classe Object() e adicionamos propriedades em nossa aeronave. Agora ela possui largura (width), rotação (rotation) e altura (height). Atrelamos essas propriedades através do nome do objeto (no caso, aeronave), o ponto (.) e a propriedade que definimos. É como se disséssemos que agora a propriedade width faz parte de nossa aeronave.

Como utilizar isso em um Sprite? No decorrer do curso, os alunos receberam um arquivo .fla que continha este projeto:

Não é nada muito complicado. Na verdade simulei grama, montanhas e céu na camada de baixo e bloqueei-a para que não atrapalhasse. Na camada de cima ficou apenas a nave. Os pormenores de edição de objetos e camadas não serão apresentados aqui. Sugiro que busque tutoriais e apostilas de exemplo na internet. O próprio Flash tem alguns modelos de exemplo e um manual bem explicado.

22

Games em ActionScript 3.0

Certifique-se que neste exercício nosso código seja inserido no quadro 1 da camada da nave (veja figura). Assim que for inserido algum código, a letra a minúscula aparecerá no quadro, indicando que ali há um código ActionScript. A nave que temos na tela será nosso Sprite, que pode ser uma imagem importada de sua preferência, ou até mesmo uma bolinha criada com as ferramentas do Flash se você assim preferir. Todos os desenhos irão passar pelo mesmo processo. Selecionamos a nave, e iremos iniciar o processo de transformá-la em um Movie Clip (Clipe de Filme) apertando a tecla F8 (ou clicando no menu Modificar -> Converter em símbolo...).

Para o exercício, iremos colocar o nome de nave e o ponto de registro no meio. O nome não importa neste momento, você pode nomear a nave com o nome que quiser. Após isso é só apertar OK.

23

Games em ActionScript 3.0

Desta forma, agora temos a nave em nossa biblioteca. Acesse o painel de Propriedade e na caixa <Nome da Ocorrência>, digite o nome que dará acesso a essa nave no código. No caso, colocaremos nave também. Este nome você usará durante o código, portanto guarde-o bem.

Não é necessário que a ocorrência tenha o mesmo nome da nave, mas é necessário que este nome siga as mesmas regras dos nomes das variáveis, pois é por este nome que iremos identificar a nave no código. Lembre-se: para este exercício o código deve ser digitado no quadro 1 da camada da nave. Certifique-se que este é o quadro que está selecionado no painel Linha do tempo, e abra o painel Ações. Vamos brincar um pouco com as propriedades da nossa nave. nave.x =100; nave.y = 100;

24

Games em ActionScript 3.0

Resultado:

Como agora o código reconhece que a nave faz parte do código, pudemos acrescentar propriedades a ela. Neste caso, setamos a posição em que ela apareceria na tela. Veja que a posição inicial é diferente, mesmo assim, o interpretador publicou a posição que estava no código, então nossa nave foi “movida” no eixo x e y. Mas, se estamos falando de x e y, é como um gráfico cartesiano! A nave não deveria estar lá embaixo? Na verdade, quando se trata de programação, o eixo y é invertido. Vejamos a comparação:

25

Games em ActionScript 3.0

Outra consideração importante, é que o centro do eixo começa no lado superior esquerdo da tela (salvo, se alguma coisa na programação mudar isso). O que seria algo neste estilo:

Por causa disso, a nave ficou perto do canto superior esquerdo. Experimente trocar os valores de x e y e veja o que acontece.

26

Games em ActionScript 3.0 Abaixo uma tabela de propriedades básicas de um Movie Clip. Teste-as uma a uma e veja as modificações. Depois troque os números e faça mais alguns testes para dominar essas propriedades. Descrição Posição

Propriedade x, y (minúsculos)

Escala

scaleX, scaleY

Tamanho

width, height

Rotação Transparência Visibilidade

rotation alpha visible

Sintaxe nave.x = 100; nave.y = 100; nave.scaleX = 0.5; nave.scaleY = 0.8; nave.width = 50; nave.height = 50; nave.rotation = 90; nave.alpha = 0.3; nave.visible = false;

Tipo de Unidade pixels porcentagem pixels graus (de 0 a 360) porcentagem (de 0 a 1) booleana (true ou false)

Qual a diferença entre visible = false e alpha = 0? Basicamente, setando visible o objeto é guardado na memória, mas não pode mais ser clicado ou receber uma colisão com outro objeto. É como se excluíssemos o objeto, mas mesmo assim ele ainda está lá ocupando espaço no processamento e pode ser tornado visible = true a qualquer momento. A propriedade alpha = 0 torna o objeto invisível visualmente, mas ele continua ocupando a mesma posição, e pode receber testes de colisão.

Comentando linhas Já foi dito que o programa entende o código nesta ordem: da esquerda para a direita e de cima para baixo. Ele também ignora os espaços em branco. Este é um dos motivos do por que aplicar a prática de terminar as linhas com ponto-e-vírgula (;), assim indicamos que aquela linha terminou. Na prática, o programa lê e compila todo o código como um bloco só, e considera fins e começos de blocos e linhas de código por causa dos pontos-e-vírgulas, parênteses, colchetes e parte da lógica do código. E as linhas brancas, ele ignora. É interessante separar os blocos de código que fazem a mesma função para não nos confundirmos visualmente. Muitas vezes é necessário comentarmos o código, principalmente aqueles complicados e cheios de fórmulas. Uma boa prática é comentar no começo de cada bloco de código, mas isso vai a critério de cada um. As linhas comentadas, também são consideradas como linhas “vazias”, e são ignoradas pelo programa. Para comentar uma linha, utilize duas barras no início da linha. Ex.: //setando as propriedades da nave isso é um comentário nave.x =100; nave.y = 100;

Para comentar parte de uma linha, utilize as duas barras, mas lembre-se de que o comentário só será considerado até a hora em que você pular uma linha E após o ponto e vírgula. Ex.: 27

Games em ActionScript 3.0 //setando as propriedades da nave nave.x =100;//propriedade no eixo x nave.y = 100;//propriedade no eixo y Esta também é uma prática bem comum. Acredito que ficou claro: tudo o que estiver após as duas barras naquela linha será ignorado pelo interpretador. Algumas vezes se faz necessário comentar blocos de texto inteiros, e neste caso não é viável fazer o comentário linha-a-linha, mais prático utilizar o método desta forma: /* bloco de texto a ser ignorado pelo programa.*/ Tudo o que estiver entre /* e */ será ignorado. Sendo assim, comente todas as linhas de código que fez até agora no arquivo nave.

Eventos Eis aqui um recurso de extrema facilidade e importância no Actionscript 3.0: Os Eventos. Eles são responsáveis pelas configurações dos scripts e definem parâmetros, fazendo com que eles sejam executados. Eventos de teclado (KeyboardEvent), podem adicionar propriedades às teclas do teclado, eventos de mouse (MouseEvent), podem acionar botões na tela, caixa de textos e até mesmo chamar funções personalizadas. Existem inúmeros eventos, alguns deles são disparados quando se assiste a um vídeo, se trabalha com textos, se aciona um botão no teclado, quando uma animação precisa acontecer, ou até mesmo quando uma página é aberta. E eles ficam melhor ainda quando utilizados em conjunto com os Listeners.

Ouvintes de evento Os ouvintes de evento (Listeners) são um poderoso recurso do Actionscript 3.0, que permite ao programador atrelar eventos diretamente a objetos instanciados no código. Vamos utilizar a nossa nave como exemplo. nave.addEventListener(MouseEvent.MOUSE_UP, naveRodaParaDireita); function naveRodaParaDireita(event:MouseEvent):void{ nave.rotation += 30; } Feito isso, clique na nave várias vezes. Clique fora da nave, e veja o que acontece. Com este script, toda vez que clicamos na nave, ela rotaciona 30° para o lado direito, mas nada acontece se clicarmos nas montanhas, por exemplo.

28

Games em ActionScript 3.0

Vamos destrinchar um pouco mais o código: nave.addEventListener(MouseEvent.MOUSE_UP, naveRodaParaDireita); nesta linha, através do comando addEventListener, estamos definindo que a função só irá acontecer se o evento estiver relacionado à nave. Entre os parênteses, definimos que o evento é acionado pelo mouse através do comando MouseEvent e que algo acontecerá quando a tecla do mouse for solta (MOUSE_UP). Depois dizemos qual função poderá ser acionada quando isso acontecer, no caso, naveRodandoParaDireita. No começo parece um pouco complicado, mas com a prática você verá que é muito simples: basta lembrar a ordem em que as coisas precisam ser descritas e tudo ocorrerá bem. function naveRodaParaDireita(event:MouseEvent):void{ aqui criamos uma função chamada naveRodandoParaDireita e, entre parênteses, definimos que a variável event terá o valor de um MouseEvent (Evento de mouse). Qual o tipo de evento (MOUSE_UP, MOUSE_DOWN, CLICK...) já foi definido quando criamos o listener. E definimos que a função será do tipo void, que significa que irá retornar um valor vazio, pois não precisamos disso definido para acessá-la. nave.rotation += 30; Definimos que a propriedade rotation da nave recebe +30° de valor cada vez que a função é chamada, ou seja, a cada vez que o botão do mouse é solto.. } a função termina aqui. Na prática, criamos uma função dentro do objeto nave, que é acionada toda vez que clicamos em cima dela e soltamos o botão do mouse. Como é um evento MOUSE_UP, nada acontece se você deixar o mouse pressionado em cima da nave. Experimente. 29

Games em ActionScript 3.0

Encontrando as teclas do teclado no código. Muitos dos jogos utilizam o teclado para movimentar os Sprites na tela. Cada tecla possui um número no código. Para encontrar este número iremos criar um script que retorna o número da tecla na caixa de Saída toda vez que ela é pressionada. Apague todo o código anterior (ou salve em outro arquivo e depois apague) e digite este: stage.addEventListener(KeyboardEvent.KEY_DOWN, achaTecla); function achaTecla(event:KeyboardEvent):void{ trace("O código da tecla é: ", event.keyCode); } Num primeiro momento nada acontece. Mas ao apertar algumas teclas poderemos ver seu código no painel de saída.

Localize os códigos das teclas que vai utilizar e anote. Geralmente utilizamos as teclas: esquerda, baixo, cima, direita, w, a, s, d, z, x e barra de espaço, cada conjunto para um tipo de jogo. Você definirá isso em seus projetos. Algumas vezes o flash pode precisar importar algumas bibliotecas para o código. Algo como isto: import flash.events.KeyboardEvent; import flash.events.Event; Não se preocupe em apagar estas linhas, neste caso não há diferença se elas são importadas ou não, elas serão explicadas no futuro.

38 37

40

30

39

Games em ActionScript 3.0

Mova-se nave! Para este exercício, iremos apagar todo o código e salvar o arquivo como NaveSeMovendoPeloTeclado.fla. A primeira coisa que devemos pensar é em como acontecerão os eventos. O que sabemos é que, ao apertar as teclas, a nave se moverá na direção que queremos, mas para chegar a isso precisaremos de 3 eventos: KeyboardEvent.KEY_DOWN; KeyboardEvent.KEY_UP; Event.KEY_FRAME. Os dois primeiros eventos são de fácil entendimento: O primeiro se refere à quando apertarmos a tecla e o segundo ao que acontece quando soltarmos a tecla. O último evento se refere ao que acontece a cada atualização de tela. Para entender isso melhor, pense nos desenhos animados, que nada mais são do que imagens paradas sendo atualizadas a uma quantidade X por segundo. Como é possível ver no painel de Propriedades, o Flash CS 5 Professional tem uma taxa de 24FPS (frames per second – quadros por segundo), o que significa que 24 imagens são trocadas a cada segundo no Flash. Essa taxa pode ser mudada, é claro, mas como estamos desenvolvendo para web, é melhor trabalhar com esta configuração.

31

Games em ActionScript 3.0 Iremos precisar também de algumas variáveis. Para não confundir muito, no começo iremos utilizar apenas duas, depois ajustamos as configurações necessárias. Digite o código: var movimento:Number = 5; var checarTecla:Boolean = false; stage.addEventListener(KeyboardEvent.KEY_DOWN, teclaPress); function teclaPress(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTecla = true; } } stage.addEventListener(KeyboardEvent.KEY_UP, teclaSolta); function teclaSolta(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTecla = false; } } stage.addEventListener(Event.ENTER_FRAME, movNave); function movNave(event:Event):void{ if(checarTecla == true){ nave.x += -movimento; } } Agora que você já tem as bases de como funcionam as funções e os listeners, não é tão difícil entender, não é mesmo? A variável movimento tem o valor 5 e garante que a nave se mova 5 pixels. A variável checarTecla tem valor false, porque ele checa quando o jogador irá apertar a tecla necessária para a nave se movimentar. Como no início do jogo não há movimento, ela inicia com o valor false (falso). Depois temos 3 listeners e 3 funções. Note que, dessa vez, os eventos estão atrelados ao stage (palco do flash), e não são dependentes da nave, embora influenciem o movimento dela. O primeiro bloco checa se a tecla está apertada, através do keyCode (código da tecla). Se estiver, o valor de checarTecla é true. Note aqui que, quando utilizamos == (igual duas vezes), significa que estamos checando alguma condição, ou seja, estamos comparando os valores. Para que o checarTecla seja true, precisamos verificar se a tecla apertada é a 37. Quando utilizamos apenas = (um sinal de igual), significa que estamos atribuindo um novo valor à variável. A partir de agora a variável passa a ter o valor true, e não mais false.

32

Games em ActionScript 3.0 stage.addEventListener(KeyboardEvent.KEY_DOWN, teclaPress); function teclaPress(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTecla = true; } } A mesma lógica se aplica ao bloco dois, só que invertemos o valor de checarTecla para false novamente. Se isso não for feito, a nave irá se movimentar indefinidamente na tela, pois o código não “sabe” que soltamos a tecla. Aliás, experimente comentar este bloco de código desta forma e veja o resultado. /*stage.addEventListener(KeyboardEvent.KEY_DOWN, teclaPress); function teclaPress(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTecla = true; } }*/ Não se esqueça de descomentar. Agora vamos ao ultimo bloco: stage.addEventListener(Event.ENTER_FRAME, movNave); function movNave(event:Event):void{ if(checarTecla == true){ nave.x += -movimento; } } Os dois primeiros blocos eram eventos estáticos, que dependiam da interação do jogador. Este último precisa ser atualizado sozinho, por isso utilizamos o Event.ENTER_FRAME. A função movNave simplesmente garante que, quando o valor da tecla apertada for true, a nave irá se movimentar no eixo definido. No caso, eixo x para a esquerda. Isso acontece porque colocamos o valor da variável como negativo (nave.x += -movimento;) mesmo ela iniciando com valor positivo. E este valor é checado a cada frame e atualizado a cada apertar de tecla. Na prática, cada vez que a tecla esquerda do teclado (37) receber o valor true, é subtraído 5 da posição x da nave e ela se movimenta para a esquerda. Seguindo esta lógica, precisaremos de uma variável booleana para cada tecla que apertamos. Neste caso iremos mudar ligeiramente o código. Compare: import flash.events.KeyboardEvent; import flash.events.Event; var movimento:Number = 5; var checarTeclaEsq:Boolean = false; stage.addEventListener(KeyboardEvent.KEY_DOWN, teclaPress); function teclaPress(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTeclaEsq = true; 33

Games em ActionScript 3.0 } } stage.addEventListener(KeyboardEvent.KEY_UP, teclaSolta); function teclaSolta(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTeclaEsq = false; } } stage.addEventListener(Event.ENTER_FRAME, movNave); function movNave(event:Event):void{ if(checarTeclaEsq == true){ nave.x += -movimento; } } Agora nossa variável pertence à tecla esquerda, e não a qualquer outra. Precisamos então criar variáveis para as outras teclas e fazer com que elas funcionem. Com os ajustes, o código completo ficará dessa forma: import flash.events.KeyboardEvent; import flash.events.Event; var var var var var

movimento:Number = 5; checarTeclaEsq:Boolean = false; checarTeclaCima:Boolean = false; checarTeclaDir:Boolean = false; checarTeclaBaixo:Boolean = false;

stage.addEventListener(KeyboardEvent.KEY_DOWN, teclaPress); function teclaPress(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTeclaEsq = true; }else if(event.keyCode == 38){ checarTeclaCima = true; }else if(event.keyCode == 39){ checarTeclaDir = true; }else if(event.keyCode == 40){ checarTeclaBaixo = true; } } stage.addEventListener(KeyboardEvent.KEY_UP, teclaSolta); function teclaSolta(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTeclaEsq = false; }else if(event.keyCode == 38){ checarTeclaCima = false; }else if(event.keyCode == 39){ checarTeclaDir = false; }else if(event.keyCode == 40){ checarTeclaBaixo = false; } } 34

Games em ActionScript 3.0

stage.addEventListener(Event.ENTER_FRAME, movNave); function movNave(event:Event):void{ if(checarTeclaEsq == true){ nave.x += -movimento; }else if(checarTeclaCima == true){ nave.y += -movimento; }else if(checarTeclaDir == true){ nave.x += movimento; }else if(checarTeclaBaixo == true){ nave.y += movimento; } } O movimento da nave está pronto, agora precisamos fazê-la atirar. Mas antes precisamos entender mais algumas coisas...

Adicionando MovieClips dinamicamente na tela Pensemos dessa forma: Teremos de ter um objeto que será o tiro da nave, que no caso iremos nomear laser. Para isso criamos uma bolinha simples no Flash, transformamos em Movie Clip (clipe de filme), da mesma forma que fizemos com nossa nave e damos o nome laser. O único empecilho é que a bolinha continua no palco o tempo todo, e precisaremos de mais destes laseres para atirar. Ou seja, precisamos que eles sejam enviados diretamente da biblioteca para o palco, e depois de utilizados eles retornem para a biblioteca. Para isso utilizaremos o método addChild(), que adiciona elementos no palco (ou dentro de outros objetos) de acordo com nossas especificações. Após termos criado a bolinha e feito o processo para que ela seja um Movie Clip, podemos deletá-la, pois agora ela é um objeto no painel Biblioteca.

35

Games em ActionScript 3.0

Para adicioná-la no palco dinamicamente, precisamos que ela se torne parte do código. Ela será então lincada a uma classe para poder ser reutilizada. Para isso clique com o botão direito no objeto da biblioteca e escolha a opção Propriedades.

36

Games em ActionScript 3.0

Feito isso, teremos novamente a tela onde podemos escolher o tipo de objeto. O que precisamos na verdade, é clicar na opção Avançado, e selecionar a opção Exportar para ActionScript.

37

Games em ActionScript 3.0

Note que ele indica que o nome da classe será laserClasse. É este nome que iremos utilizar para instanciarmos o tiro no código. Após isso clique em OK. Aparecerá a seguinte mensagem:

Isso significa que o Flash irá considerar laser como uma classe a partir de agora. Clique em OK. Para que entenda melhor, no painel de Ações, abaixo de todo o código já escrito, adicione este código: 38

Games em ActionScript 3.0 var laserNave:MovieClip = new laserClasse(); laserNave.x = 100; laserNave.y = 100; addChild(laserNave); Resultado: nosso laser está no palco novamente!

Destrinchando o código: var laserNave:MovieClip = new laserClasse (); Aqui definimos que o valor da variável laserNave é um MovieClip (que é uma classe do ActionScript que lida com os objetos deste tipo) e dizemos que queremos uma nova instância da classe laser com o parâmetro new. laserNave.x = 100; Posição x em que o laser irá aparecer. laserNave.y = 100;  Posição y em que o laser irá aparecer. addChild(laserNave);  Adicionando o laser no palco. Note que adicionamos o laser no palco depois de setarmos as posições. Algo a se considerar é que o nome da variável nunca pode ser o nome da classe. É possível reutilizar a classe laser várias vezes com nomes e atributos diferentes. Vejamos um exemplo: var laserNave:MovieClip = new laserClasse (); 39

Games em ActionScript 3.0 laserNave.x = 100; laserNave.y = 100; addChild(laserNave); var laserNave02:MovieClip = new laserClasse (); laserNave02.x = 150; laserNave02.y = 150; laserNave02.width = 30; laserNave02.height = 30; addChild(laserNave02); var laserNave03:MovieClip = new laserClasse (); laserNave03.x = 200; laserNave03.y = 200; laserNave03.alpha = 0.5; addChild(laserNave03); Resultado:

Agora, apague ou comente essas linhas de código. Iremos colocar a nave dinamicamente no código também. O processo é o mesmo, procurar o objeto nave na biblioteca, exportá-lo para ActionScript e adicioná-lo com o método addChild na tela.

40

Games em ActionScript 3.0 Já temos um bom pedaço de código com o nome nave sendo instanciado. Para maior comodismo iremos colocar o nome da classe da nave como naveClasse, assim não é preciso reescrever o código.

Eis o código para adicioná-la: var nave:MovieClip = new naveClasse(); nave.x = stage.stageWidth / 2; nave.y = stage.stageHeight - 100; addChild(nave); Resultado:

41

Games em ActionScript 3.0

Destrinchando o código: var nave:MovieClip = new naveClasse();  Adicionamos a nova nave nave.x = stage.stageWidth / 2;  Definimos que a posição x da nave será metade da tela com a propriedade stageWidth (largura da tela), desta forma se posteriormente precisarmos aumentar ou diminuir a largura da tela, o código se encarregará de deixa-la no meio dinamicamente. nave.y = stage.stageHeight - 100;  Definimos que a posição y da nave será sempre a stageHeitght (altura da tela) subtraída de 100. Isso faz com que a nave sempre inicie com uma distância de 100 pixels da borda inferior da tela, não importando o tamanho da mesma. addChild(nave);  Adicionamos a nave no palco.

Organizando as coisas Iremos dar uma reorganizada no código. É uma boa prática colocar as variáveis globais (que podem ser usadas em todo o código) em um mesmo bloco, os listeners em outro e no final as funções. Seguindo isso, o código ficaria assim: //variáveis globais var movimento:Number = 5; 42

Games em ActionScript 3.0 var var var var var

checarTeclaEsq:Boolean = false; checarTeclaCima:Boolean = false; checarTeclaDir:Boolean = false; checarTeclaBaixo:Boolean = false; nave:MovieClip = new naveClasse();

//adicionando elementos nave.x = stage.stageWidth / 2; nave.y = stage.stageHeight - 100; addChild(nave); //ouvintes de eventos stage.addEventListener(KeyboardEvent.KEY_DOWN, teclaPress); stage.addEventListener(KeyboardEvent.KEY_UP, teclaSolta); stage.addEventListener(Event.ENTER_FRAME, movNave); //função de tecla pressionada function teclaPress(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTeclaEsq = true; }else if(event.keyCode == 38){ checarTeclaCima = true; }else if(event.keyCode == 39){ checarTeclaDir = true; }else if(event.keyCode == 40){ checarTeclaBaixo = true; } } //função de tecla solta function teclaSolta(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTeclaEsq = false; }else if(event.keyCode == 38){ checarTeclaCima = false; }else if(event.keyCode == 39){ checarTeclaDir = false; }else if(event.keyCode == 40){ checarTeclaBaixo = false; } } //função de movimento da nave function movNave(event:Event):void{ if(checarTeclaEsq == true){ nave.x += -movimento; }else if(checarTeclaCima == true){ nave.y += -movimento; }else if(checarTeclaDir == true){ nave.x += movimento; }else if(checarTeclaBaixo == true){ nave.y += movimento; } } 43

Games em ActionScript 3.0 A partir de agora, todas as varáveis globais novas deverão ser colocadas no grupo das variáveis, todos os listeners globais no grupo de ouvintes e assim por diante. Isso ajuda a visualizar melhor o código.

Criando e trabalhando com classes Uma das grandes vantagens da Programação Orientada a Objetos são as Classes. Imagine que o laser precise ser repetido muitas vezes no código, então teríamos de fazer uma função para isso. Mas, e se quiséssemos usar a mesma função em outro jogo? Podemos colocar tudo dentro de classes, e depois reutilizar o código apenas instanciando-as em outro trecho, assim como fizemos com o laser e a nave. Para isso devemos salvar nosso código em um documento .as no Flash. Nós trabalhamos com classes básicas do ActionScript até agora. Mas precisamos aprender a criar nossas próprias classes. Como exemplo, vamos criar uma classe para os laseres, assim podemos aproveitar este código para outros jogos. Para começar, clique no menu Arquivo > Novo... Desta vez iremos escolher a opção Classe do ActionScript 3.0.

Então o Flash irá perguntar o nome da classe. Iremos colocar o nome de laserClasse, assim como colocamos na biblioteca.

44

Games em ActionScript 3.0

Assim teremos algo como isto:

Temos mais de um documento aberto ao mesmo tempo. A nova aba demonstra isso. Quando um dos documentos nรฃo estiver salvo um asterisco indicarรก isso.

Salve o arquivo com o nome laserClasse. O arquivo deve ser salvo na mesma pasta onde estรก o projeto do jogo.

45

Games em ActionScript 3.0

Estrutura do documento da classe Agora que criamos nossa classe, devemos aprender um pouco sobre sua estrutura básica. Vejamos o código: package

{

public class laserClasse { public function laserClasse() { // constructor code } } } Todas as classes no ActionScript começam com a palavra reservada package (pacote). Isso indica os pacotes de código que serão instanciados. O nome do arquivo precisa ser o mesmo da classe, e toda classe possui uma função construtora de mesmo nome. Uma classe também pode se estender de outra classe, herdando suas propriedades. Com isso é possível reaproveitar muitos trechos de código, inclusive os complicados cálculos matemáticos que já estão prontos dentro do ActionScript. Faça essas alterações no código: package { //importando bibliotecas necessárias import flash.events.Event; import flash.display.Sprite; public class laserClasse extends Sprite { //variáveis globais da classe var larguraTela:Number; var alturaTela:Number; const direcao:int = 10; const foraDaTela:int = -10; //função construtora da classe public function laserClasse():void { // constructor code addEventListener(Event.ADDED_TO_STAGE, quandoAdicionado); } //função que verifica quando objeto está adicionado na tela private function quandoAdicionado(event:Event):void { 46

Games em ActionScript 3.0 larguraTela = stage.stageWidth; alturaTela = stage.stageHeight; addEventListener(Event.ENTER_FRAME, recarregar); } //função que recarrega o tiro private function recarregar(event:Event):void { if (y < foraDaTela) { removeEventListener(Event.ENTER_FRAME, recarregar); parent.removeChild(this); } y += - direcao; } } }

Provavelmente, ainda não haverá alterações na hora de testar o projeto. Acalme-se. Destrinchando o código: package  iniciando o pacote. { //importando bibliotecas necessárias import flash.events.Event;  biblioteca de eventos. import flash.display.Sprite;  biblioteca responsável pela classe Sprite.

public class laserClasse extends Sprite  indicamos que a classe laserClasse (ela mesma) está estendendo (reutilizando) propriedades que já existem na classe Sprite. É OBRIGATÓRIO que tenha o mesmo nome da classe. {

//variáveis globais da classe var larguraTela:Number;  não indicamos o valor da variável, pois isso será indicado posteriormente. Então automaticamente a variável recebe um valor vazio. var alturaTela:Number;  idem ao anterior. const direcao:int = 10;  uma const (constante) é um valor que não varia. Se já temos certeza de que este valor nunca irá variar durante o código, o indicamos como constante. Isso garante menos processamento na hora de rodar o jogo.

47

Games em ActionScript 3.0 const foraDaTela:int = -10;  Lembre-se, números inteiros (int) não possuem ponto flutuante (ex.: 4.5, 10.3, 4,5, 10,3). Isso consome menos processamento, embora limite um pouco os cálculos do código. Utilize números inteiros se tem certeza de que não precisará de números flutuantes.

//função construtora da classe public function laserClasse():void  função principal da classe. É OBRIGATÓRIO que tenha o mesmo nome da classe. { // constructor code addEventListener(Event.ADDED_TO_STAGE, quandoAdicionado);  aqui temos um novo ouvinte (ADDED_TO_STAGE), que cuida de um evento relacionado à quando algo estiver adicionado no palco. No caso, a função quandoAdicionado irá servir para adicionarmos os laseres. }  fim da função laserClasse().

//função que verifica quando objeto está adicionado na tela private function quandoAdicionado(event:Event):void { larguraTela = stage.stageWidth;  O valor que larguraTela receberá será o valor de stage.stageWidth. Significa que isso será dinâmico ao tamanho da tela. Este tipo de recurso consome um pouco mais de processamento, mas como a idéia aqui é poder reutiliza-lo, este código irá se habituar a qualquer tamanho de tela. alturaTela = stage.stageHeight; idem ao anterior addEventListener(Event.ENTER_FRAME, recarregar);  adicionado o ouvinte da função recarregar. }  fim da função quandoAdicionado().

//função que recarrega o tiro private function recarregar(event:Event):void { if (y < foraDaTela)  se a posição y desta classe for menor do que o valor da variável foraDaTela... {

48

Games em ActionScript 3.0 removeEventListener(Event.ENTER_FRAME, recarregar);  … remove o ouvinte do evento desta função. Isso funciona como um “coletor de lixo”, pois, já que o laser estará fora da tela, não será preciso que ele fique ocupando espaço na memória. Assim não há acúmulo de tiros no topo da tela e isso evita que o processamento fique lento. parent.removeChild(this);

 Aqui temos três

novidades:   

parent - iremos usar um container para os laseres, como se fosse o canhão que os dispara. O parent serve para indicar que há uma hierarquia antes da classe. No caso definiremos isso mais adiante. removeChild – obviamente, para remover a classe do palco, economizando assim, memória e processamento. this – toda vez que utilizamos this (este/isto), se refere ao próprio objeto, no caso a classe laserClasse. Para que a classe possa ser reutilizada posteriormente, não podemos ficar presos à nomes de variáveis que existam no jogo, então parâmetros como o this auxiliam neste sentido. É como dizer: “Estou me referindo a ESTE cara, mesmo sem saber quem ele é”. }

y += acrescentada no sentido da direção.

direcao;  a posição y do objeto será sempre

} fim da função recarregar().

} fim da classe pública laserClasse.

} fim do pacote de códigos.

Dica: caso você esteja digitando e os espaçamentos fiquem um pouco bagunçados, assim que você terminar o código, o botão Formato Automático pode ajeitar as coisas pra você. Mas lembre-se: ele só poderá ajustar o código se este estiver fechado devidamente com todas as regras.

49

Games em ActionScript 3.0

Agora, precisamos instanciar essa nova classe no código da Linha do tempo. Retorne para o documento anterior (neste caso, o naveAtirando). Iremos adicionar mais algumas linhas ao nosso script que está no quadro 1. Precisaremos de mais duas variáveis globais. Então no grupo que separamos para variáveis globais acrescente: var checarTeclaBarra:Boolean = false; var atirar:Sprite = new Sprite(); addChild(atirar); Primeiramente, criamos uma variável booleana que irá checar o estado da tecla (checarTeclaBarra). A segunda variável (atirar) será o contêiner que utilizaremos para os laseres no palco. Na prática criamos este objeto que irá servir para “guardar” os laseres dentro e ir atirando-os conforme apertamos a barra de espaço. A linha addChild(atirar); adiciona o contêiner no palco. Mesmo que não possamos vê-lo, ele estará lá. Mas porque criamos esta variável? Simplesmente porque, a partir da hora quem que apertarmos a barra, o objeto que será o laser, não irá mais obedecer à esta função. E precisamos checar um anova posição de onde saiam outros laseres, não é mesmo? Acontece que esta posição também varia de lugar, já que a nave não irá ficar parada. Então é preciso ter este “canhão” que guarda o lugar para os laseres, e que irá acompanhar atualizar a posição dos tiros. Agora, precisamos adicionar as checagens da barra de espaço. Imagino que você já tenha adivinhado que teremos de revisitar as funções teclaPress e teclaSolta. No final, o código deve se parecer com isto: //função de tecla pressionada function teclaPress(event:KeyboardEvent):void{ if(event.keyCode == 37){ 50

Games em ActionScript 3.0 checarTeclaEsq = true; }else if(event.keyCode == 38){ checarTeclaCima = true; }else if(event.keyCode == 39){ checarTeclaDir = true; }else if(event.keyCode == 40){ checarTeclaBaixo = true; }else if(event.keyCode == 32){ checarTeclaBarra = true; } } //função de tecla solta function teclaSolta(event:KeyboardEvent):void{ if(event.keyCode == 37){ checarTeclaEsq = false; }else if(event.keyCode == 38){ checarTeclaCima = false; }else if(event.keyCode == 39){ checarTeclaDir = false; }else if(event.keyCode == 40){ checarTeclaBaixo = false; }else if(event.keyCode == 32){ checarTeclaBarra = false; } } Colocamos 32 como valor, pois este é o código da tecla. A próxima função a ser revistada será a função movNave. Poderíamos criar uma função somente para o que vamos fazer agora, mas iremos reaproveitar a função movNave, que já é um evento ENTER_FRAME. Faça as seguintes alterações. //função de movimento da nave function movNave(event:Event):void{ if(checarTeclaEsq == true){ nave.x += -movimento; }else if(checarTeclaCima == true){ nave.y += -movimento; }else if(checarTeclaDir == true){ nave.x += movimento; }else if(checarTeclaBaixo == true){ nave.y += movimento; } if(checarTeclaBarra == true){ var laser:Sprite = new laserClasse(); laser.x = nave.x; laser.y = nave.y; atirar.addChild(laser); } } Agora nossa nave está atirando...

51

Games em ActionScript 3.0

... mas se pressionarmos (sem soltar) a barra de espaço, ela continuará atirando ininterruptamente!

Precisamos resolver isto.

Eventos de tempo Nossa nave continua dando tiros ininterruptos porque não há um limite de tempo entre cada um dos tiros. É possível ajustar isso usando eventos do tipo TimerEvent. Este tipo de evento deve ser usado com cautela, pois consome certa parte do processamento, portanto utilize-o com cautela. Para início, no grupo de variáveis, precisamos adicionar mais algumas linhas: 52

Games em ActionScript 3.0 var tempoDoTiro:Timer = new Timer(300, 1); var podeAtirar:Boolean = true; Basicamente, a variável tempoDoTiro será do tipo Timer (algo como temporizador), e irá trazer uma nova instância do método Timer (assim como fizemos com o método Sprite). Este método pede dois parâmetros de configuração. O primeiro (onde colocamos 300), é o tempo de delay (retardamento, por assim dizer) em milissegundos entre um tiro e outro. Ou seja, 0.3 segundos (cada 1000 milissegundos equivalem a 1 segundo). Se quiser mais “espaço” entre os tiros, experimente mexer neste parâmetro. O segundo indica a quantidade de vezes que o tiro irá se repetir durante este espaço de tempo. É um parâmetro bem interessante. Ajuste- o ao seu gosto. A seguir, temos uma variável booleana chamada podeAtirar que contém o valor true. Como o próprio nome diz essa variável irá controlar quando o laser poderá (ou não) ser disparado. Na área onde separamos os listeners, iremos adicionar um listener dentro da variável tempoDoTiro, que terá como objetivo chamar a função controlaTempo. tempoDoTiro.addEventListener(TimerEvent.TIMER, controlaTempo); Veja que, controlaTempo é um TimerEvent. Agora iremos revisitar a função movNave, para acrescentar algumas novas mudanças: //função de movimento da nave function movNave(event:Event):void{ if(checarTeclaEsq == true){ nave.x += -movimento; }else if(checarTeclaCima == true){ nave.y += -movimento; }else if(checarTeclaDir == true){ nave.x += movimento; }else if(checarTeclaBaixo == true){ nave.y += movimento; } if(checarTeclaBarra == true && podeAtirar == true){ var laser:Sprite = new laserClasse(); laser.x = nave.x; laser.y = nave.y; atirar.addChild(laser); podeAtirar = false; tempoDoTiro.start(); } } E abaixo, finalmente iremos acrescentar a função controlaTempo. //função que controla o tempo do tiro function controlaTempo(event:TimerEvent):void{ podeAtirar = true; }

53

Games em ActionScript 3.0

Agora a nave atira espaçadamente!

Uma das novidades aqui fica por conta de colocarmos duas comparações ao mesmo tempo no if: if(checarTeclaBarra == true && podeAtirar == true){ Significa que estamos comparando se a barra de espaço está sendo pressionada E se a variável podeAtirar é igual a true. Nesse caso, a variável é true, pois já definimos isso na criação da variável. Os símbolos && juntos, significam E. Este é um operador de avaliação. Eis uma tabela com os mais famosos: && AND (e) || OR (ou) ! NOT (não)

Se esse E aquele... Se esse OU aquele... Se NÃO FOR este...

Logo após fazer essa checagem, nossa variável podeAtirar receberá o valor false (podeAtirar = false;) até que a variável tempoDoTiro verifique quanto tempo se passou (tempoDoTiro.start();). Lembre-se: tempoDoTiro está diretamente ligada ao evento que aciona o Timer. O método start() inicia a contagem do tempo. 54

Games em ActionScript 3.0

Depois disso o valor de podeAtirar volta a ser true, e assim poderemos atirar novamente! Mas, atirar em quem?

Frames de Animação Até agora os objetos (nave, tiro...) que utilizamos no projeto são, de certa forma, estáticos. Movem-se apenas porque demos a eles essa propriedade. Mas um game é repleto de Sprites que possuem animação. Também utilizamos até agora desenhos vetoriais criados com as ferramentas do Flash. Eles possuem a vantagem de poderem ser escalonados (mudar o tamanho) sem que se perca a qualidade da imagem. São desenhos pseudo-vetoriais, uma espécie de desenho vetorial apropriado do Flash, e não perdem qualidade justamente porque são criados por cálculos matemáticos. Mas, muitas vezes, você terá a necessidade de trabalhar com imagens (.jpg, .png, .bmp), e deverá seguir uma ordem de animação estipulada pelo designer. Para este projeto, os alunos receberam imagens de uma nave que será usada como inimiga, mas nada impede que você crie suas próprias imagens.

A idéia é que a nave inimiga siga esta ordem de animação: 01.png, 02.png, 03.png, 04.png, 01.png, 02.png, 05.png, 06.png. Primeiramente precisamos importar estas imagens para o Flash. Para isso clique no menu Arquivo  Importar  Importar para a biblioteca.

55

Games em ActionScript 3.0

Ele abrirá a janela de importação, direcione para onde estão salvas as imagens, selecione-as (é possível selecionar várias imagens em uma mesma pasta) e clique no botão Abrir.

Então as novas imagens irão ser exportadas para a Biblioteca.

56

Games em ActionScript 3.0

Agora é preciso criar um MovieClip que servirá de contêiner para essas imagens e fará a animação através dos quadros. Para isso basta clicar com o botão direito em uma parte vazia da biblioteca e escolher a opção Novo símbolo...

A partir daqui, o processo já é conhecido. Faremos as seguintes configurações:

57

Games em ActionScript 3.0

Será criado um palco em branco. Não se confunda: este é um palco que está localizado dentro do clipe de filme que acabamos de criar, e não tem relação com o palco anterior, onde se encontra nossa nave e todo o restante.

58

Games em ActionScript 3.0 Clique no painel Linha do tempo, veja que estaremos trabalhando no quadro 1. Arraste a imagem 01.png para a cruz no centro do palco.

Arraste a imagem para cá.

Linha do tempo

Quadro 1

Note que, após arrastar a imagem, o quadro 1 que antes continha uma bolinha branca, agora possui uma bolinha preta, indicando que ali naquele quadro existe algum conteúdo. Agora, vamos criar um novo quadro. Clique com o botão direito no quadro em branco que está na frente do quadro 1 e selecione a opção Inserir quadro-chave em branco.

59

Games em ActionScript 3.0

Um novo quadro com bolinha branca estĂĄ esperando que vocĂŞ arraste a imagem 02.png para o centro do palco!

60

Games em ActionScript 3.0 Repita o processo na ordem sugerida anteriormente (caso seja a mesma nave) até ter colocado todos os quadros de imagens da animação. Após isso basta apertar a tecla ENTER para ter uma prévia da animação no palco. Dica: Você pode ajustar o tempo da animação de cada quadro. A primeira vez que você clicar em um quadro, irá selecioná-lo. Basta clicar novamente neste quadro e arrastá-lo para o lado para movê-lo. Pense nos espaços da Linha de tempo como nos espaços de tempo em que o quadro da animação ficará exposto. Lembre-se, a taxa de atualização do Flash está configurada a 24fps, logo, a cada 24 destes quadros se passará 1 segundo de animação.

Organizando em pastas Existe um recurso de organização bem interessante no ActionScript 3.0, que é o fato de podermos organizar arquivos em pastas dentro da pasta do projeto e depois referenciá-la em uma classe. Em um projeto pequeno como este não faz muita diferença, mas digamos que você esteja trabalhando em um projeto grande, quando tiver criado umas 50 classes isso fará sentido. Dentro da pasta do projeto, iremos criar uma pasta chamada: inimigos, onde deveremos salvar todas as classes referentes aos inimigos. Precisamos referenciar essa pasta nas propriedades da classe inimigoClasse, para isso devemos editar essas propriedades com o caminho correto.

61

Games em ActionScript 3.0

É como uma hierarquia de pastas do Windows, onde inimigos.inimigoClasse indica que a classe que criaremos se encontra em uma pasta chamada inimigos dentro da pasta do nosso projeto. Lembre-se: o ActionScript 3.0 é case sensitive, caso tenha criado o nome de sua pasta como Inimigos, então a referência correta é: Inimigos.inimigoClasse.

Adicionando inimigos no palco Temos aqui um problema: Temos uma nave inimiga que devemos destruir, porém um jogo com um inimigo só seria no mínimo entediante, não acha?

62

Games em ActionScript 3.0 Criar várias imagens para inimigos na tela e adicioná-las uma a uma com addChild() não parece ser uma opção muito viável, já que isso pesaria bastante no código e precisaríamos de muito mais tempo para criar todos esses inimigos diferentes. Um recurso interessante que muitos games utilizam é o de reaproveitar os inimigos, duplicando-os. O que precisamos é de uma classe que duplique essa quantidade de inimigos na tela de forma dinâmica e randômica, assim cada vez que o jogador executar o game, enfrentará inimigos que partem de posições diferentes. Neste caso iremos reaproveitar a classe inimigoClasse, que foi criada quando fizemos a animação da nave. Este é script que iremos adicionar na classe inimigoClasse. package inimigos { import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; public class inimigoClasse extends Sprite { private var nucleo:Object; private var vely:Number = 2; public function inimigoClasse() { // constructor code addEventListener(Event.ADDED_TO_STAGE, quandoAdicionado); } private function quandoAdicionado(event:Event):void{ nucleo = MovieClip(root); addEventListener(Event.ENTER_FRAME, recarregar); } private function recarregar(event:Event):void{ y += vely; for(var i = 0; i < nucleo.atirar.numChildren; i++){ var atingido:Sprite = nucleo.atirar.getChildAt(i); if(hitTestObject(atingido)){ nucleo.atirar.getChildAt(i).removeListeners(); nucleo.atirar.removeChild(atingido); removeEventListener(Event.ENTER_FRAME, recarregar); nucleo.removeChild(this); } } } public function removeListeners():void{ removeEventListener(Event.ENTER_FRAME, recarregar); 63

Games em ActionScript 3.0 } } }

Destrinchando o código: package inimigos {  Desta vez referenciamos no pacote o nome da pasta que criamos, indicando que este código deve ser procurado nesta pasta quando for utilizado. import flash.display.MovieClip;  importando da biblioteca. import flash.display.Sprite;  importando da biblioteca. import flash.events.Event;  importando da biblioteca.

public class inimigoClasse extends MovieClip {  Note que desta vez estamos extendendo direto da classe MovieClip. Poderíamos utilizar a classe Sprite aqui, mas esta não aceita animações quadro a quadro. Nós precisamos da nave animada, certo? private var nucleo:Object;  Criamos uma variável do tipo Object, que servirá de núcleo-base para remover e adicionar as naves e os tiros. private var vely:Number = 2; descerão na tela.

 Velocidade que as naves

public function inimigoClasse() {  Início da função pública inimigoClasse. // constructor code  comentário addEventListener(Event.ADDED_TO_STAGE, quandoAdicionado);  Este evento se encarregará de chamar a função quandoAdicionado assim que a classe for usada. }  fim da função inimigoClasse. private function  Início da função quandoAdicionado.

quandoAdicionado(event:Event):void{

nucleo = MovieClip(root);  setamos que o valor da variável núcleo é um Clipe de Filme (MovieClip) que leva como parâmetro a variável root. Basicamente, root tem propriedades semelhantes ao método stage, identifica que estamos nos dirigindo ao quadro principal da linha do tempo. Alguns programadores preferem não mais utilizar este método, pois caiu em desuso, mas é interessante termos ele aqui para fins de estudo. addEventListener(Event.ENTER_FRAME, recarregar);  Chamamos recarregar aqui. 64

Games em ActionScript 3.0 }  Fim da função quandoAdicionado. private function recarregar(event:Event):void{  Início da função recarregar. y += vely;  Aqui é onde a velocidade em y é incrementada, adicionando +1 ao valor da variável a cada atualização e fazendo a nave descer. for(var i = 0; i < nucleo.atirar.numChildren; i++){  Iniciamos um loop For. A novidade aqui é que temos numChildren, que se refere ao número de índice da nave que é criada. var atingido:Sprite = nucleo.atirar.getChildAt(i);  Criamos uma variável que guarda o valor da nave atingida. O getChildAt “pega” o número de índice que é criado para cada nave e guarda na memória. No caso, é guardado o número da variável “i”. if(hitTestObject(atingido)){  If checando se a nave foi atingida. O método hitTestObject é utilizado quando queremos fazer testes de colisão entre dois ou mais objetos. Neste caso, é preciso que a nave seja atingida, ou seja, o tiro irá colidir com a nave. O conceito é simples, mas muitos programadores experientes ainda não dominam bem o método e criam extensas linhas de código para fazer a mesma coisa. nucleo.atirar.getChildAt(i).removeListeners();  Agora sim a função pública removeListeners é acionada nas duas classes, removendo a nave inimiga e o tiro do palco. nucleo.atirar.removeChild(atingido);  Aqui remove-se o índice da nave para uma nova contagem. removeEventListener(Event.ENTER_FRAME, recarregar);  A função remove o evento que a escuta. nucleo.removeChild(this); que estiver dentro de nucleo, não importando o que seja.

 Remove o

}  Fim do If. }  Fim do loop For. }  Fim da função recarregar.

public function removeListeners():void{  Início da função removeListeners, note que esta função é pública, e é acessada na classe dos tiros também. removeEventListener(Event.ENTER_FRAME, recarregar);  Remove-se a escuta da função recarregar. 65

Games em ActionScript 3.0 }  Fim da função removeListeners. }  Fim da classe pública inimigoClasse. }  Fim do package. A classe pode ser um pouco difícil de entender a princípio, mas com a prática em classes deste tipo as coisas vão ficando mais claras. Agora precisamos instanciar a classe no código da nossa linha do tempo (quadro 1). Na parte que separamos para a variável, colocaremos esta nova variável: var tempoDaNave:Timer = new Timer(1500); É bem semelhante à variável Time do tiro, então dispensa apresentações. Agora adicionaremos mais uma linha aos ouvintes: tempoDaNave.addEventListener(TimerEvent.TIMER, criaInimigo); E adicionaremos estas linhas ao final do código: tempoDaNave.start(); function criaInimigo(event:Event){ var novoInimigo:MovieClip = new inimigoClasse(); novoInimigo.x = Math.random() * stage.stageWidth; addChild(novoInimigo); }

Vamos então entender esta última função. tempoDaNave.start();  Estamos utilizando um método pronto do ActionScript 3.0 que irá iniciar a contagem do tempo. function criaInimigo(event:Event){  Início da função criaInimigo. var novoInimigo:MovieClip = new inimigoClasse();  Criamos uma variável para utilizarmos a classe do inimigo. Note que agora a instanciamos como MovieClip, pois definimos isso no arquivo da classe. novoInimigo.x = Math.random() * stage.stageWidth;  A posição x de cada novo inimigo é calculada pelo método Math.random, que serve para fazer cálculos matemáticos aleatórios complexos. Neste caso o Math.random calcula que as naves devem ser criadas no espaço do stage.stageWidth, ou seja, leva em consideração a largura do palco, não importando qual ela seja. Fizemos isso para que o código fique dinâmico, mas nada impede que você coloque um valor fixo. Experimento trocar stage.stageWidth por 100 e veja o que acontece. addChild(novoInimigo);  Adicionamos o novo inimigo. }  Fim da função criaInimigo.

66

Games em ActionScript 3.0 Resultado:

Já temos nossas naves inimigas invadindo a Terra e sendo desintegradas por nossos tiros pulverizadores! Mas seria interessante um pouco de barulho e algum tipo de explosão, não acha?

Explodindo os inimigos! Agora que nossos inimigos estão “desaparecendo”, iremos precisar de outros elementos para complementar nossa explosão: uma animação de explosão e barulho. Como o objetivo aqui não é ensinar como criar animações, você deverá criar a sua. Mas não é muito diferente do que foi feito com a nave inimiga. Basta ter um pouco de imaginação e entender como funciona o processo e não será um caminho muito difícil. O som pode ser baixado de sites que disponibilizam bibliotecas de som gratuitas. Para nosso exemplo eu usei os sons explosion.mp3 e laser_blast.mp3 do site http://www.freesfx.co.uk/. Sempre procure efeitos sonoros gratuitos para o seu jogo, ok? Importe os sons para a biblioteca da mesma forma que foi feito com as naves. A animação da explosão deve estar com estas propriedades: 67

Games em ActionScript 3.0

68

Games em ActionScript 3.0 Estas s達o as propriedades do som de explos達o:

69

Games em ActionScript 3.0 E estas são as propriedades do som do tiro laser:

Colocamos a sigla sfx na frente do nome da classe apenas por convenção. Assim indicamos que esta classe se refere a um som de efeito (sound effects - de onde vem a sfx), mas é possível nomeá-la de outra forma. Lembre-se sempre de seguir as regras de criação de nomes para variáveis e classes. Se quiser uma melhor organização, renomeie os sons para sfx_nome_do_arquivo também. Feito isso, vamos editar a classe explosaoClasse, que está vinculada às propriedades da explosão.

70

Games em ActionScript 3.0 Na verdade, o conteúdo da classe é bem simples: package

{

import flash.display.MovieClip; import flash.events.Event; import flash.media.Sound; public class explosaoClasse extends MovieClip { private var explodir:Sound = new sfx_explosao(); public function explosaoClasse() { // constructor code addEventListener(Event.ENTER_FRAME, inimigoMorto); explodir.play(); } private function inimigoMorto(event:Event):void{ if (currentFrame == framesLoaded){ removeEventListener(Event.ENTER_FRAME, inimigoMorto); parent.removeChild(this); } } } } Destrinchando o código: package

{  Início do pacote.

import flash.display.MovieClip;  importando MovieClip. import flash.events.Event; importando Event. import flash.media.Sound;  aqui uma biblioteca nova: Sound. Ela será necessária apenas para que possamos controlar as propriedades do nosso sfx. public class explosaoClasse extends MovieClip {  Início da classe pública explosaoClasse. private var explodir:Sound = new sfx_explosao();  essa é a variável que terá o valor do som da explosão. Veja que buscamos aqui o som da explosão pelo nome da classe e não do arquivo, por isso é importante que os objetos estejam vinculados a uma classe. public

function

explosaoClasse()

explosaoClasse. 71

{

Início da função

Games em ActionScript 3.0 // constructor code addEventListener(Event.ENTER_FRAME, inimigoMorto);  adicionamos uma escuta para a classe inimigoMorto. explodir.play();  E “damos play” no som da explosão. }  Fim da função explosaoClasse. private function Início da função privada inimigoMorto.

inimigoMorto(event:Event):void{

if (currentFrame == framesLoaded){  Se o quadro atual for igual ao último quadro da animação que foi carregado... removeEventListener(Event.ENTER_FRAME, inimigoMorto);  …remove-se a escuta para a função inimigoMorto... parent.removeChild(this); objeto dessa classe da tela, não importando quem seja ele.

 …e remove-se o

}  Fim do If. }  Fim da função inimigoMorto. }  Fim da classe explosaoClasse. }  Fim do pacote.

Utilizamos o método currentFrame quando queremos nos referir ao quadro atual de uma animação (a tradução literal seria quadro corrente, mas isso é feio que dói!). O método framesLoaded vai tratar de verificar se todos os quadros daquela linha de tempo já foram usados ou carregados, ou seja, se a animação já foi toda “rodada”. Agora devemos editar a classe inimigoClasse. Não é nada muito complicado, apenas iremos adicionar algumas linhas na verificação da colisão. As linhas em negrito demonstram o que deve ser adicionado: package inimigos { import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; public class inimigoClasse extends MovieClip { private var nucleo:Object; private var vely:Number = 2; 72

Games em ActionScript 3.0

public function inimigoClasse() { // constructor code addEventListener(Event.ADDED_TO_STAGE, quandoAdicionado); } private function quandoAdicionado(event:Event):void{ nucleo = MovieClip(root); addEventListener(Event.ENTER_FRAME, recarregar); } private function recarregar(event:Event):void{ y += vely; for(var i = 0; i < nucleo.atirar.numChildren; i++){ var atingido:Sprite nucleo.atirar.getChildAt(i); if(hitTestObject(atingido)){

=

nucleo.atirar.getChildAt(i).removeListeners(); nucleo.atirar.removeChild(atingido); var explodir:MovieClip = new explosaoClasse(); explodir.x = x; explodir.y = y; stage.addChild(explodir); removeEventListener(Event.ENTER_FRAME, recarregar); nucleo.removeChild(this); } } } public function removeListeners():void{ removeEventListener(Event.ENTER_FRAME, recarregar); } } }

E já temos nossa explosão com som! Devemos adicionar o som dos tiros. O raciocínio é semelhante, mas iremos utilizar o código que está no Quadro 1 da linha de tempo agora. No espaço que separamos para as variáveis adicionamos esta: var somDoTiro:Sound = new sfx_laser();

73

Games em ActionScript 3.0 E na função onde tratamos a ação da barra de espaço, adicionamos: function movNave(event:Event):void{ if(checarTeclaEsq == true){ nave.x += -movimento; }else if(checarTeclaCima == true){ nave.y += -movimento; }else if(checarTeclaDir == true){ nave.x += movimento; }else if(checarTeclaBaixo == true){ nave.y += movimento; }if(checarTeclaBarra == true && podeAtirar == true){ var laser:Sprite = new laserClasse(); laser.x = nave.x; laser.y = nave.y; atirar.addChild(laser); podeAtirar = false; tempoDoTiro.start(); somDoTiro.play(); } }

E agora temos nossa nave atirando com som!

Próximo passo: Pontuação - Score. 74

Games em ActionScript 3.0

Ganhando alguns pontos. Bem, agora que já conseguimos realizar uma verdadeira batalha contra nossos inimigos precisamos ganhar alguns pontos por cada nave abatida. Primeiramente precisamos de um placar. Para este exercício foi criado um shape simples no Flash CS5 e depois este shape foi convertido em Clipe de filme (MovieClip). O nome do objeto na conversão não irá importar neste caso, pois o placar ficará fixo na tela.

Neste caso, nomeamos a ocorrência do objeto como score.

Após isso basta dar dois cliques no Clipe de Filme para editá-lo, pois precisaremos de algum texto. O texto será colocado em uma camada acima do shape. A palavra Score do quadro é apenas ilustrativa e não terá nenhuma interação com o jogo. Vamos nos focar nos números. 75

Games em ActionScript 3.0 O importante é saber que são dois campos de texto separados.

Não importa muito a quantidade de números que for digitada aqui, isso é apenas uma marcação para sabermos qual o tamanho que os números irão ocupar. Isso será substituído depois no código. Nas propriedades do texto (os números) iremos selecionar as opções Texto clássico e Texto dinâmico. Dica: Basicamente utilizamos no Flash CS5, Texto estático para textos que não terão interação com o usuário, Texto dinâmico para interação com o código e Texto editável para textos que podem ser editados pelo usuário.

76

Games em ActionScript 3.0

Nomeamos a ocorrência do texto para scoreTxt. Atenção: A ocorrência scoreTxt do texto é diferente da ocorrência score do MovieClip.

E agora, nosso texto precisa ser incorporado ao projeto para que funcione corretamente. Para isso basta clicar em Incorporar...

Marcaremos apenas a opção Numerais [0..9], pois só serão utilizados números neste campo, então o Flash não irá incorporar a fonte toda no código.

77

Games em ActionScript 3.0

Com isso temos o texto configurado. Agora vamos ao código. Primeiro, no nosso famoso Quadro 1, criamos uma variável para armazenar o valor numérico dos pontos. var scoreInicial:Number = 0;

No final do código criaremos uma função para contar os inimigos mortos. score.scoreTxt.text = String(0); function inimigoMorto(pontos) { scoreInicial += pontos; score.scoreTxt.text = String(scoreInicial); }

78

Games em ActionScript 3.0 Destrinchando o código: score.scoreTxt.text = String(0);  definimos fora da função que o valor padrão que aparecerá no texto numérico será 0. Este valor irá substituir qualquer valor que tenhamos colocado anteriormente no placar. Note que a hierarquia segue como temos no MovieClip: scoreTxt está dentro de score, então é assim que o acessamos: score.scoreTxt. Depois acessamos a propriedade de texto usando o método text, que já é reservado do código, e a tudo isso é definido que 0 é agora uma String (String(0)). function inimigoMorto(pontos)  Início da função inimigoMorto. Note o parâmetro pontos que criamos. Essa será a variável que irá trazer para dentro da função o número do inimigo abatido. { scoreInicial += variável pontos.

pontos; Aqui o scoreInicial começa a recebe o valor da

score.scoreTxt.text = String(scoreInicial);  E este valor depois é repassado para o campo de texto, sendo convertido em String. } Agora precisamos capturar a quantidade de inimigos mortos. Para isso iremos revisitar a classe inimigoClasse, mais precisamente a função recarregar. Basta adicionarmos uma linha na função recarregar: private function recarregar(event:Event):void { y += vely; for (var i = 0; i < nucleo.atirar.numChildren; i++) { var atingido:Sprite = nucleo.atirar.getChildAt(i); if (hitTestObject(atingido)) { nucleo.atirar.getChildAt(i).removeListeners(); nucleo.atirar.removeChild(atingido); var explodir:MovieClip = new explosaoClasse(); explodir.x = x; explodir.y = y; stage.addChild(explodir); removeEventListener(Event.ENTER_FRAME, recarregar); nucleo.removeChild(this); nucleo.inimigoMorto(1);

79

Games em ActionScript 3.0 } } }

Com núcleo.inimigoMorto(1) estamos aproveitando a função de colisão para adicionarmos 1 ao valor dos pontos, então toda vez que o laser colidir com a nave inimiga a função recarregar irá passar se parâmetro para a função inimigoMorto que está no Quadro 1, aumentando assim o valor do score. Nada complicado. Dica: Definimos como valor da morte do inimigo o número 1, mas poderíamos fazer a conta de 10 em 10, por exemplo, neste caso o valor seria 10. A vantagem de fazer dessa forma é o fato de podermos atribuir valores diferentes a inimigos diferentes.

E agora já ganhamos alguns pontos!

80

Games em ActionScript 3.0

Primeiro jogo finalizado! Como dito, o objetivo dessa apostila é indicar os primeiros passos para aspirantes a desenvolvedores de jogos com uma linguagem que oferece tudo o que é necessário para se criar um jogo satisfatório. Obviamente programadores bem mais experientes poderiam encontrar soluções mais viáveis dos que as que apliquei aqui, mas visei buscar bases sólidas nos fundamentos para a construção de futuros jogos. Por isso tentei abordar toda a parte básica de entendimento de lógica para a criação de um jogo simples. Até aqui você aprendeu um pouco sobre variáveis, constantes, funções, classes, propriedades, interações com mouse e teclado, colisões e etc., e já tem uma certa bagagem para começar a usar a imaginação e tenta criar seus próprios jogos. A idéia é que esta seja apenas a primeira de uma série de apostilas. Nas próximas edições pretendo abordar outros assuntos um pouco mais complexos e oferecer outros exemplos de jogos, possivelmente, outras ferramentas e linguagens. Agradeço a todos os que me apoiaram até aqui e espero realmente que essa apostila tenha lhe auxiliado em seus primeiros passos rumo ao desenvolvimento de webgames. Caso queira enviar sugestões (e talvez alguns milhõezinhos) fique à vontade para enviar emails para: artur.guitelar@gmail.com

Até o próximo jogo!

Artur Guitelar - Killdragon.

81

Games em ActionScript 3.0

Referências bibliográficas: Livro: Aprendendo ActionScript 3.0 – Guia para iniciantes – Editora Artmed /Bookman Autores: Rich Shupe e Zevan Rosser.

Sites: http://asgamer.com/ http://www.youtube.com/user/oppcell http://www.emanueleferonato.com/

82


Web Games com ActionScript 3.0 - 01