4 jogos mobile open-source feitos com Corona SDK

Atualizado em 16/04/2017!

O post de hoje é sobre Corona SDK, meu framework para jogos mobile 2D favorito (tanto que traduzi um livro a respeito). Muitos desenvolvedores que eu conheço têm boas ideias para jogos. Boas ideias que nunca são postas em prática. As desculpas variam, desde a clássica falta de tempo, até mais esdrúxulas como “não sei por onde começar”. Se existe uma desculpa mais aceitável é a de que jogos são complexos e muito diferentes dos sistemas tradicionais que estamos acostumados a desenvolver. Jogos são os chamados ‘sistemas de tempo real’. Muitos desenvolvedores não tem a mínima ideia de como o código fonte de um jogo deve se parecer, como ele deve ser organizado, etc. Principalmente em linguagens menos usuais como Lua, por exemplo.

A ideia deste artigo é mostrar o trabalho de Michael Wilson do estúdio de games mobile Ponywolf. Ele criou três incríveis projetos de jogos feitos com Corona SDK, que rodam em diversas plataformas mobile, para que os desenvolvedores possam estudar e até mesmo usar como base para seus próprios jogos. Totalmente free! Ou seja, você pode baixar os fontes dos projetos, mudar as imagens, dar uma mexida aqui e outra ali, e lançar rapidamente a sua versão do game!

Além disso, tem o projeto Corona Cannon, feito pelo pessoal da Corona Labs mesmo, um game no melhor estilo Angry Birds.

Você pode baixar cada um dos projetos no Corona Marketplace. Não esqueça de dar o seu feedback ao Michael nos foruns do Corona!

Match 3 Space RPG

match-3-space-rpg

Este protótipo open-source é um projeto completo que mistura jogos do estilo “match 3” (combina 3, arcade-puzzles tipo Bejeweled) e RPGs old-school com infinitas possibilidades e itens para colecionar. Este template foca em design modular e organização do projeto, assuntos importantíssimos para desenvolvedores iniciantes. Caso seu inglês esteja afiado, dê uma olhada nessa série de vídeos onde Michael Wilson e Charles McKeever (Dev Evangelist do Corona) discutem o projeto e a abordagem de criação do mesmo.

Clique aqui para baixar o Match 3 Space RPG.

Sticker Knight Platformer

sticker-knight-platformer

Este projeto open-source é um jogo de plataforma (tipo Mario) baseado na temática de fantasia medieval. Ele não é um jogo completo, mas um ponto de partida para aprender técnicas modernas de desenvolvimento de jogos usando Corona e Lua. Ele inclui módulos gratuitos que podem ser usados para diversos jogos, como:

  • sistema de jogo baseado em plataformas (Platformer hero)
  • Componentes comuns a jogos desse tipo (Enemies, pickups, spikes, e exits)
  • Importação de mapas do Tiled
  • pontuação (Score counter)
  • pacote de efeitos para jogos (Game FX – ponyfx.lua)

Clique aqui para baixar o Sticker Knight Platformer.

Endless Sk8boarder

endless-sk8boarder

Este é um protótipo incompleto de jogo mobile do gênero endless runner (aqueles em que o personagem principal não pára de correr nunca, tipo Pepsi Man), com a temática de skate. Ele não é um jogo completo, mas um ponto de partida (assim como o anterior) para aprender técnicas ainda mais avançadas (considere os jogos anteriores como básico e intermediário, respectivamente) de programação com Corona e Lua. Esse jogo inclui módulos gratuitos que você pode usar para criar outros jogos, incluindo:

  • física de skateboarding
  • funções para gerar corrimãos, obstáculos, terreno, etc de maneira infinita proceduralmente
  • backgrounds Parallax (que se movem independente do terreno)
  • Importação do Tiled das telas do jogo
  • pontuação (Score counter)
  • pacote de efeitos para jogos (Game FX – ponyfx.lua)

Se seu inglês estiver bom, dê uma olhada nessa série de vídeos onde o projeto e as funcionalidades são explicadas passo-a-passo.

Clique aqui para baixar o Endless Sk8boarder.

Corona Cannon

Este jogo open-source gratuito para Corona SDK é no melhor estilo Angry Birds, onde você aponta um canhão para destruir insetos. É um projeto completo que inclui 10 fases, 2 localizações diferentes, gráficos Retina, música e suporte a controles wireless, mostrando todo o poder da plataforma!

Esse projeto foi feito no final de 2016, com a ideia de revitalizar um game open-source que vinha nas versões iniciais do Corona que era o Ghosts vs Monsters. Ela contempla uma excelente ideia de arquitetura e foi feita propositalmente para expor essas complexidades e diferentes APIs.

Clique aqui para baixar o Corona Cannon.

E aí, o que achou desses protótipos open-source? Tentadores, não?

Livro Corona SDK
Livro Corona SDK

Exemplos de apps feitos com Corona

Tem algum tempo que notei que eu devo ser o maior “advogado” de Corona SDK do país. Conheci o framework por acaso, lendo uma edição da revista Info e fui um dos primeiros a publicar material em Português sobre o assunto, em meados de 2010. Também fui o tradutor do primeiro livro em Português sobre o framework, que já vendeu mais de uma centena de cópias. Por causa disso, acabo recebendo emails de muitos desenvolvedores Brasil afora e uma das dúvidas mais comuns é: qual jogo ou app famoso foi criado com Corona? Este post pretende citar alguns exemplos e ser usado como referência mais tarde, para quem estiver em dúvida se vale ou não a pena aprender Corona, consiga embasar melhor sua decisão.

O que é um app famoso?

O primeiro ponto aqui é sintetizar o que você entende por app famoso. Se pra você “famoso” significa apps que valem bilhões, como Whatsapp, Waze e Instagram, a resposta é não, Corona nunca foi usado para criar esses apps. Na verdade nenhum framework mobile foi usado, eles foram construídos do zero, “à unha”, usando tecnologias nativas de desenvolvimento que proporcionaram terem a escala e desempenho que precisavam. Dificilmente algum framework nativo como Android SDK e iOS SDK serão substituídos por um framework de terceiros quando o assunto é construir apps que valem bilhões.

Vamos reduzir um pouco a escala. Um app baixado milhões de vezes serve pra você como app famoso? Então sim, Corona já foi usado para criar apps famosos, e é de algum deles que vou falar aqui hoje. Se ao invés de apenas downloads você considerar faturamento, e se ganhar dezenas de milhares de dólares com um app feito em Corona é interessante pra você, sim, com Corona você pode ganhar muito dinheiro.

Sem mais delongas, vamos ao que interessa.

Apps famosos feitos com Corona

Entre jogos para iOS e Android (sendo a maioria multiplataforma, principal vantagem do Corona), aqui vai uma lista de 16 apps “milionários”, que tiveram mais de 1 milhão de downloads nas lojas de aplicativos e que você pode usar para se inspirar e ver o quão poderoso é o Corona SDK. Todos os apps já foram exibidos no Showcase do Corona SDK, onde você pode conhecer dezenas de outros.

BubbleBall: o icônico Bubble Ball foi o que me fez conhecer e optar pelo Corona. Um puzzle game criado por um garoto de 14 anos do ensino fundamental que nunca havia programado antes. Robert Nay pegou um livro de programação Lua na biblioteca da escola e nas férias das aulas criou um jogo convidando sua mãe para ajudá-lo nos testes. O jogo foi um fenômeno e desbancou Angry Birds em número de downloads na semana do lançamento, impulsionando a fama da plataforma mundo afora. Ao todo, teve 16 milhões de downloads e foi o app mais baixado da App Store em 63 países na época do seu lançamento.

Se você acha que apenas adolescentes super-dotados tem boas ideias, o Dabble mostra o contrário, pois foi feito por um senhor de 84 anos morador do Brooklyn, figurando no top 10 da categoria Word Games (App Store).

Tower Crush: um jogo que mistura os gêneros “Angry Birds” e “tower defense” e que já fez mais de 1 milhão de downloads só na Google Play. Segundo o site AppPrice, só a versão Android do app deve valer no mínimo uns U$50 mil, o que não é nada mal considerando que deve ter levado algumas semanas de desenvolvimento. Mais detalhes do desenvolvimento deste app pode ser visto neste post da Corona Labs.

Freeze!: esse série de 2 jogos figura no Top 10 de apps pagos em 5 países diferentes. Custando R$6,99 pra Android, só na plataforma do Google ele já vendeu mais de 10.000 unidades, o que nos faz crer que, no pior dos casos, ele faturou algo em torno de R$70 mil apenas na segunda versão!!! A primeira versão teve mais de 11M downloads para Android e iPhone e foi o jogo #1 em 36 países diferentes.

Fun Run: a primeira edição desse jogo teve mais de 45 milhões de jogadores no mundo inteiro, o que segundo estimativas de mercado dá um valuation pra ele de algo em torno de U$2 bilhões!!! Ele também foi #1 mais baixado em 10 países diferentes e sua continuação deve trilhar o mesmo caminho de sucesso.

The Lost City: esse aqui é um jogo do gênero point-and-click de investigação que eu conheço de vista, o tempo todo aparece pra eu baixar na Google Play, sendo que outras 3.5M de pessoas já baixaram, o que o tornou o app pago #1 em 30 países diferentes. Isso me deixa muito curioso de ver como esse game é. Além disso, a Fire Maple Games, produtora do jogo, também é autora do The Secret of Grisly Manor (5M downloads) e Return to Grisly Manor.

Blast Monkeys: um jogo de plataforma viciante onde você tem de ajudar um macaquinho a comer bananas passando por vários obstáculos. Já teve 12M downloads e já foi considerado o jogo #1 na Google Play, embora também esteja disponível para iOS.

StreetFood Tycoon: um joguinho extremamente viciante onde você é o gerente de uma carrocinha de comida de rua que faz jus à série de jogos estilo “tycoon”. Mais de 9M downloads em todas lojas e eleito #1 na Amazon AppStore. Disponível para Android e iOS.

Gravity Maze: é um puzzle baseado em física que já teve mais de 1.5M downlodas, tendo sido eleito como #1 nas categorias Games, Puzzle e Strategy. Disponível para Android e iOS.

Mandora: um jogo de colheita muito bonito e com jogabilidade simples, não chega a ser um Hay Day, mas é tipo o Colheita Feliz do Orkut, lembra? Com 7M+ downloads, disponível para Android e iOS.

The Impossible Test: este não é apenas um app, mas uma série deles, todos com puzzles e quizes de todos os tipos. Juntos já somaram mais de 30M downlodas e figuram entre os top 10 apps gratuitos em 11 países diferentes. Para Android e iOS

Float: um joguinho simples e casual pra jogar com apenas uma mão nos minutos livres da fila do banco, intervalo da faculdade, almoço do serviço, etc. Com 2M de downloads, figura no top 10 nas categorias Games, Arcade e Family do iOS, embora também esteja disponível para Android.

Egg Baby: um joguinho no melhor estilo Tamagotchi (o Pou da minha época). Você choca um ovo e cuida do filhotinho que nasce dele. Mais de 5M de jogadores já chocaram seus ovos em um jogo que segundo as estatísticas do time de desenvolvimento já foi jogado mais de 100M de vezes. Para iOS e Android.

Loops: um app de puzzles no top 10 da sua categoria, com mais de 2M de downloads, disponivel para iOS e Android.

Phrase Friends: Disponível para Android e iOS, esse é um jogo de adivinhar as palavras semelhantes ao “jogo da forca”, mas em Inglês. Com 3M+ downloads, ficou em #3 na categoria Board Games e #7 em Word Games na App Store americana e inclusive apareceu no site da Forbes.com.

Draw Rider: jogo feito com bonecos de palitinho no estilo stuntman, onde você acelera uma moto e tem de chegar ao final do percurso sem bater. Disponível para Android e iOS, com 5M+ downloads e que já chegou a ser o #1 da App Store.

Pop the Pic: jogo onde você tem de adivinhar as palavras letra-por-letra e as figuras peça-por-peça, muito bacana e divertido, teve 2M+ downloads, disponível para Android e iOS.

E aí, convencido de que é uma boa opção para criar apps com grande potencial?

Espero que sim!

Livro Corona SDK
Livro Corona SDK

Introdução à linguagem de programação Lua

lua
Lua é uma linguagem de programação de extensão desenvolvida para suportar programação procedural geral com facilidades de descrição de dados. Ela foi projetada para ser uma linguagem de scripting poderosa e leve para qualquer programador usar. Conheci Lua em 2010, quando comecei a programar para Corona SDK, o meu framework mobile multiplataforma favorito. É uma linguagem incrivelmente simples e poderosa para criar a lógica de jogos, sendo usada não apenas por desenvolvedores independentes como eu, mas por grandes empresas como EA e Blizzard em seus jogos.

Muitos desenvolvedores que compraram o livro que traduzi sobre Corona SDK me pediram um apêndice em Português sobre o básico de Lua, e como não tenho o cadastro de todos para enviar uma versão atualizada do livro, resolvi publicar aqui um post bem extenso que cobre todo o básico dessa linguagem de programação para que usem como referência de consulta. O próprio livro ensina esses conceitos ao longo de suas páginas, mas aqui agrupo todos os ensinamentos em um só lugar e espero que se torne mais fácil de tirar suas dúvidas.

Convenções

Em Lua os nomes (também chamados de identificadores) podem ser qualquer conjunto de letras, números e underscore, desde que não comece com número, coincidindo com a definição do que é um nome em muitas linguagens. Esses nomes e identificadores são usados em variáveis e campos de tables (que veremos mais adiante).

As seguintes palavras-chave são reservadas e não podem ser usadas como nomes:

Os seguintes caracteres denotam tokens, símbolos especiais da linguagem:

Lua é uma linguagem case-sensitive, ou seja, diferencia maiúsculas e minúsculas, ou seja, and e AND são coisas diferentes pra ela, então tome cuidado. Como convenção, nomes começando com um underscore seguido de letras maiúsculas (ex: _VERSION) são reservadas para variáveis globais internas usados pela própria linguagem.

Um comentário começa com dois traços (hífens) antes do texto que desejamos comentar e “comentam” a linha inteira. Você também pode comentar um bloco completo de código cercando-o com –[[ e –]]. Para descomentar o mesmo bloco, simplesmente adicione outro hífem no início do bloco de comentário, como em —[[.

Um valor numérico constante pode ser escrito com uma parte decimal opcional ou mesmo um expoente decimal. Lua também aceita constantes hexadecimais inteiras, prefixando-as com 0x. Exemplos de valores numéricos válidos são:

Tipos de Valores

Lua é uma linguagem de tipagem dinâmica. Isto significa que as variáveis não possuem tipos; somente valores possuem. Não existem definições de tipo nesta linguagem. Todos valores carregam seu próprio tipo.

Todos valores em Lua são valores de primeira classe. Isto significa que todos valores podem ser armazenados em variáveis, passadas como argumentos para outras funções e retornados como resultado.

Os tipos básicos que você deve ter em mente são:

  • nil — o tipo do valor nil, cuja principal diferença é ser diferente de qualquer outro valor; usualmente representa a ausência de um valor útil.
  • boolean — o tipo dos valores false e true. Os valores nil e false em uma condição tornam-a falsa; qualquer outro valor é true.
  • number — representa números reais (com ponto-flutuante de dupla precisão).
  • string — representa arrays de caracteres. Lua trabalha apenas com caracteres de 8-bits.
  • function — veja mais adiante.
  • table — o único mecanismo para estrutura dados em Lua. Veja mais adiante.
    Lua fornece conversão automática entre strings e números em tempo de execução. Qualquer operação aritmética aplicado a uma string tenta converter a string para um número, seguindo as regras normais de conversão. No entanto, toda vez que um número é usado onde uma string deveria ser usada, ele será convertido também. Para um controle maior de como os números se tornam strings, use a função string.format da biblioteca string.

Tables

Tables são a única estrutura de dados em Lua. Elas implementam arrays associativos, significando que os arrays podem ser indexados não somente pelas suas posições (índices), mas por qualquer valor exceto nil. Tables são heterogêneas e podem conter valores de qualquer tipo exceto nil.

Para representar propriedades, Lua usa o nome do campo como um índice. A linguagem suporta esta representação fornecendo a.nome como o “syntax sugar” a[“nome”].

Como índices, o valor de um campo de uma table pode ser de qualquer tipo exceto nil. Devido ao fato de functions serem valores de primeira-classe, você pode guardar functions em tables também, embora tables não possam carregar métodos (ver adiante).

Tables são objetos: variáveis que não verdade não contém seus valores, somente referências para eles. Associação, passagem de parâmetros e retorno de funções sempre manipulam referências como valores; estas operações não implicam em nenhum tipo de cópia.

Para inicializar uma variável como sendo uma table usando chaves: {}.

Acessando registros

No exemplo acima, o registro com o nome “x” foi acessado de duas maneiras: como uma propriedade usando o operador ‘ponto’ t.x e como um índice de array usando t[“x”].

Um erro comum é confundir t.x com t[x]. O primeiro é equivalente ao t[“x”]: uma table indexada pela string “x”. O segundo é uma table indexada pelo valor da variável x.

Importante

Muitas APIs do Corona retornam objetos. Você pode manipular as propriedades documentadas destes objetos assim como faria com qualquer propriedade de table. Você pode até mesmo adicionar suas próprias propriedades desde que não use um underscore no início delas, pois isso é reservado pelo Corona.

Variáveis

Variáveis são locais em memória para adicionar valores. Existem três tipos de variáveis em Lua: global, local e campo de table. Qualquer variável não-inicializada é por padrão nil.

Global
Variáveis globais não precisam de declaração. Você simplesmente associa um valor para criá-la:

Variáveis globais existem enquanto sua aplicação está rodando. Você pode excluir uma variável global atribuindo nil à ela.

Local
Variáveis locais são declaradas usando a palavra local:

Diferente de variáveis globais, variáveis locais são visíveis somente no bloco onde elas estão declaradas. O escopo de uma variável local começo logo após sua declaração e termina no final do bloco.

Campos de Table
Campos de table são somente elementos da tabela em si. Você indexa-os dentro de um array para atribuir valores à um campo.

Expressões

Operações Aritméticas
Lua suporta os operadores de aritmética binária básica:

Se os operandos são números ou strings que podem ser convertidos para números, todas operações fazem exatamente o que você imagina que elas façam.

Operadores Relacionais
Os operadores relacionais de Lua são

Estas operações sempre resultam em true ou false.

Quando temos strings e/ou números como operandos, o operador de igualdade (==) primeiro compara os tipos dos mesmos. Se forem diferentes, o resultado é false. Caso contrário, os valores são então comparados. Já objetos são comparados pela referência, ou seja, apenas resultam em true se ambos forem o mesmo objeto, afinal, cads novo objeto criado é completamente diferente de todos os outros, do ponto de vista de referência.

A regra de conversão automática citada mais cedo neste post não se aplica à comparações de igualdade, ou seja, “0” == 0 retorna false.

Operadores Lógicos
Os operadores lógicos em Lua são and, or, e not. Todos operadores lógicos consideram false e nil como false e qualquer outra coisa como true.

  • and — o operador de conjunção retorna seu primeiro argumento se ele for false ou nil, caso contrário retorna seu segundo argumento.
    or — o operador de disjunção retorna seu primeiro argumento se seu valor for diferente de nil e false; caso contrário retorna seu segundo argumento.
    not — o operador de negação retorna o oposto do valor do argumento.

Tanto and quanto or são curto-circuitados, ou seja, somente analisam o segundo argumento se necessário.

Concatenação
A concatenção de string em Lua é denotada por dois pontos seguidos (..). Se ambos operandos forem strings ou números, eles serão convertidos para strings de acordo com as regras de conversão.

Operador length
O operador length é denotado pelo operador unário #. O length de uma string é seu número de bytes – sendo que cada caracter tem o tamanho de 1 byte.

O length de uma table é definido por qualquer índice n tal que t[n] não seja nil e t[n+1] seja nil; mais do que isso, se t[1] é nil, n pode ser zero. Idealmente um array não deve conter valores nil, caso contrário, o operador length pode se comportar de maneiras inesperadas.

Precedência
A precedência de operadores em Lua segue a seguinte tabela, do menor para o de maior prioridade:

Como usual, você pode usar parênteses para mudar a precedência de uma expressão. Os operadores de concatenação (..) e exponenciação (^) computam primeiro o elemento da direita. Os demais operadores começam pela esquerda.

Funções

Funções simples funcionam exatamente como esperado: você fornece argumentos como entradas (entre parênteses), a função executa algumas tarefas, e os resultados podem ser retornados.

A seguir, maneiras comuns de declarar funções:

Functions podem ser variáveis, logo uma table pode armazená-las como propriedades. Isto permite usos muito flexíveis para tables. Ela pode ser usada pata agrupar logicamente uma família de funções, por exemplo a biblioteca math. Neste caso, para calcular o seno de 100, você pode escrever math.sin(100). Note que math é uma mera table, e a propriedade sin é a função na verdade.

Métodos em Objetos
Objetos em Lua são representados por tables. Objetos de tela (retângulos, imagens, etc) e o objeto global Runtime são todos objetos. Como a biblioteca math, estes objetos armazenam métodos de instância como propriedades. Uma diferença importante é a sintaxe de métodos vs functions: você usa dois pontos entre o objeto e seu método (:) ao invés do ponto tradicional das functions.

Regras de Escopo

Lua é uma linguagem com escopo léxico. O escopo da variáveis começam no primeiro comando depois da sua declaração e terminam no final do bloco mais interno que inclua a declaração da mesma.

Note que, em uma declaração como local x = x, o novo x sendo declarado não está no escopo ainda, e então o segundo x refere-se à variável de fora.

Devido às regras de escopo léxico, variáveis locais podem ser livremente acessada por functions definidas dentro do seu escopo. Uma variável local usada por uma função interna é chamada de upvalue, ou variável local externa, dentro da função interna.

Note que cada execução de um comando local define novas variáveis locais:

O loop cria dez instâncias de closures (funções anônimas). Cada um desses closures usam uma variável y diferente, enquanto todos compartilham o mesmo x.

Alocação de Memória

Dispositivos móveis possuem memória limitada disponível para uso, então tome muito cuidado com o total de memória alocada em sua aplicação.

Lua executa limpeza de memória automática. Isto significa que você não tem de se preocupar sobre alocar memória para novos objetos, nem mesmo precisa liberar objetos da memória manualmente. A própria linguagem executa um coletor de lixo de tempos em tempos e coleta todos objetos mortos (órfãos) e toda memória usada pelo Lua está sujeita ao coletor automático.

No entanto, cabe à você dizer ao Lua o que é lixo. Por exemplo, qualquer coisa armazenada em uma variável global não é considerado lixo, mesmo que sua aplicação não use mais essa variável. Similarmente, qualquer coisa armazenada em uma table jamais será considerada lixo também – independente se foi instanciado localmente ou não. Nestes casos, cabe à você atribuir nil às variáveis que não deseja mais usar.

Objetos de tela em Corona exigem um passo adicional. Você deve primeiro remover o objeto da hierarquia da tela usando object:removeSelf() ou display.remove( object ), e depois defini-lo como nil.

Diferenças de Sintaxe

Algumas diferenças entre a sintaxe de Lua e outras linguagens valem a pena ser citadas pois podem prevenir alguns erros de compilação:

  • ponto e vírgula — são opcionais no final de cada linha de código.
  • chaves — aqui elas são usadas apenas para inicializar tables. O escopo dos blocos de código são delimitados por do e end.
  • if – then – else — se você veio do C, Java, Javascript, eyc., um erro comum que você irá cometer seguidamente é o de esquecer de colocar then ao final da condição do if/elseif. Outro erro comum é o de escrever ‘else if’, quando o correto é elseif.
  • arrays — em Lua eles começam na posição 1, ou seja, a primeira posição de uma table t é t[1], não t[0].
  • múltiplos valores de retorno — um recurso não-convencional mas útil em Lua é a habilidade de uma function retornar mais de um resultado.
  • atribuição múltipla — esse recurso oferece uma maneira conveniente de trocar valores. O comando x,y = y,x irá trocar x por y e vice-versa.
  • operador ternário (? 🙂 — Lua não oferece um equivalente, embora uma expressão ‘(a and b) or c’ ofereça algo semelhante desde que b não seja false.

O conteúdo deste post foi retirado da referência em Português sobre Lua no site oficial, permitido pela própria licença da linguagem: http://www.lua.org/manual/5.1/pt/

Livro Corona SDK
Livro Corona SDK