Anda di halaman 1dari 116

Desenvolvimento de Jogos

Mobile

DESENVOLVIMENTO DE JOGOS MOBILE 1


Desenvolvimento de Jogos Mobile

Introdução aos Jogos Digitais

Um jogo digital refere-se a qualquer jogo eletrônico projetado para ser utilizado em
um computador, console ou dispositivo móvel, entre outras plataformas eletrônicas.

Os jogos digitais fazem parte da cultura de massa desde a popularização dos consoles
de videogames, como o Atari Video Computer Systems (Atari VCS). Lançado em 1977,
o console que seria mais tarde chamado de Atari 2600, chegou a vender 8 milhões de
unidades até 1983.

Um jogo digital é uma atividade lúdica, composta por uma série de ações e decisões,
limitada por regras e pelo universo do jogo, dentro de um ambiente eletrônico próprio,
interativo e de fácil utilização.

A combinação dessas regras com objetivos específicos de cada jogo é o que caracteriza
o desafio, a emoção e a diversão ao jogador em sua jornada pelo jogo.

Os jogos apresentam grande heterogeneidade, e podem ser classificados de diferentes


formas, sendo a própria tipologia alvo de estudos de muitos profissionais da área de
projeto e criação de jogos digitais.

Existem várias tipologias para proceder à classificação de jogos digitais, como:

BECTA (2003), que delineou uma classificação que tenta englobar os vários gêneros
de jogos digitais existentes, de acordo com os estilos, narrativas, temáticas e
atividades.

GRAELLS (2000), que estabelece uma tipologia para jogos digitais levando em conta
a estrutura dos jogos e as principais competências mobilizadas pelo jogador no
DESENVOLVIMENTO DE JOGOS MOBILE 2
desenrolar do jogo, nomeadamente a psicomotricidade, o raciocínio, a lógica, a
estratégia e a memória.

Projeto e Criação de Jogos Digitais


O planejamento de um jogo começa com pequenos conceitos que são expandidos a
partir de brainstorm. Nenhuma ideia é descartada até que todos os elementos se
consolidem na espinha dorsal do jogo.

Ao esboçar ideias, é interessante a construção de mapas mentais (Mind Map), um


diagrama ou gráfico usado para gestão de informações, conhecimentos e para a
compreensão e solução de problemas.

A narrativa é um elemento essencial para um jogo digital, podendo ser apresentada


em primeira ou terceira pessoa. Ela é composta por cinco partes: Enredo, Personagens,
Espaço, Tempo e Clímax.

Quando narrado em primeira pessoa, percebe-se que o narrador é um dos


personagens e descreve sua versão da história, enquanto na terceira pessoa o
narrador coloca-se ao lado do jogador.

Para muitos autores, o personagem é o fundamento essencial de um roteiro. É o


coração, alma e sistema nervoso de uma história. Antes de colocar uma palavra no
papel, tem que se conhecer o personagem.

Após formatar a ideia central de um jogo digital, o passo seguinte é a formatação de


um roteiro preliminar (Story Line). É claro que surge a necessidade de entender
quem são os personagens integrantes do roteiro, qual a participação de cada um na
story line, bem como as relações entre diferentes personagens.

Com as ideias já formuladas sobre gênero, narrativa, personagens e outros itens


esboçados em mãos, o próximo passo é a criação do GDD.

DESENVOLVIMENTO DE JOGOS MOBILE 3


Documento de Game Design (Game Design Document) trata do agrupamento dos
diversos elementos acerca do jogo em um único documento, o qual funcionará como
a espinha dorsal desse e de qualquer outro projeto envolvendo jogos digitais.

Esse documento define todos os pontos de um jogo digital e guia todas as equipes
envolvidas no processo de produção, e o profissional responsável pelo GDD e por todo
o projeto de um jogo é chamado de Game Designer.

Apesar de ter uma grande liberdade com relação ao formato, os elementos


componentes de um GDD normalmente incluem:

CONCEITO - nome do jogo, apresentação resumida, público alvo, estilo de jogo,


história e principais regras.

ESPECIFICAÇÕES TÉCNICAS - sistema operacional, hardware mínimo, requisitos


de software, bem como recursos gráficos.

ESPECIFICAÇÕES DO JOGO - fases, níveis de dificuldade, modo de jogo, pontuação


e ranking, número de jogadores, save games, câmera, personagens, itens de jogo e
cenário, evolução e mensagens.

DISPOSITIVOS DE ENTRADA - suporte a mouse, uso de teclado e joystick, toque


de tela, controle de menu, teclas e botões utilizados.

DESIGN GRÁFICO E ARTE - abertura, layout de menus e telas, definição de fases e


layout do jogo em cada fase.

SONORIZAÇÃO - músicas nos menus e em cada fase, bem como efeitos sonoros em
geral.

DESENVOLVIMENTO DE JOGOS MOBILE 4


DESENVOLVIMENTO – planejamento envolvendo as tarefas em termos de tempo,
recursos e metas.

DESIGN PARA O TIPO DE JOGO - caracterização do tipo de jogo, bem como a


definição da ação em terceira ou primeira pessoa.

ENREDO E ROTEIRO - jogos com características de RPG possuem enredos que se


desenvolvem durante o jogo, e acontecimentos relevantes devem ser registrados.

CARACTERÍSTICAS GRÁFICAS - informações acerca de cenários e modo de


renderização, como tipo de iluminação, uso de estilo cartoon etc.

CONCEITO GRÁFICO - arte conceitual do projeto e dos mais diversos elementos,


como personagens, itens e cenários.

INFORMAÇÕES PARA PROGRAMAÇÃO - capacidade mínima de processamento,


incluindo quantidade de memória, tipo processador e modelo de placa de vídeo.

TIPOS DE MAPA - pode ser um mapa simples, visão isométrica, ou outro,


dependendo do tipo de jogo.

PROPRIEDADES DAS ENTIDADES –propriedades obrigatórias de cada entidade do


jogo.

Após o nascimento da ideia por trás de um jogo digital, e todos os processos


envolvendo elementos conceituais e diretrizes artísticas até a concepção de um GDD,
inicia-se o processo de desenvolvimento do jogo em si.

Uma ferramenta muito facilitadora nessa fase inicial é o Storyboard, no qual os


artistas irão demonstrar os textos do roteiro mediante imagens, simulando a ação
dentro do jogo.

DESENVOLVIMENTO DE JOGOS MOBILE 5


Tendo o StoryBoard como um guia para a produção, ocorre agora a preocupação com
a área gráfica (GFX) e com o som do jogo (SFX). Considerando-se o GFX, este deve
levar em consideração o tipo de ambiente a ser utilizado, podendo ser 2D ou 3D.
Quanto ao SFX, todos os sons devem ser contemplados, desde um simples tiro, passos,
música e até voz sintetizada, podendo ser um som plano ou em ambiente 3D.

Tendo os componentes visuais e sonoros necessários em mãos, estes devem ser


combinados segundo a lógica do jogo, aparecendo nesse ponto necessidades comuns
à grande maioria dos jogos digitais, como a detecção de colisão, por exemplo.

Há algum tempo os jogos eram criados totalmente a partir de uma linguagem de


programação, como Assembly ou C++, mas atualmente as Game Engines fazem boa
parte do trabalho, e a programação se concentra apenas nas características específicas
do novo jogo.

Gráficos e Sons nos Jogos


A representação gráfica dos personagens, cenários e demais elementos é crucial para
o desenvolvimento de um jogo. Esses elementos podem ser definidos em duas ou três
dimensões, e, para cada caso, existe uma grande diversidade de ferramentas que
podem ser utilizadas.

Alguns jogos são criados utilizando apenas elementos 2D, mesmo que com efeitos de
sombra, simulando efeitos 3D, o que tem sido muito comum nos jogos de plataforma.

Um formato muito utilizado para as imagens 2D da atualidade é o PNG, pois apresenta


características de transparência, facilitando a sobreposição de camadas.

Um componente comum no ambiente de gráficos 2D é o Sprite, o qual define uma


animação quadro-a-quadro obtida a partir de imagens renderizadas previamente.

DESENVOLVIMENTO DE JOGOS MOBILE 6


Os elementos 3D apresentam uma complexidade maior, pois trabalham com efeitos
de iluminação e texturização em tempo real, diferentemente de um vídeo, onde a
renderização ocorre toda antes da exposição da animação.

A modelagem dos elementos 3D pode ser feita com ferramentas diversas, a exemplo
do Blender, 3DS Max, Maya, entre várias outras, e o processo inicia-se com a
construção de uma malha, sobre a qual serão dispostos materiais e texturas,
utilizando-se ao final elementos de iluminação sobre o conjunto.

É comum a utilização de Model Sheet, tratando de um conjunto de visões (superior,


frontal, lateral) de um personagem, concebido de forma artística, para viabilizar a
modelagem computacional.

O maior custo computacional em termos de 3D é com relação à qualidade da imagem


final. O termo shading, ou sombreamento, se refere ao nível de detalhamento e da
percepção de profundidade em ilustrações e modelagens 3D.

DESENVOLVIMENTO DE JOGOS MOBILE 7


Os sons mais diversos são de grande importância para um jogo pois, assim como na
vida real, a audição é um de nossos sentidos mais importantes.

Qualquer som dentro de um jogo deve transmitir informação, emoção ou localização,


e hoje em dia as tecnologias de som 3D são amplamente exploradas por jogos como
God of War, e diversos simuladores realísticos, voltados para treinamento profissional,
particularmente militar.

Game Engine
Motor de jogo, também conhecido pelo termo em inglês Game Engine, é um
programa de computador utilizado para simplificar e abstrair o desenvolvimento de
jogos eletrônicos ou outras aplicações com gráficos em tempo real.

A funcionalidade tipicamente fornecida por um motor de jogo inclui: um motor gráfico


para renderizar gráficos 2D e 3D, um motor de física para simular a física em si ou
simplesmente para fazer detecção de colisão, suporte a animação, sons, inteligência
artificial, redes, gerência de memória, gerência de arquivos, gerência de linha
de execução, além de controles em geral para cenas e entidades.

É comum o uso de uma ou mais linguagens de programação, o que viabiliza a sua


personalização para a funcionalidade requisitada por um jogo específico.

DESENVOLVIMENTO DE JOGOS MOBILE 8


Existem diversos fornecedores no mercado, sendo algumas das Game Engines mais
relevantes: UDK, Unreal Engine, Unity 3D, Cry Engine, Java Monkey, Blender Game
Engine, entre diversas outras.

Uma grande vantagem da Unity 3D, em particular, é a facilidade na criação de jogos


em 2D e 3D para as mais diversas plataformas, como o Android, por exemplo. Embora
aceite outras linguagens, há uma preferência natural pela programação em linguagem
C# para essa Game Engine.

A unidade básica de trabalho na Unity 3D são os Assets, e pode-se obter muitos deles,
inclusive podendo ser gratuitos, a partir da Game Engine, pelo Asset Store.

Essa engine traz de um ambiente completo e bastante intuitivo para a criação de jogos,
aceitando também diversos formatos para importação de outras ferramentas, como o
3DS Max e o Blender, além de apresentar muitos tutoriais no site do fornecedor
(https://unity3d.com/pt).

Ela pode ser baixada e utilizada livremente, porém ressarcindo ao seu fabricante sob
a forma de royalties a partir de determinada quantidade de cópias do jogo
comercializadas.

Na criação de um projeto Unity deve ser escolhido entre os modelos de criação 2D ou


3D. Também podem ser selecionados os Assets (recursos) que serão utilizados no
novo projeto.

DESENVOLVIMENTO DE JOGOS MOBILE 9


Tendo sido criado o projeto, o ambiente será iniciado, exibindo as diversas ferramentas
disponíveis na plataforma. Na visualização padrão inicial serão observados: Toolbar,
Hierarchy Window, Scene View, Inspector Window e Project Window.

Todo elemento manipulável visualmente no Unity é um Game Object, incluindo as


primitivas 3D disponibilizadas pela Engine. Por exemplo, o menu Game Object >>
3D Object >> Cube é utilizado para a criação de um cubo, o qual poderá ser
visualizado e manipulado na Scene View ou pelo Inspector.

DESENVOLVIMENTO DE JOGOS MOBILE 10


Além do acesso pela Toolbar, as operações básicas oferecem alguns atalhos úteis via
teclado:
Q move a cena como um todo, facilitando a visualização.
W translada o objeto selecionado.
E rotaciona o objeto selecionado.
R altera a escala do objeto selecionado.

O botão direito do mouse, em conjunto com as teclas W, S, A e D permitem controlar


a visualização da câmera na Scene View.

Para as operações de translação, rotação e escala são disponibilizados Gizmos, ou


como poderiam ser descritos, eixos de transformação 3D.

A divisão Hierarchy mostra os objetos da cena e seus relacionamentos, Inspector


mostra todas as propriedades do objeto selecionado, permitindo manipulá-las. Com a
opção Add Component é possível definir comportamentos específicos, como na
utilização de física.

Terrenos são elementos de grande importância para a construção de cenários 3D, e


opção Game Object >> 3D Object >> Terrain oferece um ferramental muito
completo para a sua criação.

Com o uso das ferramentas de terreno, acessíveis a partir do Inspector, é possível


aumentar, diminuir ou suavizar elevações, e com as elevações definidas, texturas
podem ser aplicadas ao relevo com a opção de pintura (pincel). Também é possível

DESENVOLVIMENTO DE JOGOS MOBILE 11


adicionar vegetação e detalhes ao terreno, viabilizando a criação de ambientes muito
realísticos para os jogos 3D.

O fornecedor da Unity 3D mantém um sistema para obtenção de Assets denominado


Asset Store, o qual pode ser acessado pelo navegador pelo site da Unity, ou a partir
da própria engine por Window >> Asset Store, ou CTRL + 9. Muitos componentes
são gratuitos, mas também existem Assets pagos, constituindo inclusive um mercado
muito interessante para desenvolvedores de jogos.

Em termos de jogos 3D, as representações mais comuns para o jogador são a primeira
e a terceira pessoa, e a Unity 3D fornece Assets prontos para os dois modos, devendo
apenas ser acrescentado o pacote correto ao projeto e utilizado o controlador
adequado.

Para a utilização da representação em primeira pessoa no Unity, o caminho mais


simples é a utilização de PFPSController, um elemento pré-fabricado (Prefab)
presente no pacote Characters. Todo pacote, ou Asset Package, pode ser
selecionado na criação do projeto ou adicionado por Assets >> Import Package
>> [Pacote].
DESENVOLVIMENTO DE JOGOS MOBILE 12
Com FPSController disponível na área de Assets do Projeto, basta arrastá-lo para a
Scene View e ativar a visão de Game Play para experimentar os típicos movimentos
dos jogos de tiro no ambiente 3D.

Oura característica interessante da Unity 3D é o Sistema de Partículas, utilizado na


construção dos mais diversos efeitos, como fumaça, fogo, neve, elementos líquidos, e
muitos outros.

Com a utilização da Unity é bastante simples criar e configurar um sistema de


partículas a partir do início, no entanto, existem vários efeitos já configurados, no
formato de PreFab, disponíveis para utilização por Assets >> Import Package >>
ParticleSystems.

Tão simples quanto trabalhar com a primeira pessoa é trabalhar na terceira pessoa.
Certamente a definição de um personagem em terceira pessoa exigirá alguma
modelagem 3D, mas ThirdPersonController já está disponível no pacote

DESENVOLVIMENTO DE JOGOS MOBILE 13


Characters e precisa apenas ser arrastado para a cena, assumindo a malha padrão
para testes.

A câmera deve ser posicionada corretamente para visualizar o personagem, e as


dimensões corrigidas para a cena, e ao acionar Game Play, podem ser utilizados os
comandos de controle comuns de jogos 3D.

Unity traz boas ferramentas para a criação da interface de usuário, aqui se tratando
de menus e avisos, entre outros elementos de interação e HUD. Os componentes para
construção de GUI incluem: Painéis, Botões, Textos e Imagens, Campos de Entrada
e Sistema de Eventos.

Outra ferramenta muito interessante do Unity é o modelador de árvores, o qual


permite criar os mais diversos tipos de árvores e arbustos com grande facilidade. Uma
árvore configurada pode ser reutilizada em toda a cena, e pode conter aspectos
aleatórios que irão denotar uma individualização de cada instância utilizada.

DESENVOLVIMENTO DE JOGOS MOBILE 14


O uso da linguagem C# permite a criação de novos Assets e a modificação dos
comportamentos da Engine, visando a especificidade para cada jogo.

A classe básica de comunicação entre Unity e C# é a MonoBehaviour, e devemos


estendê-la para adaptar a engine às necessidades de um novo jogo. Embora possa ser
utilizada também a linguagem Java Script, a linguagem C# tem obtido a preferência
dos desenvolvedores que utilizam a Engine.

Linguagem C#

A linguagem de programação C# é multiparadigma, fortemente tipada, e inclui


paradigmas de programação imperativa, funcional, declarativa, orientada a objetos e
genérica.

Foi desenvolvida pela Microsoft como parte da plataforma dotNET, e como nas demais
linguagens dessa plataforma, o código fonte é compilado para Common Intermediate
Language (CIL) que é interpretado pela máquina virtual do dotNET, a Common
Language Runtime (CLR).

DESENVOLVIMENTO DE JOGOS MOBILE 15


A linguagem C# é orientada a objetos, o que faz com que tenha uma pequena
quantidade de tipos nativos, como ocorre no Java, por exemplo. Para cada tipo nativo
do C# existe uma classe Wrapper dotNet capaz de registrar os mesmos tipos de
valores do nativo relacionado.

Tipo Nativo Classe Limites e Observações

byte Byte 0 a 255

sbyte Sbyte -128 a 127

int Int32 -2.147.483.648 a 2.147.483.647

uint UInt32 0 a 4.294.967.295

short Int16 -32.768 a 32.767

ushort UInt16 0 a 65.535

long Int64 -9.223.372.036.854.775.808 a


9.223.372.036.854.775.807

ulong UInt64 0 a 18.446.744.073.709.551.615

float Single -3,402E38 a 3,402E38

double Double -1,797E308 a 1,797E308

Char Char Símbolos Unicode de texto.

Bool Boolean True ou False

Object Object Base para os demais tipos.

String String Cadeia de caracteres.

Decimal Decimal Números precisos, permitindo até 29


dígitos significativos.

Além dos operadores matemáticos (multiplicação, divisão, resto, soma e subtração),


comuns a praticamente todas as linguagens, o C# apresenta operadores binários e
DESENVOLVIMENTO DE JOGOS MOBILE 16
condicionais próximos aos da linguagem C, assim como operadores próprios, bem mais
específicos.

Para a comparação estão disponíveis os operadores:


> Maior que
< Menor que
>= Maior ou Igual
<= Menor ou Igual
== Igualdade
!= Diferença

Os operadores lógicos e binários são utilizados nas operações mais básicas da


programação, como na combinação de condições para execução de algum processo,
por exemplo.

C1 C2 C1 && C2 C1 || C2

false false false false

false true false true

true false false true

true true true true

b1 b2 b1 & b2 b1 | b2 b1 ^b2

0 0 0 0 0

0 1 0 1 1

1 0 0 1 1

1 1 1 1 0

DESENVOLVIMENTO DE JOGOS MOBILE 17


Para compreender a sintaxe C# é necessário conhecer as diversas estruturas de
controle de fluxo existentes em qualquer linguagem, de forma a efetuar tomada de
decisões e controle de repetições.

A estrutura condicional de maior relevância para as mais diversas linguagens é


SE..ENTÃO..SENÃO. Na linguagem C# não existe a palavra SENÃO (then), o que obriga
a utilização de parênteses.

int a, b, c;
// Operações diversas sobre as variáveis...
if ( ( a > b ) && ( a > c ) )
Console.WriteLine ("A tem o maior valor");
else
if ( b > c )
Console.WriteLine("B tem o maior valor");
else
Console.WriteLine("C tem o maior valor");

O uso de operador de decisão pode ser uma grande alternativa ao


SE..ENTÃO..SENÃO em determinada condição de uso, a qual pode ser definida como:
uma variável recebe dois valores distintos a partir do resultado de um condicional.

if ( a > b )
c = 2;
else c = ( a > b ) ? 2 : 5;
c = 5;

Quanto ao controle de iterações, a estrutura de repetição mais simples seria


ENQUANTO..FAÇA.

int a = 1;

DESENVOLVIMENTO DE JOGOS MOBILE 18


while ( a <= 256 ) {
Console.WriteLine( a );
a = a * 2;
}
Uma estrutura similar ao ENQUANTO..FAÇA, com a diferença funcional de sempre
executar ao menos uma vez seria a estrutura FAÇA..ENQUANTO.

int a = 1;
do {
Console.WriteLine( a );
a = a * 2;
} while ( a <= 256 );

A estrutura mais complexa seria a PARA..FAÇA. Nas linguagens derivadas do C, como


o C#, essa instrução apresenta muito mais opções que em linguagens mais próximas
do algoritmo, como Pascal e Fortran. A forma geral seria for (<inicialização> ; <teste>
; <incremento>), sendo as seções de inicialização e incremento aceitam mais de uma
instrução, e qualquer seção pode ser omitida.

for ( int i = 1 ; i <= 10 ; i++ )


Console.WriteLine( i );

A conversão de tipo, ou type cast, faz com que o C# reinterprete um determinado tipo
em situações específicas. Essa é uma técnica muito utilizada na orientação a objetos
quando precisamos acessar um atributo específico de um descendente utilizado no
lugar da classe inicial.

float f;
int a = 5, b = 2;
f = a / b; // f recebe 2.0
f = a / (float) b; // f recebe 2.5

DESENVOLVIMENTO DE JOGOS MOBILE 19


f = ((float) a) / b; // f recebe 2.5

Na sintaxe C#, uma classe é definida pela palavra class, devendo ser observado o
namespace utilizado. Para a definição de seus atributos e métodos, os níveis de
acesso disponíveis são: public, private e protected.

O método construtor deve ter o mesmo nome da classe, enquanto destrutores


assumem um símbolo ~ antes do nome.

// Classe com dois construtores sobrecarregados


public class Pessoa
{
public string nome;
public Pessoa() {
nome = "desconhecido";
}
public Pessoa(string nm) {
nome = nm;
}
}

Uma propriedade define um atributo com acesso controlado, e utiliza escritores e


leitores pelas palavras set e get.

public class Livro


{
private Pessoa pAutor = null;
public Pessoa Autor
{
get { return pAutor; }
set { pAutor = value; }

DESENVOLVIMENTO DE JOGOS MOBILE 20


}
}
Os métodos da linguagem permitem a definição de argumentos opcionais e chamadas
com argumentos nomeados. Argumentos opcionais são aqueles que apresentam um
valor inicial default, podendo ser omitidos na chamada do método, e o uso de
chamadas com argumentos nomeados permite que não haja preocupação com a
ordem dos parâmetros nessas chamadas específicas.

public void Exemplo(int id, string nome = "desconhecido",


int idade = 18) {
// Método com parâmetros opcionais
}

Exemplo( 123 );
Exemplo( nome: "Ana", id: 352);
Exemplo( 478, "Carlos" );

Para a implementação de herança deve ocorrer uma referência ao ascendente por


:Ascendente. Os construtores herdados, e demais elementos da superclasse, são
referenciados pela palavra base, enquanto a palavra this resolve o conflito de nomes
na própria classe.

// Herança com chamada ao construtor da superclasse


public class Profissional: Pessoa
{
public string profissao;
public Profissional(string nome, string profissao) : base(nome)
{
this.profissao = profissao;
}
}

DESENVOLVIMENTO DE JOGOS MOBILE 21


Para implementar polimorfismo em classes concretas é necessário utilizar virtual e
override.

public class Pessoa {


public string nome;
public virtual void Exibir( ) {
Console.WriteLine("Nome: {0}", nome);
}
}

public class Profissional: Pessoa


{
public string profissao;
public override void Exibir( ) {
base.Exibir( );
Console.WriteLine("Profissao: {0}", profissao);
}
}

Na programação moderna não basta definir classes, mas também é necessário


modelar comportamentos. A modelagem comportamental traz grande sustentação às
diversas estruturas de dados e vários padrões de desenvolvimento, e uma das formas
de modelar um comportamento é mediante o uso de classes genéricas.

Na programação estruturada os arrays são a maneira mais comum para utilização de


dados contíguos na memória, porém apresentam dimensão fixada na criação, o que
se torna um grande limitador. Em termos de orientação a objetos, as coleções são
mais interessantes, pois trabalham como listas encadeadas, permitindo a variação de
tamanho após a criação. Essas coleções trabalham com classes genéricas e
permitem a utilização de comandos específicos, como o foreach.

DESENVOLVIMENTO DE JOGOS MOBILE 22


// Exemplo de uso de coleção do tipo List<int>
List<int> lista = new List<int>( );
lista.Add(1);
lista.Add(4);
foreach( int numero in lista )
Console.WriteLine("Numero: {0}", numero);

// No caso do ArrayList, ele trabalha com Object


ArrayList colecao = new ArrayList( );
colecao.Add(2);
colecao.Add(4);
int[ ] valores = ( int[ ] ) colecao. ToArray( typeof( string ) );

Outra forma de implementar comportamentos é por anotações, as quais são


metadados anexados ao código, e que podem mudar por completo o comportamento
original da classe, ou outra estrutura anotada, a partir de ferramentas externas.

Um ótimo exemplo de uso de anotações em C# é na criação de Web Services,


ferramental de grande utilidade para a criação de serviços interoperáveis na Web.

[WebService(Namespace= "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public Service () { }
[WebMethod]
public string HelloWorld() {
return "Hello World";
}
}

DESENVOLVIMENTO DE JOGOS MOBILE 23


Programar em C# para Unity 3D sempre envolve a criação de um descendente de
MonoBehaviour. Os diversos eventos são os pontos de interferência nos
comportamentos da Unity, implementados por métodos polimórficos da classe criada.

Um jogo é como uma animação, mas onde os quadros de animação são gerados a
cada instante, e uma técnica fundamental na sua programação é efetuar mudanças
para a posição, comportamento e estado de objetos antes do processamento de cada
quadro.

O método Update é o lugar correto para esse tipo de código na Unity, pois é chamado
antes do processamento da imagem e antes que as animações sejam calculadas.

Para adicionar um Script, basta ir no Inspector, com o objeto alvo selecionado, e


clicar em Add Component, selecionando New Script, e dando um nome ao script
para, em seguida, editá-lo. Uma forma simples de editar o script criado seria a
utilização da opção "Sync Mono Develop", clicando com o botão direito sobre o script
no painel de Assets.

DESENVOLVIMENTO DE JOGOS MOBILE 24


Matemática para Jogos
O uso de matemática é inerente ao próprio processo de programação, podendo ser
encontrada em diferentes formas para diferentes áreas do desenvolvimento.

Inicialmente, a lógica booleana define a base do processo de construção de


algoritmos e programação em si, enquanto álgebra relacional e cálculo relacional
justificam toda a funcionalidade dos bancos de dados relacionais da atualidade.

As atuais tecnologias de Big Data trabalham com processos denominados Map


Reduce, baseados em procedimentos estatísticos extremamente formais, e vários
sistemas de otimização, para áreas como logística, envolvem programação linear.

Enfim, a matemática está em todo lugar, nas mais diversas áreas de programação,
mas nos jogos ela se tornará ainda mais relevante. Como a maior parte dos jogos
envolve elementos gráficos, o uso de geometria descritiva e álgebra linear
tornam-se evidentes na construção dos jogos.

Criado por René Descartes no intuito de localizar pontos em um determinado espaço,


o plano cartesiano consiste de dois eixos perpendiculares, sendo o horizontal chamado
de eixo das abscissas e o vertical de eixo das ordenadas.

Todo ponto é representado em termos de coordenadas (x,y), as quais não coincidem


com o sistema de coordenadas para a definição dos pixels na tela de um computador.
No computador a origem fica no canto superior esquerdo, e o eixo y aumenta de valor
no sentido Sul, o que exige pequenas transformações para a correta exibição das mais
diversas funções matemáticas.

DESENVOLVIMENTO DE JOGOS MOBILE 25


Vetores podem ser considerados como uma lista de números, a qual permite ser
expressa de forma horizontal ou vertical. Em termos de sistemas de coordenadas, um
ponto 2D pode ser representado por um vetor colunar de duas linhas, assim como um
ponto 3D pode ser expresso por três linhas.

Um vetor pode ser interpretado geometricamente como um segmento de reta


orientado, contendo uma magnitude e uma direção, e a sua dimensão determina
quantos números são expressos por esse vetor.

Por exemplo, um vetor 2D definido pelo ponto (x,y) = (3,4), em relação à origem,
apresenta magnitude 5 e direção de 53°. Para o cálculo da magnitude, basta utilizar
o Teorema de Pitágoras, e para a direção pode ser utilizado o arco-tangente, arco-
seno ou arco-cosseno, considerando o eixo x como a linha do cosseno e o eixo y como
a linha do seno.

arctan( 4 / 3 ) = 53,13°

Unity permite representar vetores 2D, 3D e 4D com grande facilidade, e as classes que
representam os vetores ainda trazem métodos específicos para normalização,
magnitude etc.

As classes em questão são: Vector2, Vector3 e Vector4.

DESENVOLVIMENTO DE JOGOS MOBILE 26


float f;
f = Vector2.Distance(new Vector2(1,3), new Vector2(0,1));
Vector3 v3 = new Vector3(4,5,0);
float a = v3.x;

Várias operações podem ser efetuadas sobre os vetores, destacando-se algumas


operações de interesse direto para a área de jogos, como rotação, translação e escala,
aplicáveis diretamente aos ambientes 2D e 3D.

Multiplicação por escalar terá relação com as operações de mudança de escala


para os vetores.

[ ax , ay ] k = k [ ax, ay ] = [ k * ax , k * ay ]

A Soma Vetorial é uma operação que pode representar um movimento de


translação.

[ ax , ay ] + [ bx , by ] = [ ax + bx , ay + by ]

DESENVOLVIMENTO DE JOGOS MOBILE 27


As operações de Produto Escalar e Produto Vetorial permitem o reconhecimento
do ângulo formado entre dois vetores.

No Produto Escalar, o resultado da multiplicação é um escalar.

[ ax , ay ] . [ bx , by ] = axbx + ayby = ||a|| ||b|| cos ( ângulo )


|| w || = magnitude do vetor w

No Produto Vetorial, o resultado será outro vetor.

[ ax,ay,az ] x [ bx,by,bz ] = [ aybz - azby , azbx - axbz , axby – aybx ]


|| a x b || = ||a|| ||b|| sen (ângulo)

Matrizes também são de grande interesse para a área de jogos e computação gráfica
em geral, tratando de tabelas com linhas e colunas de dados.

Uma matriz quadrada é aquela que tem a mesma dimensão para linhas e colunas,
e os elementos diagonais são aqueles com mesmo índice de linha e coluna. Em geral,
uma matriz de transformação M quadrada pode descrever qualquer transformação
linear.

DESENVOLVIMENTO DE JOGOS MOBILE 28


Multiplicar um vetor de posição por uma matriz M, preenchida de forma adequada, é
a forma mais efetivar de executar transformações como a escala, a rotação e a
translação.

Algumas matrizes derivadas da matriz M de transformação podem expressar a rotação.


Normalmente essas matrizes são denominadas matrizes R.

Para o caso de duas dimensões é bastante simples, pois a rotação ocorre apenas em
torno da origem, mas, ao trabalhar com 3D, será necessário considerar três matrizes
de transformação, Rx, Ry e Rz, representando rotações em torno dos eixos x, y e z,
respectivamente.

A matriz de escalonamento S apresenta os fatores de escala de cada eixo, como kx e


ky para o caso 2D, na diagonal, e no caso 3D bastaria acrescentar o fator kz.
Provavelmente a escala é uma das operações mais simples entre as diversas
transformações lineares.

DESENVOLVIMENTO DE JOGOS MOBILE 29


Para efetuar a translação é mais fácil utilizar uma dimensão a mais, ou seja, para a
translação 3D seria utilizada uma matriz M de 4x4. Para sua utilização será necessário
também a transformação do vetor 3D em vetor 4D pelo acréscimo de um elemento
unitário.

A escala pode ser feita na mesma operação, bastando preencher os elementos da


diagonal com os fatores de escala desejados (kx, ky e kz).

As transformações de Euler representam as rotações em termos de 3 rotações


simultâneas perpendiculares aos eixos (x, y e z), enquanto os Quaternions são outra
forma de representar essas rotações.

O nome quaternion é muito citado na literatura de jogos, e trata de uma forma de


representar uma orientação com o uso de quatro números. Uma forte razão para o

DESENVOLVIMENTO DE JOGOS MOBILE 30


uso de quaternions na área de animação e jogos é a possibilidade de utilizar uma
operação denominada slerp (Spherical Linear Interpolation), que permite
interpolações mais suaves que os ângulos de Euler.

As vantagens de utilizar quaternions para posicionamento angular incluem a


interpolação suave, bem como a rápida concatenação e inversão de posicionamentos.

O uso de quaternions também traz algumas desvantagens, como a representação


levemente maior que a de Euler, possibilidade de se tornarem inválidos devido aos
dados de entrada, e o fato de serem um pouco mais complexos em termos
matemáticos.

As classes de vetores da Unity 3D já apresentam operações como soma, produto


vetorial e escalar, entre vários outros, e as classes Transform e Matrix4x4 permitem
a realização das diversas operações de escala, rotação e translação.

Vector3[ ] origVerts, newVerts;


void Update() {
Quaternion rotation = Quaternion.Euler(
eulerAngles.x, eulerAngles.y, eulerAngles.z);

DESENVOLVIMENTO DE JOGOS MOBILE 31


Matrix4x4 m = Matrix4x4.identity;
m.SetTRS(translation, rotation, scale);
int i = 0;
while (i < origVerts.Length) {
newVerts[i] = m.MultiplyPoint3x4(origVerts[i]);
i++;
}
mf.mesh.vertices = newVerts;
}

A maior parte dos jogos explora de uma forma mais intensa a álgebra linear, devido à
parte gráfica envolvida, o que não significa que outras áreas da matemática se tornem
desnecessárias, como no caso do uso de probabilidade e estatística em "jogos de azar".

Física para Jogos


Os cálculos da física também são de grande relevância para a criação de jogos. Efeitos
como gravidade, vento, atrito, entre vários outros, irão mudar o comportamento de
diversos elementos presentes nos jogos 2D e 3D.

Inicialmente, para entender as relações de ordem física entre os elementos de jogo,


devemos entender o conceito e utilização da colisão. Tanto em jogos 2D quanto em
jogos 3D, a colisão é quase sempre o principal elemento funcional, pois:

Como saber que um tiro atingiu uma nave?


Como impedir que uma parede seja atravessada?
Como evitar que os objetos caiam indefinidamente?

Esses são apenas alguns exemplos, mas ilustram um pouco a importância de definir
técnicas para identificar o momento e o espaço onde ocorre o contato (colisão) entre
dois ou mais elementos do jogo.

DESENVOLVIMENTO DE JOGOS MOBILE 32


As técnicas para detecção de colisão surgiram ainda nos jogos 2D mais antigos, sendo
algumas delas utilizadas até hoje, a exemplo da Bounding-Box. O princípio dessa
técnica é a determinação de uma área retangular invisível que envolva cada Sprite,
reduzindo o problema ao simples teste da superposição dessas áreas.

Essa técnica apresenta uma performance muito boa devido ao baixo números de
contas e de verificações, mas, como ela testa colisões entre retângulos, em figuras
muito curvas e disformes pode não apresentar um resultado satisfatório.

Além da colisão, o principal elemento representativo da física nos jogos é a força. A


gravidade, por exemplo, funcionará aplicando uma aceleração negativa de valor
constante aos objetos no eixo y.

No entanto, as forças não atuam sobre todos os elementos da cena, sendo


normalmente aplicadas apenas aos corpos rígidos relacionados com elas de acordo
com os parâmetros adotados pelo jogo.

DESENVOLVIMENTO DE JOGOS MOBILE 33


Corpos rígidos apresentam características como: posição, velocidade, densidade,
massa, rotação, velocidade angular, entre várias outras. Força e torque podem ser
adicionados a um corpo rígido, modificando algumas de suas características originais.

Por exemplo, se um corpo está apoiado em uma superfície sem inclinação e com atrito,
e sob a ação da gravidade, ele estará inicialmente com velocidade zero, mas recebendo
uma força horizontal capaz de quebrar a resistência desse atrito irá iniciar uma
aceleração, modificando sua velocidade original.

Nesse contexto, algumas definições básicas da física se tornam necessárias:

Velocidade é medida a partir da variação da distância sobre a variação do tempo, e


assumindo unidades como Km/h ou m/s.

Aceleração é definida pela variação da velocidade em relação ao tempo, assume


unidades como Km/h² ou m/s².

A massa é medida em unidades como Kg ou g, podendo estar sujeita à ação da


gravidade, definindo a força peso (P=m.g), sendo normalmente utilizada a unidade
Kg.m/s², ou simplesmente Newton (N).

Materiais distintos podem ser mais ásperos ou mais lisos, apresentar diferentes
densidades, além de outras características físico-químicas capazes de interferir
diretamente nos cálculos físicos.

DESENVOLVIMENTO DE JOGOS MOBILE 34


O ferramental da Unity 3D para aplicação de física nos jogos é muito vasto, a começar
pelo suporte à colisão. Pela engine é possível utilizar uma grande gama de estratégias
de detecção sem qualquer tipo de aprofundamento matemático, sendo as áreas (2D)
e volumes (3D) de detecção denominadas colisores.

Embora a metodologia seja sempre a mesma, as fórmulas de cálculo para outros


formatos de áreas de colisão podem se tornar bastante complexas. Exemplos típicos
de áreas e volumes de colisão são círculos, no modelo 2D, esferas e cápsulas, no
modelo 3D.

É possível testar todos os vértices de um polígono ou de uma malha, mas o gasto


computacional envolvido pode não trazer tantos benefícios assim.

Mesmo sem a necessidade de efetuar complexas implementações de colisores, devido


ao suporte oferecido pela Unity 3D, é interessante observar os impactos para o jogo
na escolha de colisores mais ou menos complexos, pois o aumento demasiado da
quantidade de cálculos efetuados poderá trazer efeitos catastróficos para a fluidez no
momento de execução.

Inicialmente a Unity 3D apresenta colisores 3D, pela própria natureza da Engine, sendo
mais utilizados os colisores Box Collider, Sphere Collider e Capsule Collider. Em
situações de maior detalhamento pode ser utilizado o Mesh Collider, e outro colisor
importante é aquele utilizado na criação de terrenos, o Terrain Collider.

DESENVOLVIMENTO DE JOGOS MOBILE 35


Da mesma forma que são oferecidos colisores 3D, são oferecidos colisores 2D,
aplicáveis aos Sprites e demais elementos 2D. Os colisores mais utilizados são Circle
Collider 2D e Box Collider 2D, e para elementos mais detalhados pode ser utilizado
o Polygon Collider 2D.

A criação de um cenário simples, com um box (BoxCollider), quatro esferas


posicionadas sobre o box (SphereCollider) e um controlador em terceira pessoa
(CapsuleCollider), com o correto posicionamento de câmera, já seria suficiente para
observar o efeito da colisão, já que o personagem não consegue atravessar as esferas.

DESENVOLVIMENTO DE JOGOS MOBILE 36


Se o objetivo não for o bloqueio, podemos controlar o efeito da colisão através da
programação do evento onCollisionEnter. O Script C# abaixo pode ser aplicado às
esferas para que sumam quando tocadas.

public class SelfDestruct : MonoBehaviour {


void OnCollisionEnter(Collision collision) {
DestroyObject (gameObject);
}
}

Outro elemento interessante na física do Unity3D são as junções entre objetos, como
na simulação de dobradiças (Hinge Joint) e molas (Spring Joint). Da mesma forma
que existem junções 3D, existem as junções 2D, como Hinge Joint 2D.

Quanto aos corpos rígidos, a Unity 3D oferece suporte simples, pelo acréscimo
de um Rigidbody ou Rigidbody2D. Um exemplo típico de utilização da gravidade

DESENVOLVIMENTO DE JOGOS MOBILE 37


encontra-se no controlador em terceira pessoa, no qual é utilizado um RigidBody com
a opção Use Gravity marcada.

Inteligência Artificial
Os dicionários consideram inteligência como a capacidade de aprender, compreender
e adaptar-se às situações que se apresentarem. Os modelos de Inteligência Artificial
(AI, do inglês Artificial Intelligence) são aqueles cuja programação visa simular
ações de inteligência similares às humanas, mas em meio computacional.

Em termos computacionais, existem duas grandes áreas abordadas pela inteligência


artificial: aprendizado automatizado, ou machine learning, e tomada de decisão.
Essas duas grandes áreas podem ser combinadas, de forma a transmitir a
característica de adaptação baseada em memórias (ações ou dados), ou podem atuar
de forma totalmente independente.

Hoje em dia existem várias vertentes para a implementação de inteligência artificial,


tais como: Redes Neurais, Lógica Fuzzy e Algoritmos Genéticos. Normalmente
essas diversas técnicas visam o aprendizado para tomada de decisão.

DESENVOLVIMENTO DE JOGOS MOBILE 38


Um termo comum utilizado nesse campo da inteligência artificial é a heurística, uma
regra adotada para a busca de soluções ou decisões.

Uma Rede Neural Artificial (RNA) é composta por várias unidades de processamento,
cujo funcionamento é bastante simples. Essas unidades geralmente são conectadas
por canais de comunicação que estão associados a determinado peso.

As unidades fazem operações apenas sobre seus dados locais, que são entradas
recebidas pelas conexões. O comportamento inteligente de uma RNA vem das
interações entre as unidades de processamento da rede, cujas saídas funcionam como
entradas para outras unidades, assim como ocorre nos neurônios físicos.

O uso de Lógica Fuzzy permite a utilização de valores intermediários entre o falso e


verdadeiro da lógica booleana. A ideia básica por trás do Fuzzy é a simulação da
percepção de valor humana, onde os elementos não são apenas verdadeiros ou falsos,
mas apresentam percentuais de aceitação para as mais diversas situações.

DESENVOLVIMENTO DE JOGOS MOBILE 39


Com relação aos Algoritmos Genéticos, estes se baseiam nas combinações entre
genes e utilização de mutações, baseando-se na Teoria Evolucionista de Darwin.
Esse tipo de algoritmo utiliza heurísticas de avaliação e combinação de soluções
parciais, de forma a otimizar soluções completas, segundo princípios evolucionistas.

O método mais comum para a escolha de indivíduos para cruzamento (combinação) é


a roleta de seleção, a qual aumenta a probabilidade de escolha dos indivíduos mais
adaptáveis, segundo uma função de avaliação.

Qualquer jogo que envolva movimentos do computador, dispositivo móvel, console,


ou outro além do jogador, deverá adotar regras heurísticas para a ação dos
personagens.

Em jogos como Xadrez e Pôquer, por exemplo, as diversas heurísticas tomam como
base o conhecimento prévio de estratégias, análise estatística e árvores de decisão.

As árvores de decisão buscam criar todos os cenários decorrentes de cada ação do


usuário no formato de uma máquina de estados hierarquizada, o que exige a aplicação
de algoritmos gulosos, classificados como força-bruta, para a determinação de
todas as possibilidades e recorrente adoção da mais favorável.

DESENVOLVIMENTO DE JOGOS MOBILE 40


Duas situações podem ocorrer decorrentes da aplicação de algoritmos gulosos na
formação de árvores de decisão: demora na combinação de espaços maiores, e jogos
impossíveis de ganhar.

Para evitar essas situações, podem ser utilizadas heurísticas para a formação da
árvore, as quais não tratarão de todo o espectro combinatorial de um algoritmo guloso,
mas trarão resultados com níveis de qualidade e dificuldade adequados à garantia da
jogabilidade.

Sistemas baseados em regras são outra solução na automatização do comportamento


de personagens. Basicamente é aplicado um conjunto de regras, no formato "se...
então... senão...", e as decisões são tomadas a partir dos dados de entrada.

No contexto da inteligência artificial, os agentes inteligentes são programas com


controle autônomo, e que são capazes de perceber o ambiente e se adaptarem às
mudanças.

Sistemas multiagentes são aqueles que utilizam esses agentes de forma


colaborativa, quer seja para operações em jogos de campanha quer seja para
acrescentar certo nível de inteligência ao comportamento dos inimigos.

DESENVOLVIMENTO DE JOGOS MOBILE 41


As Máquinas de Estados Finitos, também denominadas FSM, do inglês Finite State
Machine, são utilizadas para a formalização de sistemas de eventos discretos, sendo
amplamente aplicáveis aos jogos. Basicamente tratam de uma representação de
estados do objeto, as transações possíveis entre estados, bem como os estímulos e
condições associados às transações.

Para jogos que envolvem personagens animados, naves, tiros, e demais elementos
autônomos, é comum o uso de heurísticas de busca para a localização do jogador e
tomada de decisão acerca de movimentação, defesa e ataque.

Navegação, ou Pathfinding, é uma das aplicações mais comuns de inteligência


artificial em jogos eletrônicos. De fato, a construção de um mundo virtual habitado por

DESENVOLVIMENTO DE JOGOS MOBILE 42


agentes autônomos que se movem em busca de algum objetivo, como a caça ao
jogador, requer a introdução de mecanismos que suportem essa navegação.

Um sistema de regras para cada agente fará com que siga o caminho livre que mais o
aproxima do jogador, e estando em posição adequada, este pode entrar em modo de
combate, segundo a máquina de estados (FSM).

Um modelo muito interessante de Pathfinding é fornecido pela Unity 3D, o qual é


chamado de Navigation Mesh, ou simplesmente NavMesh. Esse sistema permite a
criação de uma área de movimentação e busca aproveitando o próprio formato da
malha de cenário.

O sistema Navigation Mesh é composto de:


NavMesh - superfície sobre a qual os personagens podem se locomover, podendo ser
extraída da própria geometria do cenário.
NavMesh Agent - define personagens que reconhecem uns aos outros, ou aos
obstáculos, e perseguem objetivos sobre o NavMesh.
Off-Mesh Link - permite atalhos entre dois pontos do NavMesh, voltado para saltos
e ações especiais.
NavMesh Obstacle - permite a definição de obstáculos móveis para os agentes.

DESENVOLVIMENTO DE JOGOS MOBILE 43


Para criar um NavMesh é necessário apenas a utilização das funcionalidades do painel
Navigation. Os elementos do cenário a serem incluídos na navegação devem ser
marcados como Navigation Static, configurações mais específicas na opção Bake,
e para gerar a NavMesh deve ser utilizado o botão também com o nome Bake.

Como passos seguintes, podem ser adicionados um Game Object, como um


cilindro, configurado como NavMeshAgent, sendo adotada a programação
adequada.

public Tranform alvo;

void Update ( ) {
NavMeshAgent agente = GetComponent<NavMeshAgent> ( );
agente.destination = alvo.position;
}

DESENVOLVIMENTO DE JOGOS MOBILE 44


Adicionando um controlador de terceira pessoa e ajustando a propriedade alvo de
MoveTo, associado ao NavMeshAgent, este irá perseguir o jogador pelo caminho
definido.

Geração Procedural
Geração Procedural em jogos corresponde à adoção de um conjunto de algoritmos,
utilizados como um ferramental para criar grandes quantidades de conteúdo em
arquivos de tamanhos mínimos.

Essa técnica não é nova, pois os jogos mais antigos, limitados à baixa capacidade
computacional e de pouco espaço de armazenamento da época, precisavam criar
elementos dinamicamente para melhor aproveitamento do hardware.

O princípio matemático que serve de base para a geração procedural é a aleatoriedade


numérica, determinada por uma semente de geração e uma distribuição probabilística.
As gerações pseudoaleatórias permitem a repetição de um cenário ou simulação
quando é utilizada a mesma semente no processo de geração.

As formas mais comuns de geração procedural são o modelo matricial e uso de fractais.
Em jogos 2D de visão superior, os mapas podem ser obtidos como a combinação de
figuras menores de forma matricial, e alguns exemplos típicos disso são jogos de
corrida infinitos, jogos de campanha, bullet hell e RPG de visão superior.

DESENVOLVIMENTO DE JOGOS MOBILE 45


É fácil observar nesses jogos a repetição de elementos ao longo das cenas. Com o uso
de poucos recursos de mídia, combinados de diferentes formas, em alguns momentos
de forma aleatória, em outros configurados por listas de valores, é possível diminuir
muito o tamanho total do jogo, ou as necessidades de transmissão em rede.

Nos jogos de bullet hell o uso de aleatoriedade controlada pode trazer um desafio
maior para o jogador, pois ele não será capaz de prever movimentos inimigos.

Jogos como Minecraft e Spore utilizam a geração procedural para criar imensos
mundos 3D, permitindo aos jogadores experiências inéditas a cada novo cenário
gerado.

O tipo de geração do Minecraft chama-se "Ruído de Perlin", um algoritmo utilizado


na geração de texturas, mas que se popularizou na criação de terrenos em jogos. Esse
tipo de algoritmo trabalha com elementos fractais para a geração do "ruído", ou área
de instabilidade, o que traz informações para a geração de terrenos de forma simples
e muito eficiente.

Para a geração de um cenário de forma dinâmica devem ser consideradas as diferentes


alturas nos diversos pontos, assumindo transações suaves na malha, o que pode ser
obtido com a construção de um mapa de altura. Na área da computação gráfica um
mapa de altura é uma imagem bidimensional utilizada para armazenar valores
relativos à elevação de uma superfície, para a exibição como gráficos tridimensionais.
DESENVOLVIMENTO DE JOGOS MOBILE 46
Para geração de superfícies com Unity 3D pode ser utilizado o método estático
Mathf.PerlinNoise, onde os parâmetros utilizados (a,b) denotam o deslocamento
dentro do fractal.

Com a escolha de uma área do fractal, a partir de um ponto fornecido, é obtido um


conjunto de valores (ruído) com boa aleatoriedade no conjunto global, e bastante
suavidade nas transições, o que viabiliza a repetição do cenário através da repetição
da origem, além de apresentar superfícies consistentes e sem quebras bruscas.

public float xorig = 0.0f;


public float zorig = 0.0f;
public GameObject bloco01;
void GerarTerreno(){
GameObject gobj = null;
for(x=0;x<30;x++){
for(z=0;z<30;z++){
y = (int)(Mathf.PerlinNoise(
(x+xorig)*10/300.0f,(z+zorig)*10/300.0f)*11);
gobj = (GameObject)Instantiate(bloco01,
new Vector3(x,y,z),Quaternion.identity);
MeshRenderer mr = gobj.GetComponent<MeshRenderer>();
mr.material.color = new Color(y/11.0f,y/11.0f,1.0f,0.5f);
DESENVOLVIMENTO DE JOGOS MOBILE 47
}
}
}

No código anterior, xorig e zorig denotam o deslocamento desejado no fractal,


segundo uma área de cobertura que varia de 0 a 29 em x e z. Como o fractal retornará
um valor entre 0 e 1, ele deverá ser multiplicado pela altura máxima desejada (11).

Com MeshRenderer e uso da propriedade material é possível alterar a cor de acordo


com a altura gerada, seguindo o padrão RGB-Alpha.

Esse código pode ser adaptado para gerar qualquer terreno 3D com grande facilidade,
mas um cuidado que deve ser tomado é o de não aplicar o script ao objeto a ser
replicado, pois traria ao jogo um problema de recursividade infinita.

Elementos mais independentes podem ser utilizados, por exemplo, a Main Camera,
artifício bastante utilizado em muitos jogos que precisam de algum tipo de
configuração inicial de ambiente. Poderia também ser criado um Game Object do tipo
Empty.

Devem ser configurados no Inspector os valores de xorig e zorig, bem como


associar bloco01 ao objeto que será replicado, o que teria o resultado observável a
seguir, se GerarTerreno for chamado no Start do script.

DESENVOLVIMENTO DE JOGOS MOBILE 48


Uma forma bastante simplória de geração procedural seria com o uso de Random. Por
exemplo, um jogo similar ao Breakout, mas com os blocos sendo colocados em
posições totalmente aleatórias, bem como suas cores, poderia trabalhar diretamente
com Random na geração.

Isso pode gerar problemas com relação às sobreposições não tratadas, mas a
aleatoriedade poderia ser melhor explorada, por outro lado, na concessão de bônus,
vida extra, e demais elementos especiais.

Interface de Usuário
Uma interface pode ser considerada como uma fronteira entre dois sistemas sejam
esses eletrônicos, mecânicos ou orgânicos. Exemplos de interfaces de origem
eletrônica ou mecânica incluem conectores e barramentos, entre outros.

O hardware para entrada de dados, como mouse e teclado, constitui uma interface
física com o usuário. Partindo do âmbito físico para o lógico, ou software, este também
apresenta necessidade de interação com o usuário (sistema orgânico), por um
conjunto de componentes denominado interface de usuário.

Como em qualquer plataforma de software, várias ações envolvendo configurações,


informações e decisões no decorrer da utilização do jogo irão necessitar de uma
interface de usuário padronizada, com elementos já de utilização comum em outros
ambientes como, por exemplo, menus e botões.

Unity 3D oferece uma API e voltada exclusivamente para a construção de interfaces,


bem como ferramentais próprios, e essa API é denominada UI (User Interface).

O menu Game Object >> UI dará acesso à criação dos seguintes componentes
relacionados com a interface de usuário: Panel, Button, Text, Image, Raw Image,
Slider, ScrollBar, Toggle, Input Field, Canvas e Event System.

DESENVOLVIMENTO DE JOGOS MOBILE 49


Todo componente visual do tipo UI está associado a um Canvas, ou área de desenho,
o qual pode ser utilizado com três referenciais distintos, através do Render Mode:

Screen Space – Overlay apresenta a interface no topo da tela, ou seja, na camada


de topo do ambiente 2D.

Screen Space – Camera posiciona a interface em relação a uma câmera, de forma


fixa, acompanhando a visão do jogador em primeira pessoa.

World Space faz com que a interface seja integrada ao espaço do ambiente 3D,
constituindo parte do cenário.

Além de transformações comuns, como a rotação padrão, os componentes UI


apresentam um sistema de âncoras para redimensionamento dinâmico, permitindo
manter o mesmo aspecto em dispositivos distintos. A ferramenta Rect Transform
permite a configuração desse tipo de comportamento.

DESENVOLVIMENTO DE JOGOS MOBILE 50


A configuração dos componentes UI, no editor do Unity, é feita de forma mais fácil
com a utilização da visualização 2D, a qual permite uma visão frontal das telas.

Qualquer componente visual adicionado ao ambiente irá adicionar também o Canvas


e o Event System, e a janela Hierarchy será muito útil no processo de criação de
interfaces, pois viabilizará acesso rápido para a configuração das diversas propriedades
dos componentes no Inspector.

A resposta às ações sobre os componentes UI deve ser feita através da programação


de resposta a eventos como onClick, para Button, e onValueChanged, para Toggle
e Slider.

Uma forma simples de responder aos eventos é adicionar os ouvintes corretos através
do método AddListener. Um método callback deve ser criado para a resposta, e
utilizado como parâmetro de AddListener.

private Button btn;


void Start () {
btn = GetComponent<Button> ();
btn.onClick.AddListener(debugClick);
}
void debugClick () {
DESENVOLVIMENTO DE JOGOS MOBILE 51
Debug.Log("Clicado");
}

Apenas para exemplificar o uso de botões em uma interface de usuário, um código


similar poderia ser criado para que efetuasse a soma dos valores digitados em dois
InputFields e o resultado exibido em um componente Text.

Para tal, é necessário adicionar atributos públicos de ligação com os game objects
necessários, além da implementação do callback responsável pela operação. Há
métodos visuais de configuração de eventos, mas eles acabam se tornando mais
complexos que a utilização de programação.

public class SomaClick : MonoBehaviour {


void Start () {
GetComponent<Button>().onClick.AddListener(onSomaClick);
}
public InputField campo1, campo2;
public Text resultado;
void onSomaClick(){
int a = int.Parse (campo1.text);
int b = int.Parse (campo2.text);
resultado.text = "A soma de "+a+" e "+b+" vale "+(a+b);
}
}

DESENVOLVIMENTO DE JOGOS MOBILE 52


Em termos visuais, um componente do tipo container é aquele capaz de agrupar outros
sobre ele. Ao mover o container, todo o conjunto agrupado é movido junto.

O aspecto e funcionalidade dos containers dependerá bastante do tipo de plataforma


e do sistema operacional, sendo que o primeiro container de uma interface de usuário
típica é a janela, mas podem ser utilizados outros containers internos, como painéis,
por exemplo.

Ainda existe a possibilidade de se utilizar containers sobrepostos, os quais podem ser


alternados através do controle de visibilidade, caracterizando interfaces paginadas.

Em termos da Unity 3D, um Panel funciona como container, permitindo organizar os


espaços internos do Canvas. Quando um componente UI, como um botão, está ligado
a um Panel na estrutura hierárquica, ao mover esse Panel o componente será movido
junto, como se fosse uma janela, facilitando muito o tratamento visual do conjunto.

DESENVOLVIMENTO DE JOGOS MOBILE 53


Para adicionar componentes UI ao Panel, utilize sempre a janela Hierarchy, clicando
com o botão direito sobre o Panel e selecionando o componente UI de sua preferência.

Podem ser criados novos elementos Panel, constituindo todo um sistema interativo de
janelas. Nesse contexto, uma propriedade muito interessante é o Alpha do Panel, a
qual permite a sobreposição de painéis com transparência, o que mantém a
informação do anterior, ao mesmo tempo em que utiliza um sofisticado efeito
translúcido.

A visibilidade de cada Panel pode ser controlada, e as telas podem ser exibidas
alternadamente nos momentos de utilização da interface. Para isso, basta habilitar ou
desabilitar o Panel, a partir da janela do Inspector ou via programação.

DESENVOLVIMENTO DE JOGOS MOBILE 54


Nesse exemplo, com o acréscimo de um Script bastante simples ao botão é possível
fazer com que o clique nele torne o segundo painel visível, de forma translúcida e
sobreposto ao primeiro.

Esse tipo de comportamento é bastante comum em janelas de configuração, pois


tendo sido completadas as alterações solicitadas, é importante informar ao jogador
que a operação obteve sucesso, ou até mesmo que houve alguma falha.

A forma mais simples de relacionar o Script ao segundo painel é com o uso de uma
propriedade GameObject, a qual permitirá informar o relacionamento com o objeto
do cenário a partir do Inspector.

public class ClickConfig : MonoBehaviour {


private Button btn;
void Start () {
btn = GetComponent<Button> ();
btn.onClick.AddListener(onClickConfig);
}
public GameObject pMensagem;
void onClickConfig(){
pMensagem.SetActive (true);
}
}

DESENVOLVIMENTO DE JOGOS MOBILE 55


As interfaces visuais são muito importantes para a definição de características e opções
dos jogos, como nível de dificuldade, ativação de som e música de fundo etc.

Também podem ser úteis na escolha de itens e tarefas de caracterização de


personagens, essa última opção muito comum em jogos de RPG e de execução de
tarefas.

Alguns jogos podem ser construídos apenas com o uso dos componentes UI,
principalmente os de tabuleiro como, por exemplo, o popular "Jogo da Velha".

Imediate Mode GUI (IMGUI)


Outra forma de criar interfaces e HUD na engine Unity 3D é com o uso de IMGUI,
considerado obsoleto face à nova interface UI, porém ainda utilizado amplamente nas
plataformas móveis. Como essa era a forma padrão de criação de interfaces nas
versões anteriores da Unity 3D, é comum encontrar diversos exemplos de sua
utilização.

A vantagem do uso de IMGUI encontra-se no fato de que não há necessidade de


configurar qualquer elemento Canvas, posicionamento de câmera, ou outros
elementos visuais, constituindo um ambiente totalmente controlado por Script.
DESENVOLVIMENTO DE JOGOS MOBILE 56
Essa forma de construção se baseia no evento OnGUI para a criação de diversos
objetos GUI. Nesse ambiente, o uso de botões precisa apenas de uma simples
estrutura condicional, pois o botão em questão retornará true se for pressionado na
ocorrência do evento.

void OnGUI() {
if (GUILayout.Button("Press Me"))
Debug.Log("Hello!");
}

Esse método de criação de interfaces pode ser utilizado facilmente na criação de


menus. Um exemplo seria a criação de um menu para escolha do nível do jogo.

GUI.Box(new Rect(10,10,100,90),"Loader Menu");


if(GUI.Button(new Rect(20,40,80,20), "Level 1"))
{
Application.LoadLevel(1);
}
if(GUI.Button(new Rect(20,70,80,20), "Level 2"))
{
Application.LoadLevel(2);
}

DESENVOLVIMENTO DE JOGOS MOBILE 57


Ao invés de texto, os botões também aceitam o uso de texturas como ícones. Para
isso basta associar o Script a uma textura, por uma propriedade pública do tipo
Texture2D, e utilizar o ícone no lugar do texto.

public class GUITest : MonoBehaviour {


public Texture2D icon;
void OnGUI () {
if (GUI.Button (new Rect (10,10, 100, 50), icon)) {
print ("you clicked the icon");
}
}
}

Vários componentes estão disponíveis na biblioteca IMGUI, sendo alguns deles


descritos a seguir:

GUI.Label - representação de texto estático.


GUI.Button - botão simples.
GUI.TextField - apresenta uma caixa de texto.
GUI.Toggle - representa valores booleanos.
GUI.Toolbar - criação de uma barra de ferramentas.

Em algumas situações é necessário detectar mudanças nos objetos do ambiente


IMGUI, e isso pode ser feito por GUI.changed.
DESENVOLVIMENTO DE JOGOS MOBILE 58
void OnGUI () {
selectedToolbar = GUI.Toolbar (new Rect (50, 10,
Screen.width - 100, 30), selectedToolbar, toolbarStrings);
if (GUI.changed)
Debug.Log("Toolbar ativado na opção: "+selectedToolbar);
}

HUD

Em qualquer sistema interativo, a informação deve ser apresentada de uma maneira


integrada ao ambiente, e de forma a não atrapalhar o campo de visão do usuário.
Informações podem ser textuais, como pontuações e vidas, ou gráficas, como barras
de energia e mapas de contexto.

A sigla HUD significa Heads up Display, referindo-se a informações dispostas em


algum visor, como o capacete dos pilotos de caças, ou simplesmente na tela de um
jogo, de forma a guiar o jogador com as informações necessárias ao contexto.

Alguns exemplos da literatura traduzem a sigla HUD como Hands up Display, o que
não traz nenhum impacto real ao seu significado. A ideia básica é ter a informação
disponível na "altura dos olhos", ou no campo de visão, de forma simples e sem
atrapalhar a interatividade e visualização do ambiente.

DESENVOLVIMENTO DE JOGOS MOBILE 59


Temos exemplos de HUD na vida real e na ficção científica, como os sistemas de auxílio
à navegação diversos, projetados na tela de veículos, ou em óculos de realidade
alternada, a exemplo do Google Glass.

As aparições do personagem "Iron Man", nos filmes da Marvel, exploram de forma


muito interessante o conceito, e acabam trazendo uma expectativa para o caminho
que tomará o design utilizado para a construção do HUD na atualidade.

Nos jogos, esse conceito é antigo, e não precisa chegar à complexidade alcançada por
esses exemplos. Com a utilização da Unity é bastante simples criar elementos HUD,
por componentes UI ou IMGUI.

DESENVOLVIMENTO DE JOGOS MOBILE 60


As informações apresentadas no HUD podem ser bastante heterogêneas, mas algumas
se tornaram bastante usuais nos jogos.

Energia, ou HP (Health Points) Menus de Contexto


Quantidade de Vidas Mini Mapas
Tempo Restante (Cronômetro) Velocímetros e Tacômetros
Armas e Munições Bússolas e Radares
Experiência (XP) Opções Especiais ou Magia (MP)

As informações referentes à energia (HP) costumam adotar um padrão de cores, indo


de cores mais frias para cores mais quentes. Normalmente é observável como uma
barra de progresso, podendo estar presente junto ao jogador e também nos inimigos.

Para ambos os lados, a energia chegando a zero costuma impactar no decréscimo de


uma vida, e informações como XP e MP costumam adotar o mesmo padrão de
exibição.

A contagem de quantidade de vidas pode ser representada de forma simplesmente


numérica, ou de forma gráfica, como ocorria muitas vezes em jogos Arcade, a exemplo
do antigo Galaga.
DESENVOLVIMENTO DE JOGOS MOBILE 61
Cronômetros seguem o mesmo tipo de regra, podendo tratar de elementos gráficos
ou não, sendo apresentado de forma numérica no jogo Sonic, por exemplo.

Elementos como mapas, bússolas e radares são comuns em jogos do tipo FPS, como
Counter Strike. Como são elementos auxiliares, é comum a utilização de teclas e
controles específicos para ativar e desativar esses recursos por parte do jogador. Nesse
mesmo tipo de jogo é crucial também a apresentação da informação acerca de
munições e armas disponíveis para utilização.

Velocímetros e tacômetros eram utilizados de forma textual nos primeiros jogos de


corrida. Com a evolução dos gráficos, eles passaram a ter uma representação visual
cada vez mais próxima dos aparelhos reais. Jogos como Need for Speed exploram
muito bem a utilização desses elementos de HUD, otimizando a experiência do jogador
em meio ao ambiente de corrida virtual.

DESENVOLVIMENTO DE JOGOS MOBILE 62


Os componentes UI são de grande utilidade para a criação de HUD na Unity 3D. Um
exemplo simples seria a utilização de componentes UI, como o texto estático, para
acompanhamento da energia de um ou mais personagens.

Normalmente associamos esses indicadores a elementos visuais, através do uso de


imagens, e um dos posicionamentos mais simples para a concepção de HUD com
componentes UI é o Render Mode do tipo Screen Space – Overlay. Como esse
posicionamento a informação se mantém em frente à visão da tela, e basta posicionar
os componentes UI em pontos estratégicos que não atrapalhem a visualização central.

Apenas para exemplificar o início da construção do HUD, pode ser utilizado um texto
simples em um projeto 2D. Esse componente pode ser programado de forma a exibir
a contagem regressiva de tempo, com a atualização do texto efetuada por
programação C#.

public class Tempo : MonoBehaviour {

DESENVOLVIMENTO DE JOGOS MOBILE 63


public int tempo = 10000;
public Text texto;
void Update () {
tempo--; texto.text = "Agora: " + tempo;
}
}
Esse script deve ser associado ao um objeto de utilização global, como a Main
Camera. Associando a propriedade texto do Script ao objeto Text da cena, o
resultado final pode ser observado no Game Play.

Embora não seja funcional para um jogo real, esse pequeno exemplo demonstra o
posicionamento e a programação de um elemento HUD. Exemplos mais complexos e
de maior qualidade gráfica podem ser observados nos diversos tutoriais do fabricante
da Unity 3D.

Ambiente Mobile
Um dispositivo móvel caracteriza-se como um "computador" de bolso, normalmente
operado por bateria, com uma tela de dimensões pequenas, além de um teclado ou
entrada pelo toque direto na tela (touchscreen).

Pode ser utilizado como objeto pessoal, ou com finalidade profissional, apresentando
como vantagens elementos como a mobilidade, a comunicação facilitada e a
versatilidade.

DESENVOLVIMENTO DE JOGOS MOBILE 64


A tecnologia móvel já está presente em nosso dia-a-dia de forma corriqueira,
expandindo-se agora para níveis ainda mais densos de comunicação através da
Internet of Things.

Apesar da categoria móvel englobar tablets, TVs inteligentes e diversos outros tipos
de aparelhos, SmartPhones foram o produto de melhor absorção pelo mercado.

Esses diversos tipos de aparelho são comumente chamados de handheld, e as


primeiras versões popularizadas foram os Palm Pilots, dos quais alguns reconheciam
a escrita.

Atualmente, a maior fatia de mercado de dispositivos móveis é dividida entre o iOS,


da Apple, e o Android, da Google. O mercado de Android é particularmente mais fácil
de entrar, e devido ao preço e ao fato de ser uma plataforma aberta, abrange uma
grande quantidade de consumidores.

Nessas plataformas, assim como nas demais plataformas móveis, os jogos se tornaram
um mercado de grande relevância, assumindo diversos modelos de negócios.

Um grande avanço foi determinado nessas plataformas devido ao barateamento e


minimização da tecnologia de sensores. Qualquer SmartPhone atual trabalha com
giroscópio, GPS, acelerômetro, fora a tela de toque em si, e a possibilidade do uso de
câmeras. Exemplo que explora bem esses recursos é o jogo Pokemon Go.

DESENVOLVIMENTO DE JOGOS MOBILE 65


Unity 3D oferece um bom ambiente para desenvolvimento de jogos mobile, permitindo
a utilização de plataformas móveis como Android e iOS, entre outras. No entanto, para
utilizar qualquer uma dessas plataformas é necessário configurar ambientes e
ferramentas externas ao ambiente da engine.

Para a configuração do ambiente Android na Unity será necessário baixar e instalar


o Android SDK. Com o SDK instalado, deve ser baixada ao menos uma plataforma
Android com API Level maior que 9, ou seja, Plataforma 2.3 ou superior. O caminho
para o SDK do Android deve ser indicado para a Unity 3D por Unity >>
Preferences, opção External Tools.

Embora seja possível utilizar o emulador do Android, apenas no aparelho físico é viável
o teste de todas as características do jogo. Para depurar o jogo por um SmartPhone
DESENVOLVIMENTO DE JOGOS MOBILE 66
Android, é necessário habilitar a opção de depuração USB, dentro de opções de
desenvolvedor.

A configuração do ambiente iOS na Unity 3D exige que seja feito o cadastro na Apple
Developer Program. Deve ser instalada a versão mais recente do XCode, a qual
pode ser obtida na Mac App Store.

A ferramenta XCode é um ambiente de desenvolvimento (IDE) que contém um


conjunto de ferramentas de software criadas pela Apple para a implementação de
software para OS X, iOS, WatchOS e tvOS.

Para associar o XCode ao Apple ID, devem ser seguidos alguns passos:

1. Abrir o XCode e selecionar a opção Xcode >> Preferences na barra de menu


para abrir a janela preferências.
2. Selecionar Accounts na parte superior da janela para exibir informações sobre
os IDs da Apple.
3. Clicar no sinal de "mais" no canto inferior esquerdo e escolher Add Apple ID.

DESENVOLVIMENTO DE JOGOS MOBILE 67


Ao gerar um produto para iOS, a Unity 3D gera o projeto XCode, incluindo todas as
bibliotecas necessárias, código dotNet pré-compilado e Assets serializados.

Esse projeto deve ser compilado no ambiente do Xcode para implantar e executar no
dispositivo escolhido. Uma vez que Unity foi usado para construir o projeto XCode é
possível efetuar a compilação e executar a partir da linha de comando.

xcodebuild test -destination


"platform=iOS,id=400d20d00baf8d4997b47be0416cf5c44dd2d3bc"
-scheme Unity-iPhone

Uma solução muito interessante para depurar o jogo criado na Unity é o aplicativo
Unity Remote, o qual foi projetado no intuito de ajudar no desenvolvimento para
Android ou iOS. O app deve ser baixado e se conecta com o Unity enquanto você está
executando o projeto no modo Play do editor.

A saída visual do editor é enviada para a tela do dispositivo e o input em tempo real é
enviado de volta para o projeto em execução no Unity. Isso permite uma boa
impressão do funcionamento do jogo, sem precisar de uma compilação completa para
cada teste.

Para utilizar essa ferramenta é necessário baixar o projeto Unity na Asset Store (requer
compilação), e o app na loja de seu dispositivo, iOS ou Android. Em seguida é
necessário conectar o dispositivo através da USB e efetuar a configuração correta da
Unity 3D, através da opção de menu Edit >> Project Settings >> Editor,
selecionando em seguida a seção Unity Remote, a qual permite escolher o tipo de
dispositivo, compressão utilizada e resolução de tela.

DESENVOLVIMENTO DE JOGOS MOBILE 68


Programação Unity para Mobile

O primeiro componente que pode ser considerado na criação de jogos para dispositivos
móveis é a classe HandHeld. Essa classe permite controlar os aspectos mais globais
do jogo, como o uso de vibração, modo de tela cheia e indicador de atividade.

public class ExampleClass : MonoBehaviour {


void OnGUI() {
if (GUI.Button(new Rect(0, 10, 100, 32), "Vibrate!"))
Handheld.Vibrate();
}
}

Unity fornece um bom suporte a giroscópios e acelerômetros. Quando surgiu o


primeiro celular com uso de acelerômetro, ele automaticamente gerou uma mania
entre os consumidores.

Vários jogos foram lançados com uso dessa tecnologia de sensores, posteriormente
substituída pelo giroscópio. Jogos denominados "runner" obtiveram grande sucesso e
até hoje conseguem manter um público fiel.

O uso desses recursos é muito simples, encapsulados nas classes Gyroscope e


AccelerationEvent, e a informação é obtida diretamente a partir da classe Input,
como as demais entradas nos projetos Unity 3D.

void Update() {
dir.x = -Input.acceleration.y;
dir.z = Input.acceleration.x;
dir *= Time.deltaTime;
transform.Translate(dir * 10.0F);
}

DESENVOLVIMENTO DE JOGOS MOBILE 69


Com Input.gyro, é possível obter o Gyroscope padrão do dispositivo. Utilizar o
Quaternion attitude, de Gyroscope, é uma forma muito simples de controlar a
rotação 3D de qualquer objeto do jogo.

public class ExampleClass : MonoBehaviour {


void Update() {
transform.rotation = Input.gyro.attitude;
}
}

A aceleração do usuário também pode ser obtida com Gyroscope, com a propriedade
userAcceleration.

public class ExampleClass : MonoBehaviour {


public Vector3 forceVec;
public Rigidbody rb;
void Start() {
rb = GetComponent<Rigidbody>();
}
void FixedUpdate() {
rb.AddForce(Input.gyro.userAcceleration.x * forceVec);
}
}

As telas de toque são um padrão adotado por qualquer tecnologia móvel da atualidade,
particularmente os SmartPhones. Na verdade, a grande maioria dos jogos trabalha
com o conceito de tela de toque, incluindo movimentos de arraste e até mesmo toques
múltiplos.

Não há como pensar em jogos para dispositivos móveis sem pensar em algum controle
da tela de toque, mesmo quando lidamos com acelerômetros e giroscópios.

DESENVOLVIMENTO DE JOGOS MOBILE 70


O controle do toque de tela é feito através da classe Touch e a partir de Input, com
o uso de Input.GetTouch.

void Update() {
float speed = 0.1F;
if (Input.touchCount > 0 &&
Input.GetTouch(0).phase == TouchPhase.Moved) {
// Pega o movimento do dedo desde o último quadro
Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
transform.Translate(-touchDeltaPosition.x * speed,
-touchDeltaPosition.y * speed, 0);
}
}

Além do toque de tela simples, padrão adotado pelos diversos SmartPhones e Tablets,
alguns dispositivos oferecem a possibilidade de múltiplos toques simultâneos, os quais
possibilitam operações como "pinch", muito utilizadas no controle de zoom, por
exemplo.

É possível tratar também toques simultâneos na Unity 3D, desde que o dispositivo
suporte essa funcionalidade.

void Update ()
{
Touch[] myTouches = Input.touches;
for(int i = 0; i < Input.touchCount; i++)
{
// Cada toque do grupo pode ser manipulado aqui
}
}

DESENVOLVIMENTO DE JOGOS MOBILE 71


Uma operação similar ao duplo-clique seria o "tap", ou a batida rápida na tela de
toque. É possível capturar a quantidade de toques rápidos com o uso da propriedade
tapCount, da classe Touch. Em alguns dispositivos é possível medir a pressão dessa
batida, o que é refletido na propriedade pressure da mesma classe.

Em termos de interface de usuário, o teclado touch aparece automaticamente para o


uso de elementos GUI quando são tocados. Na versão atual, ao tocar os componentes
GUI.TextField, GUI.TextArea e GUI.PasswordField, será apresentado esse
teclado.

O teclado de dispositivos Android, iOS e Windows Phone também é acessado por


TouchScreenKeyboard.

public class ExampleClass : MonoBehaviour {


public string inputText = "text";
private TouchScreenKeyboard keyboard;
void OnGUI() {
if (GUI.Button(new Rect(0, 10, 200, 32), inputText))
keyboard = TouchScreenKeyboard.Open(inputText);
if (keyboard != null)
inputText = keyboard.text;
}
}
DESENVOLVIMENTO DE JOGOS MOBILE 72
Além do suporte ao toque nativo, a Unity 3D para iOS e Android fornece uma
simulação de mouse. Basta utilizar a funcionalidade do mouse a partir da classe de
entrada padrão (Input).

Essa opção é interessante apenas para desenvolvimento e testes, mas o sugerido é


que seja utilizado o acesso direto à entrada por toque, já que ocorrem situações de
múltiplos toques e outras em que o movimento não é similar ao do mouse.

Outra característica muito comum em SmartPhones é a possibilidade de utilização


de GPS. É importante testar se a opção de localização está ativada no dispositivo móvel
antes de utilizar essa funcionalidade.

Através da classe LocationService, a engine possibilita trabalhar com todos os


passos envolvidos na captura e utilização da localização, sendo o acesso ao GPS padrão
feito por Input.location. O serviço de localização deve ser iniciado, caso esteja
disponível.

if (Input.location.isEnabledByUser)
Input.location.Start();

Vários dados podem ser obtidos após ativar o serviço, sendo o acesso feito diretamente
a partir de Input.location.

print("Dados: " + Input.location.lastData.latitude + " " +


Input.location.lastData.longitude + " " +
Input.location.lastData.altitude + " " +
Input.location.lastData.horizontalAccuracy + " "+
Input.location.lastData.timestamp);

Alguns dispositivos trazem uma bússola interna, a qual pode ser acessada por
Input.compass, objeto da classe Compass.

DESENVOLVIMENTO DE JOGOS MOBILE 73


function Update () {
// Código para que o objeto aponte para o norte
transform.rotation = Quaternion.Euler(0,
-Input.compass.magneticHeading, 0);
}

Em termos de desenvolvimento para dispositivos móveis, é importante conhecer a


orientação do dispositivo, principalmente quando tratamos de elementos gráficos,
como os jogos.

A classe DeviceOrientation fornece as informações necessárias, como retrato


(Portrait e PortraitUpsideDown), paisagem (LandScapeLeft e
LandScapeRight), além de face para cima ou para baixo (FaceUp e FaceDown).

O acesso aos valores corrente de orientação do dispositivo é feito por


Input.deviceOrientation.

public class ExampleClass : MonoBehaviour {


AudioSource audio;
void Start() {
audio = GetComponent<AudioSource>();
}
void Update() {
if (Input.deviceOrientation == DeviceOrientation.FaceDown)
audio.Play();
}
}

DESENVOLVIMENTO DE JOGOS MOBILE 74


Algumas classes da Unity 3D são voltadas exclusivamente para a plataforma Android:

AndroidInput – suporte ao toque de tela off-screen.


AndroidJavaClass – representação de java.lang.Class.
AndroidJavaObject – representação de java.lang.Object.
AndroidJavaProxy – interfaceamento do Java com C#.
AndroidJNI – permite o uso de Android JNI.
AndroidJNIHelper – classe de auxílio para Android JNI.

Otimizações para Ambientes Móveis


Como os dispositivos móveis apresentam menor poder computacional que plataformas
desktop e consoles, otimizações na utilização de recursos podem melhorar de forma
acentuada a jogabilidade.

Normalmente o maior problema é encontrado no dispêndio de recursos com os Assets,


em geral. Por exemplo, texturas muito grandes não devem ser utilizadas.

Outro ponto a ser observado é a metodologia de compressão utilizada, devendo


ocorrer um balanceamento entre espaço e velocidade de descompressão. As texturas
devem ser pequenas e precisam utilizar algum tipo de compressão.

Outro elemento que deve ser desabilitado, se possível, são os mipmaps, os quais
tratam da mesma imagem em diferentes resoluções, técnica voltada para o aumento
da velocidade de rendering.

Nos modelos 3D é interessante utilizar compressão de malha, e não utilizar Rigs


onde não for realmente necessário.

Em qualquer situação é interessante evitar operações de escrita e leitura


desnecessárias, fazendo sempre um balanceamento entre o uso de memória e o
armazenamento no dispositivo nas diversas operações.

DESENVOLVIMENTO DE JOGOS MOBILE 75


Em termos de áudio, para iOS deve ser utilizado MP3, enquanto Android trabalha
melhor com compressão Vorbis. Deve ser garantido um baixo bitrate, e utilizada a
opção "Force Mono" para dispositivos móveis.

Além dos Assets, deve ocorrer uma preocupação também com relação ao
processamento e uso de memória pelos scripts, devendo sempre ser reutilizados os
objetos que forem possíveis, por exemplo. Várias técnicas podem ser exploradas nesse
contexto, mas levando sempre a um estudo acerca de algoritmos e uso de memória
com objetos e variáveis.

Jogo de Exemplo 1

O primeiro jogo de exemplo utilizado é um projeto 2D no estilo Flappy Birds, sem


um final definido, e com o único objetivo de acumular pontos. É utilizado o
sombreamento cartoon e são aproveitados os recursos da física 2D proporcionados
pela Unity 3D, e outro elemento interessante é o uso de pooling na geração de
obstáculos.

Esse exemplo está disponível no endereço:


https://unity3d.com/pt/learn/tutorials/topics/2d-game-creation/project-
goals?playlist=17093

DESENVOLVIMENTO DE JOGOS MOBILE 76


Os sprites e fontes podem ser obtidos no endereço:
http://bit.ly/flappybirdstyle

Além dos recursos utilizados no tutorial original, será demonstrado como pode ser feito
o acréscimo de sons ao jogo.

Inicialmente deverá ser criado um projeto 2D, sem acréscimo de qualquer Asset
Package opcional. O nome adotado para o projeto do jogo de exemplo será
FlappyBirdStyle.

Os Assets obtidos em http://bit.ly/flappybirdstyle deverão ser extraídos e copiados


para o diretório Assets do novo projeto. Na pasta Sprites estarão os arquivos PNG que
serão utilizados como base dos sprites do jogo.

A visualização do modo 2D é baseada em uma câmera ortográfica frontal, o que a


torna ideal para a exibição de imagens no plano. Quando se trabalha nesse modo, são
utilizadas imagens pré-renderizadas, ao contrário do modo 3D, onde o rendering
ocorre em tempo de jogo.

É comum trabalhar com várias camadas sobrepostas em modo 2D, e essas camadas
podem ser observadas mais facilmente chaveando para 3D. A alternância entre a
visualização 2D e 3D é obtida dcom o botão 2D, localizado na parte superior da Scene
View.

Jogos 2D são vistos em um plano, e não no espaço, como ocorre nos jogos 3D, e para
efetuar a sobreposição de elementos em um jogo 2D, o uso de camadas é um recurso
de grande relevância.

Os personagens e animações são baseados em figuras planas, sendo muito utilizados


os sprites com animações quadro-a-quadro, e o cenário de um jogo desse tipo

DESENVOLVIMENTO DE JOGOS MOBILE 77


também é constituído de figuras 2D, podendo ser usado o efeito de paralaxe para
simulação de profundidade.

As operações de I/O são muito dispendiosas para qualquer dispositivo. Como os sprites
são constituídos de várias figuras, haveria um grande custo computacional para a
obtenção de arquivos individuais, e a solução é a criação de um arquivo denominado
Sprite Sheet, ou atlas, que reúne todas as figuras, reduzindo o número de operações.

Tecnicamente, para a Unity 3D os sprites são um tipo de textura utilizado pelo


framework de construção 2D. Essas texturas são baseadas, preferencialmente, em
figuras no formato PNG, e devem ser adicionadas aos Assets do projeto, podendo ser
organizadas em subdiretórios de interesse.

Qualquer imagem adicionada ao projeto é considerada como uma textura pela Unity
3D, e para que seja classificada como sprite, a propriedade Texture Type deve estar
como Sprite (2D and UI).

Tendo configurado a textura como Sprite, o próximo passo é a configuração do Sprite


Mode, que pode ser Single ou Multiple.

No modo Single o sprite é considerado como uma figura única e estática, sendo
normalmente utilizada na concepção do cenário.

DESENVOLVIMENTO DE JOGOS MOBILE 78


Com o uso de Multiple, o sprite pode ser dividido em áreas menores, permitindo a
típica animação quadro-a-quadro dos sprites clássicos.

Quando o formato de sprite é definido para a textura no Inspector, torna-se possível


efetuar seus ajustes pelo Sprite Editor, acessível a partir do botão Sprite Editor, que
fica disponível para esse tipo de textura no próprio Inspector.

O principal uso do Sprite Editor é para a divisão do Sprite Sheet nas figuras parciais
para animação quadro-a-quadro. Através da opção Slice é muito simples efetuar a
divisão, ou fatiamento, do Sprite Sheet original.

Após efetuar a divisão nos quadros constituintes, estes ficam acessíveis na área dos
Assets do projeto, e basta selecionar os quadros desejados e arrastar para a Scene
View para que sejam criados a animação e o controle de estados de forma
automática.

DESENVOLVIMENTO DE JOGOS MOBILE 79


Voltando para o jogo de exemplo, na pasta Sprites estarão os arquivos PNG que
serão utilizados como base dos sprites utilizados no jogo. Como o projeto é do tipo
2D, esses arquivos serão importados automaticamente como texturas do tipo Sprite
(2D and UI) no modo Single.

Quatro arquivos estarão disponíveis: BirdHero (jogador), ColumnSprite


(obstáculo), GrassThinSprite e SkyTileSprite. Apenas BirdHero irá precisar de
edição, pois os demais sprites do jogo são estáticos.

O sprite BirdHero deverá ser configurado como Multiple, sendo aberto o Sprite
Editor em seguida. Na janela do Sprite Editor será utilizada a opção Slice e selecionado
Type Automatic e, ao sair dessa janela, serão gerados BirdHero_0, BirdHero_1
e BirdHero_2.

DESENVOLVIMENTO DE JOGOS MOBILE 80


Agora BirdHero_0 pode ser arrastado para a janela Hierarchy, instanciando o objeto
na cena, na posição da origem, devendo ser renomeado para Bird no Inspector.

Em seguida GrassThinSprit será adicionado à cena da mesma forma. Como ficará


sobreposto a Bird, esse novo objeto deverá ser movido para o fundo, o que irá alterar
o valor de Y no Transform de Inspector para algo em torno de -2.6.

O componente GrassThinSprite receberá SkyTileSprite como dependente, e será


renomeado para Ground na janela Inspector, sendo também adotado o nome
SkyBackground para o objeto SkyTileSprite.

Para resolver a sobreposição efetuada pelo SkyBackground, serão utilizadas Sorting


Layers. Serão criadas, na ordem: Background, Midground e Foreground.

O objetivo de uma Sorting Layer é funcionar como uma camada de ordenação para o
desenho dos objetos, trazendo a noção de profundidade ao ambiente 2D.

O objeto SkyBackground utilizará a camada Background, enquanto Bird e Ground serão


associados à camada Foreground.

DESENVOLVIMENTO DE JOGOS MOBILE 81


Com Bird selecionado, deve ser aberta a janela Animation, e criada uma nova
animação chamada Idle que, por questões de organização, deve ser salva em um
diretório Animation, dentro de Assets.

Como resultado dessa última operação, serão geradas a animação Idle e a máquina
de estados Bird no novo diretório, além de um componente Animator, na lista de
propriedade do Sprite Bird, relacionando-o com a nova máquina de estados.

Ainda na janela Animation, deverá ser adicionada a propriedade Sprite, a partir de


Sprite Renderer.

Serão geradas duas chaves de animação com Bird, mas como Idle representa o
pássaro parado, a segunda chave deve ser excluída. A chave restante pode ser copiada

DESENVOLVIMENTO DE JOGOS MOBILE 82


com CTRL+C, e deve ser gerada uma segunda animação, clicando em Idle e
escolhendo Create New Clip.

Essa segunda animação estará no mesmo diretório da primeira e se chamará Flap.


Com a animação Flap ativa, basta colar a chave copiada anteriormente com CTRL+V.

Com o botão de gravação ativado (círculo vermelho), deve ser escolhido o sprite
BirdHero_1 entre os Assets, e arrastado para a propriedade Sprite do Sprite
Renderer de Bird, a qual deverá estar com fundo vermelho.

Outra animação deverá ser criada (Die), e esta seguirá o mesmo processo anterior,
porém com o uso de BirdHero_2.

As animações serão representadas por uma FSM no Animator de forma automática.


Nessa janela deverão ser adicionadas as Triggers de nomes Flap e Die.

Será criada uma transição de Idle para Die, condicionada à ocorrência da Trigger Die
e sem Exit Time. Da mesma forma, será criada uma transição para Flap condicionada
à Trigger Flap e sem Exit Time. Por fim deverá ser criada uma transição de Flap para
Idle sem condicionais ou quaisquer configurações adicionais.

DESENVOLVIMENTO DE JOGOS MOBILE 83


O primeiro passo no uso da física 2D será o acréscimo de um Rigidbody 2D ao Bird,
tornando possível controlar o movimento do pássaro baseado nas forças aplicadas a
ele, as quais atuarão em sentido contrário à gravidade. Com essa operação inicial, ao
acionar o Game Play, o pássaro cairá indefinidamente, justamente por causa da ação
da gravidade.

Qualquer colisão do pássaro, com o solo ou obstáculos, levará ao fim do jogo, logo, é
necessário definir os colisores dos diversos sprites utilizados.

Para Bird será utilizado um PolygonCollider2D, pois trará uma envoltória mais
detalhada para o sprite. No solo (Ground) será utilizado um BoxCollider2D, mas
exigirá a sua edição. Como Ground é baseado em um PNG, o colisor do tipo Box
envolve toda a figura, inclusive a parte transparente, devendo ser ajustado apenas
para a parte visível.

A edição do colisor é iniciada com o clique no botão Edit Collider, sendo as


modificações efetuadas na Scene View, onde o colisor aparece como um contorno
verde.

DESENVOLVIMENTO DE JOGOS MOBILE 84


O acréscimo e configuração dos colisores fará com que o corpo rígido deixe de cair
indefinidamente, interrompendo sua queda ao tocar o solo. A colisão básica está
definida, mas é necessário programar o comportamento de Bird para que ele consiga
se sustentar no ar a partir de comandos do jogador.

Nesse jogo de exemplo será utilizado o toque rápido de tela (tap) para imprimir força
vertical ascendente ao pássaro, de forma a "combater" a ação da gravidade e evitar
que ele chegue a tocar o solo.

Deverá ser adicionado um Script C#, nomeado como "Bird", ao sprite de mesmo nome,
e programado o evento Update para captura dos comandos e aplicação da força
vertical.

Será criado um atributo interno "isDead", que indicará o fim de jogo por causa da
ocorrência de uma colisão. Também será utilizada uma propriedade "upForce",
indicando a intensidade da força aplicada verticalmente a cada ocorrência de "tap" do
jogador.

Inicialmente o Script deverá ter as variáveis de controle e captura dos componentes


de interesse.

DESENVOLVIMENTO DE JOGOS MOBILE 85


public float upForce = 200f;
private bool isDead = false;
private Rigidbody2D rb2d;
private Animator anim;
void Start () {
rb2d = GetComponent<Rigidbody2D> ();
anim = GetComponent<Animator> ();
}

O movimento será executado a partir do toque rápido na tela, ou "tap", e as animações


deverão estar em sincronia com os estados do pássaro durante o jogo.

void Update () {
if (isDead == false) {
if (Input.touchCount == 1)
for(int i = 0; i < Input.GetTouch(0).tapCount; i++) {
rb2d.velocity = Vector2.zero;
rb2d.AddForce(new Vector2(0,upForce));
anim.SetTrigger("Flap");
}
}
}

A colisão irá determinar o fim de jogo.

void OnCollisionEnter2D () {
isDead = true;
anim.SetTrigger("Die");
}

DESENVOLVIMENTO DE JOGOS MOBILE 86


Até esse ponto é possível sustentar o pássaro no ar com toques rápidos de tela, e
quando os toques não ocorrerem na frequência necessária ele cairá e morrerá na
colisão com o solo.

Com relação ao HUD, esse jogo de exemplo apresenta informações muito simples,
incluindo apenas a pontuação, atualizada via programação, e a mensagem de fim de
jogo. Essas informações serão exibidas em modo texto, utilizando uma fonte
personalizada, no caso a LuckiestGuy, presente entre os Assets do projeto, com
tamanho 32.

Incialmente é adicionado o componente UI do tipo Text que será nomeado como


ScoreText, lembrando que será necessário um bom nível de zoom para a manipulação
visual do componente. O componente ScoreText será ancorado na parte central
inferior do Canvas.

Outro componente de texto, denominado GameOverText, pode ser criado por


duplicação para aproveitar as configurações já feitas anteriormente. Esse novo
componente utilizará um tamanho de fonte maior, e trará a mensagem "Game Over",
ficando posicionado e ancorado ao topo.

Por fim, outro componente de texto será adicionado como filho de GameOverText,
utilizando fonte um pouco menor e com a mensagem "Flap to Restart".

Como resultado final, os componentes utilizados no HUD do jogo de exemplo


apresentarão a mensagem de fim de jogo ao topo e a pontuação ao fundo.

DESENVOLVIMENTO DE JOGOS MOBILE 87


Como a mensagem de "Game Over" deve ser exibida somente ao final do jogo, ela
deverá ser desativada no Inspector, e devido à existência de uma relação de
hierarquia, a desativação de GameOverText desativa também "Flap to Restart". A
reativação ocorrerá via programação, da mesma forma que a atualização da pontuação
no decorrer do jogo.

Nesse ponto é necessário criar um Controlador para o jogo, o qual servirá de gestor
global do projeto.

O controlador de jogo será responsável por intermediar os diversos aspectos do jogo


e personagens envolvidos. Características como pontuação e variáveis de ambiente
deverão estar presentes nesse controlador.

Para iniciar a sua criação, deverá ser adicionado à cena um Game Object do tipo
Empty com o nome GameController, e a esse objeto será adicionado um script com
o mesmo nome.

Deverá existir um acesso global ao controlador de jogo, o que é obtido por uma
instância estática e a programação correta do método Awake.

DESENVOLVIMENTO DE JOGOS MOBILE 88


public static GameController instance;

void Awake () {
if (instance == null)
instance = this;
else if (instance != this)
Destroy (gameObject);
}

A primeira função do controlador é o reconhecimento do final do jogo, com a exibição


da mensagem de "Game Over" e o controle de entrada para a execução do reinício.

A programação do fim do jogo será através do método BirdDied, e será necessário


associar a propriedade gameOverText com o Text correspondente no Inspector.

Além da criação de BirdDied, o método Update deverá reconhecer o toque de tela


para reinício do jogo, onde ocorre a recarga da cena, mas apenas no estado de fim de
jogo.

public GameObject gameOverText;


public bool gameOver = false;
public void BirdDied () {
gameOverText.SetActive (true);
DESENVOLVIMENTO DE JOGOS MOBILE 89
gameOver = true;
}
void Update () {
if (gameOver == true && Input.touchCount == 1)
Application.LoadLevel ("Main");
}

O método BirdDied deverá ser chamado ao final da detecção de colisão do script


Bird.

void OnCollisionEnter2D () {
isDead = true;
anim.SetTrigger("Die");
GameController.instance.BirdDied ();
}

Estando o controle de finalização pronto, será necessária agora a movimentação do


fundo, e para que ocorra, deverá ser adicionado a Ground um Rigidbody 2D do tipo
Kinematic.

Após essa operação, o próximo passo no objeto Ground é a criação e acréscimo do


script ScrollingObject, o qual será responsável por imprimir uma velocidade
horizontal constante para o fundo. Essa velocidade será negativa, de forma a trazer a
ilusão de que o pássaro está se movendo para a frente.

DESENVOLVIMENTO DE JOGOS MOBILE 90


O uso do corpo rígido, no passo anterior, servirá para imprimir uma velocidade
constante ao fundo, sem a necessidade de programar qualquer tipo de cálculo.

public float scrollSpeed = -1.5f;


private Rigidbody2D rb2d;

void Start () {
rb2d = GetComponent<Rigidbody2D> ();
rb2d.velocity = new Vector2 (scrollSpeed, 0);
}

void Update () {
if (GameController.instance.gameOver)
rb2d.velocity = Vector2.zero;
}

Com a adoção desse script o fundo irá se mover, mas irá desaparecer da tela após
algum tempo.

Para resolver esse problema deverá ser feita a repetição do fundo, o que implica na
cópia de Ground, seguida do agrupamento das duas instâncias sob um novo Game
Object do tipo Empty, o qual será nomeado Scenery.

Scenery deverá ser colocado na posição de origem (0,0,0) antes do agrupamento, e


será utilizado apenas por questão de organização, pois os scripts estão associados aos
objetos internos (Ground e Ground2).

DESENVOLVIMENTO DE JOGOS MOBILE 91


A nova instância do fundo (Ground2) deve ser movida na horizontal até se ajustar ao
final da primeira, dando a impressão de continuidade.

Deverá ser criado o script RepeatingBackground, o qual será associado a Ground


e Ground2. Esse script moverá a instância corrente para o final da outra quando a
primeira estiver fora de alcance.

private float groundLength;


void Start () {
groundLength = GetComponent<BoxCollider2D> ().size.x;
}
void Update () {
if (transform.position.x < -groundLength) {
Vector2 offset = new Vector2(groundLength*2f,0);
transform.position = (Vector2) transform.position + offset;
}
}

O próximo passo é a geração de obstáculos, para os quais deverão ser utilizados dois
objetos ColumnSprite, ajustados corretamente via rotação e translação, e com Box
Collider 2D.

DESENVOLVIMENTO DE JOGOS MOBILE 92


Esses dois sprites serão agrupados sob um Empty Object chamado Columns, o
qual terá um Box Collider 2D marcado como Triggered, e um pouco deslocado em
relação às colunas. Ao final será possível observar o conjunto de colisores na cor
verde.

Também será necessário um Rigidbody 2D do tipo Kinematic no objeto Columns,


e todo o conjunto estará na camada Midground, o que fará com que seja escondido
pelo solo, mas fique à frente das nuvens.

DESENVOLVIMENTO DE JOGOS MOBILE 93


A manutenção da pontuação deverá ser adicionada ao script GameController, e a
propriedade scoreText deverá ser associada ao objeto Text de pontuação presente
na cena.

private int score = 0;


public Text scoreText;

public void BirdScored(){


if (!gameOver) {
score++;
scoreText.text = "Score: "+score;
}
}

No objeto Columns deverá ser adicionado ScrollingObject, além de um novo script


chamado Column. Esse segundo script deverá verificar a passagem pela área de
colisão do objeto Columns, indicando que o pássaro passou entre as pilastras e a
pontuação deve ser atualizada.

public class Column : MonoBehaviour {

private void OnTriggerEnter2D (Collider2D other){


if (other.GetComponent<Bird> () != null)
GameController.instance.BirdScored ();
}

Após efetuar todas essas operações, deve ser criado um diretório Prefabs nos Assets,
e arrastado o objeto Columns para esse novo diretório. Será gerado um Prefab, ou

DESENVOLVIMENTO DE JOGOS MOBILE 94


objeto pré-fabricado, o qual é reutilizado no jogo, podendo ser excluído o objeto
original.

Os obstáculos deverão ser gerados de forma dinâmica e posicionados aleatoriamente,


o que exigirá instanciar esse Prefab via programação, e para tal um novo script será
adicionado ao objeto GameController, recebendo o nome ColumnPool, de forma a
efetuar essa geração com uso de pool de objetos. Esse script apresenta muitas
variáveis de controle.

public int columnPoolSize = 5;


public GameObject columnPrefab;
public float spawnRate = 4f, columnMin = -1f, columnMax = 3.5f;
private GameObject[ ] columns;
private Vector2 objectPoolPosition = new Vector2 (-15f, -25f);
private float timeSinceLastSpawned = 0;
private float spawnXPosition = 10f;
private int currentColumn = 0;

No método Start deve ser alocado o pool de colunas, e para que funcione
corretamente, o Prefab Columns deve ser arrastado a partir de Assets para a
propriedade columnPrefab do script, no Inspector.

void Start () {
columns = new GameObject[ columnPoolSize ];
for (int i=0; i<columnPoolSize; i++)
columns [i] = (GameObject)
Instantiate (columnPrefab, objectPoolPosition,
Quaternion.identity);
}

DESENVOLVIMENTO DE JOGOS MOBILE 95


A palavra spawn, no jargão de jogos, se refere à geração de elementos no decorrer
do jogo, o que é feito nesse exemplo por um pool para reutilização de objetos.

No método Update deve ser atualizada a posição da coluna corrente no tempo indicado
por spawnRate, e a classe Random permite a escolha de uma posição vertical
aleatória para a coluna que irá ser modificada.

timeSinceLastSpawned += Time.deltaTime;
if (!GameController.instance.gameOver &&
timeSinceLastSpawned >= spawnRate) {
timeSinceLastSpawned = 0;
float spawnYPosition = Random.Range(columnMin,columnMax);
columns[currentColumn].transform.position =
new Vector2(spawnXPosition,spawnYPosition);
currentColumn++;
if(currentColumn>=columnPoolSize)
currentColumn = 0;
}

Nesse ponto o jogo está totalmente funcional, sendo possível trabalhar com facilidade
a parte de áudio. O controle de recursos sonoros na Unity 3D apresenta características
muito avançadas, como som 3D e componentes de mixagem, mas para um jogo
voltado para a plataforma móvel basta utilizar os elementos básicos.

Inicialmente deve ser criada uma pasta Sound em Assets para receber os arquivos de
áudio, e para o som ambiente será adicionado um Audio Source na cena, setando
Audio Clip para um arquivo OGG ou MP3 que deverá ficar na nova pasta.

Não é necessário um mixer, sendo a saída voltada de forma automática para o Audio
Listener associado à Main Camera, e as propriedades Loop e Play on Awake
deverão ser marcadas.

DESENVOLVIMENTO DE JOGOS MOBILE 96


Deverá ser adicionado outro Audio Source, mas dependente do Game Object Bird,
tendo como Audio Clip outro arquivo MP3 ou OGG com propriedades Loop e Play on
Awake desmarcadas, sendo reconhecido no método Start do script Bird.

private AudioSource audioQuack;


void Start () {
audioQuack = GetComponentInChildren<AudioSource> ();

O script de Bird será modificado para incluir esse reconhecimento no Start, bem como,
ao final do método Update, após a linha anim.SetTrigger("Flap"), será adicionada a
linha audioQuack.play( ), fazendo com que o som seja ativado a cada toque de tela.

Com esses últimos passos, o jogo encontra-se completo e sonorizado, transmitindo


uma sensação de imersão ainda mais completa para o jogador.

Jogo de Exemplo 2
O segundo jogo de exemplo trata de um jogo de nave, e segue passos muito próximos
aos do primeiro exemplo. Inicialmente é necessário criar um projeto 2D chamado
JogoNave, e adicionar alguns PNGs no diretório Sprites.

DESENVOLVIMENTO DE JOGOS MOBILE 97


Nave Inimiga Explosão

Mísseis

Jogador

Nesse segundo exemplo, vários SpriteSheets utilizarão o Sprite Editor, sendo


normalmente feita a divisão através do modo automático, mas podendo ser manual
quando as bordas ficam muito próximas e geram erros. Apenas a nave inimiga não
terá animação, para os sprites de exemplo.

Começando com a configuração da nave do jogador, ela deve trabalhar com uma
máquina de estados e animações adequadas. Inicialmente deve ser configurada como
Multiple e feita a divisão pelo Sprite Editor, obtendo três instantes da nave:
inclinando à direita, inclinando à esquerda e centralizada.

DESENVOLVIMENTO DE JOGOS MOBILE 98


O sprite que representa a nave centralizada deve ser arrastado para a cena, sendo
renomeado em seguida para Nave, e seguindo os mesmos passos de Bird, no
exemplo anterior, serão criadas as animações de estado.

Com Nave selecionada, deve ser aberta a janela Animation, e criada uma nova
animação chamada Centro que, por questões de organização, deve ser salva em um
diretório Animation, dentro de Assets.

Ainda na janela Animation, deverá ser adicionada a propriedade Sprite, a partir de


Sprite Renderer, e serão geradas duas chaves de animação com Nave, sendo que a
segunda deve ser excluída. A chave restante pode ser copiada com CTRL+C, e deve
ser gerada uma segunda animação, clicando em Centro e escolhendo Create New
Clip.

Essa segunda animação estará no mesmo diretório da primeira e se chamará


Esquerda. Com a animação Esquerda ativa, basta colar a chave copiada anteriormente
com CTRL+V, e mudar o sprite corrente para a imagem que representa a nave
inclinada para a esquerda.

O mesmo processo deve ser feito para criar a animação Direita, com a nave inclinando
para a direita, e com as três animações criadas, deve ser configurada a FSM através
do Animator.

DESENVOLVIMENTO DE JOGOS MOBILE 99


Serão criadas as Triggers Direita, Esquerda e Centro, e haverá transações de Any
State para cada estado, condicionadas sempre às triggers de mesmo nome.

Em seguida, deve ser adicionado à nave um Rigidbody 2D, marcado como Fixed
Angle, arraste linear 10 e escala de gravidade zero, além de acrescentar também um
Polygon Collider 2D.

Estando configuradas as características da Nave, o sprite da nave inimiga, que será


Single, poderá ser arrastado para a cena e renomeado para Inimigo. A ele será
adicionado o Circle Collider 2D, devidamente ajustado ao formato da nave, podendo
ser utilizado outro colisor, dependendo do formato de nave utilizado, além de um
Rigidbody 2D sob ação da gravidade, de forma que a nave inimiga desça de forma
automática pela tela.

DESENVOLVIMENTO DE JOGOS MOBILE 100


O sprite da explosão deverá ser Multiple, editado com corte automático, e
simplesmente gerado com o arraste de todos os quadros para a tela, o que irá gerar
a animação da explosão e o controlador, ambos salvos no diretório Animations.

Esse objeto deverá ser renomeado para Explosao, e a animação deverá ter
desmarcada a opção Loop Time, pois ela não deve se repetir.

Os mísseis também utilizarão modo Multiple, porém precisam do Loop Time, pois
a animação, nesse caso, repete-se. Como a figura utilizada aqui tem o míssil na
horizontal, ele será arrastado para a cena e rotacionado de 90° no eixo Z, sendo
renomeado para Missil, e representando o tiro da Nave.

O objeto Missil utilizará um Rigidbody 2D do tipo Kinematic e um Box Collider


2D.

DESENVOLVIMENTO DE JOGOS MOBILE 101


Para o tiro do inimigo, será copiado o objeto Missil, renomeado para MissilInimigo,
e alterada a rotação para 270°.

Após esses passos, podem ser adicionados os recursos de áudio do jogo. Nesse caso,
o som será proveniente apenas dos mísseis e das explosões.

Em Missil e MissilInimigo serão acrescentados componentes Audio Source, com


Audio Clip apontando para um mesmo MP3 de lançamento de míssil, com Play on
Awake marcado e Loop desmarcado. Essa configuração fará com que, ao surgir, o
barulho seja emitido apenas uma vez, como no lançamento de um míssil real.

A mesma configuração será adotada para o Audio Source adicionado ao objeto


Explosao, mas claro que com um MP3 com som de uma explosão.

Com os objetos definidos, pode ser iniciada a programação C#. Inicialmente


acrescentamos um script de nome Explosao ao objeto Explosao, com o único
objetivo de destruir o Game Object após seu uso.

DESENVOLVIMENTO DE JOGOS MOBILE 102


public class Explosao : MonoBehaviour {
float tempo;
void Start () {
tempo = 0;
}
void Update () {
tempo += Time.deltaTime;
if (tempo > 2)
Destroy (gameObject);
}
}

Para os próximos passos será necessário o reconhecimento simples dos Game Objects
envolvidos, e isso é obtido com o uso de Tags.

As tags serão utilizadas da seguinte forma: Nave e Inimigo recebem tags com seus
mesmos nomes, enquanto Missil recebe a tag Tiro, e MissilInimigo recebe a tag
TiroInimigo. A escolha da tag é feita pelo Object Inspector, e o uso dessas tags
permitirá reconhecer de forma muito simples os objetos que colidiram no evento
OnCollisionEnter2D.

Definidas as tags, o próximo script que deve ser implementado é MissilScript,


utilizado por Missil e MissilInimigo. Esse script aplica uma velocidade constante ao

DESENVOLVIMENTO DE JOGOS MOBILE 103


míssil no método Start, e faz a remoção da sua memória quando atinge os limites de
tela ou ocorre o fim de jogo, a partir de Update.

public class MissilScript : MonoBehaviour {


public float velocidade = 3;
Rigidbody2D rb2d;
void Start ( ) {
rb2d = GetComponent<Rigidbody2D> ();
if (gameObject.tag == "TiroInimigo")
velocidade *= -1;
rb2d.velocity = new Vector2 (0, velocidade);
}
void Update( ) {
if (rb2d.position.y>6 || rb2d.position.y<-6||
Controlador.instance.gameOver)
Destroy (gameObject);
}
}

Apenas observando que, apesar de não ter sido criado ainda o controlador de jogo, a
sua propriedade gameOver representará o fim do jogo.

O início da programação do controlador envolve a definição de muitas variáveis de


controle e uma instância global estática.

public class Controlador : MonoBehaviour {


public float spawnRate = 4f;
public float posMin = -3.8f;
public float posMax = 3.8f;
public GameObject inimigo;
private float timeSinceLastSpawned = 0;

DESENVOLVIMENTO DE JOGOS MOBILE 104


private float spawnY = 6f;
public bool gameOver = false;
public Text scoreText;
public GameObject gameOverText;
public static Controlador instance;
private int pontos = 0;

void Awake () {
if (instance == null)
instance = this;
else if (instance != this)
Destroy (gameObject);
}

public void Score( ) {


pontos++;
scoreText.text = "Score: " + pontos;
}

Será fácil observar uma grande semelhança, nesse início, com o controlador utilizado
no Jogo de Exemplo 1 – Flapp Bird Style. No entanto, esse controlador também
faz o spawn das naves inimigas, mas da mesma forma que no primeiro exemplo,
devem ser configuradas as propriedades do script pelo Inspector, a partir do objeto
Controlador, definindo o scoreText e o gameOverText, além do inimigo. Esses
elementos estarão prontos para uso em passos posteriores.

void Start () {
GerarInimigo ();
}
void Update () {
if (gameOver) {

DESENVOLVIMENTO DE JOGOS MOBILE 105


gameOverText.SetActive(true);
if(Input.touchCount == 1)
Application.LoadLevel("Main");
} else {
timeSinceLastSpawned += Time.deltaTime;
if (timeSinceLastSpawned >= spawnRate) {
timeSinceLastSpawned = 0;
GerarInimigo ();
}
}
}
public void GerarInimigo ( ) {
float spawnX = Random.Range(posMin,posMax);
Vector3 posicao = new Vector3(spawnX,spawnY,0);
Instantiate (inimigo,posicao,(Quaternion)
inimigo.transform.rotation);
}
}

A funcionalidade desse controlador envolve, portanto, chamadas ao método


GerarInimigo, o qual instancia uma nova nave inimiga, a partir da propriedade
inimigo, a primeira no Start, e as demais no Update, de acordo com o intervalo de
geração, e antes do gameOver.
Para complementar a configuração do controlador será necessário criar o HUD e
definir os PreFabs, o que será feito posteriormente.

A programação do Inimigo envolve o reconhecimento de que o objeto Nave está na


mira para efetuar o tiro, o que pode ser feito com LineCast ou RayCast de forma
muito simples. Não há preocupação quanto à movimentação da nave inimiga já que
ela sofrerá o efeito da gravidade.

DESENVOLVIMENTO DE JOGOS MOBILE 106


public class Inimigo : MonoBehaviour {
public GameObject explosao;
public GameObject tiro;
Rigidbody2D rb2d;

void Start () {
rb2d = GetComponent<Rigidbody2D> ();
}

void Update () {
if ((rb2d.position.y < -6)||(Controlador.instance.gameOver)) {
Destroy (gameObject);
return;
}
Vector3 origem = transform.position;
origem.y -= 2f;
RaycastHit2D alvo=Physics2D.Raycast(origem, -Vector2.up);
if (alvo.collider != null) {
if (alvo.collider.gameObject.tag == "Nave")
Atirar ();
}
}

O método Update também faz a remoção da nave inimiga da memória quando ela
passa pelo extremo inferior do jogo, não tendo mais chance de colisão com o objeto
Nave, ou quando ocorre o fim do jogo.

O método Atirar deve instanciar um tiro, no caso representado pelo MissilInimigo,


e colocá-lo na posição inicial e rotação corretos. A partir daí o próprio míssil se move
de forma autônoma por seu script.

DESENVOLVIMENTO DE JOGOS MOBILE 107


void Atirar( ) {
Vector3 posicao = (Vector3) transform.position;
posicao.y -= 2f;
Instantiate (tiro,posicao,
(Quaternion)tiro.transform.rotation);
}

Finalmente, na ocorrência de colisão, deve ser testado pela tag se o que colidiu foi
um tiro do objeto Nave e, sendo verdade, instanciar a explosão, aumentar o score, e
remover da memória tanto o tiro quanto a nave inimiga atingida.

void OnCollisionEnter2D(Collision2D coll) {


if (coll.gameObject.tag == "Tiro") {
Destroy (coll.gameObject);
Instantiate(explosao,transform.position,
Quaternion.identity);
Destroy (gameObject);
Controlador.instance.Score( );
}
}
}

O script de Inimigo deve estar em plena sincronia com o de Nave. A preocupação


inicial do script de Nave é detectar as entradas do jogador e efetuar os movimentos
relacionados.

Inicialmente, como sempre, são definidas as variáveis necessárias, componentes


associados, e a inicialização pelo Start. Como Nave utiliza diferentes estados de
animação, de acordo com o movimento efetuado, o Animator deverá refletir esses
movimentos.

DESENVOLVIMENTO DE JOGOS MOBILE 108


public class Nave : MonoBehaviour {
public float force = 50f;
public RuntimeAnimatorController explosao;
private Animator anim;
private Rigidbody2D rb2d;
public GameObject tiro;
void Start () {
anim = GetComponent<Animator> ();
rb2d = GetComponent<Rigidbody2D> ();
}

Na colisão deve ser testado se a tag é "Inimigo" ou "TiroInimigo", pois ambos


determinam o fim do jogo. A animação de explosão é instanciada no local, e o objeto
que colidiu deve ser removido.

void OnCollisionEnter2D(Collision2D coll) {


if ((coll.gameObject.tag == "TiroInimigo") ||
(coll.gameObject.tag == "Inimigo")) {
Controlador.instance.gameOver = true;
Destroy (coll.gameObject);
anim.runtimeAnimatorController = Instantiate(explosao);
}
}
O método mais complexo é o Update, pois além de tratar dos movimentos e
animações associadas, deve garantir que não ocorra arraste vertical quando forem
colocados limites laterais no jogo.

void Update () {
if (Controlador.instance.gameOver )
return;
if (transform.position.y != -3.7f) {

DESENVOLVIMENTO DE JOGOS MOBILE 109


// Impede arraste vertical da Nave
Vector3 posicao = transform.position;
posicao.y = -3.7f;
transform.position = posicao;
}
if (Input.acceleration.x > 0) {
anim.SetTrigger ("Direita");
rb2d.AddForce (new Vector2 (force, 0));
} else if (Input.acceleration.x < 0) {
anim.SetTrigger ("Esquerda");
rb2d.AddForce (new Vector2 (-force, 0));
} else
anim.SetTrigger ("Centro");
if ( Input.touchCount == 1 ) {
Vector3 posicao = (Vector3) transform.position;
posicao.y += 1.4f;
Instantiate (tiro,posicao,
(Quaternion)tiro.transform.rotation);
}
}
}

Neste ponto podem ser criadas as Sorting Layers, assumindo os mesmos valores do
primeiro exemplo: Background, Midground e Foreground.

Os objetos Nave e Inimigo ficarão na Foreground, enquanto Missil, MissilInimigo


e Explosao ficarão na Midground. A camada Background será reservada ao fundo
que será adicionado posteriormente.

Após a configuração dessas camadas, os objetos Explosao, Missil, MissilInimigo devem


ser transformados em três PreFabs, sendo removidos da cena em seguida.

DESENVOLVIMENTO DE JOGOS MOBILE 110


No objeto Nave, o PreFab Missil deve ser associado à propriedade tiro do script,
enquanto no objeto Inimigo, o PreFab MissilInimigo é associado ao tiro. Em ambos
os objetos, o PreFab Explosao é associado à propriedade explosao nos respectivos
scripts.

Com mais essa configuração, Inimigo deve ser transformado em PreFab e removido
da cena. O controlador será configurado em seguida, recebendo como a propriedade
inimigo do script o PreFab Inimigo.

Ao final de mais esse passo, restará apenas a Nave visível na cena, e deve ser
adicionado o fundo, de forma similar ao primeiro exemplo, porém com movimentação
vertical. Para a definição do fundo é utilizado mais um arquivo PNG.

Para o fundo escolhido deve ser aplicada uma rotação de 90°. Talvez haja a
necessidade de escalonar os demais objetos para que se tornem proporcionais ao
fundo, ou escalonar o próprio fundo, de forma a gerar uma boa área de movimentação
para a Nave.

Também devem ser adicionados dois Box Collider 2D, editados para que fique um
em cada lateral do fundo, com o objetivo de limitar a movimentação da Nave. Os
colisores utilizados aparecerão na cor verde com a opção Edit Collider. Também
será adicionado um Rigidbody 2D do tipo Kinematic.

DESENVOLVIMENTO DE JOGOS MOBILE 111


Para que não fique sobreposto à nave, deve ser escolhida a camada Background
para o novo sprite adicionado, o qual também será renomeado para Fundo na cena.

Como foi feito no primeiro exemplo, o fundo deverá ser duplicado e a cópia (Fundo1)
movida, agora na vertical até o topo do original, de forma a transmitir a sensação de
continuidade. Apenas por questão de organização, esses dois componentes serão
agrupados sob um novo Empty Object de nome Cenario.

Para que ocorra o movimento correto, dois scripts devem ser utilizados em Fundo e
Fundo1: ScrollBackground, responsável pela rolagem do componente, e
RepeatBackground, para transmitir a sensação de repetição do fundo.

O script ScrollBackground apenas controla a velocidade de rolagem vertical, sendo


definida por scrollSpeed, ou paralisa o fundo ao determinar velocidade zero, na
ocorrência de fim de jogo.

public float scrollSpeed = -1.5f;


private Rigidbody2D rb2d;
void Start () {

DESENVOLVIMENTO DE JOGOS MOBILE 112


rb2d = GetComponent<Rigidbody2D> ();
rb2d.velocity = new Vector2 (0, scrollSpeed);
}
void Update () {
if (Controlador.instance.gameOver)
rb2d.velocity = Vector2.zero;
}

O script RepeatBackground move o componente de fundo para a posicaoInicial


definida quando este se torna fora de alcance, garantindo a repetição do fundo de
forma cíclica.

private float posicaoInicial = 32;


void Update () {
if (transform.position.y < -posicaoInicial) {
Vector2 offset = new Vector2(0,posicaoInicial*2);
transform.position = (Vector2) transform.position + offset;
}
}

Com o comportamento do background definido, pode ser iniciado o design do HUD,


que contará apenas com dois componentes UI do tipo Text, os quais serão nomeados
como ScoreText e GameOverText. Ambos os componentes utilizarão fonte Arial de
tamanho 36, sendo aplicada a cor azul para ScoreText e amarela para
GameOverText.

DESENVOLVIMENTO DE JOGOS MOBILE 113


O componente GameOverText deve ser desabilitado no Inspector, pois só deverá
ser exibido no momento correto, ao fim do jogo, e ScoreText será atualizado a partir
do método Score. Em ambos os casos as operações são efetuadas pelo script do
Controlador.

As propriedades ScoreText e GameOverText do script do Controlador devem ser


configuradas para utilizar os componentes ScoreText e GameOverText da cena.

Completando esses passos, o jogo estará completo e poderá ser testado, apresentando
como resultado final as telas abaixo para as figuras PNG utilizadas.

DESENVOLVIMENTO DE JOGOS MOBILE 114


BIBLIOGRAFIA

DUNN, F.; PARBERRY, I. 3D Math primer for graphics and game development. Texas:
Wordware Publishing, 2002.

FERGUSON, J.; PATTERSON, B.; BERES, J.; BOUTQUIN, P.; GUPTA, M. C# bible.,
Indiana: Wiley, 2002.

GOLDSTONE, W. Unity 3.x game development essentials. s/l: Packt Publishing Ltd,
2011.

GREGORY, J. Game engine architecture. s/l: AK Peters, 2009.

HARBOUR, J. S. Advanced 2D game development. 1. ed. s/l: Course Technology PTR.,


2008.

LEMES, D. O. Games independentes. São Paulo: PUC-SP, 2009.

MENARD, M. Game development with Unity. Cengage Learning, 2011.

SAINT-VICTOR, M.; OPAL, D. Professional unity and C#: multi-platform 3D game


development. s/l: Wiley, 2011.

DESENVOLVIMENTO DE JOGOS MOBILE 115


SEIDELIN, J. HTML5 games: creating fun with HTML5, CSS3, and WebGL. 1. ed. s/l:
Wiley, 2011.

DESENVOLVIMENTO DE JOGOS MOBILE 116

Anda mungkin juga menyukai