67
Bruno Bottino Ferreira e Yanko Gitahy Oliveira Dystopia e SumoCheckers Rio de Janeiro - RJ, Brasil 3 de março de 2011

Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Bruno Bottino Ferreira e Yanko Gitahy Oliveira

Dystopia e SumoCheckers

Rio de Janeiro - RJ, Brasil

3 de março de 2011

Page 2: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Bruno Bottino Ferreira e Yanko Gitahy Oliveira

Dystopia e SumoCheckers

Monografia apresentada para obtenção do Graude Bacharel em Ciência da Computação pelaUniversidade Federal do Rio de Janeiro.

Orientador:

Adriano Joaquim de Oliveira Cruz

INSTITUTO DE MATEMÁTICA

CENTRO DE CIÊNCIAS MATEMÁTICAS E DA NATUREZA

UNIVERSIDADE FEDERAL DO RIO DE JANEIRO

Rio de Janeiro - RJ, Brasil

3 de março de 2011

Page 3: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”, de-

fendida por Bruno Bottino Ferreira e Yanko Gitahy Oliveira e aprovada em 3 de março de

2011, no Rio de Janeiro, Estado do Rio de Janeiro, pela banca examinadora constituída pelos

professores:

Prof. Ph.D. Adriano J. de O. CruzOrientador

Prof. D.Sc. João Carlos Pereira da SilvaUniversidade Federal do Rio de Janeiro

Prof. D.Sc. Geraldo Bonorino XexéoUniversidade Federal do Rio de Janeiro

Page 4: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Resumo

Este trabalho destina-se a documentar o desenvolvimento do arcabouço Dystopia, desti-nado a auxiliar no desenvolvimento de jogos eletrônicos e aplicações interativas em geral, queteve como focos principais a organização, reusabilidade e o baixo custo, além do requisito deatender a múltiplas plataformas. É utilizado como exemplo o SumoCheckers, jogo eletrônicoimplementado utilizando este arcabouço, adicionado de bibliotecas disponíveis gratuitamentepara uso não-comercial. Também são abordados conceitos de game design e planejamento,estudando as diferentes influências presentes na criação de um jogo eletrônico.

Page 5: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Abstract

The present work intends to document the development of the Dystopia framework, usedfor making video games and interactive applications in general, having as its main goals codeorganization, reusability and low cost, and also attending the requirement of being cross plat-form. SumoCheckers, a game implemented using the framework and available free-for-non-commercial-use libraries, is used as an example. Concepts of game design and planning arealso discussed, studying the different influences in the creation of a video game.

Page 6: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Dedicatória

Dedico este trabalho à minha mãe Elizabeth, que me ensinou a ter caráter e integridade;

ao meu pai Marcus André, que me ensinou que com força de vontade qualquer um pode chegar

onde quiser; à minha irmã Barbara, por ter estado ao meu lado e apoiando meus projetos desde

sempre; e à minha namorada, Débora Andrade, por tudo que já passamos e ainda passaremos

juntos.

- Bruno Bottino Ferreira

Este trabalho é dedicado a meus pais Osmar e Regina, irmãos Yuri e Yane, minha namorada

Erika M. Z. K. Piffer e à Confraria, aqueles que sempre me apoiaram nessa longa jornada de

muitos primeiros passos.

- Yanko Gitahy Oliveira

Page 7: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Agradecimentos

Agradecemos principalmente ao professor Adriano Cruz pelo apoio e pela liberdade de

pesquisa;

aos nossos colegas do Laboratório de Inteligência Computacional pelo apoio constante e

auxílio nos momentos necessários;

aos nossos amigos que ouviram falar, e jogaram, SumoCheckers até dizerem “chega”;

a Steve "Sinbad" Streeting e toda a equipe de desenvolvimento pela OGRE3D;

a toda a comunidade OpenSource e criadores de middlewares acessíveis por tornarem o

mundo um lugar mais fácil para indies;

a Yuji Naka, Ron Gilbert, John Carmack e Gabe Newell.

Page 8: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Sumário

Lista de Figuras

1 Introdução p. 13

1.1 Motivação e objetivos deste trabalho . . . . . . . . . . . . . . . . . . . . . . p. 14

1.2 Contextualizacão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 15

1.3 Estrutura da monografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 16

2 O arcabouço: Dystopia p. 17

2.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 18

2.2 Arquitetura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 18

2.2.1 Wrappers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 19

2.2.1.1 Entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 20

2.2.1.2 Rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 20

2.2.1.3 Áudio . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 22

2.2.2 Módulos diretos . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 22

2.2.2.1 Controle de tempo . . . . . . . . . . . . . . . . . . . . . . p. 23

2.2.2.2 Máquina de estados finitos . . . . . . . . . . . . . . . . . p. 23

2.2.2.3 Aplicação Orientada a Objetos . . . . . . . . . . . . . . . p. 25

2.2.2.4 Cálculo Vetorial e Geometria Analítica: Vetores 2D e 3D . p. 26

2.2.2.5 GameObject . . . . . . . . . . . . . . . . . . . . . . . . . p. 26

2.2.2.6 Tratamento de erros . . . . . . . . . . . . . . . . . . . . . p. 28

2.3 Detalhes da Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 28

Page 9: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3.1 Wrappers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 28

2.3.1.1 Áudio . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 29

2.3.1.2 Rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 30

2.3.1.3 Entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 32

2.3.2 Integração com OGRE3D . . . . . . . . . . . . . . . . . . . . . . . p. 33

2.3.2.1 Aplicação Orientada e Objetos OGRE . . . . . . . . . . . p. 34

2.3.2.2 Integração com o módulo de CVGA . . . . . . . . . . . . p. 34

2.3.2.3 Integração com GameObject . . . . . . . . . . . . . . . . p. 34

2.3.2.4 Integração com o módulo de Áudio . . . . . . . . . . . . . p. 35

2.3.2.5 Módulos auxiliares usando OGRE . . . . . . . . . . . . . p. 35

2.3.3 Questões multiplataforma . . . . . . . . . . . . . . . . . . . . . . . p. 36

3 O jogo: SumoCheckers p. 37

3.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 38

3.2 Protótipo Inicial (2D) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 38

3.2.1 Bibliotecas externas utilizadas . . . . . . . . . . . . . . . . . . . . . p. 40

3.2.2 Experimentos com Inteligência Artificial . . . . . . . . . . . . . . . p. 41

3.2.3 Experimentos com jogo em rede e Internet . . . . . . . . . . . . . . p. 43

3.3 Versão 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 44

3.3.1 Conteúdo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 45

3.3.2 Efeitos e melhorias visuais . . . . . . . . . . . . . . . . . . . . . . . p. 47

3.3.3 Adaptação da lógica de jogo . . . . . . . . . . . . . . . . . . . . . . p. 49

3.3.4 Playtests e mudanças no gameplay . . . . . . . . . . . . . . . . . . . p. 51

4 Conclusões e trabalhos futuros p. 53

Referências p. 56

Page 10: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Anexo A -- Documentação das classes do Dystopia p. 58

A.1 Referência da Classe Dystopia::Application . . . . . . . . . . . . . . . . . . p. 58

Métodos Públicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 58

A.1.1 Descrição Detalhada . . . . . . . . . . . . . . . . . . . . . . . . . . p. 59

A.1.2 Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 59

A.1.2.1 afterSetup . . . . . . . . . . . . . . . . . . . . . . . . . . p. 59

A.1.2.2 frameUpdate . . . . . . . . . . . . . . . . . . . . . . . . . p. 59

A.1.2.3 getWindowTitle . . . . . . . . . . . . . . . . . . . . . . . p. 59

A.2 Referência da Classe Dystopia::InputManager . . . . . . . . . . . . . . . . . p. 59

Métodos Públicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 60

A.2.1 Descrição Detalhada . . . . . . . . . . . . . . . . . . . . . . . . . . p. 60

A.2.2 Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 60

A.2.2.1 addJoystickListener . . . . . . . . . . . . . . . . . . . . . p. 60

A.2.2.2 addKeyListener . . . . . . . . . . . . . . . . . . . . . . . p. 60

A.2.2.3 addMouseListener . . . . . . . . . . . . . . . . . . . . . . p. 60

A.2.2.4 setWindowSize . . . . . . . . . . . . . . . . . . . . . . . p. 60

A.2.2.5 update . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 60

A.3 Referência da Classe Dystopia::NetworkInterface . . . . . . . . . . . . . . . p. 61

Métodos Públicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 61

A.3.1 Descrição Detalhada . . . . . . . . . . . . . . . . . . . . . . . . . . p. 61

A.3.2 Construtores & Destrutores . . . . . . . . . . . . . . . . . . . . . . . p. 61

A.3.2.1 NetworkInterface . . . . . . . . . . . . . . . . . . . . . . p. 61

A.3.3 Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62

A.3.3.1 freePacket . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62

A.3.3.2 getNumberClients . . . . . . . . . . . . . . . . . . . . . . p. 62

A.3.3.3 pollPacket . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62

Page 11: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.3.3.4 send . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62

A.3.3.5 shutdown . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62

A.3.3.6 startup . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62

A.3.3.7 startup . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62

A.3.3.8 update . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 63

A.4 Referência da Classe Dystopia::SoundManager . . . . . . . . . . . . . . . . p. 63

Métodos Públicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 63

A.4.1 Descrição Detalhada . . . . . . . . . . . . . . . . . . . . . . . . . . p. 64

A.4.2 Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 64

A.4.2.1 attachListenerToOgreCamera . . . . . . . . . . . . . . . . p. 64

A.4.2.2 createEmitter . . . . . . . . . . . . . . . . . . . . . . . . . p. 64

A.4.2.3 flushAllSounds . . . . . . . . . . . . . . . . . . . . . . . p. 64

A.4.2.4 getListenerLook . . . . . . . . . . . . . . . . . . . . . . . p. 64

A.4.2.5 getListenerPos . . . . . . . . . . . . . . . . . . . . . . . . p. 64

A.4.2.6 getListenerUp . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.7 getListenerVel . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.8 getSoundId . . . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.9 getWorldScale . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.10 loadSound . . . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.11 setListenerLook . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.12 setListenerPos . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.13 setListenerUp . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.14 setListenerVel . . . . . . . . . . . . . . . . . . . . . . . . p. 65

A.4.2.15 setupAudio . . . . . . . . . . . . . . . . . . . . . . . . . . p. 66

A.4.2.16 setWorldScale . . . . . . . . . . . . . . . . . . . . . . . . p. 66

A.4.2.17 unloadSound . . . . . . . . . . . . . . . . . . . . . . . . . p. 66

Page 12: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.4.2.18 unloadSound . . . . . . . . . . . . . . . . . . . . . . . . . p. 66

Page 13: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Lista de Figuras

1 Arquitetura geral do Dystopia . . . . . . . . . . . . . . . . . . . . . . . . . p. 19

2 Aparência do primeiro protótipo do SumoCheckers . . . . . . . . . . . . . . p. 39

3 Segunda versão dos gráficos do SumoCheckers . . . . . . . . . . . . . . . . p. 41

4 Aparência da versão 3D do SumoCheckers . . . . . . . . . . . . . . . . . . . p. 46

5 Técnicas utilizadas para criação do cenário do jogo . . . . . . . . . . . . . . p. 48

6 Comparação exemplificando a utilização da técnica de Normal Mapping . . . p. 50

Page 14: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

13

1 Introdução

“All your base are belong to us.”

CATS (Zero Wing)

Neste capítulo são apresentados o objetivo desta monografia e a estrutura da mesma.

Page 15: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

1.1 Motivação e objetivos deste trabalho 14

1.1 Motivação e objetivos deste trabalho

A área de jogos eletrônicos é inerentemente ligada à Ciência da Computação, evocando

conhecimento não só de linguagens de programação, mas também de estruturas de dados e al-

goritmos, programação paralela, inteligência artificial e computacional, redes de computadores,

interface humano-computador, além de computação gráfica[1, 2]. Com o alcance de parcelas

cada vez maiores da população a computadores pessoais, videogames e instalações interativas,

faz-se necessário o estudo de métodos e técnicas para a implementação destes tipos de sistemas.

Para tal, tem-se dois caminhos comumente seguidos: ou licencia-se tecnologia proprietária que,

quando tem preços acessíveis para o uso, o acesso ao código fonte tem preço proibitivo, ou

utiliza-se bibliotecas de código aberto, mas que normalmente são muito especificas e pouco

flexíveis.

Além disso, frequentemente há a necessidade em laboratórios de pesquisa de um ambiente

virtual para experimentos, sendo necessária uma plataforma já existente para tal; uma imple-

mentação do zero não só tomaria tempo, como fugiria ao foco das pesquisas. Montando-se um

sistema facilmente reutilizável, diversos projetos poderiam tê-lo como base, sendo feitas apenas

as modificações estritamente necessárias para sua utilização.

Finalmente, temos o fator de aprendizado: o melhor meio de entender como funciona um

sistema é de fato construí-lo, pesquisando e pesando diferentes possibilidades com melhor cus-

to/benefício tanto na estrutura geral quanto em seus componentes. Tendo em mente esses três

fatores (baixo custo, reusabilidade e possibilidade de pesquisa), foi criado o Dystopia, arca-

bouço que vem sendo desenvolvido desde 2007, tendo como objetivo maior criar um ambiente

para implementação rápida de projetos interativos sem a necessidade de licenciamento de tec-

nologia.

Este trabalho tem como objetivos analisar o planejamento e a implementação do arcabouço

Dystopia, assim como do primeiro projeto que o utiliza, um jogo eletrônico chamado Sumo-

Checkers. O foco maior será dado à implementação, mas serão abordados também temas di-

retamente relacionados ao jogo, como decisões de game design e jogabilidade, que acabam se

mostrando intimamente ligadas às escolhas de tecnologia e direção geral de um arcabouço para

aplicações interativas.

Page 16: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

1.2 Contextualizacão 15

1.2 Contextualizacão

Todo jogo eletrônico possui uma engine, ou seja, um "motor" responsável por controlar

todas as partes envolvidas (vídeo, áudio, estruturas de dados, fases, personagens etc) na sua

execução. Estas normalmente são bem específicas sobre seu funcionamento: um jogo de estra-

tégia, por exemplo, não será feito utilizando uma engine para jogos de tiro em primeira pessoa;

apesar de tecnicamente possível, o retrabalho envolvido é muito grande. Sendo assim, é fácil

encontrar diversas possibilidades para jogos de estilos específicos, com soluções específicas

para aqueles tipos de cenário.

Mais raras, no entanto, são soluções que tentam ser abertas o suficiente para englobar qual-

quer tipo de jogo sem grandes necessidades de modificações–não só porque é mais complicado

manter uma arquitetura mais geral, mas porque o tempo necessário para uma implementação

deste tipo é grande. Sendo assim, a maioria destas engines generalistas é comercial: dois

exemplos atuais são a Unity3d e a Unreal Engine. Embora recentemente ambas tenham se

tornado muito mais acessiveis a desenvolvedores pequenos (tendo versões gratuitas para uso

não-comercial) temos alguns problemas. Primeiro, o acesso ao código fonte requer uma licença

especial (no caso da Unreal Engine, por exemplo, estima-se um custo de US$700.000,00). Disso

deriva-se o fato de que não é possível deixar de lado os recursos mais avançados no código do

programa, mesmo que estes não sejam utilizados. Finalmente, cada uma tem um fluxo de tra-

balho bem específico, ou seja, é preciso aprender o mesmo para a realização de um projeto.

Tendo em vista estas limitações, o foco do arcabouço é justamente apresentar uma base

para faciltar a implementação de uma engine própria do usuário. Para uma maior facilidade, fo-

ram selecionadas bibliotecas para compor um conjunto "padrão", delegando o trabalho mínimo

necessário à implementação do código específico da aplicação que se deseja criar, mas sempre

mantendo-se a possibilidade de trocar facilmente estas bibliotecas por outras, ou até mesmo não

utilizar certos módulos.

Outras idéias importantes para o entendimento completo desta monografia são ligados à

Ludologia, ou seja, o estudo dos jogos (sejam eles eletrônicos ou não). Os conceitos de game-

play e rejogabilidade são especialmente importantes: um diz respeito às regras e mecânicas dos

jogos, ou seja, como funciona o jogo em si, ignorando-se gráficos, história e demais formas de

conteúdo. O segundo referencia a idéia de "quantas vezes um jogador joga um jogo", ou seja,

é uma medida da qualidade ligada, principalmente, ao gameplay, mas que é influenciada por

todos os outros fatores envolvidos. Para um jogo atingir sucesso e longevidade, o foco nesses

dois fatores é especialmente importante.

Page 17: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

1.3 Estrutura da monografia 16

1.3 Estrutura da monografia

No capítulo 2 é descrita a estrutura do arcabouço desenvolvido e cada um de seus compo-

nentes.

No capítulo 3 é descrita a mecânica do jogo desenvolvido e alguns detalhes de sua imple-

mentação.

No capítulo 4 são apresentadas as conclusões deste trabalho e sugestões para trabalhos

futuros.

Page 18: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

17

2 O arcabouço: Dystopia

“You’ll need something of the thread, something of the head, something of the body, and

something of the dead.”

Voodoo Lady (Monkey Island 2: LeChuck’s Revenge)

Neste capítulo são apresentados a estrutura básica do arcabouço desenvolvido, sua arquite-

tura e detalhes da implementação de cada um dos módulos.

Page 19: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.1 Introdução 18

2.1 Introdução

O arcabouço Dystopia foi pensado e desenvolvido como um conjunto de classes na lingua-

gem C++, para auxiliar na criação de jogos eletrônicos e aplicativos interativos relacionados.

A arquitetura do Dystopia foi definida de maneira a atender alguns objetivos gerais impor-

tantes:

• Facilidade de Uso: objetivo principal e mais óbvio, as interfaces providas pelo framework

devem ser de uma dificuldade menor do que a alternativa de acesso direto ao hardware,

sistema operacional ou biblioteca especifica;

• Modularidade: os componentes do framework podem ser usados separadamente, ou em

conjunto; o programador poderá optar por utilizar quaisquer módulos dentre os existentes,

sem prejuízo à sua funcionalidade individual. Ainda que possa existir alguma integração

entre os diferentes módulos, o código que implementar tal integração deverá ser condici-

onado à presença de todos os módulos respectivos;

• Portabilidade: os componentes devem funcionar na maior quantidade de plataformas pos-

sível. Sempre que aplicável, o código deve ser escrito de uma única maneira que funcione

de maneira portável; onde isso não for possível, implementações condicionais relativas a

cada arquitetura alvo serão feitas;

• Abstração: relacionado à portabilidade, as interfaces devem ser apresentadas de uma

maneira consistente e alheia à arquitetura e Sistema Operacional presentes no momento

da utilização.

2.2 Arquitetura

Em uma primeira instância, pode-se considerar que o código do framework consiste de

alguns módulos bem definidos, separados em dois tipos básicos:

• Wrappers: expõem uma interface comum para acesso a alguma funcionalidade imple-

mentada por bibliotecas externas. É o caso dos módulos de entrada, rede e som;

• Módulos diretos: implementações completas e isentas de dependências externas, relaci-

onadas a alguma funcionalidade pertinente ao desenvolvimento de jogos. É o caso dos

módulos de controle de tempo, máquina de estados, AppMain, vetores 2D e 3D e Game-

Object.

Page 20: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 19

Figura 1: Arquitetura geral do Dystopia

2.2.1 Wrappers

Foram definidos wrappers para três tipos de funcionalidades: entrada, rede e áudio. Foi

decidido que, a princípio, não seria feito um wrapper para biblioteca gráfica porque cada bibli-

oteca costuma ter um conjunto bem específico de funcionalidades, além de existirem bibliotecas

gráficas 2D e 3D que já são multiplataforma e simples o suficiente para uso direto. Apesar disso,

foram desenvolvidos alguns pequenos módulos de suporte à biblioteca OGRE3D[3], conforme

pode ser visto na seção 2.3.2.

Os wrappers de entrada, áudio e rede no Dystopia são chamados, respectivamente, de Input-

Manager, SoundManager e NetworkInterface. Foi decidido chamar de “Manager” os wrappers

de entrada e áudio porque, em geral, só deve existir uma instância de cada um destes (ou seja,

eles implementam o design pattern[4] “Singleton”); por sua vez, deve-se usar uma instância

de NetworkInterface para cada conexão de rede aberta em um dado momento, podendo haver

várias conexões abertas ao mesmo tempo na mesma aplicação (daí "Interface").

Vale lembrar que os nomes e as funcionalidades descritos nesta seção são relativos às clas-

ses abstratas que representam cada um dos wrappers, sendo as implementações de fato con-

templadas por classes derivadas destas, utilizando bibliotecas externas. Mais detalhes sobre as

implementações e exemplos de utilização podem ser encontrados na seção 2.3.1.

Page 21: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 20

2.2.1.1 Entrada

O módulo de entrada provê funcionalidade de eventos de entrada de teclado, mouse e joys-

tick. Os eventos são comunicados à aplicação por meio de callbacks em listeners. Ou seja, uma

classe da aplicação implementa uma interface programática predefinida e se registra com o mó-

dulo de entrada para receber certos tipos de eventos. Cada tipo de dispositivo possui uma dessas

interfaces, sendo a mesma responsável pelos métodos relativos a cada tipo de evento disparado

por ele. Os tipos de eventos recebidos para cada tipo de dispositivo são como a seguir:

• Teclado: tecla pressionada (KeyPressed) e tecla levantada (KeyReleased);

• Mouse: movimento (MouseMoved), botão pressionado (MousePressed) e botão levantado

(MouseReleased).

• JoyStick: movimento do eixo (AxisMoved), botão pressionado (ButtonPressed) e botão

levantado (ButtonReleased).

Cada tipo de evento tem um conjunto de informações associado, contendo um identificador

numérico do dispositivo que gerou o evento (caso haja mais de um do mesmo tipo instalado no

sistema), um identificador do botão, tecla ou eixo que gerou o evento em questão e, no caso de

mouse e joystick, o estado completo de todos os botões e eixos do dispositivo naquele momento.

2.2.1.2 Rede

Uma característica cada vez mais comum nos jogos eletrônicos é a capacidade de se jogar

com outras pessoas, seja em rede local ou ao redor do mundo, através da Internet. Para im-

plementar este tipo de funcionalidade, é necessário uma robusta infra-estrutura, que cuide dos

detalhes dos protocolos de comunicação entre computadores e exponha ao desenvolvedor de ga-

meplay apenas o necessário para que ele possa implementar a comunicação entre os elementos

do jogo de uma maneira simples e funcional.

Sendo assim, foi definido que a interface de rede do Dystopia seria o mais simples possível,

a princípio, focando apenas em enviar e receber pacotes utilizando o paradigma cliente-servidor.

Para abrir uma porta de rede para comunicação, basta instanciar e inicializar um NetworkInter-

face, passando apenas os dados essenciais para estabelecimento da conexão: o papel da interface

na comunicação (cliente ou servidor), e:

• No caso do servidor, a porta a ser utilizada, que será aberta localmente, e a quantidade

máxima de clientes suportada;

Page 22: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 21

• No caso do cliente, a porta a ser procurada para conexão remota ao servidor e o endereço

do servidor remoto.

É importante salientar novamente que mais de uma interface deste tipo pode existir ao mesmo

tempo, sendo inclusive possível clientes e servidores comunicando-se entre si na mesma má-

quina. Para isto, basta que os clientes estabeleçam uma conexão de loopback para “localhost”

ou “127.0.0.1”.

Uma vez inicializado, o servidor está pronto para funcionar. O cliente, porém, precisa espe-

rar a resposta do servidor para que possa enviar e receber pacotes. Sendo assim, o método que

inicializa o cliente retorna imediatamente, mas isso não significa que foi estabelecida uma co-

nexão; o primeiro valor de retorno do método “update” do cliente determinará se uma conexão

foi estabelecida com sucesso ou não.

Após verificado que uma conexão de sucesso foi estabelecida ou, no caso do servidor, assim

que a porta foi aberta com sucesso, a aplicação deve, a intervalos regulares (por exemplo, a cada

passo da simulação):

• Chamar o método “update” da interface. Este método retorna uma série de valores in-

dicando um erro na conexão, ou um valor indicando que a conexão ainda está ativa e

pacotes podem ou não terem sido recebidos. Para processar estes pacotes, deve-se fazer

um loop de chamadas ao método abaixo;

• Chamar o método “pollPacket” da interface para receber um pacote pendente, passando

um ponteiro para uma estrutura de pacote, até que este método retorne FALSE, indicando

que não há mais pacotes pendentes;

• Realizar o processamento adequado do pacote recebido, de acordo com a lógica da apli-

cação;

• Chamar o método “freePacket” passando como parâmetro a estrutura de pacote preen-

chida, para que recursos internos sejam liberados.

Além disso, a qualquer momento a aplicação pode enviar um pacote de tamanho arbitrário,

indicando, se for o servidor, se ela deve ser enviada a todos os clientes e, caso contrario, também

o cliente destino da mensagem. Por outro lado, o cliente só pode enviar um pacote ao servidor

e não a outros clientes.

Page 23: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 22

2.2.1.3 Áudio

Para aplicações interativas, não somente jogos eletrônicos, serem bem sucedidas, é neces-

sário que o usuário consiga abstrair-se ao máximo em relação à interface, sentindo-se “imerso"

no universo da aplicação no mínimo o suficiente para que tenha interesse em utilizá-la. Desta

forma, é essencial a presença de ambientação auditiva, na forma de efeitos sonoros e música.

No mundo real, alguns fatores afetam fortemente a maneira como percebemos os sons, em

especial a posição e velocidade do ouvinte em relação à origem do som (atenuando o volume

percebido e causando o chamado efeito Doppler) e as características do ambiente onde ele é

propagado – a maneira como um som se propaga num campo aberto não é a mesma que em

uma caverna, por exemplo. Sendo assim, de maneira geral as bibliotecas de áudio expõem

funcionalidades para lidar com isto de alguma forma.

A princípio, foi implementado apenas o conceito de posição e velocidade do ouvinte e

do emissor através de um paradigma baseado em orientação a objetos. Enquanto os atributos

do ouvinte (posição e velocidade) são especificados diretamente no SoundManager, é preciso

instanciar um objeto emissor (SoundEmitter) para tocar um som posicional. Este emissor possui

atributos de posição e velocidade, assim como o ouvinte, e métodos que permitem tocar sons.

As características de efeitos sonoros tocados por um emissor serão afetadas pelos atributos

deste, mesmo que ele se mova enquanto o som está sendo tocado. Existem também métodos

para reprodução de sons sem informação posicional, definidos diretamente no SoundManager.

Em aplicações reais, geralmente um emissor está associado a um objeto do mundo do jogo

(GameObject) e o ouvinte acompanha a posição da câmera. Alguns funcionalidades imple-

mentadas pelo framework que podem auxiliar bastante neste tipo de utilização estão descritos,

respectivamente, nas seções 2.2.2.5 e 2.3.2.

Por último, mas não menos importante, os componentes vitais necessários para uma am-

bientação acústica bem sucedida são as amostras sonoras (sejam efeitos sonoros ou músicas).

Logo, é necessária uma funcionalidade para carregar e gerenciar sons de maneira prática. No

Dystopia, um som carregado de um arquivo possui um ID numérico e um nome, podendo ser

referenciado por qualquer destes em todos os métodos de reprodução.

2.2.2 Módulos diretos

Além dos módulos wrappers do framework, foram desenvolvidas algumas funcionalidades

auxiliares com implementações diretas, sem utilização de bibliotecas externas. Estas funcionali-

Page 24: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 23

dades em geral visam diminuir a quantidade de retrabalho sempre presente no desenvolvimento

de jogos, que evocam a utilização recorrente de algumas estruturas de dados e de controle de

execução. Em alguns casos menores, o objetivo destes módulos foi encapsular chamadas ao

sistema operacional da máquina hospedeira, além de auxiliar no processo de desenvolvimento

em si.

2.2.2.1 Controle de tempo

Foi desenvolvido um pequeno módulo para obtenção de informações de tempo e delay

artificial, por meio de funções estáticas. Além de uma função para causar um delay artificial

de até um segundo (Sleep), foram criadas funções para retornar a quantidade de segundos,

milissegundos e microssegundos desde algum momento inicial (que, dependendo do SO, pode

ser o momento de boot da máquina ou o momento em que o programa começou a ser executado).

Como os valores retornados por este módulo são sempre utilizados relativos uns aos outros, a

referência inicial da contagem é irrelevante desde que seja mantida entre os valores a serem

comparados.

A implementação deste pequeno módulo busca encapsular chamadas ao sistema operacio-

nal ou a outras bibliotecas que já estejam sendo utilizadas para outras funcionalidades, sempre

da maneira que retorne a maior precisão possível. As chamadas dependem de quais bibliote-

cas estejam definidas para utilização, recaindo a chamadas diretas ao SO apenas caso nenhuma

biblioteca que disponha de funções de controle de tempo esteja presente no momento da com-

pilação.

2.2.2.2 Máquina de estados finitos

Uma estrutura de controle de fluxo extremamente recorrente e quase onipresente em jogos

eletrônicos é a Máquina de Estados Finitos (Finite State Machine–FSM). Como o fluxo de

execução de um jogo em geral depende muito da situação atual (por exemplo: introdução,

menu, cutscene, exploração, batalha, pausa), estas situações podem ser modeladas como estados

distintos em uma máquina de estados, onde a cada passo de atualização o estado pode requisitar

que seja modificado para algum outro (por exemplo: ao apertar START durante a introdução, vá

para o menu).

Outro campo onde FSM’s são bastante utilizadas é a Inteligência Artificial, para modelar

o comportamento de um agente autônomo ao longo do tempo. Um inimigo poderia, digamos,

estar constantemente no estado PATRULHANDO até que o jogador se aproxime o suficiente e o

Page 25: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 24

estado do inimigo mude para ATACANDO.

Em algumas situações, pode ser interessante que haja alguma memória a respeito do his-

tórico de estados visitados. Em especial, um estado pode ser chamado a partir de mais de um

outro, e requisitar que seja retornado para o anterior, independentemente de qual fosse. Por

isso, frequentemente é implementada uma pilha de estados que representa o conceito abstrato

de estados hierárquicos. Além disso, um estado em si pode conter outra máquina de estados,

para criar comportamentos tão complexos quanto se queira.

No Dystopia, foi implementado uma classe de Máquina de Estados Finitos com pilha de

estados. Cada estado deve implementar um método “update” que realiza seu trabalho por um

passo e retorna a transição desejada, que pode ser PUSH, para empilhar um novo estado e mudar

para ele; POP, para desempilhar o estado atual e mudar para o próximo na pilha; CHANGE, para

trocar o estado atual por outro sem modificar a pilha de estados; ou nenhuma, para que o estado

atual continue sendo o mesmo na próxima atualização.

A máquina de estados possui um método “update” que deve ser chamado a cada passo da

aplicação, e repassa esta chamada para o estado no topo da pilha. Além disso, implementa todas

as interfaces de Listener do sistema de entrada, repassando os eventos para o estado atual. Desta

forma, após inicializar o sistema de entrada, basta registrar uma máquina de estados para rece-

ber os tipos de eventos desejados, sendo estes automaticamente enviados para processamento

no estado atual, desde que ele implemente os métodos receptores correspondentes (para mais

informações, veja a seção 2.2.1.1).

// Exemplo de utilização da máquina de estados

class MyState: public Dystopia::State

{

public:

std::pair<Dystopia::StateTransition, Dystopia::State*>

update(void) {

if(manter_estado)

return make_pair(STATE_CHANGE, this);

else if(mudar_estado)

return make_pair(STATE_CHANGE, new Outro());

else if(empilhar_estado)

return make_pair(STATE_PUSH, new Outro());

else if(desempilhar_estado)

return make_pair(STATE_POP, NULL);

Page 26: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 25

}

};

Dystopia::StateMachine states;

states.push(new MyState());

//durante o loop principal...

//MyState::update será chamado automaticamente

states.update();

2.2.2.3 Aplicação Orientada a Objetos

Programas escritos em C ou C++ tradicionalmente têm seu ponto de entrada em uma fun-

ção “main”. Porém, esta abordagem não condiz muito bem com o paradigma de orientação a

objetos almejado no design do Dystopia. Por isso, foi criado um módulo que implementa a

função “main” necessária para ser utilizada como ponto de entrada da aplicação pelo SO, e uma

pequena classe abstrata chamada Application que define alguns métodos vazios, chamados em

momentos oportunos, como “go” e “abort” (chamados na inicialização e finalização, respecti-

vamente). Esta classe também implementa listeners para todos os tipos de eventos de entrada,

e deve ser herdada e incrementada para ser usada de fato.

Porém, o objetivo maior é que esta classe seja especializada para tipos específicos de bibli-

otecas gráficas, de modo que possa encapsular a criação da janela e outros detalhes da inicia-

lização visual e do sistema de entrada (que necessita de um handle para a janela do programa

para ser inicializado). Além disso, nesta especialização pode-se criar a estrutura do loop prin-

cipal de acordo com a biblioteca gráfica utilizada, chamando o método abstrato “frameUpdate”

a cada quadro renderizado. Assim, uma aplicação precisa apenas herdar desta especialização

e implementar este método para ter uma janela pronta que chama um método de atualização a

cada quadro.

Uma especialização desta classe foi desenvolvida para a biblioteca OGRE3D, com várias

funcionalidades pertinentes. Uma descrição mais detalhada sobre esta especialização pode ser

encontrada na seção 2.3.2.1.

Page 27: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 26

2.2.2.4 Cálculo Vetorial e Geometria Analítica: Vetores 2D e 3D

Embora utilidade mais óbvia de um sistema de coordenadas em um jogo seja a exibição

gráfica e, por isso mesmo, a maioria das bibliotecas gráficas 3D (e mesmo algumas 2D) im-

plemente essa funcionalidade, quando se deseja um sistema altamente modularizado e flexível

deve haver um subsistema dedicado apenas a isso. Um erro recorrente em projetos mal planeja-

dos é utilizar as estruturas de coordenadas da tela ou espaço 3D para controlar todas as demais

partes do programa, causando pesadelos intermináveis em relação à portabilidade.

A informação posicional deve ser propagada a diversos outros módulos (por exemplo, o

de Áudio, como visto na seção 2.2.1.3). Além disso, a lógica de um jogo ou ambiente virtual

qualquer está quase sempre ligada às posições de seus objetos. Se todo este tráfego de informa-

ções vetoriais utilizar ferramentas de uma biblioteca gráfica específica, todo código que trabalhe

com informação posicional terá que ser retrabalhado caso seja necessário remover ou trocar tal

biblioteca. Por outro lado, se um sistema comum e unificado tiver todas as funcionalidades

necessárias, estas são implementadas uma única vez e criam-se conversões para quaisquer mó-

dulos específicos que necessitem, sendo possível mudar de módulos gráficos e até mesmo criar

uma aplicação sem interface visual (um servidor dedicado, por exemplo) sem nenhum tipo de

retrabalho.

O módulo de Cálculo Vetorial e Geometria Analítica (CVGA) no Dystopia é composto pe-

las classes Vec2 e Vec3, que implementam, respectivamente em 2D e 3D, operações tradicionais

de vetores, como soma, subtração, multiplicação por escalar, produto interno, produto vetorial,

normalização etc. Estas operações são implementadas utilizando-se sobrecarga de operadores

sempre que for possível e apropriado, de forma a ser intuitivo lidar com vetores utilizando-se

os símbolos habituais usados para tratar grandezas numéricas na linguagem C++.

Uma longa explicação sobre Geometria Analítica e Álgebra Linear para jogos, com exem-

plos de implementação e muito além do que o descrito aqui, pode ser encontrada em [5].

2.2.2.5 GameObject

Todo ambiente de um jogo eletrônico ou aplicação interativa é composto de elementos

estáticos e elementos dinâmicos. Como elementos estáticos, podemos citar principalmente os

componentes do cenário, fundo etc; tais elementos não mudam de estado ao longo da execução

do jogo–no máximo são criados, por exemplo, no começo de uma fase, e destruídos no final

desta. Por outro lado, elementos dinâmicos como o jogador, inimigos, itens, projéteis, sistemas

de particulas, além de objetos com os quais o jogador pode interagir, como alavancas, cordas

Page 28: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.2 Arquitetura 27

e veículos, mudam de estado constantemente no universo do jogo, seja apenas mudando de

posição, ou mesmo tendo regras únicas e complexas que regem seu comportamento, como a IA

de um inimigo.

Enquanto na maioria das vezes pouca atenção precisa ser dada aos elementos estáticos,

já que eles interferem pouco no gameplay (exceto por questões de gerenciamento de visibili-

dade e verificação de colisões, para as quais existem várias soluções prontas e bem testadas,

primariamente com a utilização de técnicas de divisão espacial como árvores BSP, Octrees ou

KD-Trees[5]), elementos dinâmicos precisam ser bem controlados e gerenciados devido à sua

volatilidade, na forma de uma quantidade arbitrária de atributos que variam ao longo do tempo.

Por isso, muitas engines de jogos implementam o conceito de GameObject, que é uma repre-

sentação abstrata de um elemento dinâmico do jogo.

Este conceito pode ser implementado de várias maneiras diferentes, se dividindo em duas

categorias principais: centrada no objeto, e centrada nos atributos. No primeiro caso, cada ob-

jeto é representado por uma instância de uma classe na linguagem de programação do jogo,

possivelmente existindo uma hierarquia de classes representando vários tipos diferentes de ob-

jetos, sendo os atributos implementados pela própria classe. Já na segunda abordagem, cada

objeto é representado apenas por um identificador, que funciona como índice para um conjunto

de tabelas, uma para cada tipo de atributo existente.

Ambas abordagens têm vantagens e desvantagens que não serão discutidas aqui; uma dis-

cussão extensa sobre os diferentes paradigmas de gerenciamento de objetos pode ser vista em

[5]. O Dystopia implementa, em sua versão atual, apenas o paradigma centrado no objeto,

com uma única classe simples chamada GameObject, que simplifica a organização de alguns

atributos e comportamentos recorrentes. Esta classe encapsula, de acordo com os subsistemas

definidos para uso, os seguintes tipos de atributos (ou componentes):

• Um nome, implementado como um objeto string;

• Um emissor de som (SoundEmitter) que acompanha automaticamente a posição do objeto

(veja a seção 2.2.1.3);

• Uma entidade (que representa um modelo) da OGRE3D, juntamente com seu nó de posi-

ção (SceneNode; veja a seção 2.3.2.3);

• Uma posiçao 3D, representada por um objeto Vec3 nos métodos set e get, mas interna-

mente mapeada para as informações de posiçao do nó da OGRE, caso esteja definida para

uso, evitando redundância de memória.

Page 29: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 28

É importante salientar que as referências a objetos da OGRE3D só existem se o framework es-

tiver configurado para utilizar esta biblioteca, através da definição da constante correspondente

(veja a seção 2.3.2 para mais detalhes sobre a integração do Dystopia com OGRE3D). Caso

contrário, não existirá referência a nenhuma entidade ou modelo, e a posição 3D do objeto será

definida em termos de um Vec3 do Dystopia.

Esta abordagem também é considerada baseada em componentes, porque cada atributo

é apenas uma referência a um objeto de outro subsistema (gráfico, sonoro, física etc), e as

atualizações de cada um dos componentes são realizadas de fato nos passos de atualização de

cada um dos subsistemas, e não durante a atualização dos estados dos objetos.

2.2.2.6 Tratamento de erros

Dois pequenos mecanismos auxiliares de detecção e tratamento de erros foram criados no

framework. O primeiro deles é uma classe de exceção, contendo apenas uma descrição do erro.

Esta classe não chegou a ser utilizada em nenhum momento na implementação do Dystopia,

mas está diponível para alguma aplicação que queira utilizar-se dela.

O outro mecanismo implementado foi uma macro de assert (asserções). Esta macro visa

garantir que uma certa expressão, assumida verdadeira no momento do desenvolvimento, é

realmente verdadeira em tempo de execução. Caso ela não seja, a execução do programa é

interrompida e a asserção é reportada no console. Caso a constante _PRODUCTION esteja

definida, porém, a macro da asserção avalia para código vazio. Isto é feito para que as versões

finais da aplicação não contenham estas checagens, que podem causar uma queda desnecessária

na performance de execução. A estrutura básica desta macro, com poucas modificações, foi

retirada de [5].

2.3 Detalhes da Implementação

2.3.1 Wrappers

Com as definições das interfaces prontas, passamos a pesquisar quais seriam boas bibliote-

cas a serem usadas para iniciar o que seria a "implementação padrão" do arcabouço. Os únicos

requisitos eram que as bibliotecas fossem multiplataforma e gratuitas para uso não-comercial.

Considerou-se, portanto, tanto bibliotecas código aberto quanto código fechado. As seções a

seguir tratam da escolha das bibliotecas externas e alguns comentários a respeito de suas funci-

onalidades e adaptação ao Dystopia, além de exemplos de utilização de cara um dos módulos.

Page 30: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 29

2.3.1.1 Áudio

Foram consideradas três opções de bibliotecas de tratamento de áudio inicialmente:

• OpenAL[6]: criada com o intuito de ser análoga ao OpenGL, é utilizada como base para

diversas aplicações e engines de jogos. Até sua versão mais recente, era de código aberto,

sob licença LGPL, atualmente sendo propriedade da Creative Technology. Tem duas

versões alternativas, a original (que não é mais desenvolvida) e uma opção open-source

chamada OpenAL Soft, que ainda está sendo desenvolvida;

• FMOD[7]: a mais utilizada hoje em dia para jogos de grande porte, é uma solução propri-

etária completa, com editores e ferramentas. Gratuita para uso não comercial, mas com

uma licença cara (com investimento indo de US$3 mil a US$9 mil), sem caso especial

para orçamentos pequenos;

• IrrKlang[8]: código proprietário, com desenvolvimento ativo, simples e gratuita para uso

não comercial. A licença "pro" tem um preço relativamente acessível; para jogos que

sejam vendidos a menos de US$35,00, a licença "indie" custa apenas US$400,00, para

um número ilimitado de títulos.

Cruzando estas características, a que demonstrava melhor relação custo-benefício era a Irr-

Klang, sendo esta a escolhida para a implementação padrão. Assim, foi criada a IrrKlangIn-

terface, que seria responsável por implementar as especificações do Dystopia::SoundManager

utilizando os métodos desta biblioteca.

Como o mecanismo interno de gerenciamento e reprodução de sons da IrrKlang é bastante

próximo ao definido para o Dystopia, a implementação desta interface foi relativamente sim-

ples, requerendo cuidado apenas no reposicionamento constante dos sons tocados, já que esta

biblioteca não implementa o conceito de “emissor”, mas sim uma referência para cada som

sendo tocado, que pode ser utilizada para mudar seus atributos dinamicamente.

// Exemplo de utilização do SoundManager com IrrKlang.

//Inicialização

Dystopia::SoundManager *soundManager;

soundManager = new Dystopia::IrrKlangInterface();

soundManager->setupAudio();

//Carregar sons

Page 31: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 30

soundManager->loadSound("som1.wav", "som #1");

soundManager->loadSound("musica.ogg", "musica de fundo");

//Executar uma música (sem informacão posicional)

soundManager->play("musica de fundo", true);

//Alterar propriedades do ouvinte

soundManager->setListenerPos(listener_pos);

soundManager->setListenerVel(listener_vel);

//Criar um emissor e alterar suas propriedades

Dystopia::SoundEmitter *emitter;

emitter = soundManager->createEmitter();

emitter->setPosition(emitter_pos);

emitter->setVelocity(emitter_vel);

//Executar um som posicional

emitter->play("som #1");

2.3.1.2 Rede

Uma excelente solução para redes é a RakNet[9]. Seu código é fechado mas, além de

sua robustez, as licenças são altamente acessíveis: se o orçamento do projeto onde será utili-

zada é inferior a US$100.000,00, a biblioteca pode ser utilizada gratuitamente. Além disso, é

amplamente utilizada pela indústria, inclusive em títulos de produtoras de grande porte, sem

mencionar o suporte constante e atualizações freqüentes. Assim, foi uma escolha imediata.

Assim como no módulo de Áudio, o funcionamento da RakNet é bastante parecido com a

especificação da interface equivalente, com a maior parte dos comandos apenas repassados, com

duas ressalvas. A primeira é que muitas das chamadas foram simplificadas: como a RakNet

é uma biblioteca extremamente completa e extensa, disponibilizando várias maneiras de se

realizar a comunicação, muitos parâmetros foram fixados internamente para expor apenas uma

interface simples.

A outra ressalva diz respeito à fila de pacotes recebidos por uma máquina. Embora a

NetworkInterface exponha uma funcionalidade de fila idêntica à RakNet, foi implementada

uma fila interna para filtrar os “pacotes virtuais” gerados pela RakNet, como mensagens de

Page 32: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 31

erro e gerenciamento de conexão, de forma a serem devidamente tratadas pela interface e não

repassados para a fila de pacotes da aplicação.

// Exemplo de utilização do NetworkInterface com RakNet.

#define PORT_NUMBER 35123

//Servidor: inicialização

Dystopia::NetworkInterface *server;

server = new RakNetInterface(Dystopia::NETWORK_SERVER, PORT_NUMBER);

server->startup(max_clients);

//Cliente: inicialização

//Pode ser passado um domínio ou endereço IP.

Dystopia::NetworkInterface *client;

client = new RakNetInterface(Dystopia::NETWORK_CLIENT, PORT_NUMBER);

client->startup("my_server_address.coolservers.com");

bool connected = false;

bool loop = true;

while(!loop)

{

switch(client->update())

{

case NETWORK_SERVER_FULL:

cout << "Sorry, server is full." << endl;

loop = false;

break;

case NETWORK_CONNECTION_SUCCESS:

cout << "Connection success!" << endl;

connected = true;

loop = false;

break;

case NETWORK_CONNECTION_FAILED:

cout << "Connection failed." << endl;

loop = false;

Page 33: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 32

break;

}

Dystopia::Sleep(100);

}

//Servidor: recebendo pacotes e reenviando para todos

enum MyPackets {ID_CLIENT_TO_SERVER, ID_SERVER_TO_CLIENTS};

Dystopia::NetworkPacket* np;

server->update();

while(server->pollPacket(&np))

{

switch(np->id)

{

case ID_CLIENT_TO_SERVER:

server->send(ID_SERVER_TO_CLIENTS, //ID do pacote

np->len, //Tamanho dos dados

np->data, //Ponteiro para os dados

-1, //Cliente destino

true); //Enviar para todos

break;

}

}

2.3.1.3 Entrada

Para trabalhar com a entrada, escolhemos como padrão a OIS[10] (Object-Oriented Input

System). De código aberto e licença zlib, suporta Windows e Linux de maneira completa, e

possui “suporte parcial” a MacOS X. Consegue gerenciar entradas de mouse, teclado, joysticks

e até mesmo Wiimotes[11] nativamente.

Assim como nos casos de áudio e rede, o funcionamento da OIS é análogo à interface

definida no Dystopia: um objeto se registra com a biblioteca para receber tipos de eventos

dos dispositivos. Porém, neste caso os eventos são repassados diretamente à aplicação, apenas

passando por um processo de conversão de estruturas.

Um detalhe digno de nota em relação à implementação específica desta interface é relacio-

nado à sua portabilidade para outras plataformas, sendo coberto, portanto, na seção 2.3.3.

Page 34: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 33

// Exemplo de utilização do InputManager com OIS.

//Inicialização.

//"windowHnd" é o handle da janela da aplicação.

Dystopia::InputManager *inputManager;

inputManager = new OISInterface(windowHnd);

inputManager->setWindowSize(640, 480);

//Registra um objeto para receber os eventos de entrada.

//Supondo que "myListener" seja objeto de uma classe que

//herda de KeyListener, MouseListener e JoystickListener

m_inputManager->addKeyListener(myListener);

m_inputManager->addMouseListener(myListener);

m_inputManager->addJoystickListener(myListener);

//Exemplo de tratamento de eventos de teclado

void MyListener::keyPressed(const Dystopia::KeyEvent &arg)

{

if(arg.code == KC_X)

{

cout << "Apertei a tecla X!" << endl;

}

}

2.3.2 Integração com OGRE3D

Embora o framework não encapsule completamente o acesso a nenhuma biblioteca grá-

fica específica, o desenvolvimento de algumas funcionalidades para auxiliar a sua utilização

com a biblioteca OGRE3D[3] se mostrou bastante relevante, devido a tais funcionalidades se-

rem recorrentes e passíveis de encapsulamento parcial. Porém, diferentemente dos wrappers

(que encapsulam totalmente a utilização das bibliotecas externas), quase todas as referências

internas à OGRE utilizadas por estes componentes são compartilhadas com a aplicação; seja

criadas pelo framework e disponibilizadas a ela (como no caso da Aplicação Orientada e Obje-

tos OGRE), como no caso de requisitar referências à aplicação para seu funcionamento (como

o GameObject, sistema de áudio e os módulos auxiliares de splash e player de vídeo).

Page 35: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 34

É importante salientar também que esta biblioteca possui seu sistema próprio de Scene

Graph[12] (gerenciamento de cena) que cuida das posições de todas as entidades em um dado

momento. Não há nenhum tipo de gerenciamento de cena com objetos OGRE implementado

explicitamente no Dystopia, apenas referências a nós do Scene Graph, utilizados para controlar

(ou obter informações de) um objeto em especial, como no caso do GameObject.

Uma explicação sobre o funcionamento da biblioteca OGRE3D está além do escopo deste

trabalho, mas existem alguns livros que exploram em detalhes suas funcionalidades, como [13]

e [14], além de extensiva documentação (em forma de manual e wiki) e um fórum no website

da biblioteca[3].

2.3.2.1 Aplicação Orientada e Objetos OGRE

Foi criada uma especialização da classe Application (seção 2.2.2.3) para uso com OGRE,

contendo a criação da janela e inicialização da engine gráfica, gerenciamento do loop princi-

pal, inicialização de um InputManager com a biblioteca OIS (se definida para uso), criação de

um display com informações de debug no topo da tela (que pode ser posteriormente oculto) e

criação e gerenciamento dos movimentos de uma câmera de movimento livre (modo "noclip",

muito útil para situações de teste).

2.3.2.2 Integração com o módulo de CVGA

Como em OGRE, assim como no Dystopia, existem classes que representam vetores 2D

e 3D, foram implemendas conversões (em ambos os sentidos) para cada tipo de vetor. Desta

forma, um vetor Dystopia pode ser utilizado onde é pedido um vetor OGRE e vice-versa, au-

tomaticamente. Para isto, foi utilizada a funcionalidade de sobrecarga de operadores de C++;

como nesta linguagem um typecast (conversão de tipo) é considerado um operador, seu compor-

tamento pode ser sobrecarregado para tipos não-primitivos, de modo a implementar conversões

de tipo automáticas.

2.3.2.3 Integração com GameObject

A classe GameObject do Dystopia encapsula, como visto na seção 2.2.2.5, uma entidade

OGRE e seu respectivo SceneNode. Um SceneNode em OGRE é apenas um nó da árvore

do Scene Graph[12], e toda entidade precisa estar ligada a um SceneNode para ser visível na

cena. A posição e orientação de uma entidade são, então, determinadas pela concatenação das

transformações respectivas acumuladas no caminho desde a raiz do scene graph até o nó que a

Page 36: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 35

representa.

Durante a criação de um GameObject, a aplicação pode pedir que o SceneNode seja criado

no primeiro nível da árvore (ou seja, tenha como pai a raiz e suas transformações sejam abso-

lutas em relação à origem do espaço tridimensional), ou passar como parâmetro um SceneNode

que deve ser o pai do objeto na árvore do SceneGraph. Além disso, como pode existir mais

de uma cena em memória ao mesmo tempo, é necessário que a aplicação passe também uma

referência ao SceneManager (a representação em OGRE de um scene graph) onde o objeto

existirá.

2.3.2.4 Integração com o módulo de Áudio

Foram adicionados ao subsistema de áudio alguns métodos para automatizar a atualização

de posição e velocidade, tanto do ouvinte quanto dos emissores, além da orientação do ouvinte,

a partir de informações da OGRE. Pode-se definir que o ouvinte seja atualizado sempre por uma

câmera OGRE (já que, na prática, o ouvinte é sempre aquele que está visualizando o mundo

virtual), e que um emissor seja atualizado a partir da posição de um SceneNode OGRE.

2.3.2.5 Módulos auxiliares usando OGRE

Dois módulos pequenos que usam OGRE foram desenvolvidos para tarefas repetitivas re-

lacionadas à exibição de gráficos pré-renderizados:

• Tela de Espera (Splash Screen): desenha uma imagem em tela cheia, geralmente utilizada

na inicialização e em momentos em que recursos do jogo, como fases, estejam sendo

carregados;

• Player de Vídeo: reproduz um vídeo pré-renderizado de um arquivo para uma textura

OGRE. Esta textura poderá então ser usada juntamente com a tela de splash para fazer um

vídeo em tela cheia (FMV - Full Motion Video) ou aplicada em um modelo normal, como

uma textura animada. Além disso, se for passada uma referência para um SoundManager

na criação do player, o som do vídeo também será tocado em sincronia com a imagem,

possivelmente com informação posicional se for passado também um emissor. O formato

suportado para os vídeos é o Ogg Theora, que é um formato aberto mantido pela fundação

Xiph.org. Já o áudio poderá estar em qualquer formato suportado pela biblioteca de som

utilizada pelo SoundManager.

Page 37: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

2.3 Detalhes da Implementação 36

2.3.3 Questões multiplataforma

Todo o arcabouço teve em mente a importância do paradigma de múltiplas plataformas.

Apesar de que para jogos comerciais a plataforma Windows, atualmente, é amplamente a mais

utilizada, recentes números mostram que o suporte para desenvolvedores independentes é maior

entre usuários de Linux e MacOS. No Humble Indie Bundle[15], uma promoção de diversos jo-

gos independentes com uma abordagem que deixava o usuário pagar o quanto quisesse pelo

pacote inteiro, apesar de mais da metade das compras terem sido feitas por usuários Windows,

o preço médio pago por eles foi o mais baixo (US$8,05 contra US$10,17 de usuários MacOS

e US$14,44 de usuários Linux). Na segunda edição desta promoção, no ano de 2010, os nú-

meros são mais expressivos: US$6,68 , US$9,27 e US$13,78 foram os preços médios pagos

por usuários Windows, MacOS e Linux, respectivamente. Além disso, há o fator "oceano azul"

agregado: como há poucos jogos em plataformas Apple e Linux, é mais fácil destacar-se nesse

ambiente.

No Dystopia, todo o código foi planejado para utilizar apenas comandos independentes de

plataforma. Quando isso não era possível, flags eram criadas no código para utilizar as versões

específicas dos comandos. Foi feita uma rápida conversão para ambiente Linux para comprovar

que esta abordagem foi feita de maneira correta e constatou-se que havia apenas dois pontos em

que alguma intervenção era necessária:

• Temporizador: o comando para se aguardar um tempo determinado sem nenhuma ação

em plataforma Win32 é o Sleep(). No Linux, há o usleep(), que recebe microssegundos

(µ).

• Entrada: a biblioteca padrão de entrada do arcabouço é a OIS (Object Oriented Input

System). Para a configuração do mouse nesta biblioteca deve-se passar dois parâmetros

relacionados a capturar a entrada do mouse e mostrar o cursor ou não quando este está

sobre a janela da aplicação. Essas constantes são diferentes entre Windows e Linux mas,

após trocar esses parâmetros, o funcionamento foi idêntico.

Sendo assim, constatou-se que o código do arcabouço era perfeitamente compatível entre os

dois sistemas operacionais, sendo a maior parte do trabalho de porte a configuração do ambi-

ente. Não foram realizados testes paras plataformas Apple por falta de equipamentos mas, por

ser o MacOS uma variação do Unix como o Linux, acreditamos que não haja grande diferença

no processo.

Page 38: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

37

3 O jogo: SumoCheckers

"HAI!”

Red Sumotori #9 (SumoCheckers)

Neste capítulo é apresentado o processo de desenvolvimento do jogo, desde a criação do

primeiro protótipo até a versão atual, em 3D.

Page 39: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.1 Introdução 38

3.1 Introdução

Tendo a estrutura básica do arcabouço definida, o próximo passo consistia em colocá-lo

à prova num ambiente de desenvolvimento real. Assim, foi decidido criar um jogo que fosse

simples o suficiente para uma equipe pequena (no caso, duas pessoas), mas que envolvesse todos

os módulos do sistema. Foi feito então um rascunho dos requisitos: o jogo deveria ter gráficos,

sons, suportar mais de um jogador (localmente e via rede) e ter entradas utilizando mouse,

teclado e, opcionalmente, joysticks. Outro objetivo importante foi o jogo ser um ambiente onde

pudessem ser testados diferentes tipos de inteligência artificial.

Atendendo a esses requisitos, foi criado o SumoCheckers, um jogo de estratégia por turnos

com batalhas em tempo real. Basicamente, peças de damas seriam espalhadas num tabuleiro

e, quando uma peça fosse capturar a outra, haveria uma batalha semelhante ao sumô, sendo

perdedora a primeira peça que saísse de um ringue circular. É importante notar que o movi-

mento na arena da batalha é feito controlando-se a aceleração do personagem, e não velocidade

diretamente, o que torna esta mecânica bem mais interessante e desafiadora – mas, ao mesmo

tempo, foi o fator responsável por alguns problemas técnicos, vistos na seção 3.2.3.

A relação entre jogo e framework foi simbiótica: grande parte do desenvolvimento foi feita

em paralelo, pesando sempre a prioridade de implementação dos módulos do arcabouço com as

necessidades do jogo, e usando os limitadores da tecnologia para moldar o gameplay.

Neste capítulo, abordaremos as diferentes versões do jogo, as experiências em redes e inte-

ligência artificial feitas e a evolução das regras de acordo com as limitações da tecnologia.

3.2 Protótipo Inicial (2D)

A primeira versão do jogo foi implementada com gráficos 2D simples, consistindo apenas

em quadrados e círculos coloridos representativos do tabuleiro, das peças e do ringue. Como

os objetivos principais desta iteração eram testar a estrutura básica do framework, os módulos

de rede e entrada, além de realizar experiências de IA, pouca atenção foi dada à estética neste

momento. Logo, o jogo ainda não contava com gráficos além do essencial para visualização dos

elementos, e não havia qualquer forma de música ou efeitos sonoros, tanto em conteúdo como

em implementação.

É importante salientar uma vantagem paralela (porém bastante relevante) de se criar um

protótipo inicial desprovido de estética: a experiência do jogador é fortemente influenciada

pelos fatores audiovisuais. Sendo o protótipo desprovido disso, o fator mais aparente na expe-

Page 40: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.2 Protótipo Inicial (2D) 39

Figura 2: Aparência do primeiro protótipo do SumoCheckers

riência é o núcleo do gameplay–exatamente o que se quer pôr à prova nos estágios iniciais do

desenvolvimento, juntamente com a tecnologia proposta. É isso que, no fim das contas, deter-

mina a rejogabilidade e a qualidade do jogo, no quesito diversão; ao longo da história muitos

jogos que tinham gráficos e sons acima da média de sua época não tiveram a longevidade de

títulos clássicos como da era de videogames 8-bits, que são jogados até hoje.

Sendo assim, todo jogo deve passar por um período de prototipação onde cada ação mais

básica deve ser testada e iterada diversas vezes. É a qualidade dessas ações que determinam se

o jogador irá passar mais ou menos tempo com aquele título. Um exemplo clássico é o do jogo

Super Mario 64, um carro-chefe da plataforma Nintendo 64, onde a equipe de desenvolvedores

passou meses refinando uma pequena demo onde o personagem principal apenas podia correr

e pular. Apenas quando estas ações estavam bem sintonizadas deu-se início a produção de

diferentes níveis e conteúdo.

Uma falha muito comum (não só em desenvolvedores iniciantes, mas também em gran-

des títulos) é tentar corrigir as falhas encontradas nos testes de ações básicas adicionando mais

funcionalidades ao jogo. Diversos jogos com dezenas de mecânicas no seu gameplay não con-

quistaram sucesso critico e comercial porque as ações mais básicas (algo tão primário como

o feel de correr e pular com seu personagem) não eram agradáveis, ou porque o conjunto das

mesmas não era bem unificado.

No que se diz respeito à implementação, o protótipo do SumoCheckers foi projetado com

um paradigma cliente-servidor completo, ou seja, sempre haveria um servidor e dois clientes

sendo executados em um dado momento, sendo que um dos clientes poderia um jogador real

ou um oponente virtual controlado por IA. Toda a comunicação entre clientes e servidor seria

Page 41: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.2 Protótipo Inicial (2D) 40

realizada por meio da interface de rede, mesmo que todos estivessem sendo executados na

mesma máquina. Tal estratégia foi utilizada para minimizar a redundância de código e ajudar a

garantir o isolamento entre a interface com o jogador e a lógica central (regras) do jogo.

Como no momento do desenvolvimento do protótipo 2D ainda não havia o módulo da

Aplicação Orientada a Objetos (seção 2.2.2.3), o controle básico de inicialização e execução foi

feito com uma função “main” padrão da linguagem. Porém, a estrutura de Máquina de Estados

(seção 2.2.2.2) já havia sido construída e foi utilizada nesta versão: havia um estado para o

tabuleiro e outro para a arena para o servidor, o cliente humano e o cliente com IA (veja a seção

3.2.2), num total de 6 estados. O estado inicial de todos os jogadores e do servidor é o do

tabuleiro. Ao iniciar uma batalha, o estado da arena é empilhado sobre o do tabuleiro, e ao fim

desta, desempilhado para que a execução retorne, sem perda de informações.

3.2.1 Bibliotecas externas utilizadas

Para este primeiro protótipo, eram necessárias bibliotecas que tratassem da parte gráfica,

entrada (teclado e mouse) e rede. As bibliotecas utilizadas para entrada e rede foram respec-

tivamente a OIS[10] e a RakNet[9], conforme descrito na seção 2.3.1, por intermédio de suas

interfaces respectivas (InputManager e NetworkInterface). Por outro lado, como a arquitetura

do framework não comporta wrappers para bibliotecas gráficas, tal escolha foi feita especifica-

mente para esta versão do jogo.

Optou-se então pelo uso da biblioteca SDL[16], uma das mais populares disponíveis para

uso livre e destinada primariamente à confecção de aplicativos interativos com gráficos 2D. Por

mais que esta biblioteca provenha funcionalidades adicionais, como gerenciamento de áudio,

entrada e threads, foram utilizadas apenas as funcionalidades gráficas: criação e gerenciamento

de janelas, e desenho bidimensional. Uma documentação sobre esta biblioteca, principalmente

o subsistema gráfico, pode ser encontrada em [17]. O fator determinante para esta escolha foi a

experiência prévia com o SDL e a facilidade de seu uso para gráficos bidimensionais.

A unidade básica de desenho na SDL é uma superfície, que é representação de uma imagem

matricial em memória. A tela é representada por uma superfície, e a operação básica de desenho

é a cópia de parte de uma superfície para outra. Desta forma, foram geradas (analiticamente)

superfícies que representavam o tabuleiro, o ringue e as peças. A cada quadro do jogo, estas

superfícies eram redesenhadas na tela em suas posições apropriadas.

Posteriormente foram desenvolvidos gráficos um pouco melhorados, com imagens pré-

renderizadas para o tabuleiro, ringue e peças no lugar das figuras geométricas simples anteriores

Page 42: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.2 Protótipo Inicial (2D) 41

Figura 3: Segunda versão dos gráficos do SumoCheckers

(figura 3). Apesar de não haver absolutamente nenhuma mudança na mecânica do jogo, a me-

lhora estética causa uma mudança clara na reação dos jogadores e torna a experiência geral bem

mais agradável, mesmo para um protótipo. Enquanto para alguém acostumado com desenvol-

vimento de jogos abstrair da parte gráfica é algo corriqueiro, para jogadores e interessados nem

sempre isso ocorre. Sendo assim, com essa pequena mudança foi possível conseguir pessoas de

perfis mais diferenciados para testar as mesmas mecânicas propostas anteriormente.

3.2.2 Experimentos com Inteligência Artificial

O SumoCheckers é composto de duas mecânicas bastante distintas: o tabuleiro, jogado por

turnos e com movimentação lenta; e a arena, jogado em tempo real com movimentos rápidos.

Isto faz com que estratégias bastante distintas sejam necessárias para abordar o problema da

criação de um oponente virtual para o jogo.

Por um lado, o problema da IA para um jogo de tabuleiro tradicional como damas é bastante

conhecido e estudado; o algoritmo Min-Max ou Minimax[18] é amplamente reconhecido como

uma opção muito boa para gerar oponentes virtuais desafiadores para este jogo, sendo utilizado

para implementar a IA no tabuleiro (uma ótima referência sobre este tipo de algoritmo pode ser

encontrada em [19]). Portanto, o foco da pesquisa em IA desenvolvida no momento da criação

deste protótipo foi o controle de oponentes em tempo real.

Como o Laboratório de Inteligência Computacional do NCE-UFRJ, onde foi desenvolvido

este trabalho, tem como foco a pesquisa em Lógica Nebulosa, Algoritmos Genéticos e Redes

Neurais Artificiais, foi considerada a utilização de alguma destas técnicas para desenvolvimento

do oponente virtual para a arena. Decidiu-se então, inicialmente, pela utilização de Redes

Neurais Artificiais (RNAs), que seriam de implementação mais simples e rápida.

Page 43: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.2 Protótipo Inicial (2D) 42

Isentando-nos de uma explicação extensa a respeito do funcionamento das RNAs (para um

livro dedicado a este assunto, veja [20]), podemos nos limitar a dizer, de maneira simplificada,

que uma RNA do tipo MLP (Multi-Layer Perceptron, como a que foi utilizada neste caso) é

um aproximador de funções contínuas definidas de Rn → Rm, treinado a partir de um conjunto

de pares de entrada e saída conhecidos. Este tipo de rede é composta de várias camadas de

neurônios artificiais que processam os dados de entrada e geram uma saída correspondente.

Para gerar o conjunto de amostras conhecidas, uma sessão de aproximadamente 10 minutos

de jogo entre dois jogadores reais foi gravada, com cada comando de movimentação realizado

por cada jogador (inclusive a ausência de comandos) em cada estado da arena representando

uma amostra do treinamento.

Foram utilizadas então duas estratégias para organizar estas amostras para o treinamento.

Na primeira, uma amostra de entrada era formada pela posição e velocidade atual, em X e

Y, de cada jogador, totalizando 8 dimensões. As saídas eram apenas a direção, em X e em

Y, para onde o jogador deveria se mover. Na segunda, foi aproveitado o fato de que a arena é

circularmente simétrica: as posições dos jogadores foram convertidas para coordenadas polares,

e foi considerado que um dos jogadores sempre estava no ângulo zero, ou seja, a coordenada do

ângulo de um jogador é subtraída do outro, e elimina-se uma dimensão de entrada, chegando a

7 dimensões.

A arquitetura de rede MLP foi definida como tendo duas camadas de neurônios: uma ca-

mada de saída e uma camada escondida. A camada de saída possui sempre um neurônio artifi-

cial para cada dimensão de saída, e a camada escondida foi definida como tendo 12 neurônios

nas duas abordagens utilizadas.

Após o treinamento de uma RNA para cada uma das duas abordagens, foi observado o com-

portamento de cada uma quando posta à prova frente a um jogador real. Para relativa surpresa,

a segunda abordagem, que esperava-se ser mais adequada pela compactação de amostras aná-

logas, terminou por mostrar-se evidentemente menos eficaz que a primeira quando executada

durante o jogo. Por sua vez, a abordagem das entradas diretas, apesar de se sair melhor que

a outra, ainda fraquejava em algumas situações, aparentando estar “confusa” e “indecisa”, e

acabando por ficar parada no mesmo lugar e abrindo espaço para ser atacada.

Uma provável explicação para este cenário é que RNAs, ao contrário de seres humanos,

são inerentemente determinísticas e baseadas apenas nas entradas que lhes são apresentadas.

Os jogadores que geraram o conjunto de amostras de treinamento provavelmente reagiram de

maneiras diferentes em situações muito parecidas, seja por motivos externos à situação do jogo

em si ou porque humanos são (aparentemente) não-determinísticos. Como o treinamento da

Page 44: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.2 Protótipo Inicial (2D) 43

MLP se dá a partir da minimização de um erro médio quadrático, a tendência no caso de amos-

tras conflitantes é que a saída se equilibre na média entre as duas respostas, que em muitos

destes casos (onde há uma escolha entre se esquivar para a direita e para a esquerda, por exem-

plo) equivale ao oponente permanacer parado.

Esta análise também explicaria por que a segunda abordagem à criação das amostras foi

pior: com a “compactação” das amostras, uma quantidade ainda maior de situações conflitantes

passou a existir no conjunto de treinamento, criando menos regiões de entrada onde a rede

retorna uma saída “decidida”.

3.2.3 Experimentos com jogo em rede e Internet

Inicialmente, para o prototipo 2D, desenvolveu-se um sistema de controle via rede total-

mente bloqueante: o usuário entra com um comando, este é enviado para o servidor para vali-

dação, e só então os clientes (inclusive o que enviou o comando) recebem a resposta e a aplicam

em seus estado locais do jogo. Apesar deste esquema funcionar bem o suficiente para o tabu-

leiro, e mesmo para a arena em jogos em LAN sem tráfego paralelo, ele é totalmente inviável

para a arena em jogos via Internet devido à alta latência envolvida neste tipo de comunicação,

que é da ordem de centenas de milissegundos em grande parte das vezes.

Sendo assim, uma solução que, ao menos aparentemente, removesse esta impressão de

atraso percebida pelo jogador se fez necessária. A estratégia mais óbvia neste caso é simples-

mente deixar que o jogador tenha autoridade sobre a validade de seu movimento, retirando do

servidor a tarefa de validar todos os comandos antes que o jogador veja os resultados. Além

disso, a validação ainda pode ocorrer a posteriori, enviando uma mensagem que cancela o co-

mando anterior e reverte o estado do jogo para o que o servidor considera “válido”.

Porém, isto ainda apresenta dois problemas. O primeiro, que surge em todo jogo com movi-

mentação em tempo real, é que o outro jogador ainda receberá a informação do movimento com

algum atraso, causando uma discrepância na posição e velocidade dos jogadores nos mundos

percebidos por cada um. Esta questão pode ser contornada, porém, supondo que nenhum outro

comando foi enviado durante o atraso da transmissão, estimando este atraso, e extrapolando a

posição e velocidade do outro jogador baseando-se nas informações recebidas na comunicação

e no tempo estimado para sua recepção. Caso tenha havido de fato algum outro comando envi-

ado neste meio tempo, basta que seja sempre enviado o estado completo do mundo percebido

pelo servidor para que os erros devidos a estas estimativas não se acumulem muito. Esta técnica

é chamada de compensação de lag (ou lag compensation[21]).

Page 45: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 44

O segundo problema, específico à maneira como os objetos se movimentam e reagem no

SumoCheckers, ocorre porque o movimento de um jogador pode influenciar diretamente no

outro, no momento em que ocorre uma colisão. Um atraso de algumas dezenas de milissegundos

já é suficiente para causar uma grande discrepância no estado do mundo percebido por cada

jogador quando uma colisão ocorre neste tempo, fazendo com que o servidor tenha que tomar

decisões difíceis. Por exemplo, se na visão de um jogador ele conseguiu esbarrar, por pouco,

no outro, mas para o outro jogador, este realizou um movimento que o fez esquivar-se a tempo,

qual situação o servidor deve arbitrar como válida se ambas são válidas de acordo com o estado

do universo no momento em que foram processadas?

Uma rápida pesquisa mostrou que existem muito poucos tipos de jogos com este tipo de

comportamento, com controle de movimentação acelerada e onde um jogador afeta direta e for-

temente a movimentaçao de outro(s), com a opção de jogos multiplayer online. Uma exceção

são os jogos de corrida, onde pode-se perceber que este problema de fato existe e não con-

segue ser contornado satisfatoriamente: colisões do carro do jogador com o cenário em geral

se comportam bem, mas colisões com outros jogadores online muitas vezes causam resultados

estranhos e uma sensação inverossimel para o jogador. Ainda assim, este problema é um pouco

menor neste tipo de jogo devido à frequência das colisões com outros jogadores ser bem menor

que no caso do SumoCheckers (onde estas colisões são de fato a base do próprio gameplay), e

pelo controle da movimentação dos carros ser mais “pesado”, tendo assim uma trajetória difícil

de mudar repentinamente.

Sendo assim, os esforços para a implementação de um sistema satisfatório de diminuição

dos efeitos percebidos pela latência da comunicação via Internet foram abandonados por terem

se mostrado um problema grande demais para o jogo em questão, ainda mais após perceber a

dificuldade em encontrar alguma evidência, bibliográfica ou visual, de que esta questão foi sa-

tisfatoriamente resolvida para situações suficientemente similares. Soluções para este problema

são abordadas na seção 3.3.4.

3.3 Versão 3D

Após verificarmos que o SumoCheckers era de fato um projeto factível, tanto nos quesitos

de quantidade de trabalho quanto em relação ao funcionamento das mecânicas (mesmo que

fossem necessárias algumas mudanças), partimos para o próximo passo, tanto do jogo quanto

do arcabouço. Nesta fase, foram criados os módulos de Áudio e CVGA (seções 2.2.1.3 e 2.2.2.4,

respectivamente), além da adaptação do Dystopia para trabalhar com a engine gráfica OGRE3D

Page 46: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 45

(seção 2.3.2). Devido aos problemas relacionados à compensação de lag vistos na seção 3.2.3,

a implementação de jogo por rede foi adiada, sendo esta versão, atualmente, jogável apenas por

dois jogadores na mesma máquina.

3.3.1 Conteúdo

A diferença primordial do protótipo bidimensional para esta versão é que era preciso co-

meçar a se definir uma direção geral no estilo visual do jogo. Mais que um teste de tecnologia

e de gameplay, o projeto agora deveria tomar direções que apontassem mais para uma versão

finalizada, para evitar retrabalho futuro também na parte de conteúdo. Assim, cada elemento

deveria ser considerado ou como algo a ser feito de maneira simples e rápida, que seria comple-

tamente substituído mais adiante, ou algo que pudesse ser iterado posteriormente para se tornar

parte integrante da versão final.

Outra diferença é que os gráficos da segunda versão do protótipo puderam ser criados de

maneira rápida. Na criação de conteúdo (modelos) 3d, os passos a serem tomados são bem mais

complexos, especialmente em relação a personagens animados:

• Arte conceitual: um esboço do personagem que servirá de base para sua recriação em 3d;

• Modelagem: é criada uma escultura tridimensional do personagem, observando sempre

as limitações impostas pela plataforma e tecnologia sendo utilizadas;

• Preparação para texturização: cria-se um mapa bidimensional, que projeta o modelo 3d

em um plano, para que sua textura seja pintada (UVW Map);

• Texturização: pinta-se por cima da guia do UVW Map, para que essa textura seja proje-

tada no modelo;

• Preparação para animação: processo chamado de rigging, onde um esqueleto é construído

e diferentes partes do modelo são associadas a cada osso [22]. Movendo-se o esqueleto,

move-se estas partes, facilitando o processo de animação;

• Animação: são criados keyframes, ou seja, quadros com poses fixas que serão interpola-

das pelo programa de criação de conteúdo para gerar os movimentos;

• Exportação: o modelo texturizado é exportado para o formato padrão da engine sendo

usada (neste caso, da OGRE3D).

Page 47: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 46

Figura 4: Aparência da versão 3D do SumoCheckers

Page 48: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 47

Alguns desses processos podem ser paralelizados (por exemplo, animação e texturização) em

equipes que contem com mais de um artista. Em objetos estáticos, apenas os quatro primeiros

passos são feitos, além da exportação. Como os modelos são artefatos lógicos a serem guarda-

dos em memória e que, para sua exibição, envolvem cálculos matemáticos intensos, dois fatores

devem ser observados com cuidado: a contagem de polígonos e a resolução das texturas. Deve-

se sempre pesar quantos modelos serão exibidos simultaneamente, tanto no cenário como em

personagens/adereços, com a sua importância visual, tendo como guia a plataforma; enquanto é

aceitável que para um jogo que vá rodar em uma placa de vídeo de última geração e ter poucos

personagens na tela que um modelo tenha de 15 a 20 mil polígonos e texturas de 1024x1024

pixels, tentar fazer o mesmo em um netbook ou smartphone seria completamente inviável.

A criação das cenas segue um fluxo semelhante ao dos modelos individuais. No entanto,

ela é exportada como um todo para o padrão DotScene[23], criado pela comunidade para a

OGRE3D, que consiste basicamente em um arquivo XML que descreve as posições e rota-

ções de diversos SceneNodes relativos a cada objeto da cena. Esta é carregada através de uma

pequena extensão chamada DotSceneLoader[24]. Enquanto pode-se criar a cena inteira num

programa gráfico e exportar todos os objetos, além do arquivo .scene de uma so vez, é prefe-

rível exportar os modelos separadamente e criar a cena em um editor, de forma que modelos

idênticos não sejam duplicados sem necessidade.

Para economizar processamento sem perder qualidade gráfica, algumas técnicas são utili-

zadas na criação dos cenários, sendo vistas na seção 3.3.2.

Finalmente, o diferencial final era a presença de sons. Com essa versão, foi desenvolvido

o sistema de áudio do Dystopia, sendo possível a adição de diferentes músicas para a fase de

tabuleiro (calma) e de batalha (agitada), além de efeitos sonoros para os personagens, não so

para ambientação, mas também para feedback, indicando quando movimentos eram aceitos,

colisão entre as peças e a derrota de um oponente.

3.3.2 Efeitos e melhorias visuais

Para garantir a melhor qualidade visual possível, diversos truques podem ser utilizados,

como criar adereços de cenário que consistam apenas de um plano tridimensional simples, com

uma textura pintada por cima, para dar a ilusão de um ambiente extenso (técnicas similares são

utilizadas no cinema há décadas, os chamados "matte paintings" [25]). Outra possibilidade é o

uso de técnicas de LOD, ou Level of Detail[26], onde diversas versões do mesmo modelo com

uma quantidade cada vez menor de polígonos são criadas e, quanto mais longe se está do objeto,

versões cada vez menos detalhadas são desenhadas na tela.

Page 49: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 48

Figura 5: Técnicas utilizadas para criação do cenário do jogo

Algumas vezes, efeitos simples podem fazer uma grande diferença na ambientação do jo-

gador. Além disso, há certas técnicas que já são um padrão esperado para jogos nos dias de

hoje. Além da definição de feedback visual para certas situações (como diferentes texturas para

quando as peças se transformassem em damas), foram realizadas duas melhorias na versão em

3d do jogo: a adição de grama no cenário e de um shader de normal mapping nos personagens.

A adição de grama é feita através de centenas de pequenos planos com uma textura de

grama que, quando sobrepostos e colocados de maneira aleatória no cenário, criam a ilusão de

folhas individuais (mas com um certo volume). Em placas gráficas atuais, o pipeline de rende-

rização trabalha melhor com poucos batches (chamadas de renderização) compostos de muitos

polígonos, comparado a muitos batches de poucos polígonos. Sendo assim, quando há diver-

sos modelos que usam o mesmo material (que equivale a um render state do driver de vídeo),

pode-se acelerar bastante o processamento agrupando-os em um só batch. Na OGRE3D, existe

uma solução pronta chamada StaticGeometry, implementando exatamente este mecanismo; esta

solução foi então utilizada para renderizar a grama do cenário do jogo.

A figura 5 mostra como são organizados na cena os componentes que definem o cenário

do jogo, em três camadas: em (a), um plano circular com aplicação de uma textura de floresta;

em (b), algumas instâncias de modelos de troncos de árvores e pedras, que completam a ilusão

de profundidade da imagem plana em (a); em (c), dois planos circulares com aplicação de uma

textura de arbustos, levemente rotacionados um em relação ao outro, fechando o volume do

ambiente.

Shaders são pequenos programas que rodam diretamente na placa gráfica. Com eles, é

Page 50: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 49

possível gerar de maneira mais eficiente diversos efeitos de cores e iluminação, sendo estes

partes integrantes de qualquer jogo 3d moderno. Antigamente, o sombreamento de modelos

3d era calculado apenas com base nos vértices ou nos triângulos de sua estrutura. Atualmente,

como ainda é muito mais custoso calcular transformações em malhas complexas de polígonos, a

maior parte dos detalhes mais finos de personagens e cenários virtuais é feita através de técnicas

que utilizam mapas de textura como base, já que as placas trabalham bem mais rápido com as

informações contidas neles.

Uma dessas técnicas é o Normal Mapping[27], que consiste em calcular a direção em que

a luz refletiria num objeto de acordo com um mapa de textura bidimensional, gerado a partir

de um modelo de alta quantidade de polígonos. Basicamente, cria-se o modelo 3d de base (que

será utilizado dentro da aplicação em tempo real), com uma contagem baixa de polígonos, e

outro com uma alta contagem de polígonos e muito detalhado, com base no anterior. Através

das informações do UVW Map, uma projeção é feita de um em outro, criando, assim, o normal

map. Essa textura extra é utilizada por um shader, que a mescla com as informações do mapa de

texturas de cor e da iluminação da cena, criando assim a ilusão de um modelo muito detalhado

e com muitos polígonos, mas que na verdade é simples e renderizado muito mais rapidamente.

O pipeline de criação gráfica varia, sendo algumas vezes o modelo em alta definição criado

primeiro, e o em baixa a partir deste, utilizando-se uma técnica chamada "retopology".

A figura 6 exemplifica os efeitos da técnica de Normal Mapping aplicada aos personagens

do SumoCheckers. Fica evidente na comparação não somente o aumento do detalhe perce-

bido no modelo, mas também o maior realismo alcançado pelo detalhamento da iluminação,

evidenciando nuances mais humanos e diminuindo a impressão “plástica” do modelo original.

3.3.3 Adaptação da lógica de jogo

Por mais que a mecânica de gameplay fosse inerentemente a mesma entre o protótipo 2D e a

versão 3D do jogo, foi decidido começar a implementação do zero, aproveitando as experiências

anteriores para desenvolver uma arquitetura mais organizada e aproveitando novos componentes

do framework que foram desenvolvidos ao longo do tempo.

O paradigma cliente-servidor completo, apesar de robusto e adequado para um jogo mais

complicado, acabou por adicionar complexidade desnecessária no caso do SumoCheckers, por-

que o controle do fluxo das informações estava espalhado por vários lugares diferentes (ora no

cliente, ora no servidor). Além disso, vários trechos do código muito parecidos, porém não o

suficiente para serem encapsulados em uma só, acabavam duplicados nos dois lados, sem con-

tar a quantidade de código necessária para repassar os comandos do jogo e o estado do mundo

Page 51: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 50

Figura 6: Comparação exemplificando a utilização da técnica de Normal Mapping

Page 52: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 51

entre servidor e clientes. Por isso, esta idéia foi abandonada no desenvolvimento da versão 3D

atual em função de um fluxo de execução autocontido.

A estrutura da máquina de estados, com um estado para o tabuleiro e outro pra a arena,

por outro lado, se mostrou eficaz, sendo repetida para a elaboração desta nova versão. Outro

trecho de funcionalidade que seguiu inalterado foi a maneira de organizar o tabuleiro, como

uma simples matriz de inteiros 8x8, e a função de validação de movimento (que define as regras

do jogo).

Por fim, uma mudança importante na arquitetura foi a utilização da estrutura de Aplicação

Orientada a Objetos OGRE, que auxiliou bastante na organização do código e resultou quase

que na total ausência de código de inicialização da biblioteca gráfica, sendo apenas necessário

inicializar os elementos das cenas (cenários e personagens).

Para integrar de maneira simples e direta o espaço contínuo 3D da cena com o espaço dis-

creto 2D das peças no tabuleiro, foi criada na hierarquia de transformações da cena do tabuleiro

um nó que colocava o ponto (0, 0, 0) no meio da superfície da posição (0, 0) do tabuleiro, e fazia

com que uma unidade 3D equivalesse à distância lateral entre posições do mesmo. Desta forma,

uma posição (x, y) do tabuleiro poderia ser utilizada diretamente como (x, y, 0) para posicionar

uma peça do tabuleiro na cena 3D, tornando a implementação da lógica de jogo mais intuitiva.

3.3.4 Playtests e mudanças no gameplay

Tendo um protótipo em 3D com o núcleo das mecânicas implementado, passou-se a uma

nova fase de testes. Como já abordado na seção 3.2, é essencial que as ações mais básicas

do gameplay sejam divertidas o bastante para prender a atenção do jogador. Além disso, o

feedback audiovisual deve ser considerado a cada nova versão, já que alterações nos gráficos e

sons podem alterar profundamente a experiência.

Nesta transição, fomos de um rascunho em 2D, onde o que o jogador experiencia é a colisão

entre dois pequenos círculos (tanto na versão com cores sólidas quanto na com desenhos), a

uma representação bem mais realista, com volume e personagens que, apesar de não serem

tão fotorrealistas, representam claramente um ser humano com certas características visuais.

Devido a essas mudanças, algo inesperado surgiu: o movimento dos personagens não era mais

tão bem aceito quanto nas suas representações anteriores.

Enquanto círculos com desenhos em cima são facilmente aceitos tendo seus movimentos

similares a objetos que deslizam, uma representação tridimensional de um lutador de sumô

carrega mais significado ao jogador; a noção de volume e a representação de características

Page 53: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

3.3 Versão 3D 52

físicas como força muscular e peso corporal fazem o movimento anterior se tornar alheio ao

que se espera. Aliado a isso, este mesmo tipo de movimento era um dos maiores responsáveis

pelos problemas na implementação de compensação de lag vistos na seção 3.2.3. Assim, vimos

a necessidade de adaptação da mecânica primordial do jogo: as lutas em tempo real.

Atualmente, estudamos diversas opções para manter o mesmo tipo de gameplay, mas que

resolvam estes problemas. Uma das abordagens a ser testada é a de os movimentos onde há

contato entre os dois personagens serem controlados de maneira indireta, como por exemplo,

apenas definir uma direção e "atacar" nesta, não havendo a possibilidade de alteração da rota.

Com isso, a movimentação das peças poderia ser adicionada de mais "peso", se tornando mais

parecida com a humana e, ao mesmo tempo, poderíamos utilizar técnicas amplamente testadas

de compensação de lag–neste caso, definir apenas se dado um vetor de direção haverá ou não

uma colisão com outro objeto. [21]

Page 54: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

53

4 Conclusões e trabalhos futuros

“Thank you Mario! But our princess is in another castle!”

Toad (Super Mario Bros.)

Neste capítulo são apresentadas as conclusões e alguns trabalhos ainda a serem realizados.

Page 55: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

4 Conclusões e trabalhos futuros 54

Criar um jogo eletrônico desde suas bases é claramente um trabalho extenso e intrincado.

Enquanto utilizando uma engine pronta o trabalho de implementação é acelerado significativa-

mente (já que o necessário é apenas a programação da lógica do jogo e a criação de conteúdos

audio-visuais), criar um arcabouço funcional como o Dystopia só foi possível porque pudemos

utilizar diversas bibliotecas já existentes. Ao longo desses três anos de trabalho, passamos por

um período de surgimento de middlewares excelentes com licenças acessíveis ou até mesmo

gratuitas, projetos open-source já antigos atingindo sua maturidade e se estabelecendo como

padrões da indústria e, principalmente, de crescimento da comunidade de desenvolvimento de

jogos, com recursos para pesquisa e ajuda mútua amplamente presentes na Internet.

Das ferramentas e bibliotecas escolhidas, até então nenhuma apresentou problemas que

requeressem uma mudança. O mesmo pode-se dizer das decisões da arquitetura do arcabouço

que, apesar de ter sofrido modificações ao longo do tempo, nenhuma dessas afetou a direção

geral do projeto (sendo a maioria, inclusive, esperada). Desenvolver com foco na portabilidade

entre plataformas e na reusabilidade se provou, de fato, uma excelente escolha.

Trabalhos futuros incluem adicionar suporte completo à linguagem de scripting Lua[28] no

Dystopia. Com uma linguagem mais leve como a Lua tendo acesso a métodos do framework,

pessoas menos acostumadas com programação teriam mais facilidade de utilizá-lo para expe-

rimentos, já que não teriam que lidar com a maior complexidade do código em C++. Além

disso, haveria uma estrutura pronta para que a aplicação expusesse apenas partes da sua fun-

cionalidade para serem controladas por scripts. Posteriormente, seria feito o porte do código

da jogabilidade do SumoCheckers para esta linguagem, expondo todas as partes necessárias da

implementação, o que facilitaria e aceleraria o processo de iteração do gameplay.

Pesquisas em inteligência artificial e computacional também devem ser feitas, para criação

de um oponente virtual para o SumoCheckers que consiga não só se movimentar bem em tempo

real, mas também pesar a estratégia do tabuleiro de acordo com os resultados desta faceta do

jogo.

Finalmente, deve-se reconsiderar o paradigma cliente-servidor, quando novos testes de co-

municação via rede forem feitos, para validar as novas idéias de gameplay que possam contornar

o problema da compensação de lag, sem perder a essência das mecânicas desejadas.

Mais do que planejamento, é necessária a experiência direta com a implementação para

entender o quão complexa é a tarefa de se criar um jogo eletrônico do início ao fim. Com a

prática, entende-se melhor as limitações dos sistemas e, com isso, como trabalhar com elas

para atingir o melhor resultado possível. Dos requisitos de um único projeto, podem surgir

diversos outros, como por exemplo pesquisas em inteligência artificial (qual o melhor jeito de

Page 56: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

4 Conclusões e trabalhos futuros 55

“ensinar” um oponente virtual a jogar um jogo conhecido em uma situação nova?), redes (como

podemos compensar os atrasos inerentes da comunicação via Internet?), computação gráfica

(qual a melhor maneira de se tratar informações para o pipeline de uma placa de vídeo para

renderização?); e até mesmo em áreas consideradas completamente alheias à computação (como

a representação de um objeto afeta a maneira que percebemos e interagimos com aquele mundo

virtual?). Com isso, podemos concluir que a pesquisa na área de jogos é não só gratificante, mas

também extremamente desafiadora, onde um simples jogo eletrônico pode requerer o esforço

de estudos profundos nas mais diversas áreas do conhecimento.

Page 57: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

56

Referências

[1] DEMASI, P. Princípios fundamentais da programação de jogos eletrônicos através de umemulador por software. (Projeto Final de Curso). 2000.

[2] DEMASI, P. Estratégias adaptativas e evolutivas em tempo real para jogos eletrônicos. (Dis-sertação de Mestrado). 2003.

[3] HOMEPAGE da biblioteca OGRE3D. Disponível em: <http://www.ogre3d.org/>.

[4] WIKIPEDIA: Design Pattern. Disponível em: <http://en.wikipedia.org/wiki/Design_pattern_(computer_science)>.

[5] GREGORY, J. Game Engine Architecture. [S.l.]: A K Peters, 2009.

[6] HOMEPAGE da biblioteca OpenAL. Disponível em:<http://connect.creativelabs.com/openal/default.aspx>.

[7] HOMEPAGE da biblioteca FMOD. Disponível em: <http://www.fmod.org/>.

[8] HOMEPAGE da biblioteca IrrKlang. Disponível em:<http://www.ambiera.com/irrklang/>.

[9] HOMEPAGE da biblioteca RakNet. Disponível em: <http://www.jenkinssoftware.com/>.

[10] HOMEPAGE da biblioteca OIS. Disponível em: <http://sourceforge.net/projects/wgois/>.

[11] WIKIPEDIA: Wii Remote. Disponível em: <http://en.wikipedia.org/wiki/Wii_Remote>.

[12] WIKIPEDIA: Scene Graph. Disponível em: <http://en.wikipedia.org/wiki/Scene_graph>.

[13] JUNKER, G. Pro OGRE 3D Programming. [S.l.]: Apress, 2006.

[14] KERGER, F. OGRE 3D 1.7 Beginner’s Guide. [S.l.]: Packt Publishing, 2010.

[15] THE Humble Indie Bundle. Disponível em: <http://www.humblebundle.com/>.

[16] HOMEPAGE da biblioteca SDL. Disponível em: <http://www.libsdl.org/>.

[17] FERREIRA, B. B. A biblioteca multimídia sdl. 2007. Disponível em:<http://equipe.nce.ufrj.br/adriano/c/apostila/sdl/index.html>.

[18] WIKIPEDIA: Minimax. Disponível em: <http://en.wikipedia.org/wiki/Minimax>.

[19] Stuart Russell; Peter Norvig. Inteligência Artificial. 2a. ed. [S.l.]: Elsevier, 2004.

[20] Antonio de Pádua Braga; André Ponce de Leon F. de Carvalho; Teresa Bernarda Ludemir.Redes Neurais Artificiais - Teoria e Aplicações. 2a. ed. [S.l.]: LTC, 2007.

Page 58: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

Referências 57

[21] BERNIER, Y. W. Latency compensating methods in client/server in-game pro-tocol design and optimization. Visitado em 21/02/2011. 2001. Disponível em:<http://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization>.

[22] WIKIPEDIA: Skeletal Animation. Disponível em:<http://en.wikipedia.org/wiki/Skeletal_animation>.

[23] OGRE Wiki: DotScene. Disponível em: <http://www.ogre3d.org/tikiwiki/DotScene>.

[24] OGRE Wiki: DotScene. Disponível em: <http://www.ogre3d.org/tikiwiki/New+DotScene+Loader>.

[25] WIKIPEDIA: Matte Painting. Disponível em: <http://en.wikipedia.org/wiki/Matte_painting>.

[26] WIKIPEDIA: Level of Detail. Disponível em: <http://en.wikipedia.org/wiki/Level_of_detail>.

[27] WIKIPEDIA: Normal Mapping. Disponível em: <http://en.wikipedia.org/wiki/Normal_mapping>.

[28] HOMEPAGE da biblioteca Lua. Disponível em: <http://www.lua.org/>.

Page 59: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

58

ANEXO A -- Documentação das classes do Dystopia

Para utilizar as classes definidas no Dystopia, basta incluir o header “Dystopia.h” e definir

algumas constantes do pré-processador para indicar quais módulos deseja-se usar. Como o

Dystopia.h é apenas um meta-header que inclui todos os outros dependendo das constantes

definidas, basta investigá-lo para descobrir quais constantes devem ser utilizadas em cada caso.

Apenas a documentação para as classes principais consta neste anexo. As classes mais

simples são de utilização suficientemente intuitiva e/ou as explicações ao longo do texto cobrem

suficientemente sua funcionalidade.

A.1 Referência da Classe Dystopia::Application

#include <AppMain.h>

Diagrama de Hierarquia para Dystopia::Application:

Dystopia::Application

Dystopia::OgreApplication

Dystopia::KeyListener Dystopia::MouseListener Dystopia::JoystickListener

Métodos Públicos

• virtual void afterSetup ()

• virtual void frameUpdate (float timeDelta)

• virtual const char ∗ getWindowTitle ()

Page 60: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.2 Referência da Classe Dystopia::InputManager 59

A.1.1 Descrição Detalhada

Provê um framework de aplicação interativa orientada a objetos. É implementado como um

Singleton.

A.1.2 Métodos

A.1.2.1 virtual void Dystopia::Application::afterSetup () [inline, virtual]

É chamado automaticamente após o término da execução do setup. Pode ser reimplemen-

tado pela aplicação, se necessário.

A.1.2.2 virtual void Dystopia::Application::frameUpdate (float timeDelta) [inline,virtual]

É chamado automaticamente a cada frame. Pode ser reimplementado pela aplicação, se

necessário.

A.1.2.3 virtual const char∗ Dystopia::Application::getWindowTitle () [inline,virtual]

Retorna o título da janela. Deve ser reimplementado pela aplicação.

A.2 Referência da Classe Dystopia::InputManager

#include <InputInterface.h>

Diagrama de Hierarquia para Dystopia::InputManager:

Dystopia::InputManager

Dystopia::OISInterface

Page 61: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.2 Referência da Classe Dystopia::InputManager 60

Métodos Públicos

• void addKeyListener (KeyListener ∗kl)

• void addMouseListener (MouseListener ∗ml)

• void addJoystickListener (JoystickListener ∗jl)

• virtual void setWindowSize (int width, int height)

• virtual void update (void)=0

A.2.1 Descrição Detalhada

Interface para recebimento de eventos de entrada.

A.2.2 Métodos

A.2.2.1 void Dystopia::InputManager::addJoystickListener (JoystickListener ∗ jl)[inline]

Adiciona um objeto para receber eventos de joystick.

A.2.2.2 void Dystopia::InputManager::addKeyListener (KeyListener ∗ kl) [inline]

Adiciona um objeto para receber eventos de teclado.

A.2.2.3 void Dystopia::InputManager::addMouseListener (MouseListener ∗ ml)[inline]

Adiciona um objeto para receber eventos de mouse.

A.2.2.4 virtual void Dystopia::InputManager::setWindowSize (int width, int height)[inline, virtual]

Informa o tamanho da janela. Deve ser chamado na inicialização e sempre que o tamanho

da janela mudar.

A.2.2.5 virtual void Dystopia::InputManager::update (void) [pure virtual]

Atualiza o estado interno, recebendo informações dos dispositivos. Deve ser chamado pre-

ferencialmente a cada passo.

Page 62: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.3 Referência da Classe Dystopia::NetworkInterface 61

A.3 Referência da Classe Dystopia::NetworkInterface

#include <NetworkInterface.h>

Diagrama de Hierarquia para Dystopia::NetworkInterface:

Dystopia::NetworkInterface

Dystopia::RakNetInterface

Métodos Públicos

• NetworkInterface (int role, int port)

• bool startup (char ∗serverAddress)

• bool startup (int maxClients)

• virtual void shutdown (void)=0

• int getNumberClients (void)

• virtual int update (void)=0

• virtual void send (unsigned char id, int len, char ∗data, int dest, bool broadcast=false,

bool timestamp=false)=0

• virtual bool pollPacket (NetworkPacket ∗∗p)=0

• virtual void freePacket (NetworkPacket ∗p)=0

A.3.1 Descrição Detalhada

Interface para comunicação cliente/servidor via LAN e Internet.

A.3.2 Construtores & Destrutores

A.3.2.1 Dystopia::NetworkInterface::NetworkInterface (int role, int port) [inline]

Constrói uma interface para conexão. role define se será um servidor (NETWORK_-

SERVER) ou cliente (NETWORK_CLIENT). port define a porta a ser aberta, no caso do servi-

dor, e a porta remota a ser conectada, no caso do cliente.

Page 63: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.3 Referência da Classe Dystopia::NetworkInterface 62

A.3.3 Métodos

A.3.3.1 virtual void Dystopia::NetworkInterface::freePacket (NetworkPacket ∗ p)[pure virtual]

Libera os dados internos de um pacote já processado.

A.3.3.2 int Dystopia::NetworkInterface::getNumberClients (void)

Retorna a quantidade de clientes conetados, se for um servidor.

A.3.3.3 virtual bool Dystopia::NetworkInterface::pollPacket (NetworkPacket ∗∗ p)[pure virtual]

Verifica se há um pacote esperando na fila de pacotes. Em caso positivo, o copia para o

ponteiro passado.

A.3.3.4 virtual void Dystopia::NetworkInterface::send (unsigned char id, int len, char∗ data, int dest, bool broadcast = false, bool timestamp = false) [purevirtual]

Envia um pacote com o identificador id, tamanho len e dados contidos no endereço data.

Se for o servidor, dest indica o índice cliente destino, e broadcast define se será enviado para

todos.

A.3.3.5 virtual void Dystopia::NetworkInterface::shutdown (void) [pure virtual]

Fecha quaisquer conexões ativas e destrói a interface de rede criada.

A.3.3.6 bool Dystopia::NetworkInterface::startup (int maxClients)

Abre a porta definida para conexão de até maxClientes ao mesmo tempo, se for um servidor.

A.3.3.7 bool Dystopia::NetworkInterface::startup (char ∗ serverAddress)

Inicializa a conexão com o servidor remoto, se for um cliente.

Page 64: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.4 Referência da Classe Dystopia::SoundManager 63

A.3.3.8 virtual int Dystopia::NetworkInterface::update (void) [pure virtual]

Atualiza o estado interno. Deve ser chamado preferencialmente a cada passo. Retorna um

código indicando que tudo está certo, ou alguma condição adversa aconteceu.

A.4 Referência da Classe Dystopia::SoundManager

#include <AudioInterface.h>

Diagrama de Hierarquia para Dystopia::SoundManager:

Dystopia::SoundManager

Dystopia::IrrKlangInterface

Métodos Públicos

• virtual int setupAudio ()=0

• virtual int loadSound (const char ∗file, std::string alias)=0

• virtual void unloadSound (std::string sound)=0

• virtual void unloadSound (int id)=0

• virtual void flushAllSounds ()

• int getSoundId (std::string label)

• void setWorldScale (Real scale)

• Real getWorldScale ()

• Vec3 getListenerPos ()

• Vec3 getListenerVel ()

• Vec3 getListenerUp ()

• Vec3 getListenerLook ()

• void setListenerPos (Vec3 pos)

• void setListenerVel (Vec3 vel)

• void setListenerUp (Vec3 up)

Page 65: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.4 Referência da Classe Dystopia::SoundManager 64

• void setListenerLook (Vec3 look)

• void attachListenerToOgreCamera (Ogre::Camera ∗camera, bool autoUpdateVel=true)

• virtual SoundEmitter ∗ createEmitter ()=0

A.4.1 Descrição Detalhada

Interface para reprodução de som, posicional ou não. Tanto esta interface quando o Soun-

dEmitter possuem os métodos play, pause, stop, seek e getPos para tratar de sons sendo repro-

duzidos, sendo que os sons são não-posicionais se chamados no SoundManager (pag. 63), e

posicionais se chamados num emissor.

A.4.2 Métodos

A.4.2.1 void Dystopia::SoundManager::attachListenerToOgreCamera (Ogre::Camera∗ camera, bool autoUpdateVel = true) [inline]

"Liga" o ouvinte a uma câmera OGRE. Se autoUpdateVel for true, atualiza automatica-

mente também a velocidade.

A.4.2.2 virtual SoundEmitter∗ Dystopia::SoundManager::createEmitter () [purevirtual]

Cria um emissor de som.

A.4.2.3 virtual void Dystopia::SoundManager::flushAllSounds () [inline,virtual]

Descarrega todos os sons carregados atualmente.

A.4.2.4 Vec3 Dystopia::SoundManager::getListenerLook () [inline]

Retorna a direção "frente" do ouvinte.

A.4.2.5 Vec3 Dystopia::SoundManager::getListenerPos () [inline]

Retorna a posição do ouvinte.

Page 66: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.4 Referência da Classe Dystopia::SoundManager 65

A.4.2.6 Vec3 Dystopia::SoundManager::getListenerUp () [inline]

Retorna a direção "para cima" do ouvinte.

A.4.2.7 Vec3 Dystopia::SoundManager::getListenerVel () [inline]

Retorna a velocidade do ouvinte.

A.4.2.8 int Dystopia::SoundManager::getSoundId (std::string label) [inline]

Retorna o identificador de um som a partir do nome.

A.4.2.9 Real Dystopia::SoundManager::getWorldScale () [inline]

Retorna a escala global do mundo (valor pelo qual todas as posições e velocidades são

multiplicados)

A.4.2.10 virtual int Dystopia::SoundManager::loadSound (const char ∗ file, std::stringalias) [pure virtual]

Cerrega um som do arquivo file e dá a ele o nome alias. Retorna seu identificador.

A.4.2.11 void Dystopia::SoundManager::setListenerLook (Vec3 look) [inline]

Define a direção "frente" do ouvinte.

A.4.2.12 void Dystopia::SoundManager::setListenerPos (Vec3 pos) [inline]

Define a posição do ouvinte.

A.4.2.13 void Dystopia::SoundManager::setListenerUp (Vec3 up) [inline]

Define a direção "para cima" do ouvinte.

A.4.2.14 void Dystopia::SoundManager::setListenerVel (Vec3 vel) [inline]

Define a velocidade do ouvinte.

Page 67: Dystopia e SumoCheckers - DeVoid Gamesdevoidgames.com/artigos/DystopiaESumocheckers-Projeto...Monografia de Projeto Final de Graduação sob o título “Dystopia e SumoCheckers”,

A.4 Referência da Classe Dystopia::SoundManager 66

A.4.2.15 virtual int Dystopia::SoundManager::setupAudio () [pure virtual]

Inicializa o SoundManager (pag. 63).

A.4.2.16 void Dystopia::SoundManager::setWorldScale (Real scale) [inline]

Define a escala global do mundo (valor pelo qual todas as posições e velocidades são mul-

tiplicados)

A.4.2.17 virtual void Dystopia::SoundManager::unloadSound (int id) [purevirtual]

Descarrega o som de identificador id.

A.4.2.18 virtual void Dystopia::SoundManager::unloadSound (std::string sound)[pure virtual]

Descarrega o som de nome alias.