Criando seu primeiro app com Corona SDK

Neste post vamos criar um jogo simples baseado em toques na tela para manter um balão no ar. Junto dele vamos estudar alguns aspectos básicos do desenvolvimento de jogos. Tentarei manter este post o mais simples possível e não, não fui eu quem criei este tutorial, ele é uma adaptação de um tutorial existente no site oficial da CoronaLabs, em Inglês. Como sei que o material em Português sobre Corona SDK é escasso, resolvi dar essa mão pro pessoal que está começando.

Para quem quiser mais material, o livro que traduzi está à disposição!

Espero que gostem!

Programando com Corona

Corona usa linguagem de scripting Lua. Se você já programou em alguma outra linguagem de programação, vai achar o Lua muito fácil. Espero fazer em breve um post com uma introdução ao Lua, mas você deve encontrar o básico pela Internet, é bem fácil de aprender.

Para fazer nosso tutorial, além de alguns conhecimentos básicos de programação, você vai precisar baixar o Corona SDK no site do fabricante, é rápido e de graça: https://coronalabs.com/.

Editores de Código

Além do Corona SDK, você vai precisar de algum editor de código. Existem diversos no mercado e vai muito do gosto pessoal escolher um ou outro. Algumas opções que possuem suporte à Corona e/ou Lua:

Editor PlugIn p/ Corona
Atom baixar autocomplete
Visual Studio Code Corona Tools
Sublime Corona Editor
VIM
Zero Brane Studio
Notepad++
TextWrangler
MacroMates

Criando o App

Seu primeiro app será bem simples, mas irá demonstrar alguns conceitos importantes. Vamos fazer um jogo no estilo tapping, onde você tem que ficar tocando a tela constantemente para manter um balão no ar. Cada vez que o balão é tocado, ele vai ser impulsionado um pouquinho pra cima.

A melhor maneira de usar este tutorial é seguindo-o passo-a-passo – código, imagens, etc – e vendo seu projeto ganhar vida gradualmente. Pode levar um pouco mais de tempo, mas você entenderá muito melhor.

Todos os fontes e materiais desse projeto podem ser baixados no Github, neste link.

Curso React Native

Começando um Projeto

Criar um novo projeto com Corona é fácil:

  1. Abra o Corona Simulator
  2. Clique em “New Project” na tela de boas vindas ou selecione “New Project…” no menu “File”
  3. Para o nome do projeto, digite BalloonTap e escolha a opção de template Blank. Deixe as outras configurações como estão e clique em “OK” (Windows) ou “Next” (Mac). Isto irá criar os arquivos básicos para seu primeiro jogo na pasta que você escolher. Esta também é a pasta onde você deverá colocar todos os arquivos do app, incluindo imagens, arquivos-fonte, etc.
sbs-balloon-0

Adicionando Imagens

Você irá precisar de imagens para este app, colocadas dentro da pasta do projeto que você acabou de criar. Existem três imagens neste projeto:

Arquivo Tamanho Descrição
background.png 360 × 570 O background – somente decoração, para que não fique uma tela preta.
platform.png 300 × 50 A plataforma/piso – evita que o balão caia fora da tela.
balloon.png 112 × 112 O balão.

Para este projeto você pode criar as imagens do zero, se quiser, ou usar as que estão inclusas no zip de download do projeto. Caso venha a fazer suas imagens (algo inevitável no futuro), tenha em mente o seguinte:

  • Corona suporta os formatos PNG e JPG.
  • Imagens não devem conter perfil ICC embutidos.
  • Evite arquivos JPG progressivos pois demoram muito pra carregar.

Carregando o Background

A primeira imagem que precisamos carregar é o background. Corona coloca coloca tudo na tela do fundo para o primeiro plano, como se fossem camadas, uma por cima da outra. Assim, a primeira imagem que carregarmos vai ficar por trás das próximas a serem carregadas. Ou seja, o mais fácil é manter o projeto simples e carregar as imagens na ordem lógica.

Usando o editor de código da sua escolha, localize e abra o arquivo main.lua dentro da pasta do seu projeto. O arquivo main.lua é o principal arquivo de qualquer projeto Corona e você não pode criar um app sem ele. Este é o arquivo que é executado quando o app inicia, cada vez que você mandar rodar ele.

Neste arquivo main.lua, digite o seguinte:

Existem muito o que ser discutido neste único comando. Vamos quebrar em partes:

A primeira palavra, local, é um comando Lua indicando que a próxima palavra será uma variável. Uma variável, como você aprendeu em matemática, é usada para armazenar um valor. Neste caso, esse valor será uma imagem usado como seu background.

Note que local é toda escrita em minúsculas e é usada aqui para declarar a variável, nas chamadas subsequentes à essa variável, não precisa usar local novamente.

A segunda palavra, background, é nome da nossa variável. Quando quisermos alterar o conteúdo dela mais tarde, usaremos este nome.

Lembre-se de sempre usar nomes de variáveis diferentes cada vez que for criar uma. Assim como é muito confuso todo mundo em uma turma se chamar João, usar o mesmo nome de variável em todos seus objetos criará confusão no seu programa.

O = (sinal de igualdade) é usado para atribuir uma imagem à variável background.

display.newImageRect() é uma das APIs do Corona (comandos especiais que podemos chamar para que coisas aconteçam no app). Ele é usado para carregar uma imagem a partir de um arquivo para que então possa ser usada no app. Existem diversas maneiras de carregar uma imagem no seu app, mas display.newImageRect() é especial porque permite redimensionar a imagem no processo.

Dentro dos parênteses estão os parâmetros que devemos passar ao display.newImageRect(), também chamados de argumentos. O primeiro parâmetro é o nome do arquivo com a imagem que queremos carregar, incluindo a extensão do mesmo (.png).

Importante: o nome fornecido deve ser exatamente igual ao do arquivo, incluindo maiúsculas e minúsculas! Se o arquivo se chama background.png, você não pode tentar carregá-lo chamando-o de “BackGround.PNG”.

Os próximos dois parâmetros, 360 e 570 especificam o tamanho que queremos que a imagem de background tenha. Neste caso, nós estamos simplesmente dizendo as dimensões da imagem em pixels, embora como informado antes, o comando display.newImageRect() permite redimensionar a imagem mudando esses números.

O passo final para o background é posicioná-lo no lugar correto da tela. Imediatamente depois da linha que você digitou, adicione estes dois comandos:

Por padrão, Corona irá posicionar o centro de um objeto na coordenada 0/0, ou seja, no canto superior esquerdo da tela. Ao trocar as propriedades x e y do objeto, entretanto, nós podemos mover a imagem de background para um novo local.

Para este projeto, nós posicionaremos o background no centro da tela, e para isso Corona nos dá uma ajuda com os valores display.contentCenterX e display.contentCenterY, que permitirão centrelizar as coordenadas de background.x e background.y.

sbs-balloon-1

Ação!

Vamos testar nosso código. Save seu arquivo main.lua modificado e mande executar novamente o seu projeto no Corona Simulator (Ctrl+R ou Command+R). Se tudo correu bem, o background deve estar agora aparecendo, centralizado na tela.

Se você receber um erro ou não puder ver o background, existem algumas possibilidades para isso:

  • Um dos comandos foi digitado incorretamente.
  • O arquivo da imagem não está na mesma pasta que o arquivo main.lua.
  • O arquivo ou extensão do mesmo está incorreto ou não está com a mesma capitalização (maiúsculas e minúsculas).

Carregando a Plataforma

Hora de carregar a plataforma. Isto é bem parecido com o background. Abaixo das três linhas de código que você já digitou, coloque estes três comandos:

Como você provavelmente notou, existem uma pequena diferença em relação ao código anterior: ao invés de posicionar a plataforma centralizada verticalmente, nós queremos mantê-la no rodapé da tela. Ao usar o comando display.contentHeight, nós sabemos a altura da área visível. Lembre-se também que platform.y posiciona o centro do objeto no local especificado. Então, devido à altura do objeto ser 50px, nós subtraímos 25px do valor, garantindo que poderemos ver toda plataforma na tela.

Salve e execute novamente o arquivo main.lua no Simulator para ver a imagem da plataforma.

Carregando o Balão

Para carregar o balão, seguiremos o mesmo processo. Abaixo dos comandos anteriores, digite as seguintes linhas:

Além disso, para dar ao balão uma leve transparência, vamos reduzir a opacidade (alfa) levemente. Na linha a seguir, defina a propriedade alfa do balão para 80% (0.8):

Salve seu arquivo main.lua e execute novamente o Simulator. Agora deverá aparecer um balão no centro da tela.

Adicionando Física

sbs-balloon-2

Hora de adicionarmos física! Corona inclui o motor de física Box2D para você usar em seus apps. Obviamente física não é algo obrigatório em todos jogos, mas em algumas situações torna a tarefa de manipular o jogo muito mais fácil.

Incluir física é muito fácil com Corona. Abaixo das linhas anteriores adicione:

Vamos entender estas duas linhas em mais detalhes:

O comando local physics = require( “physics” ) carrega o motor de física Box2D no seu app e associa-o à variável local physics para uso posterior. Isto dá a você a habilidade chamar comandos internos da biblioteca de física usando essa variável, como você verá mais adiante.

physics.start() faz exatamente o que você deve adivinhar sozinho – inicia o motor de física.

Se você salvar e reexecutar não verá qualquer diferença no jogo…ainda. Isto é porque nós damos ao motor de física nada para fazer. Para a física funcionar, nós precisamos converter os objetos de imagens em objetos físicos. Isto é feito com o comando physics.addBody:

Isto diz ao motor de física adicionar um corpo físico à imagem da plataforma. Além disso, o segundo parâmetro diz ao Corona para tratá-lo como um objeto físico estático. O que significa? Basicamente objetos estáticos não são afetados pela gravidade ou outras forças físicas, ou seja, sempre que quiser que um objeto não se mova de jeito algum, torne-o “static”.

Agora vamos adicionar um corpo físico ao balão:

Em contraste à plataforma, o balão será um objeto dinâmico. Isto significa que ele é afetado pela gravidade, colisões com outros objetos físicos, etc. Neste caso, o segundo parâmetro (“dynamic”) é na verdade opcional porque este é o tipo padrão que os objetos são, mas incluirei por questões didáticas.

A parte final deste comando physics.addBody é usada para ajustar as propriedades do corpo do balão – neste caso daremos uma forma arredondada e ajustaremos o seu valor de bounce (recuo). Parâmetros devem ser colocados entre chaves (uma estrutura chamada table na programação Lua).

Devido ao balão ser um objeto arredondado, nós definimos uma propriedade radius (raio) com um valor 50. Este valor basicamente combina com o tamanho da nossa imagem de balão, sendo que se você criou uma imagem própria, terá de ajustá-lo de acordo.

O valor bounce (recuo) pode ser qualquer decimal positivo ou valor inteiro. Um valor de 0 significa que o balão não possui recuo, enquanto que um valor de 1 fará com que ele recue (quique) de volta com 100% da sua energia de colisão. Um valor de 0.3, como visto acima, irá fazer com que ele recue de volta com 30% de sua energia.

Atenção

Um valor de bounce maior que 1 irá fazer com que um objeto recue com mais do que 100% a energia da colisão, ou seja, ele irá recuar ainda mais acelerado do que colidiu. Tome cuidado com valores de bounce superiores a 1.

Mesmo que você defina o balão como tendo um bounce de 0, ele ainda quicará porque a plataforma, por padrão, tem um bounce de 0.2 (todo corpo físico tem esse padrão). Se não quiser que ele quique, defina o bounce da plataforma como 0 também.

Salve seu arquivo main.lua e dê um relaunch no Simulator. Como um experimento divertido, você pode tentar ajustar o valor de bounce e reexecutar para ver os efeitos.

Funções

Até este momento, nós temos um balão que cai em uma plataforma e dá uma quicada de leve. Não é muito divertido, então vamos transformar isso em um jogo! Para nosso jogo de tocar no balão funcione, temos que estar aptos à empurrar o balão para cima um pouco a cada vez que ele é tocado.

Para executar esse tipo de recurso, linguagens de programação usam funções (functions). Funções são seções curtas (geralmente) de código que somente executam quando são ordenadas para tal, como quando o jogador tocar no balão.

Vamos criar nossa primeira função:

Função são essenciais para desenvolver apps com Corona, então vamos examinar a estrutura básica:

Como antes, nós usamos a palavra-chave local para declarar a função.

A palavra-chave function diz ao Corona que esta é uma função e que ela definirá um conjunto de comandos que serão chamados pelo nome pushBalloon.

Os parênteses finais ‘()’ são obrigatórios. Em tutoriais mais avançados temos uso para eles, mas por ora, apenas deixe como está.

Como mencionado acima, funções são seções (blocos) de código que executam somente quando são chamado. Sendo um bloco, temos de fechá-lo quando terminamos de definir o seu grupo de comandos, com a palavra-chave end. Isto diz ao Lua que aquela função terminou.

Excelente, agora temos uma função! Infelizmente e’uma função vazia até o momento, o que não fará nada caso a invoquemos pelo nome. Vamos resolver isso adicionando as seguintes linhas de código dentro da função, entre a linha onde nós declaramos a função e a palavra-chave end:

balloon:applyLinearImpulse é um comando realmente legal. Quando aplicado a um objeto dinâmico como o balão, ele aplica um empurrão no objeto em qualquer direção. Os parâmetros que passamos diz ao motor de física com quanta força ele deve empurrar (horizontalmente e verticalmente) e também onde aplicaremos a força no corpo do objeto.

Os primeiros dois parâmetros, 0 e -0.75, indicam a quantidade de força direcional. O primeiro número é a horizontal, ou direção x, e o segundo é a vertical, ou direção y. Uma vez que nós queremos puxar o balão para cima (nada de esquerda ou direita), usaremos 0 como primeiro parâmetro. Para o segundo parâmetro, com o valor de -0.75, dizemos ao motor de física empurrar o balão para cima um pouquinho. O valor deste número determina quanta força será aplicada: quanto maior o número, mais alta a força.

axes

Atenção

Como visto no diagrama à direita, valores positivos em x se estendem à direita, enquanto valores positivos em y levam o objeto para baixo. Por isso que um valor negativo (como -0.75) levam o balão para cima (o inverso do plano cartesiano).

O terceiro e quarto parâmetros, balloon.x e balloon.y, dizem ao motor de física onde aplicar a força, relativo ao balão em si. Se você aplicar a força em um local que não está no centro do balão, pode fazer com que ele se mova em uma direção inesperada ou girar. Para este jogo, manteremos a força focada no centro do mesmo.

Ao todo, a função pushBalloon deve se parecer com essa:

É considerado uma boa prática de programação indentar ao menos uma tab ou 3-4 espaços quando você adiciona linhas de código dentro de funções. Isto faz com que seu código seja mais legível e mais fácil de reconhecer as funções dentro de grandes arquivos de código.

Eventos

Eventos são o que criam interatividade e, em muitas maneiras, Corona é um framework baseado em eventos onde as informações são despachadas durante eventos específicos a event listeners, algo como “gatilhos de evento”. Ou seja, toda vez que o usuário toca um objeto que aparece na tela do smartphone/tablet (como seu balão), Corona reage disparando um evento.

Adicionar um event listener (gatilho de evento) é fácil. Considere este exemplo:

Vamos inspecionar a estrutura deste comando:

Primeiro, devemos dizer ao Corona qual objeto está envolvido neste event listener. Para este jogo, queremos detectar um evento relacionado diretamente ao objeto balão.

Imediatamente depois, adicione dois pontos (:), e então addEventListener. Em Lua, isto é chamado de método do objeto. Essencialmente, addEventListener, após os dois pontos, diz ao Corona que queremos adicionar um event listener ao balão, especificado antes dos dois-pontos.

Dentro dos parênteses temos dois parâmetros que completam o comando. O primeiro parâmetro é o tipo de evento que o Corona ficará esperando, neste caso um “tap” (toque rápido). O segundo parâmetro é a função será executada (chamada) quando o evento acontecer, neste caso a função pushBalloon que escrevemos na seção anterior. Essencialmente, estamos dizendo ao Corona para executar a função pushBalloon toda vez que o usuário tocar no balão.

Ação!

Isto é tudo – você tem um jogo funcional agora! Se você salvar seu arquivo main.lua e reexecutar o Simulator, ele deverá funcionar completamente. Tente manter o balão no ar o máximo possível tocando nele enquanto a gravidade o puxa para baixo, sem deixá-lo tocar a plataforma!

Aqui está o código completo, caso tenha perdido alguma coisa:

Bônus

Parabéns, você criou seu primeiro jogo básico com 25 linhas de código! Mas tem algo faltando, não é mesmo? Não seria legal se o jogo registrasse quantas vezes o balão foi tocado? Felizmente é fácil de fazer isso!

Primeiro, vamos criar um objeto para exibir o número de toques no balão. Lembre-se das regras de sobreposição explicadas no início desse post: novos objetos são colocados à frente dos outros que já foram carregados, ou seja, temos de adicionar nosso novo objeto depois do background, caso contrário não iremos vê-lo.

Imediatamente depois das três linhas onde definimos a posição do background, adicione estas duas linhas:

Vamos inspecionar estes comandos em detalhes:

local tapCount = 0 — Similar às anteriores, esta linha cria uma variável Lua local. Neste caso, usaremos ela para armazenas um valor numérico ao invés de uma imagem. Uma vez que o jogador começa o jogo sem nenhuma pontuação, iniciaremos a mesma com valor 0, que será alterado depois.

A segunda linha começa com ‘local tapText’ que você facilmente deve entender que é a declaração de uma variável tapText.

display.newText() é outra API do Corona, mas ao invés de carregar uma imagem como fizemos antes, este comando cria um objeto de texto. Uma vez que estamos associando a variável taptext à ele, estaremos aptos a fazer mudanças no texto durante nosso jogo, como mudar o número impresso para que seja referente ao número de toques no balão.

Dentro dos parênteses estão os parâmetros que passamos ao display.newText(). O primeiro parâmetro é o valor inicial que será exibido no texto, mas note que ao invés de definir um texto como “0”, na verdade definimos uma variável que já tinha sido declarada anteriormente (tapCount). Em Corona, é perfeitamente válido especifica uma variável como um parâmetro de uma API, desde que seja uma variável existente e que seu tipo seja condizente com a API.

Os dois parâmetros seguintes display.contentCenterX e 20, são usados para posicionar este objeto de texto na tela. Você notará que usamos um atalho de display.contentCenterX para posicionar o objeto no centro horizontal da tela, e 20 para dizer que a posição vertical (y) seja próxima do topo.

O quarto parâmetro desta API é a fonte que será usada para renderizar o texto. Corona suporta fontes de todas plataformas, mas para este jogo usaremos a fonte padrão do sistema com native.systemFont.

O parâmetro final é o tamanho do texto renderizado.

sbs-balloon-3

Ação!

Vamos testar o resultado deste novo código. Salve seu arquivo main.lua modificado e execute o Simulator. Se tudo correr bem, o objeto de texto irá ser exibido, posicionado no topo da tela.

Continuando nosso programa: por padrão o texto criado com display.newText() será branco. Felizmente, é muito simples mudar isso. Diretamente abaixo das duas linhas que acabou de adicionar, digite o comando:

De uma maneira simples, o comando setFillColor() modifica a cor do texto do objeto tapText. O comando setFillColor() aceita até quatro valores numéricos que vão de 0 a 1, um para cada canal de cor (vermelho, verde e azul) e um para alfa (transparência). Neste jogo, vamos preencher com cor preta, definindo todos canais como 0.

sbs-balloon-4

Seguindo em frente, o novo objeto de texto parece legal, mas ainda não serve para nada. Para atualizá-lo conforme o jogador toca no balão, modificaremos nossa função pushBalloo. Dentro desta função, logo depois do comando balloon:applyLinearImpulse(), insira duras linhas de código:

Vamos examinar estas linhas individualmente:

O comando ‘tapCount = tapCount + 1’ aumenta a variável tapCount em 1 a cada vez que o balão é tocado.

Nosso segundo comando novo, ‘tapText.text = tapCount’, atualiza o texto do objeto tapText. Isto permite-nos mudar rapidamente o texto sem ter de criar um novo objeto a cada vez.

Observe cuidadosamente – para atualizar o texto na tela, nós atualizamos a propriedade text do objeto, não o objeto em si. Neste caso, nós modificamos a propriedade text de tapText escrevendo tapText.text, seguido por ‘=’, então seu novo valor. Por termos atualizado o valor da variável tapCount na linha anterior, acabaremos atualizando o texto do objeto com o mesmo valor, sendo um o espelho do outro.

É isso! Se você salvar seu arquivo main.lua e re-executar o Simulator, seu jogo estará terminado (de novo).

Este tutorial foi traduzido e adaptado do original presente no site da CoronaLabs, neste link.

* OBS: curtiu o post? Então dá uma olhada no meu livro de Corona SDK clicando no banner abaixo pra aprender a criar outros tantos apps incríveis!

Livro Corona SDK
Livro Corona SDK

Publicado por

Luiz Duarte

Pós-graduado em computação, professor, empreendedor, autor, Agile Coach e programador nas horas vagas.