Tutorial: Desenvolvimento de jogos para Android – Parte 4

Já configuramos um monte de coisas, programamos o jogo Jokenpô e mostramos para os outros que somos programadores Android, mas … e se nos perguntarem como programamos? Vamos entender o que significam aqueles códigos que fizemos?

Relembrando o que fizemos até agora, no Desenvolvimento de jogos para Android – Parte 2 nós programamos o jogo Jokenpô. No Desenvolvimento de jogos para Android – Parte 3 eu mostrei como executar o jogo no emulador que vem com o SDK Android. Nesse tutorial nós vamos aprender o que significa cada linha de código e a lógica usada no Jokenpô.

Projeto Android e pastas editadas:

Antes de sabermos o que tem no código do Jokenpô, eu mostrarei as pastas que mexemos e a função delas em um projeto Android. As pastas editadas foram “src”, “res”, “drawable”, “layout” e “values”, como mostrado na figura ao lado. Segue uma explicação breve sobre a função de cada uma delas no projeto Android.

  • src: contém todos os arquivos de código fonte do aplicativo. Arquivos de código fonte, para quem não sabe, são os arquivos que contém códigos em uma linguagem de programação e que ditam toda a lógica do aplicativo. Esses arquivos são escritos na linguagem Java;
  • res: contém todos os arquivos de recursos do aplicativo. Esses podem ser arquivos de layout (disposição dos elementos na tela), arquivos de imagem, vídeo e de efeitos sonoros;
  • drawable: contém arquivos de imagem e arquivos descritores de objetos que mudam seu design visual (botão clicado e não clicado, por exemplo);
  • layout: contém arquivos XML que descrevem a disposição dos elementos nas diferentes telas do aplicativo;
  • values: contém arquivos que definem constantes com valores pré-definidos pelo programador.

Existem outras pastas importantes que não mexemos no jogo do Jokenpô. Se você quiser saber mais sobre cada uma dessas pastas, dê uma olhada aqui. Não vamos nos desconcentrar do objetivo do tutorial. =]

Arquivos editados e função de cada um:

Os arquivos editados foram três no total: “JokenpoActivity.java”, “activity_jokenpo.xml” e “strings.xml”. Se você não lembra onde eles estão, dê uma olhada na figura acima. Vou explicar de forma sucinta a função de cada um deles. A ordem de explicação foi mudada para vocês entenderem melhor o funcionamento do jogo.

strings.xml:

É um arquivo que especifica os valores das constantes textuais que serão utilizadas no código. O nome do aplicativo e textos que fazem parte dos objetos da tela estão especificados em cadeias de caracteres declaradas nesse arquivo. O que continha no arquivo era:

<?xml version=“1.0” encoding=“utf-8”?>

<resources>

    <string name=“app_name”>Jokenpo</string>

    <string name=“action_settings”>Settings</string>

    <string name=“opcoes”>Escolha uma opção</string>

    <string name=“ultimaJogada”>Última Jogada</string>

    <string name=“jogadaPlayer”>Você</string>

    <string name=“resultado”>Resultado</string>

    <string name=“jogadaPC”>Computador</string>

</resources>

Na primeira linha, apenas é especificada qual versão do XML que o código está escrito, conforme a W3C, e em qual tipo de codificação o arquivo será lido. Isso é meio que padrão, a não ser que você queira mudar a codificação. Eu recomendo não mudar, senão caracteres especiais como ‘ç’ e ‘ã’ serão apresentados de forma errada na tela.

Cada linha que inicia com a tag “string” é uma declaração de constante. Os nomes das constantes estão entre aspas duplas e os valores delas estão entre a tag de abertura (<tag>) e a tag de fechamento (</tag>).

No Jokenpô, foram criadas as constantes “app_name”, “action_settings”, “opcoes”, “ultimaJogada”, “jogadaPlayer”, “resultado” e “jogadaPC”. Essas constantes serão utilizadas no arquivo “activity_jokenpo.xml”, quando criarmos a tela do jogo, e durante a programação da lógica, no arquivo “JokenpoActivity.java”.

activity_jokenpo.xml:

É um arquivo de layout, ou seja, especifica a disposição dos objetos gráficos na tela do celular ou tablet. Toda a tela do aplicativo tem um arquivo XML que descreve a posição e formato dos objetos. É possível você criar, limitar as bordas e posicionar cada objeto diretamente no código Java, porém esse é um trabalho cansativo e desnecessário. A edição de um objeto é feita no código Java como, por exemplo, a inclusão de uma opção em um box, após o usuário clicar em um botão da tela. Como no jogo teve somente uma tela, então existe somente esse arquivo na pasta “layout”. No arquivo tinha:

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

    xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:paddingBottom=“@dimen/activity_vertical_margin”

android:paddingLeft=“@dimen/activity_horizontal_margin”

android:paddingRight=“@dimen/activity_horizontal_margin”

android:paddingTop=“@dimen/activity_vertical_margin”

tools:context=“.JokenpoActivity” >

<TextView

        android:id=“@+id/textView1”

        android:layout_width=“wrap_content”

        android:layout_height=“wrap_content”

        android:layout_above=“@+id/button2”

        android:layout_centerHorizontal=“true”

        android:text=“@string/opcoes”

        android:textSize=“30sp” />

<Button

        android:id=“@+id/button1”

        android:layout_width=“100dp”

        android:layout_height=“100dp”

        android:layout_above=“@+id/textView2”

        android:layout_toLeftOf=“@+id/button2”

        android:background=“@drawable/pedra” />

<Button

        android:id=“@+id/button2”

        android:layout_width=“100dp”

        android:layout_height=“100dp”

        android:layout_above=“@+id/textView2”

        android:layout_centerHorizontal=“true”

        android:background=“@drawable/papel” />

<Button

        android:id=“@+id/button3”

        android:layout_width=“100dp”

        android:layout_height=“100dp”

        android:layout_above=“@+id/textView2”

        android:layout_toRightOf=“@+id/button2”

        android:background=“@drawable/tesoura” />

<TextView

        android:id=“@+id/textView2”

        android:layout_width=“wrap_content”

        android:layout_height=“wrap_content”

        android:layout_centerHorizontal=“true”

        android:layout_centerVertical=“true”

        android:text=“@string/ultimaJogada”

        android:textSize=“30sp” />

<TextView

        android:id=“@+id/textView3”

        android:layout_width=“wrap_content”

        android:layout_height=“wrap_content”

        android:layout_below=“@+id/textView2”

        android:layout_toLeftOf=“@+id/imageView2”

        android:text=“@string/jogadaPlayer” />

<TextView

        android:id=“@+id/textView4”

        android:layout_width=“wrap_content”

        android:layout_height=“wrap_content”

        android:layout_below=“@+id/textView2”

        android:layout_centerHorizontal=“true”

        android:text=“@string/resultado” />

<TextView

        android:id=“@+id/textView5”

        android:layout_width=“wrap_content”

        android:layout_height=“wrap_content”

        android:layout_below=“@+id/textView2”

        android:layout_toRightOf=“@+id/imageView2”

        android:text=“@string/jogadaPC” />

<ImageView

        android:id=“@+id/imageView1”

        android:layout_width=“100dp”

        android:layout_height=“100dp”

        android:layout_below=“@+id/textView4”

        android:layout_toLeftOf=“@+id/imageView2” />

<ImageView

        android:id=“@+id/imageView2”

        android:layout_width=“100dp”

        android:layout_height=“100dp”

        android:layout_below=“@+id/textView4”

        android:layout_centerHorizontal=“true” />

<ImageView

        android:id=“@+id/imageView3”

        android:layout_width=“100dp”

        android:layout_height=“100dp”

        android:layout_below=“@+id/textView4”

        android:layout_toRightOf=“@+id/imageView2” />

</RelativeLayout>

Nesse código, são especificados vários objetos que fazem parte de um layout, que é especificado na tag “RelativeLayout”. Ele nos dá a liberdade de incluir os objetos onde bem entendemos, desde que seja especificada a posição dele na tela. Alguns atributos interessantes dessa tag são “android:layout_width” e “android:layout_height” que especificam o tamanho do layout. Nesse caso, ambos foram atribuídos com “match_parent”, que deixa claro que estamos lidando com toda a área da tela do aparelho.

A tag “Button” informa que foi adicionado um botão na tela, a tag “TextView” uma etiqueta textual e a tag “ImageView” uma simples imagem. Dessa forma, adicionamos um total de três botões, cinco etiquetas de texto e três imagens.

Quanto aos atributos, muitos se repetem entre os objetos. Vou explicar cada um deles:

  • “android:id”: é um nome que o programador dá para que esse objeto possa ser referenciado nos arquivos Java;
  • “android:layout_width” e “android:layout_height”: especificam a largura e a altura do objeto, respectivamente;
  • “android:centerHorizontal” e “android:centerVertical”: especificam se o objeto está centralizado horizontalmente e verticalmente na tela, respectivamente;
  • “android:text”: especifica o texto que será mostrado ao usuário. Nesse caso, todos fazem referência a uma constante criada no arquivo “strings.xml”;
  • “android:textSize”: especifica o tamanho da fonte do texto;
  • “android:above” e “android:below”: especificam se o objeto está acima ou abaixo de outro objeto, respectivamente;
  • “android:toLeftOf” e “android:toRightOf”: especificam se o objeto está à esquerda ou à direita de outro objeto, respectivamente;
  • “android:background”: especifica a imagem de fundo que vai em um objeto. Essa imagem precisa estar localizada na pasta “drawable”.

Se você for olhar bem, verá que existe uma etiqueta (TextView) central na tela (com “id” igual a “textView2”) e todos os outros objetos são inseridos baseando-se na posição dessa etiqueta. Tomando como base o significado de cada tag e atributo, não é difícil entender como eu modelei a tela do jogo. =]

JokenpoActivity.java:

É um arquivo de código fonte, ou seja, ali está toda a lógica do jogo implementada na linguagem Java. Todo arquivo de código fonte Java precisa ter a extensão “.java” e precisa estar localizado em uma subpasta da pasta “src”. No caso desse jogo, foi necessário somente um arquivo de lógica. Esse arquivo tinha:

package com.santy.jokenpo;

import java.util.Random;

import android.os.Bundle;

import android.app.Activity;

import android.view.Menu;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

public class JokenpoActivity extends Activity {

      private Random numeroAleatorio;

      protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_jokenpo);

            numeroAleatorio = new Random();

            Button pedra = (Button)findViewById(R.id.button1);

            pedra.setOnClickListener(new OnClickListener() {

                  public void onClick(View v) {

                        findViewById(R.id.imageView1).setBackgroundResource(R.drawable.pedra);

                        realizaJogadaPC(1);

                  }

            });

            Button papel = (Button)findViewById(R.id.button2);

            papel.setOnClickListener(new OnClickListener() {

                  public void onClick(View v) {

                        findViewById(R.id.imageView1).setBackgroundResource(R.drawable.papel);

                        realizaJogadaPC(2);

                  }

            });

            Button tesoura = (Button)findViewById(R.id.button3);

            tesoura.setOnClickListener(new OnClickListener() {

                  public void onClick(View v) {

                        findViewById(R.id.imageView1).setBackgroundResource(R.drawable.tesoura);

                        realizaJogadaPC(3);

                  }

            });

      }

      
public void realizaJogadaPC(int jogadaPlayer) {

            int jogadaPC;

            jogadaPC = numeroAleatorio.nextInt(3) + 1;

            if(jogadaPC==1) {

                        findViewById(R.id.imageView3).setBackgroundResource(R.drawable.pedra);

                  if(jogadaPlayer==1)

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.empatou);

                  else if(jogadaPlayer==2)

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.venceu);

                  else

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.perdeu);

            }

            else if(jogadaPC==2) {

                  findViewById(R.id.imageView3).setBackgroundResource(R.drawable.papel);

                  if(jogadaPlayer==1)

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.perdeu);

                  else if(jogadaPlayer==2)

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.empatou);

                  else

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.venceu);

            }

            else if(jogadaPC==3) {

                  findViewById(R.id.imageView3).setBackgroundResource(R.drawable.tesoura);

                  if(jogadaPlayer==1)

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.venceu);

                  else if(jogadaPlayer==2)

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.perdeu);

                  else

                        findViewById(R.id.imageView2).setBackgroundResource(R.drawable.empatou);

            }

      }

      
public boolean onCreateOptionsMenu(Menu menu) {

            // Inflate the menu; this adds items to the action bar if it is present.

            getMenuInflater().inflate(R.menu.jokenpo, menu);

            return true;

      }

}

Nas primeiras linhas, que iniciam com a palavra “import”, são inclusas algumas bibliotecas que especificam as funções dos objetos que são utilizados no código. Não vou explicar hoje sobre linguagem Java, mas saibam que esse é um requisito para quem quer programar Android. Talvez eu faça tutoriais sobre linguagem Java (o que vocês acham?).

Na linha onde tem “public class”, eu estou criando uma classe que descreve o comportamento da aplicação. Nessa classe, existe um método chamado “onCreate”, que é iniciado quando o usuário da aplicação clica no ícone dela, lá na tela principal do Android. Na linha onde tem “setContentView”, nós falamos para a aplicação jogar na tela o layout especificado no arquivo “activity_jokenpo.xml”. Fácil, não? ;D

As linhas que iniciam “Button pedra”, “Button papel” e “Button tesoura” eu especifiquei o que acontece quando o usuário clica nos botões pedra, papel e tesoura, respectivamente. Vocês podem ver que são bem parecidas as linhas de código entre eles. Onde tem “findViewById”, eu pego a referência dos botões que especificamos no arquivo “activity_jokenpo.xml”. Depois de eu “selecionar” o botão que eu escolhi em “findViewById”, eu programo a funcionalidade dele. A funcionalidade desses três botões são similares: adicionar na tela a imagem da opção que o usuário fez na jogada e iniciar o método (subrotina) “realizaJogadaPC”.

O método “realizaJogadaPC” recebe como parâmetro um valor inteiro (“jogadaPlayer”) que informa qual foi a opção que o jogador escolheu: 1 caso for pedra, 2 caso for papel e 3 caso for tesoura. Inicialmente esse método realiza um sorteio entre três números: 1, 2 e 3. Logo após ele verifica qual número foi sorteado, coloca na tela a opção do computador (a que foi sorteada) e faz a verificação entre a jogada do usuário e a do computador. Dependendo do resultado, ele mostra se o jogador perdeu, se ganhou ou se houve empate.

Existem algumas linhas de código que eu não expliquei porque eu achei desnecessário, além de algumas que não valem a pena eu perder tempo explicando. Parte dessas linhas são código geradas pelo próprio Eclipse, quando você cria uma aplicação e parte eu adicionei, como o caso da variável para números aleatórios “numeroAleatorio”. Mas, como vocês podem ver, a essência do programa está explicada: se o jogador clicar em pedra, o aplicativo mostra a escolha do jogador na tela, faz um sorteio para definir a opção do computador, mostra a opção dele na tela e dá o resultado final com base na escolha do jogador e do computador.

Aqui terminamos mais um tutorial de desenvolvimento de jogos na plataforma Android. Você já parou para pensar em tudo o que você aprendeu? Bastante coisa, né?

Nesse tutorial nós aprendemos como funciona o núcleo do jogo Jokenpô que programamos no segundo tutorial. No próximo, saberemos como incluir efeitos sonoros nos nossos jogos. ;D

Até mais pessoal, deixem suas opiniões sobre os meus tutoriais e se valem a pena ou não alguns tutoriais sobre programação Java.

Um grande abraço e nos encontramos no próximo tutorial.

Santiago Viertel

Santiago Viertel

Formado em Bacharelado em Ciência da Computação (UDESC), mestre e doutorando em Análise de Algoritmos (UFPR). Foi programador da Céu Games por 8 anos. Possui a preferência por jogos de estratégia e de tiro em primeira pessoa. Jogando bastante DotA 2, Left 4 Dead 2 e Age of Empires II HD.

Send this to a friend