DESENVOLVIMENTO DE UM JOGO MULTIUSUÁRIO UTILIZANDO ANDROID



Documentos relacionados
API's e Aplicações para Android

Programação para Dispositivos Móveis

DESENVOLVIMENTO DE UM APLICATIVO DO TIPO SECRETÁRIO VIRTUAL PARA A PLATAFORMA ANDROID

Manual de instalação e configuração da Ferramenta Android SDK

1 REQUISITOS BÁSICOS PARA INSTALAR O SMS PC REMOTO

Introdução a programação de dispositivos móveis. Prof. Me. Hélio Esperidião

IMPLEMENTAÇÃO DE SOCKETS E THREADS NO DESENVOLVIMENTO DE SISTEMAS CLIENTE / SERVIDOR: UM ESTUDO EM VB.NET

PROGRAMAÇÃO PARA DISPOSITIVOS MÓVEIS

Desenvolvimento de um aplicativo básico usando o Google Android

Dispositivos móveis e o mercado Android Open Handset Alliance Informações sobre Android Arquitetura

O que é o Android? O que é o Android

Google Drive. Passos. Configurando o Google Drive

INF1013 MODELAGEM DE SOFTWARE

Manual do Usuário Android Neocontrol

Sistemas Distribuídos. Professora: Ana Paula Couto DCC 064

5 Mecanismo de seleção de componentes

Introdução a Computação Móvel

Manual SAGe Versão 1.2 (a partir da versão )

Sistemas Distribuídos

Satélite. Manual de instalação e configuração. CENPECT Informática cenpect@cenpect.com.br

Programação para Dispositivos Móveis

MANUAL DE INSTALAÇÃO CONFIGURAÇÃO IDE ECLIPSE

Visão geral Estrutura do sistema Ferramentas de desenvolvimento Uma aplicação. Android. Universidade Federal de Santa Catarina. 17 de dezembro de 2008

INDICE 1. INTRODUÇÃO CONFIGURAÇÃO MÍNIMA INSTALAÇÃO INTERLIGAÇÃO DO SISTEMA ALGUNS RECURSOS SERVIDOR BAM...

Google Android para Tablets

Programação para Dispositivos Móveis

DESENVOLVIMENTO PARA DISPOSITIVOS MÓVEIS. PROFª. M.Sc. JULIANA H Q BENACCHIO

Hardware (Nível 0) Organização. Interface de Máquina (IM) Interface Interna de Microprogramação (IIMP)

Sistemas Operacionais

Manual de Instalação do Agente Citsmart

1 ACESSO AO PORTAL UNIVERSITÁRIO 3 3 PLANO DE ENSINO 6 4 AULAS 7 5 AVALIAÇÃO E EXERCÍCIO 9 6 ENQUETES 12 7 QUADRO DE AVISOS 14

Computação II Orientação a Objetos

Lógica de Programação

Guia. PDA e SmartPhones. Windows Mobile, Pocket PC e CE.

Índice: CMS 3 O que é Content Management System? Clientes 4 O que é o Cliente? 4 Configurando o i-menu/i-view para trabalhar. com o CMS.

Faculdade de Tecnologia SENAC Goiás. Disciplina: Gerenciamento de Rede de Computadores. Goiânia, 16 de novembro de 2014.

"Manual de Acesso ao Moodle - Discente" 2014

NetEye Guia de Instalação

Sumário. Apresentação O que é o Centro de Gerenciamento de Serviços (CGS) NTI? Terminologia Status do seu chamado Utilização do Portal Web

Manual do usuário - Service Desk SDM - COPASA. Service Desk

Microsoft Lync Manual de Instalação e Uso

Orientação a Objetos

Sistemas Operacionais

ESTUDO DE CASO WINDOWS VISTA

LICENCIAMENTO V14 USANDO REPRISE LICENSE MANAGER

Atualizaça o do Maker

Feature-Driven Development

Manual de Instalação. SafeSign Standard (Para MAC OS 10.7)

Manual de Utilização do Sistema GRServer Cam on-line (Gerenciamento de Câmeras On-line)

Manual do Google agenda. criação e compartilhamento de agendas

CONCEITOS INICIAIS. Agenda A diferença entre páginas Web, Home Page e apresentação Web;

Motorola Phone Tools. Início Rápido

Manual do Usuário Nextel Cloud. Manual do Usuário. Versão Copyright Nextel

Sumário. Capítulo 2 Iniciando o TR Como efetuar o login... 8

Leia antes de instalar Mac OS X

Aplicativo da Manifestação do Destinatário. Manual

Sistemas Distribuídos

OMT-G Design. Instalação por pacotes

Um Driver NDIS Para Interceptação de Datagramas IP

Manual Captura S_Line

Acadêmico: Maicon Machado Orientador: José Carlos Toniazzo

Sistemas Distribuídos Capítulos 3 e 4 - Aula 4

Considerações no Projeto de Sistemas Cliente/Servidor

Índice. Para encerrar um atendimento (suporte) Conversa Adicionar Pessoa (na mesma conversa)... 20

TOTVS Série 1 Varejo (Simples) - Módulo e-commerce

Introdução Dalvik Linux 2.6. Android. Diogo de Campos, João Paulo Pizani Flor, Maurício Oliveira Haensch, Pedro Covolan Bachiega

Manual das funcionalidades Webmail AASP

Versão Liberada. Gerpos Sistemas Ltda. Av. Jones dos Santos Neves, nº 160/174

Google Drive: Acesse e organize seus arquivos

Manual de Instalação (TEF LOJA)

Outlook XML Reader Versão Manual de Instalação e Demonstração UNE Tecnologia

Entrar neste site/arquivo e estudar esse aplicativo Prof. Ricardo César de Carvalho

Manual do Usuário Certificação

Sistema de Chamados Protega

Manual do Aplicativo - Rastreamento Veicular

TRBOnet MDC Console. Manual de Operação

MANUAL 2ª CAMADA DE SEGURANÇA E NOVAS REGRAS DE CADASTRAMENTO

ROTEIRO PARA TREINAMENTO DO SAGRES DIÁRIO Guia do Docente

INTRODUÇÃO E CONFIGURAÇÃO DO PRIMEFACES MOBILE EM APLICAÇÕES JSF

MODEM USB 3G+ WM31. Manual do Usuário

Engenharia de Requisitos Estudo de Caso

Como foi exposto anteriormente, os processos podem ter mais de um fluxo de execução. Cada fluxo de execução é chamado de thread.

Sistema de Controle de Solicitação de Desenvolvimento

Manual do Painel Administrativo

Manual do usuário. Mobile Auto Download

Capture Pro Software. Introdução. A-61640_pt-br

Conceitos Básicos de Rede. Um manual para empresas com até 75 computadores

Introdução ao Modelos de Duas Camadas Cliente Servidor

Despachante Express - Software para o despachante documentalista veicular DESPACHANTE EXPRESS MANUAL DO USUÁRIO VERSÃO 1.1

ISO/IEC 12207: Gerência de Configuração

APLICATIVO MOBILE CATÁLOGO DE PÁSSAROS - PLATAFORMA ANDROID/MYSQL/WEBSERVICE

MANUAL DO USUÁRIO SORE Sistema Online de Reservas de Equipamento. Toledo PR. Versão Atualização 26/01/2009 Depto de TI - FASUL Página 1

Desenvolvendo uma Arquitetura de Componentes Orientada a Serviço SCA

Cadastramento de Computadores. Manual do Usuário

ÍNDICE. 1. Introdução O que é o Sistema Mo Porã Como acessar o Site Mo Porã Cadastro do Sistema Mo Porã...

ArcSoft MediaConverter

Programação para Internet Orientada a Objetos com PHP & MySQL Instalando e configurando um ambiente de ferramentas PHP e MySQL. Prof. MSc.

SCIM 1.0. Guia Rápido. Instalando, Parametrizando e Utilizando o Sistema de Controle Interno Municipal. Introdução

Transcrição:

UNIVERSIDADE DO ESTADO DO AMAZONAS - UEA ESCOLA SUPERIOR DE TECNOLOGIA ENGENHARIA DE COMPUTAÇÃO VICTOR MATHEUS DE SOUZA PEREIRA DESENVOLVIMENTO DE UM JOGO MULTIUSUÁRIO UTILIZANDO ANDROID Manaus 2012

VICTOR MATHEUS DE SOUZA PEREIRA DESENVOLVIMENTO DE UM JOGO MULTIUSUÁRIO UTILIZANDO ANDROID Trabalho de Conclusão de Curso apresentado à banca avaliadora do Curso de Engenharia de Computação, da Escola Superior de Tecnologia, da Universidade do Estado do Amazonas, como pré-requisito para obtenção do título de Engenheiro de Computação. Orientador: Prof. M. Sc. Jucimar Maia da Silva Júnior Manaus 2012

ii Universidade do Estado do Amazonas - UEA Escola Superior de Tecnologia - EST Reitor: José Aldemir de Oliveira Vice-Reitor: Marly Guimarães Fernandes Costa Diretor da Escola Superior de Tecnologia: Mário Augusto Bessa de Figueirêdo Coordenador do Curso de Engenharia de Computação: Daniele Gordiano Valente Coordenador da Disciplina Projeto Final: Raimundo Correa de Oliveira Banca Avaliadora composta por: Data da Defesa: 23 / 06 / 2012. Prof. M.Sc. Jucimar Maia da Silva Júnior (Orientador) Prof. M.Sc. Raimundo Correa de Oliveira Prof. M.Sc. Rodrigo Choji de Freitas CIP - Catalogação na Publicação P436d Pereira, Victor Desenvolvimento de um Jogo Multiusuário utilizando Android/ Victor Pereira; [orientado por] Prof. MSc. Jucimar Maia da Silva Júnior - Manaus: UEA, 2012. 92 p.: il.; 30cm Inclui Bibliografia Trabalho de Conclusão de Curso (Graduação em Engenharia de Computação). Universidade do Estado do Amazonas, 2012. CDU: 004

iii VICTOR MATHEUS DE SOUZA PEREIRA DESENVOLVIMENTO DE UM JOGO MULTIUSUÁRIO UTILIZANDO ANDROID Trabalho de Conclusão de Curso apresentado à banca avaliadora do Curso de Engenharia de Computação, da Escola Superior de Tecnologia, da Universidade do Estado do Amazonas, como pré-requisito para obtenção do título de Engenheiro de Computação. BANCA EXAMINADORA Aprovado em: 23 / 06 / 2012 Prof. Jucimar Maia da Silva Júnior, Mestre UNIVERSIDADE DO ESTADO DO AMAZONAS Raimundo Correa de Oliveira, Mestre UNIVERSIDADE DO ESTADO DO AMAZONAS Rodrigo Choji de Freitas, Mestre UNIVERSIDADE DO ESTADO DO AMAZONAS

iv Agradecimentos É com muita emoção, após um ano de dedicação, os agradecimentos que ofereço às pessoas que se encontravam ao meu redor e fizeram com que eu permanecesse e enfrentasse qualquer obstáculo: À Deus, por ter me proporcionado essa oportunidade. A minha mãe Silene Martins e ao meu irmão Jamil Júnior, que sempre confiaram no meu potencial apesar de toda dificuldade por qual passamos. Ao meu grande amigo e parceiro Ronny Martins, por ter me acompanhado durante essa jornada. Ao meu orientador, Prof. Msc. Jucimar Júnior, e a todos os meus professores, que me ensinaram e contribuíram para o meu crescimento profissional. E a todos os meus amigos, aos quais me ausentei por diversas vezes, mas sempre me compreenderam e me deram toda força.

v Resumo Este trabalho apresenta o desenvolvimento de um jogo da velha multiusuário usando a plataforma Android. O jogo, nomeado de OX Game, permite que dois usuários joguem, um contra o outro, partidas utilizando as regras do jogo da velha tradicional. A plataforma Android é uma plataforma aberta voltada para dispositivos móveis e que possui um kit de desenvolvimento próprio, utilizando a linguagem de programação Java. O jogo OX Game implementa a arquitetura cliente-servidor e a comunicação existente entre os jogadores é realizada a partir de fluxos de entrada e saída de dados conhecidos como sockets. Palavras-Chave: jogo, jogo da velha, Android, arquitetura cliente-servidor, sockets, comunicação em rede, java.

vi Abstract This work presents the development of a multiplayer tic-tac-toe game using the Android platform. This game, named by Ox Game, lets two users play the tic-tac-toe against each other using the traditional rules. The Android platform is an open source platform for mobile devices and it has a development kit itself, using the programming language Java. The game OX Game implements the client-server architecture and the communication between players is made by input and output data stream known as sockets. Keywords: game, tic-tac-toe, Android, client-server architecture, sockets, network communication, java.

vii Sumário Lista de Figuras ix 1 Introdução 1 1.1 Objetivo..................................... 2 1.1.1 Específicos................................ 2 1.2 Justificativa................................... 3 1.3 Metodologia................................... 3 1.4 Estrutura do Trabalho............................. 4 2 Plataforma Android 5 2.1 História..................................... 5 2.2 Open Handset Alliance (OHA)......................... 7 2.3 Licença..................................... 9 2.4 Arquitetura................................... 9 2.5 Segurança.................................... 11 2.6 Características................................. 11 2.7 O Kit de Desenvolvimento de Software - SDK................ 12 3 Programação Distribuída usando Android 15 3.1 Componentes das Aplicações em Android................... 15 3.1.1 Activities................................ 17 3.1.2 Broadcast e Intent Receivers...................... 20 3.1.3 Services................................. 21 3.1.4 Content Providers........................... 22 3.2 Programação Distribuída usando Android.................. 22 3.2.1 Arquitetura Cliente-Servidor...................... 23 3.2.2 Arquitetura Ponto-a-Ponto....................... 24 3.3 Serviços de Comunicação............................ 25

viii 3.3.1 Implementando um servidor utilizando Sockets de fluxo....... 26 3.3.2 Implementando um cliente utilizando Sockets de fluxo........ 28 3.3.3 Estabelecendo uma comunicação utilizando a arquitetura clienteservidor................................. 30 4 Desenvolvimento 34 4.1 Etapas de Desenvolvimento.......................... 34 4.2 O Projeto.................................... 35 4.3 Jogo da Velha.................................. 36 4.3.1 Regras.................................. 36 4.4 Arquitetura do Jogo.............................. 37 4.5 Modelagem................................... 38 4.6 Codificando o Jogo............................... 45 4.6.1 Codificando o cliente.......................... 45 4.6.2 Codificando o Servidor......................... 61 4.7 Imagens do Jogo................................ 68 5 Conclusão 75 5.1 Trabalhos Futuros................................ 75 Referências Bibliográficas 77

ix Lista de Figuras 2.1 Membros da Open Handset Alliance - OHA................. 8 2.2 Arquitetura da Plataforma Android...................... 10 3.1 Exemplo de um projeto Android........................ 16 3.2 Ciclo de vida de uma Activity......................... 18 3.3 Diagrama representando a arquitetura cliente-servidor............ 24 3.4 Diagrama representando a arquitetura ponto-a-ponto............ 25 3.5 Servidor aguardando uma requisição de conexão............... 31 3.6 Confirmação de conexão do cliente com o servidor.............. 32 3.7 Confirmação de fluxo de dados no servidor.................. 32 3.8 Exemplo de um projeto Android........................ 33 4.1 Tabuleiro 3x3 e símbolos padrões utilizados no Jogo da Velha........ 36 4.2 Possibilidade de Vitoria no Jogo da Velha.................. 37 4.3 Arquitetura do Jogo OX Game........................ 37 4.4 Diagrama de Casos de Uso do Jogo da Velha OX Game........... 40 4.5 Diagrama de Atividades do Jogo da Velha OX Game............ 41 4.6 Diagrama de Classes do Jogo da Velha OX Game referente ao Cliente... 43 4.7 Diagrama de Classes do Jogo da Velha OX Game referente ao Servidor.. 44 4.8 Localização dos arquivos XML no projeto OX Game............ 47 4.9 Primeira parte da tela do Jogo OX Game................... 49 4.10 Primeira e segunda parte da tela do Jogo OX Game............. 51 4.11 Primeira, segunda e terceira parte da tela do Jogo OX Game........ 52 4.12 Tela do Jogo OX Game............................. 53 4.13 Menu principal do jogo OX Game....................... 54 4.14 Diagrama de sequência do fluxo de dados do jogo OX Game........ 67 4.15 Fluxo de telas do jogo OX Game....................... 69 4.16 Tela de Aplicativos do Android........................ 70

4.17 Tela de Apresentação do Jogo......................... 70 4.18 Menu principal do jogo............................. 71 4.19 Tela de seleção de nível e Tela de inserção do nome do jogador....... 72 4.20 Tela do jogo da velha e Tela de opções durante uma partida........ 72 4.21 Tela com a lista de jogadores online...................... 73 4.22 Aviso de desafio a um jogador......................... 74 4.23 Tela referente ao resultado do jogo...................... 74 x

xi Lista de Códigos 3.3.1 Código de criação de um objeto ServerSocket................. 26 3.3.2 Código responsável por gerenciar requisições de conexão........... 27 3.3.3 Código de criação dos objetos OutputStream e InputStream no Servidor. 27 3.3.4 Código exemplo de processamento de fluxo de dados............. 28 3.3.5 Código de finalização dos fluxos de dados e Socket no Servidor....... 28 3.3.6 Código de criação do Socket no Cliente.................... 29 3.3.7 Código de criação dos objetos OutputStream e InputStream no Cliente.. 29 3.3.8 Código exemplo de processamento de fluxo de dados no Cliente...... 29 3.3.9 Código exemplo de processamento de fluxo de dados no Cliente...... 29 3.3.10Código fonte referente a implementação do servidor............. 30 3.3.11Código fonte referente a implementação do cliente.............. 31 4.6.1 Código fonte referente a implementação do cliente.............. 46 4.6.2 Declaração das características do arquivo telajogo.xml........... 48 4.6.3 Codificação da primeira parte da tela do Jogo OX Game.......... 48 4.6.4 Codificação de um botão do tabuleiro 3x3 do Jogo OX Game........ 49 4.6.5 Codificação do tabuleiro 3x3 do Jogo OX Game............... 50 4.6.6 Codificação do placar do Jogo OX Game................... 51 4.6.7 Codificação dos detalhes de design do Jogo OX Game............ 52 4.6.8 Requisição de conexao ao Servidor....................... 54 4.6.9 Descrição dos métodos criarconexao(ip, porta) e conectar()......... 55 4.6.10Classe responsável por aguardar o desafio de um oponente......... 56 4.6.11Loop responsável pela análise das mensagens enviadas pelo servidor.... 57

xii 4.6.12Método responsável por avisar o jogador de um desafio e iniciar uma nova partida...................................... 57 4.6.13Construtor da classe Partida localizada no servidor............. 58 4.6.14Método responsável pelo clique de uma jogada no tabuleiro......... 58 4.6.15Classe concorrente Analisador......................... 59 4.6.16Método avisarterminou(boolean terminou).................. 60 4.6.17Loop de recebimento de jogadas na classe Mensageiro............ 60 4.6.18Método avisarreultado(string resultado)................... 61 4.6.19Método desconectar().............................. 61 4.6.20Método desconectar().............................. 62 4.6.21Inicialização do servidor em uma porta especificada............. 62 4.6.22Método desconectar().............................. 63 4.6.23Código que distingue qual o tipo de jogador................. 64 4.6.24Construtor da classe Partida.......................... 64 4.6.25Método run() responsável pela rotina do jogo................ 65 4.6.26Método lerjogada()............................... 65 4.6.27Método desativarjogadaoponente(int pos).................. 65 4.6.28Método trocarjogador(jogador jogador)................... 66 4.6.29Método desconectar().............................. 66 4.6.30Método desconectar().............................. 67

Capítulo 1 Introdução O mercado de celulares está crescendo cada vez mais. Estudo realizado no ano de 2011 pela empresa Teleco - Inteligência em Telecomunicações, mostra que já existiam mais de 6 bilhões de celulares, isso corresponde a mais ou menos um celular por pessoa no mundo[teleco2012]. O crescimento do número de celulares é caracterizado pela busca dos usuários por diversos recursos como músicas, interface visual, jogos, GPS, acesso a internet e e-mails, câmera e ainda TV digital[lecheta2010]. Segundo Lecheta, o mercado corporativo também está crescendo muito, e diversas empresas estão buscando incorporar aplicações móveis ao dia-a-dia no intuito de agilizar negócios. Dessa forma, empresas e desenvolvedores focam em desenvolver aplicativos que visam negócios e lucros enquanto os usuários buscam dispositivos móveis que abragem as necessidades do cotidiano[lecheta2010]. Os celulares smartphones, celulares com funcionalidades avançadas que podem ser estendidas por meio de programas executados por seu sistema operacional, estão tendo um diferencial quanto aos celulares das gerações passadas. Todo esse diferencial pode ser notado por meio das melhorias que vem acontecendo em hardware, como telas maiores e uma resolução melhor, e em software, com CPUs mais rápidas ajudando na melhoria de desempenho. Além disso, vale ressaltar que esses celulares são capazes de se conectar a Internet pelos vários tipos de conexão (GSM, GPRS, 3G, WiFi) além de prover de diversos meios alternativos como tela touchscreen, GPS, camera, etc. Dentre as áreas de interesse dos usuários, os jogos vem despertando a atenção dos mais

Objetivo 2 variados grupos de pessoas. Permitir que um usuário jogue jogos online com seus amigos ou qualquer tipo de pessoa, é um entreternimento bastante complexo de ser oferecido, pois o maior desafio é construir jogos multiusuários. O indíce de procura de jogos multiusuários vem crescendo cada vez mais, pois pessoas jogam colaborando um com os outros ou competindo um com o outro, utilizando o mesmo ambiente, conectados por algum tipo de rede[geek2012]. A área de jogos e, principalmente, as aplicações de jogos para dispositivos móveis são estimulantes pela complexidade dos desafios tecnológicos que apresentam e pelo potencial de aplicabilidade que existe. O sistema operacional Android[Android2012], que surgiu voltado para esse avanço tecnológico, permite a construção de jogos desse tipo. Esse sistema operacional vem conquistando o mercado[nottec2012] e proporcionando experiências aos usuários e desenvolvedores, pois é um sistema que engloba as necessidades do cotidiano e éopen source, facilitando o desenvolvimento de aplicações. 1.1 Objetivo O objetivo desse trabalho é desenvolver um jogo multiusuário utilizando a plataforma Android. O jogo é baseado no jogo tradicional e popular Jogo da Velha, no qual permite a comunicação entre os jogadores a partir das jogadas realizadas. 1.1.1 Específicos Aplicar as regras do jogo da velha na construção de um jogo multiusuário. Aplicar os conceitos da plataforma Android no desenvolvimento do jogo da velha. Aplicar o conceito de sockets na comunicação de dados do jogo. Desenvolver o protótipo de uma biblioteca de comunicação multiusuário por meio de sockets.

Justicativa 3 1.2 Justificativa Os jogos multiusuários são considerados jogos divertidos por permitirem que pessoas joguem entre si sem ser necessário estarem próximos um dos outros. Além disso, a implementação de um jogo multiusuário requer a análise e decisão de como o jogo será implementado. Ao desenvolver um jogo desse tipo, há a necessidade de se ater a vários problemas inerentes ao dispositivo em que é utilizado, como limitação de memória, recursos e processamento, tamanho da tela e mecanismo de entrada não apropriada, acrescido, ainda, das dificuldades inerentes no desenvolvimento de sistemas distribuídos de tempo real como tempo de resposta, sincronia de instruções, entre outros. Desenvolver um jogo multiusuário é complexo por envolver muitas áreas de conhecimento e, ao mesmo tempo, um desafio para quem possui conhecimentos na área de computação. Esse trabalho se destaca por abordar problemas de infraestrutura de desenvolvimento de componentes relacionados a jogos em dispositivos móveis e se enquadra em uma área de pesquisa bem recente, denominada jogos computacionais, que vem despertando muito interesse da comunidade científica e de empresas, por revolucionar substancialmente as aplicações de entretenimento digital. No Brasil, a área de desenvolvimento de jogos ainda está em processo de evolução, mas é bastante promissora do ponto de vista de empresas, universidades e em outras áreas do conhecimento[geek2012]. 1.3 Metodologia O projeto adota a seguinte metodologia de trabalho: Estudar e Implementar os conceitos da plataforma Android Projetar as telas que o jogo possui. Elaborar o fluxo das telas projetadas. Implementar uma interface gráfica para o jogo da velha utilizando XML Modelar o jogo utilizando a engine do jogo da velha Implementar o nível básico para o jogo da velha

Estrutura do Trabalho 4 Implementar o nível avançado para o jogo da velha Implementar o conceito de multiusuário no jogo da velha utilizando socket Executar e testar o jogo em dispositivos móveis. 1.4 Estrutura do Trabalho Nesse trabalho, é apresentado o jogo multiusuário OX Game. No capítulo 2, a plataforma Android, plataforma utilizada pelo jogo, é descrita, informando o tipo de plataforma, o kit de desenvolvimento disponível, a linguagem de programação utilizada, entre outros. No capítulo 3, a comunicação de dados entre dispositivos móveis é o foco. No capítulo 4, o desenvolvimento do jogo é tratado e, por fim, no capítulo 5, uma conclusão é apresentada assim como sugestões de futuros desenvolvimentos utilizando o jogo OX Game como base.

Capítulo 2 Plataforma Android O Android é uma plataforma completa para dispositivos móveis em geral, contendo um sistema operacional baseado em Linux, middleware, aplicativos e interface de usuário[pereira2009]. 2.1 História A tecnologia voltada aos dispositivos móveis está se desenvolvendo cada vez mais e os seus usuários buscam um dispositivo que melhor atenda as necessidades do cotidiano. Com base nesse cenário, Andy Rubin (co-fundador da Danger), Rich Miner (co-fundador da Wildfire Communications, Inc.), Nick Sears (vice-presidente da T-Mobile) e Chris White (líder de projeto e desenvolvimento de interface na WebTV ) fundaram em outubro de 2003, na cidade de Palato Alto, Califórnia, Estados Unidos, a Android, Inc. Inicialmente, pouco se sabia sobre a Android, Inc. em virtude de operarem secretamente e apenas informarem que estavam trabalhando em software para celulares. Em julho de 2005, o Google adquiriu a Android, Inc. e os co-fundadores Andy Rubin, Rich Miner, Nick Sears e Chris White passaram a fazer parte desse novo time. Enquanto suposições surgiam de que o Google estaria planejando competir no mercado de dispositivos móveis, o time liderado por Rubin tentava desenvolver uma plataforma poderosa baseado no kernel do Linux e com a premissa de prover flexibilidade, tornando-o um sistema aberto

História 6 e de fácil atualização. Segundo Nunes, especulações sobre a intenção do Google em entrar no mercado de comunicações móveis continuaram a surgir até dezembro de 2006. Houveram rumores de que o Google estaria desenvolvendo um celular com a sua marca, definindo especificações técnicas e mostrando protótipos para os fabricantes de celular e operadores de telefonia móvel. Além disso, em setembro de 2007, a InformationWeek cobriu um estudo da Evalueserve reportando que o Google apresentou vários pedidos de patentes na área de telefonia móvel[nunes2011]. Por volta de dois meses após o estudo levantado pela InformationWeek, no dia 05 de novembro de 2007, um grupo formado por grandes empresas do mercado de telefonia móvel, sob nome Open Handset Alliance (OHA), é criado e liderado pelo Google. Dentre as várias empresas, destacam-se a Texas Instruments, Broadcom Corporation, Google, HTC, Intel, LG, Marvell Technology, Motorola, Nvidia, Qualcomm, Samsung Electronics, Sprint Nextel e T-Mobile. Segundo Lecheta, no site da OHA existe uma ótima descrição do que seria essa aliança: Hoje, existem 1,5 bilhões de aparelhos de televisão em uso em todo o mundo e 1 bilhão de pessoas têm acesso à Internet. No entanto, quase 3 bilhões de pessoas têm um telefone celular, tornando o aparelho um dos produtos de consumo mais bem sucedidos do mundo. Dessa forma, construir um aparelho celular superior melhoraria a vida de inúmeras pessoas em todo o mundo. A Open Handset Alliance é um grupo formado por empresas líderes em tecnologia móvel que compartilham essa visão para mudar a experiência móvel de todos os consumidores[...]. [Lecheta2010]. Assim, o objetivo do grupo era definir uma plataforma única e aberta para celulares de modo a deixar os consumidores mais satisfeitos com o produto final além de criar uma plataforma moderna, flexível para o desenvolvimento de aplicações coorporativas. Como resultado da OHA, seu primeiro produto consistiu na plataforma Android, uma plataforma de desenvolvimento para aplicações móveis com sistema operacional baseado no kernel 2.6 do Linux, interface visual, diversas aplicações instaladas e um ambiente de desenvolvimento inovador, flexível e poderoso. Essa nova plataforma surgiu a partir do projeto Android Open Source Project (AOSP) e tem sido acompanhada com diversas manutenções e atualizações[lecheta2010][nunes2011].

Open Handset Alliance (OHA) 7 2.2 Open Handset Alliance (OHA) O Android surgiu da parceria do Google com a Open Handset Alliance (OHA), uma aliança onde figuram as principais empresas do mercado móvel mundial. Segundo Pereira, essa aliança possui a seguinte estrutura[pereira2009]: Operadoras de telefonia móvel: responsável pela conexão, fornecem o serviço para o usuário final; Fabricantes de aparelhos: responsáveis pela criação do hardware; Empresas Semicondutores: fazem os chips dos aparelhos celulares; Empresas de software: desenvolvem os softwares que serão executados no Android; Empresas de comercialização: responsáveis pela divulgação, marketing e comercialização dos produtos para o usuário. No sítio oficial da OHA, é possível verificar as 84 empresas que compõem a aliança, conforme figura 2.1:

Open Handset Alliance (OHA) 8 Figura 2.1: Membros da Open Handset Alliance - OHA

Licença 9 2.3 Licença O código fonte do Android está disponível sob licenças livres e de plataforma aberta. O Google publica a maior parte dos códigos fontes sob a Licença Apache versão 2.0 e o restante, as mudanças do kernel do Linux, sob a Licença GNU General Public License versão 2.0. A OHA desenvolve modificações ao kernel do Linux a parte, com código fonte disponível publicamente a qualquer momento, sob licença GPL do Android. O resto do Android é desenvolvido em particular, com código fonte liberado publicamente quando uma nova versão principal é lançada. A única versão cujo cógido fonte não foi publicado após um lançamento de um nova versão foi a Honeycomb. Como justificativa, o Google informou que a versão havia sido lançada de forma rápida e que era direcionada a tabletes, evitando que os usuários a utilizassem em celulares até a mesclagem das funcionalidades dessa versão com a versão destinada a celulares que viria posteriomente. Com o lançamento da versão Ice Cream Sandwich, o código fonte foi liberado e assim eliminou as dúvidas sobre o compromisso com o código aberto do Android[Nunes2011]. 2.4 Arquitetura A arquitetura da plataforma Android está estruturada conforme figura 2.2:

Arquitetura 10 Figura 2.2: Arquitetura da Plataforma Android Segundo Schemberger, a arquitetura da plataforma Android é dividida em quatro camadas: Kernel GNU Linux, bibliotecas, framework para aplicações e as próprias aplicações - além da porção runtime, necessária para a execução dos aplicativos no dispositivo[schemberger2012]. Todo o gerenciamento dos processos, threads, arquivos, pastas, redes e drivers dos dispositivos são gerenciados pelo kernel 2.6 do Linux, a camada mais baixa da arquitetura. O runtime do Android é construído em cima do kernel 2.6 do Linux e é responsável por criar e executar aplicações Android. Cada aplicação é executada em seu próprio processo e com a própria máquina virtual chamada Dalvik. As aplicações Android são compactadas em um arquivo de formato.apk e armazenadas na pasta de aplicativos chamada dados, no sistema operacional Android. Essa pasta é acessível apenas para o usuário root por razões de segurança. As bibliotecas de sistema são as responsáveis por tarefas computacionalmente pesadas, como renderização gráfica, reprodução de audio e

Segurança 11 acesso ao banco de dados, que não seria adequado para a maquina virtual Dalvik, e a camada de aplicação, por sua vez, reune as bibliotecas de sistema e o runtime. Essa camada gerencia as aplicações e fornece um framework elaborado no qual as aplicações funcionam[lecheta2010][pereira2009][schemberger2012]. 2.5 Segurança Devido o sistema operacional do Android ser baseado no kernel 2.6 do Linux, a segurança do Android é baseada na segurança do Linux. Toda vez que um aplicativo é instalado em um dispositivo Android, um novo usuário Linux é criado para aquele programa. Cada aplicativo no Android inicia um novo e único processo no sistema operacional, sendo que cada processo possui uma thread específica para sua execução. Esses processos são nomeados de sandbox, um mecanismo de segurança que separa os programas em execução em um ambiente isolado, com acesso limitado aos recursos do sistema e com diretórios que serão usados pelo aplicativo e somente pelo usuário Linux correspondente. Como os aplicativos ficam completamente isolados uns dos outros, qualquer tentativa de acessar informações de outro aplicativo é necessário ser explicitamente autorizado pelo usuário, podendo ser negado a instalação do aplicativo ou autorizado a instalação[pereira2009][lecheta2010][schemberger2012][nunes2011]. 2.6 Características Segundo Pereira, o Android é uma plataforma para a tecnologia móvel completa, envolvendo um pacote com programas para celulares, já com um sistema operacional, middleware, aplicativos e interface do usuário. Foi construída para ser verdadeiramente aberta e com intenção de permitir aos seus desenvolvedores criar aplicações móveis que possam tirar proveito do que um aparelho portátil possa oferecer[pereira2009]. Por possuir uma plataforma aberta, diversas atualizações são realizadas de modo a incorporar novas tecnologias conforme as necessidades surgem. Cada atualização no Android refere-se a solução de algum bug ou a adição de alguma funcionalidade nova. Cada versão é nomeada alfabeticamente por nomes de sobremesa:

O Kit de Desenvolvimento de Software - SDK 12 Versão 1.5 - Cupcake Versão 1.6 - Donut Versão 2.0 - Éclair Versão 2.2 - Froyo Versão 2.3 - Gingerbread Versão 3.0/ 3.1/ 3.2 - Honeycomb Versão 4.0 - Ice Cream Sandwich A versão 1.5 (Cupcake) adicionou suporte a bibliotecas nativas as aplicações Android, que antes eram restritas a serem escritas em Java puro. Código nativo pode ter muitos benefícios em situações onde o desempenho é o mais importante. A versão 1.6 (Donut) introduziu suporte para diferentes resoluções de tela. Na versão 2.0 (Éclair) foi adicionado suporte a telas multi-toques, e na versão 2.2 (Froyo) adicionaram a compilação just-intime (JIT) a máquina virtual Dalvik. O JIT acelera a execução de aplicações Android, dependendo do cenário, em até 5 vezes. A versão 2.3 (Gingerbread) adicionou um garbage collector concorrente ao da máquina virtual Dalvik e refinou a interface de usário, melhorando o teclado virtual e acrescentando a funcionalidade copiar-colar. As versões 3.0/ 3.1/ 3.2 (Honeycomb) são orientadas para tabletes e com suporte para dispositivos de telas grandes, com multiprocessadores e aceleradores de gráficos, sistema de encriptação completa, carregamento de mídia a partir de cartões de memória e suporte para dispositivos de entradas via USB. A versão 4.0 (Ice Cream Sandwich) é a mais recente, anunciada em 19 de outubro de 2011, e trouxe as funcionalidades da versão 3.0 (honeycomb) para smartphones além de incluir desbloqueio por reconhecimento facial, controle e monitoramento de dados via rede, unificação de contatos por redes sociais e busca de e-mails offline. 2.7 O Kit de Desenvolvimento de Software - SDK O kit de desenvolvimento de software(sdk) é a ferramenta principal para desenvolver aplicações utilizando a plataforma Android. O SDK inclui um conjunto abrangente de ferra-

O Kit de Desenvolvimento de Software - SDK 13 mentas de desenvolvimento, incluindo um depurador, bibliotecas, um emulador de terminal móvel (baseada em QEMU - uma máquina virtual de código aberto para simular diferentes plataformas de hardware), documentação, código de exemplo e tutoriais. As plataformas de desenvolvimento suportadas incluem computadores que executam o Linux (qualquer distribuição Linux moderna), Mac OS X 10.4.9 ou superior e Windows XP ou posterior. O ambiente de desenvolvimento integrado (IDE) suportado oficialmente é o Eclipse (versões 3.4, 3.5 ou 3.6) usando o Android Development Tools (ADT) Plugin, embora os desenvolvedores possam usar qualquer editor de texto para editar arquivos Java e XML e, em seguida, usar ferramentas de linha de comando (Java Development Kit e Apache Ant são necessários) para criar, construir e depurar aplicativos do Android[Lecheta2010][Schemberger2012]. Em 12 de novembro de 2007, ocorreu o pré-lançamento do SDK do Android. Em 15 de Julho de 2008, com o concurso de desenvolvimento de aplicações em Android, Android Developer Challenge, a equipe organizadora acidentalmente enviou um e-mail a todos os participantes do Android Developer Challenge anunciando que uma nova versão do SDK estava disponível em uma área privada de download. O e-mail era destinado somente para os vencedores da primeira rodada do concurso. A revelação de que o Google estava fornecendo novas versões do SDK para alguns desenvolvedores e não para outros, levou muitos à frustração, sendo divulgado dentro da comunidade de desenvolvimento para Android. Em 18 de Agosto de 2008, o Android SDK beta 0.9 foi liberado. Esta versão forneceu uma API atualizada e ampliada, ferramentas de desenvolvimento melhoradas e um design atualizado para a tela inicial. Instruções detalhadas para a atualização estavam disponíveis para aqueles que já trabalhavam com uma versão anterior. Em 23 de Setembro de 2008, o Android SDK 1.0 foi lançado, e de acordo com as notas de lançamento, incluiu principalmente correções de bugs além de terem algumas funcionalidades adicionadas. Várias versões foram lançados desde então. Melhorias no SDK do Android estão fortemente ligadas com o desenvolvimento da plataforma Android. O SDK também oferece suporte a versões mais antigas da plataforma, no caso de desenvolvedores desejarem atingir suas aplicações em dispositivos mais antigos. As ferramentas de desenvolvimento são componentes de download, sendo assim, depois de se ter baixado a última versão e plataforma, plataformas mais antigas e ferramentas

O Kit de Desenvolvimento de Software - SDK 14 também pode ser baixadas para realizar testes de compatibilidade[schemberger2012]. Segundo Nunes e Schemberger, as características gerais do SDK são: O depurador, capaz de depurar aplicações executando em um dispositivo ou emulador; O profile de memória e desempenho, que ajudam a encontrar vazamentos de memória e identificar trechos de código lento; O emulador de dispositivos, baseado em QEMU (uma máquina virtual de código aberto para simular diferentes plataformas de hardware), que, apesar de preciso, pode ser um pouco lento algumas vezes; Utilitários de linha de comando, que comunicam com os dispositivos; Scripts prontos e ferramentas para empacotamento e instalação de aplicações[nunes2011][schemberger2012].

Capítulo 3 Programação Distribuída usando Android Um sistema distribuído em Android é definido como um sistema no qual os componentes de uma aplicação, localizado nos dispositivos móveis, interligados em rede, se comunicam e coordenam suas ações apenas enviando e recebendo mensagens entre si. 3.1 Componentes das Aplicações em Android As aplicações em Android podem ser divididas em quatro tipos de componentes básicos que são definidos pela própria arquitetura[ableson2007], que são: Activities Broadcast e Intent Receivers Services Content Providers Nem toda aplicação precisa possuir todos os tipos de componentes básicos, mas pode ser construída a partir de alguma combinação entre eles. Uma vez decidido quais componentes são necessários para a construção de um aplicativo, deve-se listá-los em um arquivo

Componentes das Aplicações em Android 16 chamado AndroidManifest.xml. Segundo Pereira, toda aplicação deve ter um arquivo AndroidManifest.xml no diretório raiz. Este arquivo de configuração descreve os elementos da aplicação, as classes de cada componente a ser utilizado, qual o tipo de dado ele pode tratar, quando pode ser ativado, ou seja, serve para definir os dados de cada elemento[pereira2009]. Na figura 3.1, a estrutura básica de um projeto Android é representado. O projeto ClienteAndroid possui a biblioteca de pacotes referente a versão 2.2 do Android, uma pasta chamada sourcing (src) - contém todas as classes e activities especificadas pelo usuário (ClienteAndroid, GerenciadorConexoes, Mensageiro e Mensagem), uma pasta chamada generated Java files (gen)- contém arquivos que consistem em referências estáticas para todos os recursos que possam ser referenciadas de forma fácil e dinâmica a partir do código Java, uma pasta chamada resources (res) - contém todos os recursos do projeto: ícones, imagens, cadeias de caracteres e layouts, e o arquivo AndroidManifest.xml. Figura 3.1: Exemplo de um projeto Android

Componentes das Aplicações em Android 17 3.1.1 Activities Activity, ou atividade, é uma tela da aplicação. A maioria das aplicações consiste de várias telas. Por exemplo, uma aplicação de mensagens de texto, deve possuir uma tela para exibir a lista de contatos, possíveis destinatários da mensagem, uma segunda tela para escrever a mensagem para o contato selecionado, e outras telas para ver as mensagens antigas e alterar configurações. Cada uma dessas telas deve ser implementada como uma activity. Cada activity é implementada como uma única classe que estende a classe de base Activity. Essa classe exibe a interface com o usuário, responde a eventos e segue um ciclo de vida específico. O ciclo de vida de uma activity está representada conforme figura 3.2[Pereira2009]:

Componentes das Aplicações em Android 18 Figura 3.2: Ciclo de vida de uma Activity

Componentes das Aplicações em Android 19 OnCreate(): método chamado quando a activity é inicialmente criada. obrigatório, chamado apenas uma vez. É um método OnStart(): chamado quando a activity torna-se visível para o usuário. OnResume(): é o topo da pilha de activity, chamado quando vai iniciar a interação com o usuário. OnPause(): chamado quando o sistema está perto de começar uma próxima activity. É utilizado para gravar as informações que ainda não foram salvas. OnStop(): é chamado quando a activity não estiver mais sendo utilizada pelo usuário e perdeu o foco para outra activity. OnDestroy(): pode ser chamado quando a activity terminou, ou quando o sistema precisa finalizar activities para liberação de recursos. OnRestart(): chamado quando a activity está interrompida e prestes a ser acionada pelo usuário novamente. Segundo Lecheta, uma activity tem um ciclo de vida bem definido. Quando uma activity é iniciada, ela é inserida no topo de uma pilha, chamada de activity stack ou pilha de atividades, e a activity anterior que estava em execução permanece abaixo dessa nova[lecheta2010]. As activities podem se encontrar em quatro estados[pereira2009]: Executando: a activity está ativa no visor do dispositivo. Parada: uma activity que perdeu o foco para outra, mantendo todas as informações de estado, porém não está interagindo com o usuário. Pode, ainda, ser finalizada em situações de baixo nível de memória disponível. Interrompida: caso uma activity não esteja sendo utilizada pelo usuário, ela mantém as suas informações de estado, porém são muitas vezes finalizadas quando uma recuperação de memória seja necessária, perdendo informações.

Componentes das Aplicações em Android 20 Finalizada: o sistema pode remover uma activity da memória, caso esteja interrompida ou parada. O estado anterior só pode ser restaurado se os métodos tiverem sido implementados pelo desenvolvedor. Segundo a documentação do Android, existem três subníveis do ciclo de vida principal, que por sua vez ficam se repetindo durante a execução da aplicação. Esses três ciclos são basicamente[androiddev2012][lecheta2010]: Entire Lifetime: inicia-se no método OnCreate(), onde a activity realiza toda a configuração, passa de um estado para outro e termina no método OnDestroy(), quando todos os recursos utilizados por esta activity são liberados. Visible Lifetime: inicia-se no método OnStart() e termina no método OnStop. É o ciclo onde a activity está disponível e visível para o usuáro, mesmo que este não esteja interagindo com ela. Quando o usuário não visualizar mais a activity, o método OnStop() é chamado, ou então, para colocar a activity visível, chama o método OnStart(). Foreground Lifetime: ocorre entre os métodos OnResume() e OnPause(). Este é o estado em que a activity está no topo da pilha de atividades e interagindo com o usuário. Durante esse ciclo, a activity pode alternar frequentemente entre os estados executando e pausado, sendo assim, recomendado que o código que executa os métodos OnPause() e OnResume() seja leve e rápido, proporcionando a troca dos estados sem a necessidade de uma requisição robusta. 3.1.2 Broadcast e Intent Receivers Brodacast e Intent Receivers são componentes que ficam aguardando a ocorrência de um determinado evento. Um evento, nesse caso, pode ser a inicialização do sistema operacional, uma chamada de voz, a chegada de um SMS ou um evento disparado por uma aplicação[meier2009]. Intents são elementos chave no Android porque facilitam a criação de novas aplicações a partir de aplicações já existentes. A classe Intent interage com outras aplicações e serviços que proporcionam informações necessárias para uma aplicação.

Componentes das Aplicações em Android 21 Segundo Lecheta, uma intent está presente em todas as aplicações Android e representa a necessidade da aplicação realizar algum processo. Uma intent é enviada ao sistema operacional como uma mensagem, chamada broadcast. Quando o sistema operacional recebe essa mensagem, decisões são tomadas dependendo do processo a ser realizado. Uma intent pode ser utilizada para: abrir uma nova tela de aplicação. solicitar ao sistema operacional que ligue para determinado número de celular. abrir o browser em um determinado endereço da internet. exibir algum endereço, localização ou rota no Google Maps. executar algum processamento pesado em segunda plano. abrir o mercado de aplicativos oficiais do Android (Play Store) para fazer a instalação de um determinado aplicativo. enviar uma mensagem para outra aplicação para executar algum outro processo[lecheta2010]. 3.1.3 Services Segundo Pereira, um service, que significa serviço, é um codigo sem interfaces de usuário, que rodam em segundo plano, não sendo interrompidos quando da troca de activities pelo usuário. Ao contrário da activity que tem um ciclo de vida próprio e um vida curta, os services mantêm o serviço ativo até que seja recebida outra ordem. Uma vez conectado com o serviço, pode-se comunicar com este através de uma interface apresentada para o usuário[pereira2009]. Um bom exemplo é um media player reproduzindo músicas a partir de uma lista de músicas. Em uma aplicação deste tipo, há uma ou mais activities que permitem ao usuário escolher músicas e reproduzi-las. Entretanto, o playback da música não pode ser tratado por uma atividade, pois o usuário espera que a música continue tocando mesmo depois que ele tenha mudado de tela. Neste caso, a atividade do media player pode iniciar um serviço

Programação Distribuída usando Android 22 para rodar em segunda plano e manter a música tocando. O sistema mantém o serviço de playback da música executando até que o serviço seja terminado. 3.1.4 Content Providers Segundo Lecheta, o Android permite armazenar diversas informações utilizando banco de dados, arquivos e o sistema de preferências. Contudo, geralmente essas informações ficam salvas dentro do pacote da aplicação, e somente a aplicação que criou o banco de dados ou o arquivo pode ter acesso às informações[lecheta2010]. Content Provider, ou provedor de conteúdos, pode ser interpretado como uma classe que permite que determinadas informações sejam públicas para todas as outras aplicações instaladas no sistema operacional. Utilizando essa classe, outras aplicações podem consultar, inserir, alterar e excluir informações. 3.2 Programação Distribuída usando Android Os aplicativos para Android são programados na linguagem Java, mas são compilados e executados na máquina virtual Dalvik - máquina virtual do sistema operacional Android. A IDE oficial para desenvolvimento em Android é o Eclipse, que fornece um ambiente Java rico, incluindo ajuda sensível ao contexto e sugestões de códigos[ibm2012]. Segundo Albuquerque, a linguagem Java apresenta características que facilitam a implementação de aplicações distribuídas. A linguagem é portátil e independente de plataforma, isto é, o código pode ser desenvolvido em uma plataforma e executado em outra plataforma diferente. Quando um programa Java é compilado, em vez de ser gerado um código destinado a uma plataforma específica, é gerado um código para uma máquina virtual. Qualquer máquina pode executar este código desde que saiba como interpretar as instruções geradas. Esta é uma abordagem diferente de outras linguagens de programação onde o código fonte precisa ser compilado para a plataforma onde será executado. Outra característica útil da linguagem Java no desenvolvimento de aplicações distribuídas é o suporte a múltiplas threads de execução. Isto facilita a implementação, por exemplo, de programas servidores. Em tais programas pode ser necessário atender simultaneamente a solicitação de múltiplos

Programação Distribuída usando Android 23 clientes[albuquerque2012]. A programação distribuída em Android utiliza classes existentes da linguagem Java e pacotes de comunicação em rede disponibilizadas pelo SDK. Esses pacotes são conhecidos como interfaces de programação de aplicativos - APIs (Application Programming Interface) para comunicação entre aplicações. Essas APIs abstraem muitos dos detalhes de configuração e implementação necessários em outras linguagens além de diminuir o volume de código da aplicação destinado a aspectos de comunicação e recursos de rede. Uma API é um recurso de rede multiuso que permite que os desenvolvedores Java possam criar aplicativos com esses pacotes. Um exemplo de API de comunicação, dentre outras, é o Socket. Segundo Vieira, a arquitetura de um sistema distribuído é basicamente definido em duas: a arquitetura cliente-servidor e a arquitetura ponto-a-ponto. Existem também variações destas arquiteturas que visam aumentar o desempenho e contornar alguns problemas ou necessidades específicas que estes sistemas possam apresentar para diferentes aplicações[vieira2011]. 3.2.1 Arquitetura Cliente-Servidor A arquitetura Cliente-Servidor é o modelo mais tradicional para aplicações online. Essa arquitetura constitui a maneira mais versátil de distribuir mensagens para um grande número de usuários e é caracterizada por ser centralizada, ou seja, existe um servidor que possui uma visão completa e permanentemente atualizada de todos os clientes conectados a ele. Na figura 3.3, pode-se observar um diagrama representando-a:

Programação Distribuída usando Android 24 Figura 3.3: Diagrama representando a arquitetura cliente-servidor Segundo Andrews, o principal problema desta arquitetura é o excesso de carga depositada no servidor. Muitas vezes os servidores precisam atender centenas ou milhares de conexões, o que exige um significativo esforço computacional. Outro ponto importante é a natureza centralizada da arquitetura, pois qualquer falha no hardware ou na conectividade da estação servidora, todas as conexões existentes podem ser abortadas[andrews2000]. 3.2.2 Arquitetura Ponto-a-Ponto A arquitetura ponto-a-ponto é definida por computadores que se encontram em rede e que estão todos interligados em uma cadeia descentralizada, onde cada um possui funções equivalentes, não havendo uma hierarquia entre eles. Todos os usuários são clientes e servidores, funcionando, assim, de forma totalmente independente e livre da existência de um servidor central. A figura 3.4 mostra a representação dessa arquitetura:

Serviços de Comunicação 25 Figura 3.4: Diagrama representando a arquitetura ponto-a-ponto Segundo Vieira, pelo fato dessa arquitetura ser caracterizada como descentralizada e robusta em relação aos problemas que afetam a arquitetura cliente-servidor, novos questionamentos surgem com esta descentralização. A largura de banda limitada de cada ponto, a troca de dados entre os pontos, a garantia de autenticidade e segurança dos dados são alguns desses questionamentos. Todavia, uma arquitetura ponto-a-ponto estruturada, permite que técnicas de roteamento e organização sejam utilizadas com certa eficiência, ao mesmo tempo em que a rede se torne escalável para uma grande quantidade de clientes[vieira2011]. 3.3 Serviços de Comunicação Aplicações distribuídas usam os serviços de comunicação providos pela rede através de interfaces de programação de aplicativos(apis). Os recursos fundamentais de rede utilizados pelo Android são declarados pelas classes e interfaces do pacote java.net, no qual possui funções que permitem o estabelecimento de comunicações baseadas em fluxo. Por intermé-

Serviços de Comunicação 26 dio dessas comunicações, os aplicativos visualizam a rede como um fluxo de dados, ou seja, enviando e recebendo dados de forma contínua por essa rede[albuquerque2012][ibm2012]. O Socket é exemplo de serviço de comunicação. Permite que um processo estabeleça uma conexão com outro processo. Enquanto a conexão estiver no ar, os dados fluem entre os processos em fluxos contínuos. Pode-se dizer que os Sockets são baseados em fluxo e que fornecem um serviço orientado para conexão. Essa comunicação é feita através das classes ServerSocket e Socket. O servidor usa a classe ServerSocket para aguardar conexões a partir dos clientes e, quando ocorre a conexão, a comunicação é efetivada através de um objeto da classe Socket. Estas classes escondem a complexidade presente no estabelecimento de uma conexão e no envio de dados através da rede. 3.3.1 Implementando um servidor utilizando Sockets de fluxo Implementar um servidor utilizando Sockets de fluxo e que trata as conexões e se comunica com os possíveis clientes requer cinco passos[deitel2010]: 1. Criar um objeto ServerSocket. 2. Esperar um conexão. 3. Obter os fluxos de entrada e saída do socket. 4. Realizar o processamento (comunicação). 5. Fechar a conexão. No passo 1, deve-se criar um objeto do tipo ServerSocket. A criação desse objeto é realizado pela chamada do construtor ServerSocket, demonstrado no código 3.3.1: 1 ServerSocket servidor = new ServerSocket( porta, limitedeconexoes ); Código 3.3.1: Código de criação de um objeto ServerSocket No construtor ServerSocket existem dois parâmetros. O parâmetro porta registra o número da porta TCP disponível para a conexão e o parâmetro limitedeconexoes especifica um número máximo de clientes que podem esperar para se conectar ao servidor, ou seja, o

Serviços de Comunicação 27 número máximo de conexões. O número da porta é utilizado pelos clientes para localizar o aplicativo servidor no computador servidor. Isso costuma ser chamado de ponto de handshake. No passo 2, o servidor deve gerenciar as requisições de conexão dos clientes, para tanto deve ser criado um objeto do tipo Socket para cada requisição aceita pelo objeto Server- Socket. O servidor passa a ouvir indefinidamente uma tentativa de conexão por meio do método ServerSocket accept. Esse método encontra-se descrito no código 3.3.2: 1 Socket conexao = server.accept(); Código 3.3.2: Código responsável por gerenciar requisições de conexão Esse método retorna um Socket quando uma conexão com um cliente é estabelecida. O Socket, então, permite ao servidor interagir com o cliente. As interações com o cliente ocorrem em uma porta diferente de servidor a partir do ponto de handshake, permitindo, assim, que a porta especificada no passo 1 seja utilizada novamente em um servidor de múltiplas threads de modo a aceitar outras conexões. No passo 3, após a conexão entre o servidor e o cliente, faz-se necessário que a comunicação seja possível. Desse modo, os objetos do tipo OutputStream e InputStream devem ser criados de modo a permitir que o servidor se comunique com o cliente enviando e recebendo bytes. O servidor envia informações ao cliente via um objeto OutputStream e recebe informações do cliente via um objeto InputStream. Além disso, o servidor invoca o método getoutputstream no Socket para obter a referência ao OutputStream do Socket e invoca o método getinputstream no Socket para obter uma referência ao InputStream do Socket. Esse passo encontra-se demonstrado no código 3.3.3: 1 ObjectInputStream entradadedados = new ObjectInputStream( conexao.getinputstream() ); 2 ObjectOutputStream saidadedados = new ObjectOutputStream( conexao.getoutputstream() ); Código 3.3.3: Código de criação dos objetos OutputStream e InputStream no Servidor No passo 4, a comunicação é realizada entre o servidor e o cliente via os objetos OutputStream e InputStream. Como exemplo, o código 3.3.4 utiliza os métodos writeobject(objeto) e readobject() de modo a enviar uma mensagem de sucesso referente a conexão

Serviços de Comunicação 28 realizada. 1 String mensagem = "Conexao realizada com sucesso!"; 2 saidadedados.writeobject( mensagem ); 3 saidadedados.flush(); 4 String resposta = (String) entradadedados.readobject(); Código 3.3.4: Código exemplo de processamento de fluxo de dados É importante lembrar que existem vários métodos que possibilitam a leitura e escrita a partir de Streams. No exemplo mencionado, os métodos utilizados são de escrita e leitura de objetos, no caso, especificamente, são enviadas e recebidas Strings. Entretanto é possível enviar e receber vários outros objetos, tipos primitivos, entre outros. No passo 5, após a transmissão ter sido realizada, faz-se necessário finalizar os objetos de comunicação, assim como a conexão do Socket. O encerramento ocorre utilizando o método close() nos objetos InputStream e OutputStream e no Socket, conforme código 3.3.5: 1 entradadedados.close(); 2 saidadedados.close(); 3 conexao.close(); Código 3.3.5: Código de finalização dos fluxos de dados e Socket no Servidor 3.3.2 Implementando um cliente utilizando Sockets de fluxo A implementação do cliente é bastante semelhante ao servidor. implementação se faz necessário executar quatro passos: Para realizar essa 1. Criar um Socket. 2. Obter os fluxos de entrada e saída do socket. 3. Realizar o processamento (comunicação). 4. Fechar a conexão. No passo 1, deve-se criar um Socket de modo a conectar-se ao servidor. O construtor do Socket, conforme código 3.3.6, estabelece a conexão.

Serviços de Comunicação 29 1 Socket conexaocliente = new Socket( enderecodoservidor, porta ); Código 3.3.6: Código de criação do Socket no Cliente O construtor do Socket possui duas variáveis: enderecodoservidor e porta. A requisição de conexao ao servidor é realizada indicando o endereço e a porta no qual a aplicação está hospedada. Se a tentativa de conexão for bem sucedida, essa instrução retorna um Socket. Caso contrário, uma falha de exceção de entrada e saída é invocada. No passo 2, o cliente também necessita criar objetos InputStream e OutputStream e utilizar os métodos getinputstream e getoutputstream para obter as referências ao Input- Stream e OutputStream do Socket. Desse modo, caso o servidor envie valores com um objeto ObjectOutputStream, o cliente deverá ler esses valores com um objeto ObjectInputStream. O código 3.3.7 relata essa implementação no cliente: 1 ObjectInputStream entrada = new ObjectInputStream( conexaocliente.getinputstream() ); 2 ObjectOutputStream saida = new ObjectOutputStream( conexaocliente.getoutputstream() ); Código 3.3.7: Código de criação dos objetos OutputStream e InputStream no Cliente No passo 3, ocorre a comunicação entre o cliente e servidor. As informações são enviadas e recebidas utilizando os objetos InputStream e OutputStream. Como exemplo, o código 3.3.8 demonstra a informação recebida do servidor referente a confirmação de conexão e, em seguida, o cliente encaminha uma outra mensagem. 1 String confirmacaodeconexao = (String) entrada.readobject(); 2 String ok = "OK!"; 3 saida.writeobject(ok); 4 saida.flush(); Código 3.3.8: Código exemplo de processamento de fluxo de dados no Cliente No passo 4, o cliente encerra os fluxos de dados e finaliza a conexão com o servidor. Nesse caso, o método close é utilizado, conforme código 3.3.9: 1 entrada.close(); 2 saida.close(); 3 conexaocliente.close(); Código 3.3.9: Código exemplo de processamento de fluxo de dados no Cliente

Serviços de Comunicação 30 3.3.3 Estabelecendo uma comunicação utilizando a arquitetura cliente-servidor A partir da utilização de Sockets de fluxo, uma comunicação entre cliente e servidor pode ser implementada. Executando os passos para a implementação do servidor e do cliente, demonstrado, respectivamente, nos subtópicos 3.3.1 e 3.3.2, pode-se obter uma conexão e realizar a troca de informações. No código 3.3.10 é demonstrado a implementação completa de um servidor simples que tem como objetivo receber uma conexão e enviar uma confirmação ao cliente caso tenha sido bem sucedida. 1 import java.io.objectinputstream; 2 import java.io.objectoutputstream; 3 import java.net.inetaddress; 4 import java.net.serversocket; 5 import java.net.socket; 6 7 public class Servidor { 8 public static void main(string[] args) { 9 try { 10 //Passo 1: Criando um objeto ServerSocket 11 ServerSocket server = new ServerSocket(9876, 10); 12 System.out.println("Servidor -> Esperando Conexao."); 13 14 //Passo 2: Esperando uma conexao 15 Socket conexao = server.accept(); 16 17 //Passo 3: Obtendo os fluxos de entrada e saida 18 ObjectInputStream entradadedados = new ObjectInputStream(conexao.getInputStream()); 19 ObjectOutputStream saidadedados = new ObjectOutputStream(conexao.getOutputStream()); 20 21 //Passo 4: Realizando o processamento/comunicacao 22 String mensagem = "Conexao realizada com sucesso!"; 23 saidadedados.writeobject( mensagem ); 24 saidadedados.flush(); 25 String resposta = (String) entradadedados.readobject(); 26 System.out.println("Servidor -> " + resposta); 27 28 //Passo 5: Finalizando os fluxos de dados e o socket 29 saidadedados.close(); 30 entradadedados.close(); 31 conexao.close(); 32 } catch (Exception e) { 33 e.printstacktrace(); 34 } 35 } 36 } Código 3.3.10: Código fonte referente a implementação do servidor No código 3.3.11 é demonstrado a implementação de um cliente de modo a requerer uma conexão com o servidor. Caso a conexão seja realizada com sucesso, o cliente receberá uma mensagem de sucesso e, em seguida, enviará uma outra mensagem de modo a informar ao servidor que a comunicação está sendo efetuada corretamente.

Serviços de Comunicação 31 1 import java.io.ioexception; 2 import java.io.objectinputstream; 3 import java.io.objectoutputstream; 4 import java.net.socket; 5 6 public class Cliente { 7 public static void main(string[] args) throws ClassNotFoundException{ 8 try { 9 //Passo 1: Criando um Socket 10 Socket conexaocliente = new Socket("192.168.0.10", 9876); 11 12 //Passo 2: Obtendo os fluxos de entrada e saida do socket. 13 ObjectOutputStream saida = new ObjectOutputStream(conexaoCliente.getOutputStream()); 14 ObjectInputStream entrada = new ObjectInputStream(conexaoCliente.getInputStream()); 15 16 //Passo 3: Realizando o processamento 17 String confirmacaodeconexao = (String) entrada.readobject(); 18 String ok = "OK!"; 19 saida.writeobject(ok); 20 saida.flush(); 21 System.out.println(confirmacaoDeConexao); 22 23 //Passo 4: Fechando os fluxos de entrada, de saida e o socket 24 saida.close(); 25 entrada.close(); 26 conexaocliente.close(); 27 }catch (IOException e) { 28 System.out.println("Erro: "+ e); 29 } 30 } 31 } Código 3.3.11: Código fonte referente a implementação do cliente Ao executar o código 3.3.10 - código referente ao servidor, observa-se, na figura 3.5, que o mesmo está aguardando a requisição de uma conexão: Figura 3.5: Servidor aguardando uma requisição de conexão

Serviços de Comunicação 32 Ao executar o código 3.3.11 - código referente ao cliente, o servidor aceita a conexão e envia a mensagem de confirmação. Após o recebimento dessa mensagem, o cliente envia uma mensagem de modo a mostrar que o fluxo de dados ocorre normalmente. Na figura 3.6 temos a mensagem de confirmação no cliente, assim como na figura 3.7, a mensagem no servidor de que o fluxo ocorre normalmente. Figura 3.6: Confirmação de conexão do cliente com o servidor Figura 3.7: Confirmação de fluxo de dados no servidor Por fim, ambos fluxos e Sockets são finalizados, terminando assim todo esse processo. Na figura 3.8 é representado o diagrama de sequência referente a essa comunicação. Em resumo, o cliente cria um objeto Socket (new Socket()) e realiza a conexão com o servidor (representado no diagrama pelo método conectar()). Por sua vez, o servidor autentica essa

Serviços de Comunicação 33 conexão e o fluxo de dados se inicia logo após os objetos (Streams) de entrada e saída serem criados. Terminando a comunicação, esses objetos são finalizados (fecharstreams()) assim como as respectivas conexões fecharconexao(). Figura 3.8: Exemplo de um projeto Android

Capítulo 4 Desenvolvimento Este capítulo apresenta o desenvolvimento do jogo da velha multisuário online chamado OX Game, onde são descritas as etapas de desenvolvimento, a abstração da arquitetura utilizada e a codificação do sistema. 4.1 Etapas de Desenvolvimento O processo de desenvolvimento de um jogo requer decisões que devem ser avaliadas de modo a torná-lo mais funcional e atraente. Decisões como a metodologia de desenvolvimento a ser utilizada, o tipo de arquitetura e que linguagem de programação escolher são cruciais para construir um jogo de qualidade. Segundo Bates, o desenvolvimento de jogos não requer somente a programação, mas diversas etapas antes e depois da codificação. As etapas mencionadas por Bates são descritas a seguir[bates2004]: Reunião Criativa Técnica adotada de modo a obter idéias de construção do jogo, baseada em uma reunião chamada de brainstorming - tempestade de idéias em português brasileiro. Rascunho Definição das principais características do jogo (interfaces, modo do jogo, regras, fluxos, entre outros). Detalhamento Momento de descrever as principais características definidas na etapa Rascunho, como quais ações serão desempenhadas pelo jogador, o sistema de pontuação, o estilo do jogo, etc.

O Projeto 35 Game Design Document Etapa em que o jogo precisa ser descrito em um documento físico, um roteiro que permite guiar a construção do jogo durante o desenvolvimento e codificação. Level Design É a etapa que mapeia todos os desafios que o jogador deve confrontar durante uma partida do jogo. Produção de Arte Construção do efeito sonoro e efeitos visuais do jogo. Integração Etapa que realiza a integração entre a lógica do jogo com a linguagem de programação definida e os mecanismos adotados pela plataforma a ser utilizada. Versão Beta Versão que engloba as versões Alpha (versões parciais que são definidades com o acréscimo de cada funcionalidade) e é composta por todas as funcionalidades propostas. Teste Etapa que realiza testes de funcionalidade a fim de detectar qualquer erro até obter a versão final do jogo. 4.2 O Projeto As decisões do projeto de desenvolvimento do jogo OX Game estão descritas a seguir: Android versão 2.1 ou superior: compatível com celulares de alta tecnologia e que possui conectividade 2G, 3G e Wifi. Controles na tela (Touchscreen): uso da tela para a manipulação do jogo e que está disponível na maioria dos celulares que possui a plataforma Android. Jogo da Velha Tradicional: baseado em partidas entre dois jogadores e realizadas em um tabuleiro 3x3 (9 posições).

Jogo da Velha 36 4.3 Jogo da Velha É um jogo casual e que possui regras e características acessíveis a um público infantil, juvenil e adulto. Esse jogo surgiu no Egito, mas o nome foi originado na Inglaterra quando mulheres se reuniam a tarde para conversar e bordar. As mulheres idosas, por serem impossibilitadas de bordar devido a problema oftamológicos, jogavam esse jogo simples, que passou a ser conhecido como o da velha. 4.3.1 Regras O jogo da velha utiliza um tabuleiro 3x3, ou seja, uma matriz composta de três linhas e três colunas. As partidas acontecem entre dois jogadores que fazem suas marcas em umas das posições livres do tabuleiro. Geralmente os símbolos utilizados são um círculo (O) e um xis (X), como mostrado na figura 4.1. Figura 4.1: Tabuleiro 3x3 e símbolos padrões utilizados no Jogo da Velha Cada jogador realiza uma jogada enquanto existir posições livres no tabuleiro. As jogadas são alternadas até que um jogador vença a partida ou ao completar o tabuleiro, ocasionando um empate. Um jogador é considerado vencedor quando consegue colocar três marcas em sequência, podendo ser no sentido horizontal, no sentido vertical ou diagonal, de acordo com a figura 4.2. Dessa forma, o jogo consiste que um jogador coloque três marcas em um dos sentidos que decide a vitória enquanto tenta evitar que seu oponente faço o mesmo antes.

Arquitetura do Jogo 37 Figura 4.2: Possibilidade de Vitoria no Jogo da Velha 4.4 Arquitetura do Jogo Ao desenvolver um jogo, é necessário analisar qual arquitetura é a mais adequada para atender as funcionalidades requeridas. O jogo da velha OX Game utiliza a arquitetura cliente-servidor (explicado no subtópico 3.2.1) e é formado por quatro componentes principais, mostrados na figura 4.3: Figura 4.3: Arquitetura do Jogo OX Game A figura mostra quatro clientes, hospedados em dispositivos móveis diferentes, e um servidor simples, em uma máquina (computador). Os quatros componentes possuem as seguintes funções: Interface de Usuário A interface de usuário, denominado pela letra I, é uma unidade de interface no qual é responsável por exibir ao jogador toda e qualquer funcionalidade do jogo, como por exemplo o menu de opções e a própria funcionalidade de jogar.

Modelagem 38 Cliente O cliente, denominado pela letra C, gerencia as comunicações com a interface e com o servidor. A comunicação usuário-interface é realizada pela navegação de telas do aplicativo. A comunicação com o servidor é obtida durante um jogo no qual um determinado jogador mantém a partida com seus adversários, possibilitando, assim, o fluxo das jogadas. Servidor O servidor, denominado pela letra S, é o responsável por processar e gerenciar o jogo e as partidas que estão sendo jogadas pelos usuários. Para cada dois clientes conectados e desafiados entre si, o servidor é responsável por conectá-los e iniciar a partida. Partida A partida, denominado pela letra P, representa um jogo entre dois jogadores. O gerenciamento e controle de quem é o vencedor, perdedor e se houve ou não um empate é realizado pela partida, cabendo apenas ao servidor informar aos jogadores o resultado. Mensageiro O mensageiro, denominado pela letra M, é o responsável por realizar a comunicação entre o cliente e o servidor. Essa comunicação é realizada utilizando sockets (explicado no tópico 3.3). Esse componente esconde a interface baixo-nível de socket entre os dispositivos móveis e o computador que hospeda o servidor. 4.5 Modelagem Segundo Booch, a modelagem de um sistema se caracteriza por ser uma parte central de todas as atividades que levam à implantação de um bom software. Modelos são construídos para comunicar a estrutura e o comportamento desejado do sistema, para visualizar e controlar a arquitetura escolhida, para compreender melhor o sistema que deseja elaborar e gerenciar possíveis riscos, muitas vezes proporcionando oportunidades de simplificação e reaproveitamento[booch2005]. A modelagem consiste, então, em elaborar diagramas

Modelagem 39 que permitem alcançar quatro objetivos essenciais na compreensão do sistema que se está desenvolvendo: Visualizar o sistema como ele é ou como é desejado. Permitir especificar a estrutura ou o comportamento de um sistema. Proporcionar um guia para a construção do sistema. Documentar as decisões tomadas. O primeiro diagrama produzido foi o de Casos de Uso, que denota o comportamento essencial do sistema. É identificado a interação dos atores com o sistema sem ser necessário especificar como essa interação é realizada. No jogo OX Game existe apenas um jogador humano que pode estar interagindo com a inteligência artificial ou com outro humano, caracterizando a ação de jogar uma partida. É permitido, ainda, que esse jogador interaja com o sistema de modo a usufruir de suas funcionalidades. O diagrama está descrito na figura 4.4:

Modelagem 40 Figura 4.4: Diagrama de Casos de Uso do Jogo da Velha OX Game O diagrama de atividades do jogo da velha OX Game está descrito na figura 4.5. Nesse diagrama é possível analisar o fluxo de controle de uma atividade para outra, ou seja, o passo a passo do programa. Esse diagrama também mostra a concorrência bem como as devidas ramificações de controle.

Modelagem 41 Figura 4.5: Diagrama de Atividades do Jogo da Velha OX Game

Modelagem 42 A partir do comportamento essencial do sistema, dos atores, suas atividades e do fluxo das atividades no decorrer da execução do jogo, os diagramas de classes estão representados nas figuras 4.6 e 4.7. Esses diagramas mostram o conjunto de classes e seus relacionamentos no dispositivo móvel (cliente) e no servidor, respectivamente. O Diagrama de classes referente ao cliente possui 10 classes. As classes estão descritas a seguir: TelaSplash: classe responsável pela apresentação do jogo quanto ao seu desenvolvedor e a razão de seu desenvolvimento. MenuPrincipal: apresenta o menu do jogo(praticar, novo jogo, desafiar, sair). Jogo: classe responsável pelo jogo entre um oponente humano e a inteligência artificial. JogoEspera: é uma especificação da classe Jogo. O jogador humano está aguardando por um oponente humano. JogoRede: classe responsável pelo jogo entre dois jogadores humanos. ConexaoMensageiro: encapsula a solicitação do fluxo de entrada e saída de dados. Mensageiro: classe responsável pelo fluxo de entrada e saída de dados com o servidor. ListaJogadores: solicita a lista de jogadores disponíveis que serão desafiados em uma partido do jogo. ConstrutorLista: gera a lista de jogadores. ItemJogador: cria uma instância na lista para cada jogador conectado e esperando por um desafio.

Modelagem 43 Figura 4.6: Diagrama de Classes do Jogo da Velha OX Game referente ao Cliente O diagrama de classes referente ao servidor possui 4 classes. As classes estão descritas a seguir: ServidorExecutavel: cria uma instância do servidor e é iniciado de modo a receber conexões. Servidor: classe responsável por gerenciar as conexões dos clientes. Jogador: é a classe responsável por realizar o fluxo de dados e armazenar os dados do jogador. Partida: é a classe responsável por analisar as jogadas e validá-las.

Modelagem 44 Figura 4.7: Diagrama de Classes do Jogo da Velha OX Game referente ao Servidor

Codicando o Jogo 45 4.6 Codificando o Jogo Com a modelagem do sistema pronto, o próximo passo para implementação do jogo OX Game consiste na codificação utilizando a plataforma Android. Por se tratar de um jogo multiusuário online, cada componente do sistema possui um ou mais processos sendo executados. Estes processos são trechos de código que são executados paralelamente e possuem linhas de controle distintas. Dessa forma, cada processo é responsável por uma atividade de modo a permanecer ativa enquanto necessária, caso contrário, o processo é encerrado. Um processo se comunica por meio do fluxo de entrada e saída de dados, utilizando sockets (abordado no tópico 3.3), e é por intermédio desse fluxo que cada processo sabe o momento exato em que deve iniciar. 4.6.1 Codificando o cliente Qualquer aplicação em Android que necessita realizar processos envolvendo rede, é de extrema importância declarar a permissão de uso no arquivo AndroidManifest.xml. Como mencionado anteriormente no tópico 3.1, este arquivo descreve os elementos da aplicação, as classes de cada componente a ser utilizado, qual o tipo de dado ele pode tratar, quando pode ser ativado, ou seja, serve para definir os dados de cada elemento[pereira2009]. Com base nesse conceito, no trecho de código 4.6.1 se encontra o arquivo AndroidManifest.xml do jogo OX Game. Na linha 8 desse código, é possível verificar a permissão do uso da internet pela aplicação. De modo que um cliente possa utilizar o acesso a rede WiFi, outra permissão precisa ser imposta, como na linha 9.

Codicando o Jogo 46 1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.teste" 4 android:versioncode="1" 5 android:versionname="1.0" > 6 7 <uses-sdk android:minsdkversion="8" /> 8 <uses-permission android:name="android.permission.internet"></uses-permission> 9 <uses-permission android:name="android.permission.access_wifi_state"></uses-permission> 10 11 <application 12 android:icon="@drawable/logo" 13 android:label="@string/app_name" > 14 <activity 15 android:screenorientation="nosensor" 16 android:label="@string/app_name" 17 android:name=".telasplash"> 18 <intent-filter > 19 <action android:name="android.intent.action.main" /> 20 <category android:name="android.intent.category.launcher" /> 21 </intent-filter> 22 </activity> 23 <activity 24 android:screenorientation="nosensor" 25 android:label="@string/app_name" 26 android:name=".menuprincipal" > 27 </activity> 28 <activity 29 android:screenorientation="nosensor" 30 android:label="@string/app_name" 31 android:name=".jogo" > 32 </activity> 33 <activity 34 android:screenorientation="nosensor" 35 android:label="@string/app_name" 36 android:name=".jogoespera" > 37 </activity> 38 <activity 39 android:screenorientation="nosensor" 40 android:label="@string/app_name" 41 android:name=".jogoemrede" > 42 </activity> 43 <activity 44 android:screenorientation="nosensor" 45 android:label="@string/app_name" 46 android:name=".listajogadores" > 47 </activity> 48 </application> 49 50 </manifest> Código 4.6.1: Código fonte referente a implementação do cliente Nas linhas 11-48 do trecho de código 4.6.1, entre as tags <application> e </application>é declarado cada componente Activity que existe no jogo. Dessa forma, é possível notar que existe seis telas em toda a aplicação. O nome de cada tela se refere a classe em que a instancia, como por exemplo, na linha 7, a tela é denominada TelaSplash, dado por android:name=.telasplash. Por existir mais de um componente Activity, ao iniciar uma aplicação um desses com-

Codicando o Jogo 47 ponentes precisa ser declarado como o componente principal. De modo a definir qual componente deve iniciar uma aplicação, faz-se necessário a utilização das tags <intent-filter > e </intent-filter> e a declaração desse componente como a activity principal (linha 19), e executável (linha 20). Interface do Jogo da Velha A interface do aplicativo é baseado em XML. Toda a codificação da interface é realizada separadamente da codificação lógica do jogo. Os arquivos XML estão localizados na pasta res/layout-port, conforme figura 4.8. Figura 4.8: Localização dos arquivos XML no projeto OX Game Cada arquivo XML é responsável pela construção da interface de uma determinada

Codicando o Jogo 48 Activity. No trecho de código 4.6.2, as características como o identificador da tela, a utilização do espaço da tela, a orientação, o plano de fundo e o efeito do som são declarados. É importante ressaltar que os termos android : layout w idth = match p arent e android : layout h eight = match p arent definem a largura e a altura do layout na dimensão disponível da tela. 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:id="@+id/layout_id" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:background="@drawable/fundo" 7 android:orientation="vertical" 8 android:soundeffectsenabled="true" > 9 10 </LinearLayout> Código 4.6.2: Declaração das características do arquivo telajogo.xml Tendo em vista que codificar e gerenciar parte da tela permite controlar os eventos com facilidade, no trecho de código 4.6.3 é definido a primeira parte da tela. Nesse trecho de código é declarado uma imagem utilizando a tag <ImageView>. Nessa tag é informado o identificador (android:id= @+id/titulo2 ) dessa imagem, para que possa ser chamado durante a codificação lógica do jogo, as dimensões e a orientação. 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:id="@+id/layout_id" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:background="@drawable/fundo" 7 android:orientation="vertical" 8 android:soundeffectsenabled="true" > 9 10 <LinearLayout 11 android:layout_width="match_parent" 12 android:layout_height="78dp" 13 android:orientation="vertical" > 14 15 <ImageView 16 android:id="@+id/titulo2" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:layout_marginright="5dip" 20 android:layout_margintop="15dip" 21 android:background="@drawable/titulo2" /> 22 </LinearLayout> 23 24 </LinearLayout> Código 4.6.3: Codificação da primeira parte da tela do Jogo OX Game

Codicando o Jogo 49 Na figura 4.9, a visualização da parte codificada é apresentada: Figura 4.9: Primeira parte da tela do Jogo OX Game A segunda parte da tela é referente ao tabuleiro de 9 posições. Cada posição é um botão e utiliza a tag <ImageButton> para instanciá-lo. Para cada botão existe um identificador (android:id= @+id/b3 )e as características de orientação. No trecho de código 4.6.4 é apresentado a criação de uma instancia desse botão: 1 <ImageButton 2 android:id="@+id/b3" 3 android:layout_width="60dp" 4 android:layout_height="67dp" 5 android:layout_gravity="center" 6 android:layout_marginleft="40dip" 7 android:layout_weight="0.07" 8 android:tag="3" /> Código 4.6.4: Codificação de um botão do tabuleiro 3x3 do Jogo OX Game De modo a organizar as noves posições do tabuleiro, essa segunda parte da tela é dividida em três subpartes de modo a ficarem igualmente distribuídos. Cada subparte engloba três botões. Sendo assim, cada subparte possui a implementação apresentado no trecho de código 4.6.5:

Codicando o Jogo 50 1 <LinearLayout 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" 4 android:layout_weight="1" 5 android:orientation="horizontal" > 6 7 <ImageButton 8 android:id="@+id/b3" 9 android:layout_width="60dp" 10 android:layout_height="67dp" 11 android:layout_gravity="center" 12 android:layout_marginleft="40dip" 13 android:layout_weight="0.07" 14 android:tag="3" /> 15 16 <ImageButton 17 android:id="@+id/b2" 18 android:layout_width="60dp" 19 android:layout_height="67dp" 20 android:layout_gravity="center" 21 android:layout_toleftof="@id/b3" 22 android:layout_weight="0.07" 23 android:tag="2" /> 24 25 <ImageButton 26 android:id="@+id/b1" 27 android:layout_width="60dp" 28 android:layout_height="67dp" 29 android:layout_gravity="center" 30 android:layout_marginright="40dip" 31 android:layout_toleftof="@id/b2" 32 android:layout_weight="0.07" 33 android:tag="1" /> 34 </LinearLayout> Código 4.6.5: Codificação do tabuleiro 3x3 do Jogo OX Game Na figura 4.10, a visualização da parte codificada é apresentada:

Codicando o Jogo 51 Figura 4.10: Primeira e segunda parte da tela do Jogo OX Game A terceira parte da tela do jogo é destinado para a visualização do placar. O trecho de código 4.6.6 define um texto na tela utilizando a tag <TextView>. A utilização dessa tag permite que seja alterado constatemente por meio do identificador declarado ( android:id= @+id/scoreboard ). 1 <LinearLayout 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" 4 android:layout_weight="3.5" 5 android:orientation="vertical" > 6 7 <TextView 8 android:id="@+id/scoreboard" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:layout_gravity="center_horizontal center_vertical" 12 android:textcolor="#000000" 13 android:textstyle="bold" /> 14 </LinearLayout> Código 4.6.6: Codificação do placar do Jogo OX Game Como existe apenas a codificação gráfica na interface e o texto depende da informação vinda da lógica do jogo, nenhuma valor é visualizado, mas o seu espaço na tela é reservado, conforme figura 4.11:

Codicando o Jogo 52 Figura 4.11: Primeira, segunda e terceira parte da tela do Jogo OX Game A última parte da tela é codificada de modo a incluir alguns detalhes de design. O trecho de código 4.6.7 apresenta a inclusão de duas figuras. Ambas figuras possuem seus identificadores assim como as configurações de orientação e tamanho. 1 <LinearLayout 2 android:layout_width="match_parent" 3 android:layout_height="wrap_content" 4 android:orientation="horizontal" > 5 6 7 <ImageView 8 android:id="@+id/detalhes" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:layout_weight="0.51" 12 android:background="@drawable/detalhes" /> 13 14 15 <ImageView 16 android:id="@+id/android1" 17 android:layout_width="wrap_content" 18 android:layout_height="wrap_content" 19 android:background="@drawable/androidgrande" /> 20 21 </LinearLayout> Código 4.6.7: Codificação dos detalhes de design do Jogo OX Game Na figura 4.12, a visualização da parte codificada é apresentada:

Codicando o Jogo 53 Figura 4.12: Tela do Jogo OX Game Dessa forma, a interface do jogo OX Game está construída. É importante ressaltar que as tags <LinearLayout> e </LinearLayout> dividem a tela em tamanhos proporcionais desejados. Como se pode observar, existem as tags LinearLayout principais e mais outras tags de mesmo nome dividindo a tela em partes menores. No total existe um tela que está dividida em quatro partes, e por sua vez, a segunda parte é dividida em mais três. Criando uma conexão com o Servidor O usuário do jogo OX Game solicita uma conexão com o servidor em duas circunstâncias: ao criar um novo jogo, aguardando por um oponente de modo a iniciar o jogo online, ou ao solicitar a lista de jogadores disponíveis para desafiar e iniciar uma partida. Ambas situações acontecem a partir do menu principal do jogo, conforme apresentado na figura 4.13:

Codicando o Jogo 54 Figura 4.13: Menu principal do jogo OX Game A requisição de uma conexão com o servidor é realizada por meio de sockets, conforme visto no tópico 3.2.1. Essa conexão é criada utilizando as classes MenuPrincipal e ConexaoMensageiro. No trecho de código 4.6.8 - Classe MenuPrincipal, é possível observar que a requisição dessa conexão é realizada pelos métodos criarconexao(ip, porta) e conectar(). 1 try { 2 // Inicia uma conexao com o Servidor de Socket 3 ConexaoMensageiro conexao = ConexaoMensageiro.criarConexao(ip, porta); 4 conexao.conectar(); 5 } catch (Exception e) { 6 // Mostra erro na tela 7 Toast.makeText(MenuPrincipal.this, "Nao foi possivel conectar", 8 Toast.LENGTH_LONG).show(); 9 } Código 4.6.8: Requisição de conexao ao Servidor Ao criar um objeto ConexaoMensageiro, um objeto de mesma classe é atribuído. Esse objeto é instanciado utilizando os parâmetros host e porta que foram informados no método

Codicando o Jogo 55 criarconexao(ip, porta). A partir desse objeto, uma requisição de conexão é solicitada. O método conectar(), por sua vez, é responsável por realizar a conexão com o servidor e preparar o fluxo de entrada e de saída de dados. No trecho de código 4.6.9 é apresentado essas funcionalidades: 1 private ConexaoMensageiro(String host, String porta) { 2 this.host = host; 3 this.porta = Integer.parseInt(porta); 4 } 5 6 public static ConexaoMensageiro criarconexao(string host, String porta) { 7 connection = new ConexaoMensageiro(host, porta); 8 return connection; 9 } 10 11 public void conectar() throws Exception { 12 this.socket = new Socket(host, porta); 13 dataout = new DataOutputStream(socket.getOutputStream()); 14 datain = new DataInputStream(socket.getInputStream()); 15 } Código 4.6.9: Descrição dos métodos criarconexao(ip, porta) e conectar() Aguardando um Oponente Dentre as funcionalidades do aplicativo OX Game, o jogador pode optar por inicializar um novo jogo e aguardar um oponente. Quando essa opção é escolhida, a conexão com o servidor, se realizada, permite ao usuário jogar contra a inteligência artificial enquanto um oponente não o desafia. Durante essa partida, que pode ocorrer sucessivamente, um processo concorrente é iniciado e fica aguardando esse jogador oponente. O processo concorrente é executado em uma classe interna chamada MyThread. Essa classe é criada dentro da classe JogoEspera de modo a facilitar o trabalho dessa classe sem expor a complexidade existente. A classe MyThread é apresentada no trecho de código 4.6.10:

Codicando o Jogo 56 1 private class MyThread extends Thread { 2 private boolean esperando; 3 4 public MyThread() { 5 esperando = true; 6 } 7 8 public void run() { 9 aguardaroponente(); 10 mhandler.post(new Runnable() { 11 @Override 12 public void run() { 13 avisardesafio(); 14 } 15 }); 16 } 17 18 private void aguardaroponente() { 19 do { 20 try { 21 esperando = ConexaoMensageiro.retornarConexao().aguardarOponente(); 22 } catch (Exception e) { 23 e.printstacktrace(); 24 } 25 } while (esperando); 26 } 27 } Código 4.6.10: Classe responsável por aguardar o desafio de um oponente Por se tratar de uma classe concorrente, o método obrigatório run() realiza toda a atividade necessária. A chamada do método interno aguardaroponente() faz com que todo o restante da atividade concorrente só se realize quando houver uma resposta do servidor. Nessa caso, o servidor é responsável por enviar a esse método uma mensagem de que existe um oponente desafiando o jogador. O método aguardaroponente(), por sua vez, está relacionado com o socket do jogador e sendo trabalho na classe Mensageiro, classe designada a se comunicar com o servidor. Na classe Mensageiro, um loop é executado de modo a averiguar as mensagens enviadas pelo servidor. No trecho de código 4.6.11, é possível verificar que toda vez que ocorre um envio de mensagem, essa mensagem é analisada. Caso exista uma solicitação de desafio, o loop é encerrado e assim a atividade concorrente executa o método avisardesafio().

Codicando o Jogo 57 1 try { 2 while (esperar) { 3 aguardaroponente = datain.readboolean(); 4 if (aguardaroponente == false) { 5 esperar = false; 6 } 7 } 8 } catch (IOException e) { 9 e.printstacktrace(); 10 stop(); 11 } Código 4.6.11: Loop responsável pela análise das mensagens enviadas pelo servidor O método avisardesafio() inicia uma nova partida e conecta os dois jogadores. Esse método está descrito no trecho de código a seguir: 1 public void avisardesafio() { 2 AlertDialog.Builder builder = new AlertDialog.Builder(this); 3 builder.setmessage("um oponente esta lhe desafiando... Hora de jogar!!"); 4 builder.setcancelable(true); 5 builder.setpositivebutton("ok", 6 new DialogInterface.OnClickListener() { 7 public void onclick(dialoginterface dialog1, int which) { 8 Intent intent = new Intent(JogoEspera.this, JogoEmRede.class); 9 10 Bundle parametros = new Bundle(); 11 parametros.putstring("jogador2", jogador2); 12 parametros.putstring("statussom", statussom); 13 parametros.putboolean("conectado", true); 14 15 intent.putextras(parametros); 16 17 startactivity(intent); 18 finish(); 19 } 20 }); 21 builder.show(); 22 } Código 4.6.12: Método responsável por avisar o jogador de um desafio e iniciar uma nova partida Enviando e recebendo as jogadas Após o aviso de desafio de um oponente, os dois jogadores são sincronizados de modo a compartilharem a mesma tela de jogo, alternando entre si as jogadas. A partida é executada utilizando as classes JogoEmRede e Mensageiro. A classe Mensageiro recebe do servidor uma mensagem informando qual jogador inicializa a partida. Essa mensagem é enviada através do construtor da classe Partida no qual o servidor monitora, conforme trecho de código 4.6.13.

Codicando o Jogo 58 1 public Partida(Jogador jogadorx, Jogador jogadoro) throws IOException{ 2 this.player_x = jogadorx; 3 this.player_0 = jogadoro; 4 this.jogadordavez = PLAYER_X; 5 jogadordavez.dataout.writeboolean(false); 6 } Código 4.6.13: Construtor da classe Partida localizada no servidor Por sua vez, quando a classe Mensageiro recebe a mensagem de permissão de jogada, e informa a classe JogoEmRede, a variável isminhavez permite que os botões bloqueados sejam liberados e prontos para receber uma posição do jogador. Ao ser escolhida a posição de jogada, o método enviarjogada() é executado. Caso essa jogada seja decisiva para o fim do jogo, uma análise é realizada. Caso contrário, o socket realiza o envio da posição ao servidor, de modo que possa ser distribuído ao cliente oponente. O método enviar jogada é apresentado no trecho de código 4.6.14: 1 OnClickListener button_listener = new View.OnClickListener() { 2 public void onclick(view v) { 3 controlesomandroid = (AudioManager) getsystemservice(context.audio_service); 4 if (SOM_LIGADO 5 && (controlesomandroid.getringermode() == AudioManager.RINGER_MODE_NORMAL)) { 6 media.start(); 7 } 8 9 ImageButton ibutton = (ImageButton) v; 10 String posicao = ""; 11 int pos = 0; 12 13 if (isminhavez) { 14 posicao = (String) ibutton.gettag(); // pega a posicao conforme a tag do button 15 pos = (int) posicao.charat(0) - 48; 16 17 try { 18 ConexaoMensageiro.retornarConexao().enviarJogada(pos); 19 } catch (IOException e) { 20 e.printstacktrace(); 21 } 22 atualizartabuleiro(pos); 23 atualizajogadas(pos); 24 resultado = verificaresultado(); 25 if((resultado == true) ((resultado == false) && iscompleto())){ 26 ConexaoMensageiro.retornarConexao().avisarTerminou(true); 27 avisarresultado(resultado); 28 }else{ 29 ativathread(); 30 } 31 } 32 } 33 }; Código 4.6.14: Método responsável pelo clique de uma jogada no tabuleiro Em paralelo, a classe JogoEmRede possui uma classe interna chamada Analisador que

Codicando o Jogo 59 tem como objetivo verificar quando é a vez de receber a jogada do oponente. Essa classe concorrente executa o método existente run() que, em seguida, executa um método interno chamado receberjogadaoponente(). No trecho de código a seguir é possível analisar a classe Analisador: 1 private class Analisador extends Thread { 2 int pos; 3 4 public Analisador() { 5 isminhavez = false; 6 } 7 8 public void run() { 9 receberjogadaoponente(); 10 mhandler.post(new Runnable() { 11 @Override 12 public void run() { 13 if(pos!= 0){ 14 atualizartabuleiro(pos); 15 atualizajogadas(pos); 16 resultado = verificaresultado(); 17 if((resultado == true) ((resultado == false) && iscompleto())){ 18 ConexaoMensageiro.retornarConexao().avisarTerminou(true); 19 avisarresultado(resultado); 20 }else{ 21 isminhavez = true; 22 } 23 } 24 } 25 }); 26 } 27 28 private void receberjogadaoponente() { 29 pos = 0; 30 do { 31 try { 32 pos = ConexaoMensageiro.retornarConexao().recebeJogadaOponente(); 33 } catch (Exception e) { 34 } 35 } while (pos == 0); 36 } 37 38 } Código 4.6.15: Classe concorrente Analisador O método receberjogadaoponente() verifica quando há uma jogada do oponente a receber e, quando existente, efetua o recebimento e verifica se ganhou a partida ou se houve um empate. Verificando o vencedor Quandos os jogadores efetuam suas jogadas, análises são realizadas de modo a informar ao servidor se houve ou não a finalização do jogo. Ao verificar que o jogo obteve um fim,

Codicando o Jogo 60 uma mensagem é informada ao servidor de modo que possa distribuir a informação ao oponente. O método responsável por esse processo é chamado de avisarterminou(boolean terminou) e é descrito como: 1 public void avisarterminou(boolean terminou){ 2 mensageiro.setterminou(terminou); 3 } Código 4.6.16: Método avisarterminou(boolean terminou) Esse método, por sua vez, finaliza o loop de recebimento de jogadas na classe Mensageiro. Esse loop está apresentado a seguir: 1 public void run() { 2 while (running) {// Enquanto estiver executando 3 if (vezdejogar) { 4 try { 5 while (esperar) { 6 aguardaroponente = datain.readboolean(); 7 if (aguardaroponente == false) { 8 esperar = false; 9 } 10 } 11 } catch (IOException e) { 12 e.printstacktrace(); 13 stop(); 14 } 15 }else{ 16 try { 17 if(terminou == false){ 18 jogadaoponente = datain.readint(); 19 } 20 } catch (IOException e) { 21 e.printstacktrace(); 22 stop(); 23 } 24 } 25 } 26 } 27 28 public void setterminou(boolean terminou) { 29 this.terminou = terminou; 30 } 31 Código 4.6.17: Loop de recebimento de jogadas na classe Mensageiro Por fim, uma mensagem é informada aos jogadores e, então, todo o fluxo de entrada e saída de dados é encerrado. No trecho de código 4.6.18 é detalhado o método avisarreultado(string resultado) e no trecho de código 4.6.19, o método desconectar():

Codicando o Jogo 61 1 public void avisarresultado(boolean resultado) { 2 String textoresultado = ""; 3 if (resultado == true) { 4 if (isminhavez) { 5 // altereplacar(1); 6 textoresultado = "Voce ganhou!!"; 7 } else { 8 // altereplacar(2); 9 textoresultado = "Seu Oponente ganhou!!"; 10 } 11 } else if ((resultado == false) && iscompleto()) { 12 textoresultado = "Velhou!!"; 13 } 14 mostraresultado(textoresultado); 15 } 16 17 public boolean mostraresultado(string mensagem) { 18 AlertDialog.Builder builder = new AlertDialog.Builder(this); 19 builder.setmessage(mensagem).setpositivebutton("continuar", 20 new DialogInterface.OnClickListener() { 21 public void onclick(dialoginterface dialog, int id) { 22 try { 23 ConexaoMensageiro.retornarConexao().desconectar(); 24 } catch (Exception e) { 25 Toast.makeText(JogoEmRede.this, "Nao fechou!!!", 26 Toast.LENGTH_SHORT).show(); 27 } 28 finish(); 29 } 30 }); 31 AlertDialog alert = builder.create(); 32 alert.show(); 33 return true; 34 } Código 4.6.18: Método avisarreultado(string resultado) 1 public void desconectar() throws Exception { 2 datain.close(); 3 dataout.close(); 4 mensageiro.desconectar(); 5 socket.close(); 6 } 4.6.2 Codificando o Servidor Código 4.6.19: Método desconectar() O servidor tem como objetivo gerenciar todas as conexões que são solicitadas pelos jogadores. O fluxo de entrada e saída de dados do servidor também é baseada em sockets. A codificação do servidor é bastante semelhante ao que foi implementado no subtópico 3.3.1. No trecho de código a seguir, os objetos de fluxo de dados assim como outras variáveis que são utilizadas pelo servidor são instanciados.

Codicando o Jogo 62 1 public class Servidor { 2 private final int numeroconexoes = 14; 3 private boolean executando = true; 4 private Jogador[] jogadores = new Jogador[numeroConexoes]; 5 private final int PORTA = 7771; 6 private ArrayList<Jogador> jogadoresesperando = new ArrayList<Jogador>(); 7 private boolean aguardandooponente = false; 8 private DataInputStream in; 9 private DataOutputStream out; 10 private String oponenteescolhido; 11 } Código 4.6.20: Método desconectar() A variável PORTA especifica em qual porta o servidor está hospedado e a variável numconexoes define qual o número máximo de conexões que o servidor irá gerenciar. Para cada conexão realizada, o servidor deve registrar quem são os jogadores conectados assim como distinguir quais jogadores criaram um novo jogo. De modo a solucionar essas especificações, um vetor chamado jogadores e uma lista de jogadores chamada jogadoresesperando, resolvem esses requisitos, respectivamente. Os objetos responsáveis pela comunicação de dados também são designados: in referente a entrada de dados e out referente a saída de dados. Por fim, as demais variáveis servem de controle durante o processo de execução do servidor. Inicializando o Servidor e Estabelecendo Jogos entre 2 jogadores O servidor possui apenas um único método chamado inicializar(). Esse método é responsável por iniciar o servidor, permitir que haja conexões com os clientes, distinguir os tipos de jogadores assim como permitir que dois jogadores joguem entre si. De modo a permitir que jogadores se conectem, uma instância da classe nativa Server- Socket é criada, utilizando a porta informada. O trecho de código 4.6.21 mostra a declaração e inicialização desse servidor: 1 ServerSocket server = new ServerSocket(PORTA, numeroconexoes); Código 4.6.21: Inicialização do servidor em uma porta especificada Cada conexão existente no servidor se refere a um jogador. Dessa forma, para cada conexão deve ser criado um objeto do tipo Jogador de modo a ter controle sobre o fluxo de dados que ele realiza. A partir disso, essa conexão informa que tipo de jogador será. Todo

Codicando o Jogo 63 esse processo é repetido até alcançar o numero máximo de conexões. O código a seguir demonstra como implementar esse processo: 1 for (int i = 0; i < numeroconexoes; i++) { 2 //Recebendo conexao de um novo jogador 3 jogadores[i] = new Jogador(server.accept()); 4 5 //criando os fluxos de entrada e saida do jogador 6 in = new DataInputStream(jogadores[i].getSocket().getInputStream()); 7 out = new DataOutputStream(jogadores[i].getSocket().getOutputStream()); 8 9 //detectando se o jogador cria um novo jogo ou desafia um jogador 10 aguardandooponente = in.readboolean(); 11 } Código 4.6.22: Método desconectar() A variável aguardandooponente é responsável por distinguir qual o tipo de jogador. Caso o jogador inicie uma nova partida, esse jogador é adicionado na lista jogadoresesperando. Caso o jogador seja um oponente, o servidor envia uma lista de jogadores disponíveis e, assim, escolhe qual o jogador quer desafiar. Nesse caso, uma busca é realizada na lista jogadoresesperando e, então, ambos jogadores são sincronizados, iniciando uma partida. É importante ressaltar que por meio das instruções realizadas nas linhas 17, 18 e 19 do trecho de código 4.6.23, vários jogos podem ser iniciados, respeitando o limite de conexões (jogadores) que o servidor suporta. Essa funcionalidade se encontra disponível em virtude dessas instruções serem executadas toda vez que há uma nova conexão do tipo jogador desafiante (representado pelo loop demonstrado no código 4.6.22). O código 4.6.23, localizado no loop for definido no código 2.6.22, representa essa implementação:

Codicando o Jogo 64 1 if(aguardandooponente){ 2 //jogador iniciou um novo jogo e aguarda por um oponente 3 jogadoresesperando.add(jogadores[i]); 4 System.out.println("Jogador Esperando!!"); 5 }else{ 6 //Servidor envia a lista de jogadores disponiveis 7 out.writeint(jogadoresesperando.size()); 8 for (int j = 0; j < jogadoresesperando.size(); j++) { 9 out.writeutf(jogadoresesperando.get(j).getnome()); 10 System.out.println(jogadoresEsperando.get(j).getNome()); 11 } 12 //Jogador escolhe seu oponente 13 oponenteescolhido = in.readutf(); 14 for (int j = 0; j < jogadoresesperando.size(); j++) { 15 if(oponenteescolhido.equals(jogadoresesperando.get(j).getnome())){ 16 //Uma partida eh iniciada com os dois jogadores 17 Partida jogo = new Partida(jogadoresEsperando.get(j), jogadores[i]); 18 jogadoresesperando.remove(j); 19 jogo.start(); 20 System.out.println("Jogo Comecou!!"); 21 } 22 23 } 24 } Código 4.6.23: Código que distingue qual o tipo de jogador Envio e recebimento das jogadas Ao iniciar um novo jogo, o construtor da classe Partida é executado. Com isso, o jogador que criou esse jogo e o oponente são declarados, respectivamente, o jogador X e o jogador O. Após essa declaração, o jogador X é designado como o jogador que inicia a partida, recebendo uma mensagem do servidor sinalizando essa atividade. Esse processo é implementado conforme o código 4.6.24. 1 public Partida(Jogador jogadorx, Jogador jogadoro) throws IOException{ 2 this.player_x = jogadorx; 3 this.player_0 = jogadoro; 4 this.jogadordavez = PLAYER_X; 5 jogadordavez.dataout.writeboolean(false); 6 } Código 4.6.24: Construtor da classe Partida Devido o envio da mensagem de permissão de jogada, um método é codificado de modo a cumprir a rotina do jogo. Esse método é chamado run() e está descrito no código 4.6.25.

Codicando o Jogo 65 1 public void run() { 2 try { 3 while (executando) { 4 //recebe a jogada 5 posicao = jogadordavez.lerjogada(); 6 //atualiza a posicao 7 atualizajogadas(posicao); 8 //imprime o estado do tabuleiro 9 imprimir(); 10 //envia ao oponente uma mensagem de modo a desativar o botao referente a jogada 11 desativarjogadaoponente(posicao); 12 //alterna entre os jogadores 13 trocarjogador(jogadordavez); 14 } 15 } catch (IOException e) { 16 e.printstacktrace(); 17 } 18 } Código 4.6.25: Método run() responsável pela rotina do jogo A jogada é recebida pela leitura do fluxo de dados, via socket, de cada jogador. Essa leitura é implementada pelo método jogadordavez.lerjogada() que se encontra na classe Jogador, conforme código 4.6.26. 1 public int lerjogada() throws IOException { 2 int posicao = datain.readint(); 3 return posicao; 4 } Código 4.6.26: Método lerjogada() Após essa verificação, o método interno desativarjogadaoponente(posicao) é responsável por enviar a jogada ao oponente evitando assim que se repita uma jogada já realizada. Caso o jogador que realize a jogada seja o jogador X, essa jogada é enviada ao jogador O, e vice-versa. Esse método é apresentado no trecho de código 4.6.27. 1 public void desativarjogadaoponente(int pos) { 2 try{ 3 if (jogadordavez.equals(player_x)) { 4 PLAYER_0.dataOut.writeInt(pos); 5 PLAYER_0.dataOut.flush(); 6 } else if (jogadordavez.equals(player_0)) { 7 PLAYER_X.dataOut.writeInt(pos); 8 PLAYER_X.dataOut.flush(); 9 } 10 }catch (IOException e) { 11 e.printstacktrace(); 12 } 13 } Código 4.6.27: Método desativarjogadaoponente(int pos)

Codicando o Jogo 66 Por fim, os jogadores são alternados utilizando o método interno trocarjogador(jogadordavez) e essa rotina de jogo ocorre até que haja um vencedor ou ocorra um empate. Um ponto relevante é que antes de efetuar a troca dos jogadores, uma análise é feita para que o servidor detecte o final da partida e encerre. O método trocarjogador(jogadordavez) está codificado a seguir: 1 private void trocarjogador(jogador jogador) throws IOException { 2 acaboujogo(); 3 if(jogador.equals(player_x)){ 4 jogadordavez = PLAYER_0; 5 }else if (jogador.equals(player_0)){ 6 jogadordavez = PLAYER_X; 7 } 8 } Código 4.6.28: Método trocarjogador(jogador jogador) Finalizando a Partida Quando um vencedor é definido ou a partida é finalizada por empate, o método acabou- Jogo() além de realizar essa verificação, encerra essa partida e fecha os fluxos de dados existentes. O código 4.6.29 representa essa verificação: 1 private void acaboujogo() throws IOException{ 2 if((resultado == true) ((resultado == false) && iscompleto())){ 3 System.out.println("Jogo Acabou!\n"); 4 executando = false; 5 PLAYER_0.desconectar(); 6 PLAYER_X.desconectar(); 7 } 8 } Código 4.6.29: Método desconectar() Como cada jogador é uma conexão, e cada conexão possui um fluxo de dados, o método desconectar(), presente no método acaboujogo() e instanciado na classe Jogador, realiza o fechamento do fluxo de entrada e saida de dados além de encerrar o socket do jogador. O código 4.6.30 apresenta o método desconectar().

Codicando o Jogo 67 1 public void desconectar() throws IOException { 2 datain.close(); 3 dataout.close(); 4 this.socket.close(); 5 6 } Código 4.6.30: Método desconectar() De modo a visualizar os sistema de fluxo de dados entre os jogadores e o servidor, o diagrama de sequência a seguir representa esse relacionamento: Figura 4.14: Diagrama de sequência do fluxo de dados do jogo OX Game

Imagens do Jogo 68 4.7 Imagens do Jogo O jogo OX Game possui 9 telas principais: Tela 01: apresenta as credenciais do jogo OX Game Tela 02: apresenta o menu do jogo OX Game Tela 03: solicita o nível do jogo Tela 04: solicita o nome do jogador Tela 05: apresenta a lista de jogadores esperando por um desafio Tela 06: informa um desafio a um jogador Tela 07: tela do jogo da velha Tela 08: informa o resultado do jogo Tela 09: informa as opcões disponíveis durante um jogo O fluxo dessas telas se encontra representado a seguir:

Imagens do Jogo 69 Figura 4.15: Fluxo de telas do jogo OX Game A partir do menu de aplicações de um celular Android, é possível iniciar o Jogo OX Game, conforme figura a seguir:

Imagens do Jogo 70 Figura 4.16: Tela de Aplicativos do Android Ao iniciar o jogo, a tela 01 do fluxo de dados é apresentada: Figura 4.17: Tela de Apresentação do Jogo

Imagens do Jogo 71 Logo em seguida, o menu do jogo (tela 02) é visualizado e permanece disponível para a decisão do usuário: Figura 4.18: Menu principal do jogo Caso o usuário selecione o menu Praticar, o aplicativo solicitará o nível do jogo e, posteriormente, o nome do usuário. Essas duas solicitações ocorrem por meio das telas 03 e 04:

Imagens do Jogo 72 Figura 4.19: Tela de seleção de nível e Tela de inserção do nome do jogador Dada as informações solicitadas, uma partida é iniciada contra a inteligência artificial (tela 07). Durante a partida, opções se encontram disponíveis caso o usuário deseje realizálas(tela 09). Figura 4.20: Tela do jogo da velha e Tela de opções durante uma partida

Imagens do Jogo 73 No entanto, duas outras opções de jogo ainda podem ser selecionadas. No caso do menu Novo Jogo, o aplicativo solicitará o nome do jogador, utilizando a tela 03, e iniciará um jogo contra a inteligência artificial (tela 07) enquanto aguarda um oponente humano. No caso do menu Desafiar, o jogador deverá informar o nome e, em seguida, o jogador oponente que desafiará. A solicitação do nome também é realizada por meio da tela 03 e, a lista de jogadores, pela tela 05: Figura 4.21: Tela com a lista de jogadores online Após de um desafio realizado, o jogador que se encontra jogando contra a inteligência aritificial, recebe uma notificação (tela 06) e, então, ambos os jogadores estarão iniciando uma partida um contra o outro (tela 07).

Imagens do Jogo 74 Figura 4.22: Aviso de desafio a um jogador Ao finalizar uma partida, uma notificação é informada por meio da tela 08, retornando ao menu principal posteriormente. Figura 4.23: Tela referente ao resultado do jogo