segunda-feira, 8 de julho de 2013

Level Design - Sistema de Criação do Conceito das Fases

Olá pessoal!

Hoje estarei falando sobre como elaborei um esquema no Corel PhotoPaint para a criação livre do Level Design de nosso jogo.

Aprofundando o tópico anterior (visualize aqui), para a criação de um novo labirinto, em código são necessários os seguintes passos:

a) Criar uma nova Classe de estrutura de Levels com o nome correspondendo do mesmo
b) No construtor da classe configurar o Level atual com: Assets(Fundo e Música),  posição inicial da bolinha, tempo de duração da fase, próxima fase a ser chamada e máximo de letras coletáveis.
b) No método “initWall()” criar a wall desejado na lista de walls

Ex :
      //Linha 1
      size.set(360,60); // (Largura do retângulo X altura)
      position.set(0,120); // (posição em x e y do inicio do retângulo)

Assim, optamos por uma tela de 480 x 800, que nos permitiu criar um padrão de retângulos que tem como base um quadrado de 60 x 60.

(Figura 1: Exemplo de conceito - Fase 2)

Com essa decisão tomada pensei em um esquema para facilitar a visualização das fases antes de passa-las para o código, além de permitir que qualquer pessoa faça um labirinto sem precisar se preocupar com fatores técnicos.

Observe a  Figura 1, é um png com o conceito do labirinto feito no Corel PhotoPaint, para chegar nele, em uma imagem 480x800 fiz uma grade com tamanho de 60 x 60 e verifiquei onde haveriam cortes de quadrados, como se pode observar na parte amarela, posicionei essas sobras de acordo com a HUD que iremos utilizar e o restante preenchi com quadrados de 60x60 em azul na mesma camada lado a lado, o que possibilita usar o balde de tinta para preencher os quadrados que deseja que sejam paredes, cor preta no exemplo. Em seguida, fiz novos quadrados 60x60 cada um em uma camada para poder verificar a posição x e y correspondentes ao quadrado selecionado, e é está posição que utilizo no código:

Ex:
            position.set(0,120); // (posição em x e y do inicio do retângulo)
           
        Já a largura e altura dos parâmetros size.set são correspondentes a quantidade de quadrados na horizontal ou vertical.           

      Ex: de retângulo horizontal formado por 2 quadrados

size.set(120,60); // (Largura do retângulo x altura)

           
      Ex: de retângulo vertical formado por 3 quadrados

size.set(60,180); // (Largura do retângulo x altura)


Para finalizar temos a legenda na Figura 2 com os demais elementos:

(Figura 2: Legenda de elementos do editor de fases)

E é este o esquema para criar as fases que utilizamos, graficamente qualquer um pode elaborar sua fase sem se preocupar com os aspectos técnicos em um primeiro momento, e no mesmo projeto obter as informações necessárias para a montagem dos labirintos em código.

sexta-feira, 7 de dezembro de 2012

Learning Exploder - Cultura Religiosa (parte 3)


Olá pessoal!

Hoje estarei falando dos aspectos gráficos do jogo "Learnig Exploder"  na sua versão de Cultura Religiosa e os melhoramentos e modificações para contribuir com a temática de religiões.

Menu: Optei e em utilizar uma cor roxa no fundo, fortemente relacionada com a espiritualidade e ainda faz maior contraste com o amarelo do logotipo e acrescentei sutilmente os símbolos das religiões destacadas em nossos estudos na disciplina de Cultura Religiosa, que são: Budismo, Cristianismo, Hinduísmo, Islamismo e Judaísmo. Os botões(sendo acrescentado o de HELP na ultima versão), o simbolo central e o logotipo permaneceram os mesmos, acrescentando apenas uma retângulo simples com uma cor que lembra pergaminho, para destacar a versão de Cultura Religiosa.

Figura 1 - Menu


Help: Na janela de Help temos o "Como Jogar" que ilustra o uso do acelerômetro para movimentar a bolinha pelos labirintos das fases e a função de pausar o jogo usando o toque de dois dedos na tela. Também temos a informação de que o botão BACK retorna as telas ou sai do jogo na tela principal, deixando o botão Back da página de Help como o próprio asset das explicações.

Figura 2 - Tela de Help/Ajuda

Loading: Modifiquei a cor do fundo dos Créditos(ver adiante) e um sprite de Loading, que por hora estamos usando apenas eles estático.

Figura 3 - Tela de Loading

Fundos Introdução/Transição de Fases: Cada fase possui uma tela de introdução com uma imagem de acordo a respectiva religião, um símbolo no canto superior direito e uma pequena descrição. O mesmo fundo é utilizado na fase correspondente, sem a parte escrita.

Figura 4 - Tela de Introdução do Budismo

Figura 5 - Tela de Introdução do Judaísmo

Figura 6 - Tela de Introdução do Islamismo

Figura 7 - Tela de Introdução do Cristianismo

Figura 8 - Tela de Introdução do Hinduísmo
A tela de créditos terá os dados do curso e das disciplinas a qual apresentaremos o jogo, para essa versão fiz uma esquema de montagem do fundo do menu e seus elementos, mais os símbolos entrelaçados na tela.





É isso ai. Até a próxima!

PS: As imagens sobre as religiões nessa versão são edições de figuras retiradas da internet as quais não identifiquei o autor(a) original, bem como as músicas temáticas. Estaremos trabalhando em nossas próprias versões com base nas referências atuais.

Learning Exploder - Cultura Religiosa (parte 2)


Olá a todos!!!

Neste post estarei descrevendo como funciona o jogo Learning Exploder - Cultura Religiosa. Infelizmente, não consegui gravar um vídeo do jogo devido à péssima qualidade do emulador (Google, espero que estejam cientes que seu emulador é muito ruim). Também, não consegui gravar a tela do jogo no tablet.

O jogo é dividido entre:
  • Tela de Introdução (mostra a logo da equipe);
  • Tela de Menu;
  • Tela de Ajuda (descreve como o jogo deve ser jogado);
  • Tela de Créditos;

Cada Level é precedido por uma tela de introdução que explica o desafio. No caso dessa versão, as telas descrevem um breve texto sobre a religião, com uma música e um background relacionados. Assim, o jogador deve descobrir nesse tempo qual religião o contexto se trata e buscar as letras no cenário.

O jogo possui um total de 5 fases e, portanto, 5 religiões contextualizadas. O download do jogo poder ser realizado neste link.

Imagens:

MENU

HELP

PRIMEIRA FASE DO JOGO

CRÉDITOS

TELA DE INTRODUÇÃO DA PRIMEIRA FASE


A interface de Level Design do Learning Exploder (parte 1)

Olá a todos!!!

Neste post, estarei descrevendo como funciona a interface de Level Design do jogo Learning Exploder - Cultura Religiosa, que também funciona totalmente com o Learning Exploder com desafios em inglês.

Já foi comentado em posts anteriores a respeito da engine programada usando a Android SDK para o game. No entanto essa engine não deu conta de todo o processo de desenvolvimento do jogo em si e com a programação de duas versões. Além disso, precisávamos de uma maneira mais dinâmica para a criação do Level Design.

Assim, surgiu a LEengine para suprir essas necessidades. Essa engine da suporte a todas as principais funcionalidades do jogo. São interfaces de suporte a todas as telas do jogo, às intros de cada level, com quatro efeitos de transição diferentes. Além disso, a engine cuida dos principais detalhes de colisão, controle de level (o jogador finalizou o level? o jogador errou?), dentre outras coisas.

Assim, o Level Designer possui apenas o trabalho de definir as imagens e música que ele deseja para cada tela (a de intro de cada level, game over, background das fases, ...), inserir as paredes, o comportamento da colisão e os coletáveis.

Mais detalhes sobre a parte de programação do editor podem ser vistas aqui.

SEE YOU NEXT MISSION

quinta-feira, 6 de dezembro de 2012

Learning Exploder - Cultura Religiosa (Parte 1)

Olá a todos!!!

Estamos chegando ao fim do Quarto Período. Muita coisa rolou entre o início e o fim dos projetos. Começamos com a ideia do Learning Exploder como um jogo parecido com o Ceramic Destroyer. Mas acabamos mudando de ideia devido à disciplina de Programação de Jogos para Dispositivos Móveis não cobrir o conteúdo de OpenGL ES, sendo que o jogo já roda usando formatos de colisão simples e abusando das estratégias de otimização de código em alguns celulares Android.

Em seguida, partimos para a ideia de um jogo educacional com o mesmo nome, mas com a mecânica utilizando o acelerômetro. O resultado inicial de desenvolvimento pode ser visto aqui. Esta versão ainda  estava bastante incompleta, mas os aspectos gerais do jogo ja podem ser percebidos. Para jogar a versão do jogo, baixe este arquivo apk e instale no seu Android.

O objetivo educativo do jogo é aumentar o acervo de palavras conhecidas pelos estudantes de inglês. O jogo consiste em visualizar uma imagem, pergunta ou ouvir um som, e em seguida percorrer a fase para pegar as letras em ordem para formar a palavra. Caso o jogador não termine de coletar no tempo limite, o cenário "explode", justificando assim o título do jogo.

Essa versão vem se aproximando de seu auge, porém a entrega completa não será possível, devido mais à ausência de tempo para a construção do Level Design do que à programação em si.

No entanto, nem tudo esta perdido. Esta versão acabou não ficando pronta devido a outra que programamos visando a disciplina de Cultura Religiosa do curso. O jogo segue a mesma temática, com a diferença de que cada level desafia o jogador a descobrir qual religião esta escondida nas letras do cenário. Cada introdução que antecede a fase contém uma breve descrição do que é a religião, um fundo com uma imagem e a música, e assim cabe ao jogador decifrar qual religião o contexto se trata.

Essa versão esta completa e uma review estará disponível nos próximos posts. Até lá...

SEE YOU NEXT MISSION

terça-feira, 27 de novembro de 2012

ARC - Automatic Reference Counting

Olá a todos!!!

Este será meu último post a respeito da linguagem Objective-C e as peculiaridades do desenvolvimento  geral para plataformas IOS e Mac OS X. Alias, a partir de agora, focarei somente nas especificações referentes à plataforma IOS que é o foco deste blog. Então vamos lá!!!

Não poderia começar a falar do ambiente de desenvolvimento IOS sem dizer nada sobre a mais nova forma de gerenciar memória automaticamente: o Automatic Reference Counting (ARC).

O IOS 5 trouxe uma forma mais prática de se trabalhar com a memória. Isso porque o novo compilador consegue detectar com grande precisão os potenciais problemas de memória que existem no programa. Este compilador (LLVM 3.0) está disponível a partir do Xcode 4.2.

Na prática, assim como nas aplicações usando Garbage Collector, não precisamos mais chamar os métodos release, autorelease e retain (estes métodos se tornam inclusive depreciados na SDK 5). Além disso, a partir do Mac OS X 10.8 (Mountain Lion), o ARC se tornou também o modelo padrão de desenvolvimento das aplicações para Mac.

Outros recursos que deixaram de ser usados foram: NSZone, retainCount, [super dealloc], @selector(retain), @selector(release).

Com relação ao dealloc, devemos passar a nos preocupar apenas com a anulação dos ponteiros. A desalocação de memória passa a ser função do ARC. Também usando ARC, qualquer variável ponteiro é inicializada automaticamente com nil.

Apesar das inúmeras vantagens, tornou-se mais difícil sincronizar os códigos em Objective-C com C/C++.

Para códigos legados, o Xcode 4 auxilia o processo de conversão do projeto para a SDK 5 (em edit > refactor > "Convert to Obj-C ARC").

Da mesma forma que no Garbage Collector, algumas classes podem não funcionar com o ARC, cabendo a nós fazermos o gerenciamento manual. Nesse caso, devemos sinalizar o compilador para não usar ARC nos devidos arquivos. Em Propriedades(clique no projeto) > Build Phases > Compile Sources > (duplo clique na classe) insira a tag -fno-obj-arc.

Para usar ARC, basta criar um projeto com essa opção marcada (desde que seu Xcode suporte a funcionalidade). Já para desabilitar totalmente, basta procurar nas propriedades do projeto no LLVM Compiler X.X - LANGUAGE a opção "Automatic Reference Counting" e mudar de yes para no.

Para mais informações a respeito do ARC, leia este artigo oficial. Outro artigo interessante que recomendo é este daqui.

USANDO PROPRIEDADES COM O ARC:

@property(weak) MyClass *myObj;

NSString __weak *string;

A forma como trabalhamos com propriedades também mudou com os novos atributos strong e weak. O strong tem a mesma função que o retain e é definido por padrão às variáveis e propriedades, já o weak é bem semelhante ao assign com a diferença de que, quando o objeto é desalocado, a propriedade é definida para nil (nulo em Objective-C).

Utilizar o weak é essencial para evitarmos que os objetos que não estão sendo mais usados continuem sendo apontados por um strong pointer.

No caso das variáveis, os Lifetime Qualifiers, como são chamados estes atributos, possuem pequenas diferenças e alguns novos tipos:

  • __strong: É o default. O objeto permanecerá vivo enquanto houver sendo apontado por um strong pointer.
  • __weak: Significa que o ponteiro em questão não mantém o objeto vivo (o mesmo é setado para nil quando o objeto for desalocado).
  • __unsafe_unretained: Especifica que este ponteiro não manterá o objeto vivo (como em strong) e nem será setado para nil quando o mesmo deixar de existir (como em weak).
  • __autoreleasing: Com este lifetime qualifier, o objeto liberará a memória utilizada para armazenar um objeto passado como parâmetro para um método assim que ele é retornado. Em resumo, garante que dentro da execução do método o objeto vai estar disponível, mas só durante esse período.
Para mais informações a respeito dos Lifetime Qualifiers, recomendo este artigo.

Isso é tudo. Espero que tenha sido de boa utilidade, e não deixem de comentar!

Até a próxima...

O Garbage Collector

Olá a todos!!!

Neste post irei dar uma visão geral a respeito do Garbage Collector a fim de dar uma introdução a próximo tópico em que estarei falando sobre o gerenciamento de memória no IOS 5 e 6. Vamos lá!

A partir da versão 10.5 do Mac OS X (Leopard), introduziu-se o Garbage Collector a fim de facilitar o gerenciamento de memória das aplicações. Esse gerenciador não chegou a ser portado para as plataformas IOS e se tornou depreciado na versão 10.8 (Mountain Lion). Ou seja, não existe motivos para investir no aprendizado do Garbage Collector a não ser que você esteja mirando desenvolver usando o Sistema Operacional Leopard, Snow Leopard ou Lion.

Usando o Garbage Collector, podemos avisar ao compilador os momentos certos para recolhimento do lixo (collectIfNeeded) ou obriga-lo a remover todo o conteúdo que não esta sendo usado (collectExhaustively). 

Outra preocupação da ferramenta envolve intensidade da varredura na memória. Para tal, podemos setar a varredura para focar nas variáveis que foram criadas mais recentemente (generational ou local) ou para varrer a memória toda (full).

O Garbage Collector ainda oferece maneiras de se trabalhar com gerenciamento de memória automático  para a linguagem C e Core Foundation.

Ao invés de usarmos dealloc, passamos a trabalhar com finalize. O mesmo acontece na chamada do método da classe pai dentro da implementação ([super finalize] ao invés de [super dealloc]). Assim como no Java, não é certo o momento em que o compilador irá chamar o finalize, então esse método não é muito utlizado em aplicações que utilizam o Garbage Collector.

Com relação às propriedades e variáveis, deixamos de lado o retain, release e autorelease, e passamos a chamar strong e weak. Estarei explicando no próximo post como funcionam estes novos estados.

Podemos ter ainda classes que não suportam, exijam ou suportam o Garbage Collector. Para definir tal propriedade, marcamos nas propriedades do projeto as classes que queremos que exijam, aceitem ou não suportem tal funcionalidade. Normalmente, o que define se uma Framework ou classe não suporta Garbage Collector é se a mesma implementa ou não o método finalize.

A classe responsável por dar suporte ao GC é a NSGarbageCollector.

Bem, isso é tudo. No próximo post estaremos vendo o método de gerenciamento de memória automático que veio para substituir o Garbage Collector e o gerenciamento de memória manual para aplicativos Apple tanto para IOS como para Mac OS X. 

SEE YOU NEXT MISSION

As propriedades no Objective-C

Olá a todos!!!

Talvez um assunto que tenha ficado meio obscuro nas última postagens diga respeito às propriedades. E realmente, entender todas as formas de declaração destas não é algo tão trivial em Objective-C.

As propriedades foram criadas no Objective-C 2.0 e possuem como sintaxe básica a declaração da propriedade no .h e a sua sintetização no .m


Dessa forma já é possível ter métodos getter e setter adequados para a maioria dos casos, mas não todos. Assim, criaram-se atributos para as propriedades que sinalizam como o código da @property deverá ser gerado.


É importante ressaltar que é possível inserir qualquer quantidade de número de atributos de propriedade, bastando inserir uma vírgula entre elas. Além disso, qualquer um desses estados podem ser implementados manualmente. Os atributos para a propriedade possíveis são:

  • @property(getter = nomeVar)
    • Informamos aqui qual será o método em questão que será o getter;
    • Lembre-se de implementar em seu getter todos os comportamentos que você inseriu na assinatura de sua @property.
    • Pela convenção do Objective-C, getters devem possuir o mesmo nome da variável se o prefixo get.
  • @property(setter = setNomeVar)
    • Informamos aqui qual será o método em questão que será o setter.
  • @property(readwrite)
    • A propriedade, por padrão, já vem definida com esse estado. Isso diz à propriedade que ela irá ser LIDA e SOBRESCRITA.
  • @property(readonly)
    • A propriedade pode apenas ser lida e não sobrescrita, ou seja, o usuário terá acesso somente ao GETTER.
  • @property(assign)
    • A propriedade, por padrão, já vem definida com esse estado. Este define, basicamente, que o setter será apenas uma atribuição da variável recebida na variável da instância.
  • @property(retain)
    • Marcar a propriedade com retain significa que a instância recebida em SETTER terá seu retain count incrementado em 1, ou seja, tomaremos posse do objeto atribuído;
    • Em 95% que estamos recebendo uma referência, implementamos esse estado na propriedade.
  • @property(copy)
    • Estabelecemos nesse caso que faremos uma cópia do objeto atribuído no SETTER.
  • @property(atomic)
    • A propriedade, por padrão, já vem definida com esse estado. Quando uma property esta definida como atomic, seu getter e setter serão implementados levando em consideração um ambiente multithread. Ou seja, possuirão mutexes que impedirão leitura e escrita mútua pelas threads por meio da directiva @synchronize.
  • @property(nonatomic)
    • Marcamos a propriedade com esse estado quando não queremos que ela possua mutexes que evitem leitura e escrita mútua. É certo marcar a property com esse atributo quando temos certeza que nossa classe não será utilizada em um ambiente multithread.

Além das configurações mencionadas, ainda podemos configurar o nosso @synthesize. Observe:

  • @synthesize varName = _varName
    • Quando a propriedade não possui o mesmo nome da variável, devemos realizar essa operação, onde varName é o nome da propriedade e _varName é o nome da variável.
  • @dynamic
    • Usamos esta directiva no lugar de @synthesize quando queremos que a nossa propriedade aponte para os métodos GETTER e SETTER de uma superclasse. Na prática, evita Warnings do compilador. Para saber mais, leia este artigo;
    • Em geral, as configurações do @dynamic são idênticas ao @synthesize.

Neste post fico por aqui. Até a próxima!

Visão geral do Objective-C

Olá caro leitor!

No post anterior, vimos como funcionam os principais conceitos relacionados ao gerenciamento de memória manual no Objective-C. Felizmente tudo o que é mais difícil de ser entendido sobre esse assunto já foi comentado.

Vamos agora estudar alguns exemplos básicos em Objective-C, para, mais tarde entendermos os últimos tópicos de gerenciamento de memória. Estes exemplos são uma continuidade de algumas aulas ministradas por Vitor Carreira, do Instituto Politécnico de Leiria, em Portugal.

Os programas a seguir foram compilados usando o Xcode 4.5.2 e Objective-C 2.0, portanto, usando o compilador que suporta @autoreleasepool. Caso você esteja programando em um Mac OS X Snow Leopard ou inferior (que ao menos suporte Objective-C 2.0), trate de remover esses blocos e substituir pelo clássico NSAutoReleasePool.

O primeiro exemplo trata da utilização básica de classes em Objective-C.

Observe que os objetos são instanciados chamando-se alloc seguido de init:

Fraction *f1 = [[Fraction alloc] init];

Assim, a chamada de métodos em Objective-C ocorre por meio de COLCHETES. Observe também que alloc e init são métodos da classe, pois estão sendo chamados através de Fraction. Dessa forma, existem diferenças na implementação de variáveis e métodos de instância e de classe.

[f2 setNumerator:3 andDenominator:4];

Nesse caso acima, estamos chamando um método da instância f2. Observe a assinatura do método:

- (void)setNumerator:(int)n andDenominator:(int)d;

O sinal (-) avisa ao compilador que o método pertence à instância. Em seguida, temos o tipo de retorno (void), e os nomes das mensagens com os respectivos parâmetros a serem recebidos. Observe que, diferentemente do C++, aqui declaramos dois nomes para cada parâmetro a ser recebido.



Acima podemos visualizar toda a declaração do header file. Primeiro, definimos as variáveis de instância da classe dentro do bloco. Em seguida, definimos propriedades para essas variáveis (semelhantes às do C#), as quais criarão métodos get e set automáticos.

Toda a declaração do .h acontece dentro de uma @interface e @end. Da mesma forma, toda a declaração do .m acontece dentre @implementation e @end.

Observe que a classe em questão é filha de NSObject. Muitos métodos são gerados automaticamente para nós através dessa classe. Podemos sobrescrevê-los, como é o caso do init no .m

Para gerar os getters e setters no .m, devemos chamar @synthesize:

@synthesize numerator;
@synthesize denominator;

O exemplo ainda conta com uma classe denominada de MyClass que demonstra como criamos métodos de classe (com sinal de +), variáveis de classe públicas e privadas, e variáveis de instância publicas, privadas e protegidas.




O segundo exemplo é uma continuação do primeiro, mas demonstra como criarmos Convenience Constructors. É importante ressaltar que o init com mais número de parâmetros sempre deverá ser o Designated Initializer, ou seja, o método responsável pela iniciação da classe pai:




Observe que os método description implementado no .m não possui assinatura no .h. Isso significa que este é um método que esta sendo sobrecarregado da classe pai. O compilador assim irá executar as operações polimórficas para descobrir qual foi a implementação mais próxima da última classe da hierarquia e irá executá-la. Caso não encontre, dispara uma exceção.



Observe que no método multiply, chamamos o método alloc. Então somos responsáveis por remover o conteúdo da memória. Como isso não é viável no momento, chamamos o autorelease. Assim, a referência será desalocada junto com a @autoreleasepool.

No terceiro exemplo, demonstro como utilizar a NSMutableDictionary e NSDate da rica Framework Foundation, além de dar exemplos sobre como criar métodos privados e protocolos (o mesmo que interfaces em java e C#). É importante ressaltar que não existe uma maneira de declarar métodos protected em Objective-C

Além disso, mostro como funciona o uso de foreach em Objective-C, e maneiras de melhor gerenciar a memória usando propriedades, apresentando também um novo método da NSObject chamado de dealloc. Este método equivale aos destrutores do C++. Aqui, devemos chamar o release de tudo que criamos no escopo da instância. É importante ressaltar que, pela documentação, o método dealloc JAMAIS deve ser chamado no código, sendo uma tarefa do compilador chamá-lo no momento mais adequado.

Bem, por hora é só. Para mais informações a respeito dos conteúdos abordados aqui, consulte esse resumão oficial da Apple sobre a linguagem.

Até a próxima!

O Gerenciamento de Memória Manual no Objective-C

Olá a todos!!!

Toda essa introdução e cronologia que apresentei foram exclusivamente realizadas para que entendamos o assunto mais macabro referente à linguagem Objective-C: Seu gerenciamento de memória.

A evolução do gerenciamento de memória no Objective-C acompanha os avanços das Frameworks e plataformas da Apple. Sabemos que quando estamos trabalhando nessa linguagem, podemos chegar a ter de trabalhar com o gerenciamento de memória singular das linguagens C e C++ de bibliotecas que venhamos a utilizar. Portanto são 3 linguagens não gerenciadas que devemos tratar de maneira correta para não termos problemas de Memory Leak ou Dangling Pointers no código.

As versões anteriores do Mac OS X 10.5 possuíam gerenciamento de memória manual assim como no C e C++. Essa realidade também se tornou constante nas plataformas IOS até a versão 5.

No caso do Objective-C, todas as classes devem, direta ou indiretamente, herdar de NSObject da Foundation para ter acesso aos métodos de gerência manual de memória. O que acontece na prática, é que cada objeto criado na memória que é filho de NSObject incrementa um contador denominado de Reference Count/Retain Count.

Para alocarmos um objeto na memória, usamos os métodos alloc e copy. Ambos criam o objeto, mas o segundo serve especialmente para criarmos uma cópia de um outro objeto. Da mesma forma, para desalocarmos, chamamos o método release do objeto em questão.

Na prática, alloc e copy incrementam o contador, e release decrementa. Quando o contador chegar a zero, o objeto se torna imediatamente inválido (isso não significa que será imediatamente desalocado, mas mesmo assim perdemos o acesso ao mesmo).

Se você entendeu até aqui, podemos ir para o passo 2 e mais importante com relação ao gerenciamento de memória manual no Objective-C. A fim de gerar boas práticas de programação na linguagem e facilitar o desenvolvimento, criaram-se convenções que estabelecem que:
  1. Somos responsáveis por chamar o método release dos objetos que criamos com os operadores: alloc e copy já mencionados, e os operadores new (responsável por chamar o alloc e o "construtor default" do objeto num comando só) e mutableCopy.
  2. Não somos responsáveis por desalocar da memória os objetos que criamos por meio de Factory Methods que, no Objective-C, são chamados de Convenience Constructors. Um exemplo de tais métodos são os da classe NSString que nos retornam uma NSString alocada e não necessitamos fazer chamada a alloc, copy, new ou mutableCopy.
Um guia completo sobre gerenciamento de memória manual pode ser encontrado aqui. A documentação da Apple é um guia excelente que deve ser usado abusivamente.

Até aqui, entendemos que devemos chamar release dos objetos que criamos usando os métodos já referidos. Isso significa dizer que quando temos a POSSE DO OBJETO devemos desalocá-lo.

Sendo assim, temos o caso em que podemos receber um objeto por referência e desejarmos manter a referência sobre o objeto ORIGINAL na classe, ou seja, sem utilizar copy. Para tal, chamamos o método retain do objeto. Esse irá incrementar em 1 a referência do objeto em questão (o que não ocorreria com copy, aonde criamos uma nova instância e, portanto, um novo retain count).

E no caso em que criamos os nossos próprios Convenience Constructors? Se somos responsáveis pela remoção do objeto da memória nesse caso, como a faremos?

Esse é o ponto em questão que devemos nos focar para entender de vez o gerenciamento de memória manual. Para gerar o release dos objetos criados em um Convenience Constructor, chamamos antes de retornar o objeto no método (ou seja, antes do fim do escopo) o método autorelease. Basicamente, este método dirá ao compilador que desejamos decrementar o retain count desse objeto mais tarde. Mas quando seria esse mais tarde?

Ai é que entram as AutoReleasePools. Toda a vez que o método autorelease for chamado, uma referência desse objeto será adicionada à ÚLTIMA AUTORELEASEPOOL CRIADA.

Vamos ver um exemplo em código:


Assim, todo código que estiver entre uma NSAutoreleasePool e [pool drain] que tiver um objeto chamando o método autorelease, uma referência desse objeto será adicionada à pilha. Quando o método drain for chamado, um release para cada referência dentro da pilha será chamado. Portanto, não há garantias que o objeto continue válido após o fim do escopo de uma NSAutoreleasePool.

É importante notar que no caso de NSAutoreleasePools jamais chamamos o método release!!! Devemos em vés disso chamar o método drain, que se assegurará de dar release nas referências de objetos e na pilha em questão.

Nas novas versões do Xcode (a partir da 4.2), com o novo compilador (LLVM 3.0), os projetos já suportam blocos de @autoreleasepool. Segundo a documentação, eles são mais rápidos e trabalham melhor com o novo modelo de gerenciamento de memória (o qual será comentado no próximo post). Ou seja, o código demonstrado abaixo realiza a mesma coisa que o anterior, mas é o novo padrão da Apple que deve ser seguido:


Um último tópico a ser destacado a respeito das @autoreleasepool é com relação ao momento em que se justifica a criação de uma pool. Observe a seguir os momentos em que devemos realizar tal ação:
  1. Se estivermos a desenvolver uma aplicação que não se baseia no Application Kit (o Application Kit instancia automaticamente uma pool no início de cada ciclo de eventos). Um caso desse tipo de aplicação são as criadas sobre o template Command Line Tool;
  2. Se um determinado ciclo de código gera muitos objetos temporários instanciados de um Convenience Constructor;
  3. Se criarmos uma thread secundária (cada thread deve possuir sua própria @autoreleasepool).

Ufaaa!!! Por hora é só. No próximo post, irei demonstrar as principais features da linguagem, concatenando com todos os conceitos aqui apresentados. Se você ainda não entendeu, não se preocupe. Esse é o ponto que irá te retirar no estágio larval em Objective-C para o estágio Newbie...

Até lá...

Curiosidades sobre a Apple

Bom Dia!

Neste post estarei trazendo algumas curiosidades a fim de nos interarmos ainda mais nos acontecimentos que tornaram o ambiente de desenvolvimento das plataformas Apple da maneira como vemos hoje. Perceberemos também que Steve Jobs inferiu indiretamente na indústria de games com algumas ações que realizou durante o tempo que trabalhou em sua empresa NeXT.


A respeito do Macintosh:
  • O Mac OS 8 foi o primeiro Mac a usar processadores Power PC. Seu SO era chamado de Copland e foi lançado para competir com o Windows 95 e 98 da Microsoft. Teve releases de 1997 a 1999 e nesse tempo deu-se origem aos iBooks (em 1999). Foi nessa versão também que deu-se origem à API Carbon.

  • O Mac OS 9 foi o último da linha clássica de Macs. Surgiu em 1999 e tornou-se obsoleto em 2002.

  • O Mac OS 10.3 foi o último a usar processadores Power PC. A partir dai, a maioria das aplicações clássicas se tornaram obsoletas.

  • O primeiro iMac surgiu em 1998 e incorporava o Mac OS 8. Foi o primeiro produto a ser prefixado com i, o qual significa individual.

  • O MacBook PRO surgiu em 2006 substituindo as linhas anteriores de notebook da Apple (Power Book e iBook).

A respeito de Steve Jobs:
  • Steve Jobs fundou a Apple em 1975 com Wozniac e lá permaneceu por 10 anos. Antes disso ele havia trabalhado com seu parceiro criando circuitos eletrônicos e, pouco antes de fundarem a empresa, na Atari, onde inclusive teve a oportunidade de desenvolver um Pong.

  • Os primeiros computadores lançados pela Apple foram o Apple I (sucesso de vendas), Apple II e Apple III. 

  • A partir do fracasso do Apple III, duas divisões na Apple se formaram: Uma ficou responsável pelo desenvolvimento do Apple Lisa, um computador de grande porte e potência, e a de Jobs ficou responsável pela parte que deu início ao desenvolvimento da linha Macintosh, que eram computadores que tinham o objetivo de serem de mais baixa potência e de custo baixo. No Apple Lisa e Macintosh foram criadas uma gigantesca quantidade das características que se tornaram convenções nos futuros computadores.

  • O Apple Lisa acabou se tornando um fracasso em virtude do Macintosh. Assim, criou-se uma grande rivalidade entre os dois grupos da empresa. Em meados de 1984, ambas as divisões foram reagrupadas tendo Steve como coordenador. O gênio extravagante de Jobs acabou iniciando conflitos do mesmo com a empresa, fazendo-o sair da Apple em 1985.

  • Com sua saída da Apple, Steve Jobs fundou a NeXT e trabalhou nos anos seguintes no Sistema Operacional NeXT Step. Neste computador, alguns softwares importantíssimos para a indústria de games foram desenvolvidos. São eles:
    • O primeiro Web Browser;
    • Os jogos Wolfestein 3D, Doom e Quake;

  • O NeXT Step utilizava o Objective-C como linguagem base.

  • Em 1986, Jobs compra um estúdio de Computação Gráfica que mais tarde seria chamado de Píxar, estúdio responsável por gigantes catálogos do cinema com total renderização 3D. Graças a isso, mais tarde com a compra da Píxar pela Disney, Jobs se tornaria o maior acionista individual da Disney.

  • Em 1997, a Apple compra a NeXT e Steve Jobs retorna à empresa inicialmente como consultor. No entanto, a sua genialidade acabaram por fazê-lo ocupar o cargo de CEO na empresa até o fim de sua vida. O NeXT Step e seus produtos vieram a se tornar o Mac OS X, um computador com núcleo Unix/BSD com incrível potência e capacidade, e os produtos da linha iWorks. Paralelo ao lançamento do Mac OS X veio o iPod, e então tudo veio a desencadear as grandes invenções da empresa que convivemos hoje.

Por hora é só, no próximo post estarei apresentando os conceitos relacionados ao gerenciamento de memória do Objective-C. 

Até lá!

As Frameworks da Apple

Olá a todos!!!

Neste post irei dar continuidade aos assuntos referentes ao Objective-C, Porém focando na cronologia dos ambientes de desenvolvimento oferecidos pela Apple desde muito cedo, para que entendamos como as coisas chegaram a ficar da maneira em que estão.

A primeira grande API de desenvolvimento da Macintosh considerável foi a Carbon. Esta é uma API procedural desenvolvida em C que sucedeu a Toolbox API e foi usada nas versões Mac OS 8 e 9, e nas versões do Mac OS X 32 bits anteriores à 10.8 (Mountain Lion), onde então se tornou depreciada.

A Cocoa Framework foi criada no Mac OS X 10.5 (Leopard), onde surgiram os primeiros Macs com processador 64 bits. Desde então, os desenvolvedores são encorajados a portar suas aplicações para Cocoa usando Objective-C.

Alguns programas conhecidos que usaram Carbon: Final Cut Pro (versões anteriores à X), iTunes (até a versão 10.4) e Adobe Photoshop (até Abril de 2010).

A Cocoa consistem em três Frameworks: 
  • Foundation: Contém as principais funcionalidades do Objective-C implementadas. Corresponde a todas as coleções e tipos primitivos básicos;
  • Application Kit: Representam as principais funcionalidades para se construir um App;
  • Core Data: Usado para criar-se persistências e databases.
A framework Foundation usa outra framework base conhecida como Core Foundation (CF). Esta é uma API escrita em C que possui basicamente as mesmas funcionalidades de Foundation, porém mais voltadas para aplicações multiplataforma e de mais baixo nível. Portanto, a Core Foundation é mais baixo nível que a própria Cocoa.
Muito código da Foundation usa a Core Foundation como já comentado, porém de modo menos completo. Algumas funcionalidades da CF simplesmente inexistem na Foundation.

Por hora é só!
Até mais ver...

sábado, 24 de novembro de 2012

Objective-C

Olá a todos!!!

Neste tópico irei introduzir alguns conceitos referentes à linguagem Objective-C.

O Objective-C é uma extensão da linguagem C que incorpora conceitos da linguagem Smalltalk (a primeira linguagem orientada a objetos). Sua principal diferença com relação ao C++ é que o C++ foi construído a partir da raiz incorporando conceitos de C, ou seja, não foi apenas uma extensão.

É importante ressaltar que a escolha do Objective-C pela Apple como linguagem padrão de suas plataformas não foi arbitrária, mas sim resultado do legado das bibliotecas já construídas na empresa NeXT e o SO NeXTStep, precursor do Mac OS X. Ou seja, Objective-C representa um legado mais do que uma escolha.

Assim, podemos entender por que o Objective-C e suas classes padrões da Cocoa possuem o prefíxo NS (NextStep).

Mais tarde, desenvolveu-se a versão 2.0 do Objective-C que visou acrescentar as características do Standard C99, Standard esse que visou tornar o C mais próximo do C++, porém mantendo o paradigma estrutural.

Assim, tudo o que representa uma extensão do C e, portanto, um conteúdo de Objective-C é precedido por @. Além disso, as implementações dos header files (.h) passam a ser sufixadas com .m para Objective-C (híbrido de C com as novas implementações prefixadas com @), e sufixadas com .mm para Objective-C++ (híbrido de C++ com as novas implementações prefixadas com @).

Um dos aspectos mais interessantes da linguagem Objective-C é que ela é uma linguagem compilada dinamicamente em tempo de execução. Isso significa que o Objective-C é compilado por um compilador que permite despacho dinâmico de métodos e tipos. 

Ou seja, em tempo de execução são definidos qual método corresponde à chamada do método (portanto, não existe o vínculo do objeto com a implementação, mas sim uma mensagem de um objeto para uma implementação), e qual é o tipo do objeto que estamos trabalhando. A esse conceito damos o nome de Duck Typing.
O fato de não precisarmos definir qual é o tipo de objeto, sendo o compilador inteligente o suficiente para entender qual ele é, nos da uma flexibilidade incrível para trabalhar com void pointers (chamados em Objective-C de ID), sendo muito comum, portanto, encontrarmos na Cocoa classes que recebem um ponteiro para um objeto qualquer (do tipo id) e para um método qualquer (do tipo sel - Selector, que é basicamente o mesmo que um ponteiro para uma função).

O Objective-C é também uma das linguagens precursoras do uso de interfaces (chamada na linguagem de Protocol). O java inclusive copiou a forma como Objective-C trabalha com herança (somente 1 herança por classe e sem limite de implementações de interfaces).

Por hora é só. Para mais informações sobre a linguagem, consultar o seguinte link que mostra um apanhadão do funcionamento da linguagem.

SEE YOU NEXT MISSION

O Xcode

Olá a todos!!!

Neste post irei falar sobre minhas recentes descobertas a respeito do Xcode. Devido a comentários e certas experiências prévias com esta IDE, sempre desacreditei desta ferramenta. Mas confesso hoje que o Xcode possui grande chance de se tornar uma plataforma interessante de desenvolvimento muito mais do que já é no futuro.

A primeira vantagem que elenco é que o Xcode é uma ferramenta compacta. Utilizando o design já conhecido da Apple, temos tudo o que precisamos a priori para desenvolver nas barras laterais e painel superior. O ponto negativo, por outro lado, também seria esse fator, já que muitas das funcionalidades presentes em outras IDEs inexistem no Xcode.

Uma coisa que me incomodou muito quando iniciei o desenvolvimento usando o Xcode foi a ausência de um gatilho prático para visualizar o resultado de um output. Para exibição de logs, o Xcode conta com uma barra inferior que, por algum motivo, não abre quando compilamos um projeto. Assim, logo aparece na tela que a compilação foi finalizada com sucesso, mas nenhum output é mostrado a priori. É um detalhe um tanto quanto besta e newbie, mas também por outro lado é um erro de design.

Painel Superior do Xcode com as principais opções.

Como já foi comentado acima, o Xcode é organizado em 3 barras: As duas laterais e a inferior. Esse conjunto de barras recebe o nome de Views.
  • A barra inferior mostra as informações de depuração e o output. 
  • A barra da direita mostra as propriedades do que estamos trabalhando (arquivo, imagem) e nos da acesso a ajuda rápida e aos guias de programação da Apple.
  • A barra da esquerda exibe a organização do projeto em pastas lógicas, a hierarquia das classes, erros no código e informações de depuração. Também oferece uma barra de pesquisa para localizarmos informações no código.
O Xcode também possui esquemas de visualização diferentes do editor de código. Para contextualizar, a opção central dos botões do grupo Editor do painel central exibe o .h e o .m respectivo ao  arquivo que se esta trabalhando emparelhados.

Um aspecto interessante do Xcode a se ressaltar são os Schemes presentes no painel central. Nele, configuramos para qual plataforma Apple queremos compilar nosso projeto.

A organização do projeto em pastas lógicas é iniciado da seguinte forma:

Pastas lógicas
  • Pasta com o nome do projeto: Contém todas as classes referentes ao projeto;
  • Frameworks: Contém as bibliotecas que estamos utilizando da API Cocoa. No caso estou usando a Framework Foundation;
  • Products: É o resultado do nosso projeto. Nesse caso, o produto do código dependerá do template que foi usado na criação do projeto. No meu caso, o resultado gerado será uma tela de console.
O aspecto que diferencia o Xcode de demais IDEs é a sua ferramenta de analise do código (disponível através do atalho SHIFT + COMMAND + B). Este comando faz com que o Xcode analise o código buscando possíveis problemas, como, por exemplo, memory leaks, loops infinitos e variáveis não inicializadas.


No próximo post estarei introduzindo alguns conceitos referentes a linguagem Objective-C para, então demonstrar suas principais características.

SEE YOU NEXT MISSION

Desenvolvimento do jogo para IOS

Olá a todos!!!

Até então foram demonstrados diversos conceitos e funcionalidades a respeito do desenvolvimento do projeto em Android. Apesar do mesmo ainda não estar finalizado, decidi inserir um break point momentâneo e trabalhar com o ambiente de desenvolvimento IOS já que a entrega do protótipo do jogo para a matéria de Programação de Jogos da Dispositivos Móveis também se aproxima.

Na minha opinião, desenvolver jogos para a plataforma IOS da Apple é altamente mais complexo do que desenvolver jogos para Android. Para comprovar tal afirmação, elenco os seguintes motivos:
  • Para desenvolvermos uma aplicação em IOS, na prática temos que desenvolver o projeto num Macintosh. Apesar da excelência do produto, há de se concordar que o preço não é acessível;
  • Para testar o resultado, não dispomos de acesso licito aos devices (iPhone, iPad, iPod) como fazemos em Android, a menos que pague-se os 99 dólares da licença de desenvolvedor. A vantagem é que a licença Apple Developer nos da "acesso" à Apple Store;
  • Concatenando com o comentário acima exposto, a Apple Store é considerada um meio de difícil publicação. Alguns dos motivos envolvem a espera na fila de produtos a serem lançados, a lista de exigências para seu produto ser aceito (a mais conhecida delas é que a aplicação deve remover todo o seu conteúdo da memória 5 segundos após ser fechada), a passagem dos dados do produto é recebida por eles apenas via fax, dentre outros motivos;
  • Talvez o maior motivo, a Apple utiliza como linguagem padrão para suas Aplicações o Objective-C que, apesar de possuir alguns elementos interessantes, é a princípio mais difícil de aprender;
  • O Xcode tem as suas peculiaridades, mas ainda não possui o prestígio e a qualidade de IDEs como o Visual Studio e Eclipse.

Apesar disso, diversas são as vantagens de se desenvolver para IOS e Mac OS. Dentre as principais razões, destaco:
  • As plataformas da Apple são muito mais instáveis que as demais;
  • Ao desenvolvermos uma aplicação, devemos nos preocupar apenas com a resolução do dispositivo em questão. Questões que envolvem versão do Sistema Operacional e Hardware são homogêneas para todos os aparelhos (desconsiderando diferenças de desempenho entre plataformas diferentes, como iPhone VS iPad), uma vez que a Apple oferece update gratuito do IOS para as novas versões do SO que venham a surgir;
  • Para quem já programou usando os recursos do Sistema Operacional Windows e a sua temida e mal falada Notação Húngara (existe alguém que ainda não use Windows Form ou XNA?), irá se maravilhar com a diferença entre esta e a Cocoa (API nativa do Mac que nos oferece acesso aos recursos do SO). Até mesmo os header files das frameworks da Cocoa são extremamente organizados e passíveis de leitura;
  • Querendo ou não, a Apple Store é muito mais organizada que o Google Play/Android Market. Pra começar, você dificilmente (para não dizer nunca) irá baixar uma aplicativo em seu IOS que venha infestado de propagandas ou com uma qualidade horrível. Além de que, aplicativos IOS e Mac OS possuem mais tendência a serem comprados devido ao poder aquisitivo do público que consome os produtos dessas plataformas e a dificuldade para se craquear tais produtos ser maior (lembrem-se que o Android é Open Source e isso sempre irá soar negativo para aplicações comerciais);
  • E por fim, o motivo que talvez faça muita gente preferir de cara aprender a desenvolver para dispositivos móveis a partir do IOS é que, apesar da ausência de acesso free aos recursos de um device físico, o emulador de iPhone e iPad são simplesmente fenomenais. A performance e a abertura dos mesmos acontecem em tempo real no Mac. 

Bem, por hora é isso. No próximo post estarei expondo o funcionamento do Xcode...

Até a próxima!

sábado, 10 de novembro de 2012

Audio do menu

Olá a todos!!!

A música do menu pode ser ouvida aqui. Para produção dos elementos sonoros do game, estou utilizando o Garage Band e os loops existentes. O resto é criatividade, paciência e um pouco de talento.

Por hora é só... Até mais!!!

Learning Exploder - Versão 1.0

Olá a todos!!!

Hoje estarei falando sobre o processo de desenvolvimento inicial do jogo Learning Exploder.

Em geral, o processo durou 40 horas e o resultado foi entregue na primeira parcial da matéria de Programação de Jogos para Dispositivos Móveis.

Mais detalhes podem ser consultados neste vídeo...

Enquanto estava fazendo esse vídeo lembrei o quão terrível é trabalhar com esse emulador do Android. Tive que reiniciar o mesmo 3 vezes para o emulador reconhecer o projeto.

Para ter acesso ao jogo, baixe este arquivo, copie para o SD-Card de seu Android, e execute o arquivo a partir do celular. Provavelmente, o aparelho irá bloquear a instalação do jogo, por ter já por definição de fábrica a proibição da instalação de aplicativos não adquirido no Android Market / Google Play.

Até mais!

Aspectos gráficos - Learning Explorer

Olá pessoal!

Hoje estarei falando dos aspectos gráficos do jogo "Learnig Exploder" que estamos desenvolvendo.
Vamos lá!


(Figura 1 - Tela Inicial 1)
Figura 1 - Tela Inicial 1


Eu sempre procuro usar cores associadas a proposta do projeto, assim, na figura 1 podemos ver o fundo simples em degradê azulado, optei por essa cor pelo seu significado relacionado a inteligência, assim como o amarelo do logotipo que também inspira o conhecimento, já que nosso objetivo neste jogo é mexer com o raciocínio ao se deslocar pelos labirintos(fases) com a associação de palavras que irão despertar uma percepção positiva no jogador, que irá aprender novas palavras de uma maneira divertida, bem como inspira-se a pesquisar outras além das escolhidas para o Learnig Exploder!
Associada as cores, também preso pelo significado das formas básicas, o circulo é associado a diversos significados, dentre ele destaco a qualidade de ciclo. Utilizando a ideia de ciclo, coloquei as representações do alfabeto e dos números no interior do circulo para formar o conceito de que sempre temos algo a aprender em qualquer área e que o aprendizado inicial é a base de todos o conhecimento!

Figura 2 - O Círculo e o Aprendizado Básico
Figura 2 - O Círculo e o Aprendizado Básico

A estrela completa o simbolo com a ideia de várias direções e escolhas que temos na vida, também considerada um simbolo de sucesso, demonstra que o conhecimento nos dá oportunidades para fazermos as melhores escolhas.

Figura 3 - Estrela
Figura 3 - Estrela

Por fim, a tela inicial montada, o logotipo tem um efeito de rotação e os botões aparecem através de animação.

Figura 4 - Tela Menu Inicial
Figura 4 - Tela Menu Inicial

Os fundos das fases seguiram os conceitos de cores também e a princípio são como o fundo do menu inicial com a cor alterada se acordo com o nível da fase, mas serão feitos fundos mais elaborados assim que possível. A sequência de cores é: amarelo, verde, azul, roxo, laranja, vermelho, prata e dourado.

Figura 5 - Fundo Amarelo (Fase 1)
Figura 5 - Fundo Amarelo (Fase 1)


A animação clássica de início de fase foi reproduzida com a inspiração (a pedidos) do efeito utilizado no logotipo da Capcom. Segue o Sprite:  

Figura 6 - Ready
Figura 6 - Ready
Figura 7 - Go!!!

A bolinha é uma animação bem simples:
Figura 8 - Bolinha
Figura 8 - Bolinha
E aqui temos as "Cerâmicas" que utilizaremos a princípio, elas tem uma versão contornado para ser usada como efeito:

Figura 9 - "Cerâmica" Borboleta
Figura 9 - "Cerâmica" Borboleta
Figura 10 - "Cerâmica" Cartas
Figura 10 - "Cerâmica" Cartas
Figura 11 - "Cerâmica" Tulipa
Figura 11 - "Cerâmica" Tulipa
Figura 12 - "Cerâmica" Beija-Flor
Figura 12 - "Cerâmica" Beija-Flor
Figura 13 - "Cerâmica" Abóbora
Figura 13 - "Cerâmica" Abóbora

E, um exemplo de animação da abóbora quebrando:

Figura 14 - "Cerâmica" Abóbora Quebrando
Figura 14 - "Cerâmica" Abóbora Quebrando

A explosão será utilizada em alguns efeitos como por exemplo a chamada da tela game over, quando o jogador é vencido em uma fase ela recebe várias explosões.

Figura 15 - Explosão

A tela de créditos tem os dados do curso e das disciplinas a qual apresentaremos o jogo.
Figura 16 - Tela Créditos
Essa é a tela de Game Over que aparece após a explosão, ainda está sem animações, mas pretendemos dar uma agitada nela.
Figura 17 - Tela Game Over

Por enquanto são esses os assets prontos para utilizar e alguns inclusive já implementados!
Até a próxima!