Abrindo o Jogo- Shellshock Nam 67

placeholderantigo

abrindojogoshellshocknan1

Olá pessoal, desde que comecei a jogar videogame sempre tive curiosidade de saber como eles eram desenvolvidos, que tecnologia utilizavam, quantas pessoas seriam necessárias, e o mais importante, o que eu devo fazer para desenvolver o meu. É com o objetivo de responder à todas estas perguntas que inauguro hoje a coluna Abrindo o Jogo.  Nela vocês poderão conhecer um pouco dos segredos dos bastidores das maiores desenvolvedoras de games do mercado, focando desde a arquitetura de software até o Game Design. O Primeiro artigo apresenta detalhes técnicos sobre o desenvolvimento do game de guerra Shellshock Nam 67 (SSN 67), lançado em 10 de setembro de 2004 e desenvolvido pela Guerillha Games. Apesar da empresa ser mais conhecida hoje pelo sucesso KillZone 2, um dos principais títulos do PS3, foi durante o desenvolvimento de SSN 67 que a equipe adotou pela primeira vez novos Padrões de Projetos (Design Patterns), mais especificamente um grande conhecido meu, o MVC. Vamos saber mais sobre como isto ocorreu?

Mesmo atualmente pouco se fala sobre a arquitetura de software de um game, ao contrário de artigos sobre IA, Game Design e Física, este importante assunto recebe pouco destaque. Por exemplo, você sabia que a maioria das classes  de um game derivam de uma única? Normalmente chamada de Actor, Object ou Entity.

“A escolha de uma arquitetura adequada  é um ponto vital para a construção de um game, apesar disto não ser visível para o usuário final, más escolhas irão afetar muitos aspectos no processo de desenvolvimento. Uma boa estrutura reduzirá o risco e aumentará a eficiência da equipe.”

Foi com este pensamento que a equipe da Guerillha Games, antiga Lost Boys Games, (OK! o forte deles não seria criar nomes para a empresa) iniciou o desenvolvimento do game Shellshock Nam 67. Eles procuravam uma estrutura que fosse flexível suficiente para suportar todas as idéias e ainda assim, rígida para forçar uma única forma de trabalho. O desenvolvimento do seu primeiro jogo, Killzone 2004, foi considerado muito bom, entretanto tiveram uma boa oportunidade de analisar a estrutura e vislumbrar várias melhorias. Com a base similar a anterior, as novidades seguiriam os seguinte critérios:

  • O sitema precisa ser ainda mais orientado a dados;
  • Devemos utilizar o conhecido padrão MVC Model-View-Controller;
  • A simulação do jogo rodará em uma frequência de update fixa para garantir comportamento consistente em todas as plataformas (PS2, XBOX and PC).

shellshock-nam-67-2shellshocknam67wind1_dbe201086283153

Entidades

Em SSN67 a classe base para todos os objetos do jogo é chamada de Entity(Entidade). A equipe deixou bem claro a distinção entre objetos do jogo que possuem um estado e os que não possuem. Por exemplo, a geometria estática do mundo e seu modelo de colisão não são entidades, nem tão pouco nuvens em movimento no céu. Um barril de óleo por exemplo, é uma Entidade porque quando ele explode isto pode ferir o jogador e influenciar o estado do jogo. Segundo Jorrit Rouwé, programador líder da equipe, utilizando uma definição como esta fica muito fácil separar objetos importante para o game dos que não teriam tanta relevância. O sistema de streaming do motor, por exemplo, pode baixar texturas sem afetar o estado do jogo.

Orientado à Dados

Um sistema que segue esta orientação utiliza dados ao invés de código para configurar as propriedade de um objeto. Em SSN67 eles utilizaram a classe EntityResource (Recursos da Entidade) como classe base para as propriedades de um objeto. Os recursos da entidade são definidos em um arquivo de texto e editado manualmente. O exemplo a seguir mostra como se pareceria a configuração de um NPC (Non Player Character – Personagem controlado pela máquina):

CoreObject Class=HumanoidResource
{
  Name = Ramirez
  Model = models/soldiers/ramirez
  Speed = 5
  ...
}

Quando estes arquivos textos são lidos pelo sistema de serialização deles, os objetos correspondentes são automaticamente criados e cada variável é mapeada para um atributo. Após uma EntityResource ser carregada eles validam o tipo de cada atributo e verificam se todas elas juntas formam uma configuração válida. Se as informações não forem válidas, uma mensagem de erro é mostrada e o game não roda. Em SSN67 eles não permitem entidades serem criadas sem um EntityResource. Pois isto garante que um objeto específico aja da mesma forma em todos os níveis, reduzindo significativamente a ocorrência de bugs. O Padrão de Projetos Factory (Fábrica) foi responsável por criar uma Entidade através de sua EntityResource. Isto significa que bastaria entregar uma EntityResource a fábrica para obter a Entidade correspondente, pronta para ser usada no jogo. Isto foi feito através de um  plugin para o Maya. Level Designers (Projetistas de Fases), podiam criar uma Entidade e posicioná-la em um fase apenas selecionando o arquivo da EntityResource correspondente. Entidades que necessitam de um comportamento especifico, mais dinâmico, poderiam ser criadas através da linguagem de Script LUA.

O MVC (Model-View-Controller)

O Padrão de Projetos MVC (padrão de arquitetura) é utilizado em várias áreas, desde um processador de texto há um aplicativo web. Ele basicamente define que um objeto deva ser dividido em três entidades distintas, relacionadas entre si: o Modelo, a Visão e o Controlador. Esta arquitetura encaixa como uma luva para o desenvolvimento de jogos. Compartilhando desta visão, a equipe da Guerrilha adotou o padrão relacionando o Model à Entity, a View a uma classe chamada EntityRepresentation e o Controller permaneceu com a mesma nomenclatura. Vamos ver com mais detalhes como a empresa trabalhou com cada uma delas:

O Modelo (Entity)

As Entidades devem armazenar o mínimo de estados possíveis de um objeto. Qualquer estado que for necessário apenas para a visualização, não será armazenado no Modelo. Grande parte das Entidades em SSN67 são simples máquinas de estados. Entidades por definição não deveriam saber nada sobre animações, porém infelizmente muitas animações interferem no volume de colisão do objeto e consequentemente no estado do game.  No game um Humanoid caminhando por exemplo, olha em seu EntityResource a velocidade máxima de caminhada, ao invés de observar a animação para obter esta informação. A EntityResource pré-calcula a velocidade da animação de forma que o Modelo esteja alinhado com o que o usuário esta vendo na tela, gerado pela EntityRepresentation. A equipe ainda considera que há como reduzir ainda mais a relação da Entidade com as animações

A Visão (EntityRepresentation)

A EntityRepresentation é responsável por desenhar a Entidade e todos seus efeitos. Exemplos de tarefas executadas por uma EntityRepresentation:

  • Modelos 3D
  • Partículas
  • Decals
  • Filtros de Tela
  • Som

Uma EntityRepresentation, apesar de dar esta impressão, não muda o estado de uma Entidade. Ela na verdade baseia-se neste estado para criar o seu próprio. Porém há algumas exceções onde esta informação não é suficiente. Por exemplo, quando um humano é atingido o jogador espera visualizar o sangue vindo de tal ferimento. Simplesmente olhando a quantidade de energia anterior e a atual, não seria possível saber onde o personagem foi atingido. Nestes casos eles usaram um sistema de mensagens muito utilizado no MVC. Todas as mensagem derivam de uma classe chamada EntityEvent, a qual contém um Id que indica o tipo de mensagem. A Mensagem de “Ser Atingido” contém o tipo, quantidade de dano e onde o personagem foi causado. Para atingir um realismo maior, o sincronismo dos efeitos é normalmente crítico e precisa bastante código para ser gerenciado. Separando este código da lógica essencial do jogo, a equipe reduziu o risco de bugs. Uma vantagem importante desta arquitetura é se todos os objetos seguirem as regras, o estado do jogo não fica dependente da representação, ou seja, o jogo pode rodar sem elas. Este princípio pode ser muito útil para criar servidores multiplayers onde a parte visual não é necessária.

O Controlador (Controller)

O Controlador prove abstração de entrada (input) para uma Entidade. Tendo isto como premissa, a equipe criou para cada Entidade  uma classe base que define as partes controláveis. A partir desta versão eles puderam derivar um Controlador para A.I. e um para o player. Por exemplo, um Humanoid tem um HumanoidController que serve de Super Classe para HumanoidAIController e HumanoidPlayerController. A versão do player ainda poderia dividir-se entre prover suporte a mouse e teclado (PC) ou joystick (XBOX e PS2). O objetivo do Controlador é especificar o que a Entidade deverá fazer, porém não pode mudar diretamente seu estado. A cada update o Controlador é requisitado pela Entidade e ela tenta seguir suas instruções. Por exemplo, ele nunca iria chamar o método MoveTo() em um Humanoid, mas sim o Humanoid iria sondar o método GetDesiredSpeed() (pegar velocidade desejada) do Controlador e então tentar alcançar esta velocidade enquanto executa a detecção de colisões para ter certeza que não esbarrará contra uma parede. Para fazer um Humanoid interagir com uma arma, por exemplo, o HumanoidController implementa a função chamada GetUseObject(). Esta função é acionada a cada update pelo Humanoid. Para um NPC, a A.I. usa o raciocínio para determinar se isto é benéfico ou não. Já para o player, o HumanoidPlayerController detecta que o objeto está ao alcance e dispara a lógica do menu de uso. A HUD [1] encarrega-se de desenhar as opções na tela. Após o jogador selecionar uma opção, esta informação retornará através do GetUseObject() na próxima requisição do Humanoid ao HumanoidController (o próximo pulso).

[1] HUD (Head Up Display) É um instrumento inicialmente desenvolvido para utilização em aeronaves visando fornecer informações visuais ao piloto sem que este tenha que desviar os olhos do alvo. No mercado de games ele refere-se as informações que estão dispostas na tela para o jogador, como por exemplo: Energia, Tempo, Número de Vidas, etc.

Um Simples Exemplo

Imaginemos o conceito de MVC aplicado a um Tanque. Primeiramente ele seria dividido em Entity (Tank), EntityRepresentation (TankRepresentation) e um Controller (TankController). O TankController tem funções como GetAcceleration(), GetSteerDirection(), GetAimTarget() e Fire(). A I.A. guia o tanque usando um TankAIController e o jogador através de TankPlayerController. A classe Tank acompanha o estado físico do veículo, os danos e direção. A TankRepresentation além de desenhar o tanque, cria as partículas de fumaça quando o tanque atira e reproduz um rastro onde o veículo passou. Também é comum a View tratar dos sons, neste exemplo ela trataria do som correspondente quando o tanque colide por exemplo. Uma curiosidade comentada pela equipe é que a representação teria uma certa independência da Entidade para movimentos de rotação, como adequar-se a um terreno irregular, desde que isto não interfira no volume de colisão do tanque.

Simplificação do Estado de Jogo

Vamos, através de um exemplo,  entender melhor como a Guerrilha desenvolveu o sitema de estados de SSN 67. Quando um Humanoid atira com uma arma, o game mostra a bala saindo do cano, porém esta simples ação pode representar problemas. Cada arma tem sua própria animação, ligeiramente diferente. Pistolas ficam na altura dos ombros, escopetas na linha da cintura, e armas mais pesadas, como rifles e bazucas, precisam ser apoiadas em algo para serem utilizadas. Estas diferenças podem levar a inconsistencias do cálculo de posições feitos pela AI. Por exemplo, um NPC pretende encontrar um posição coberta para poder atirar, a AI faz o cálculo envia o agente para logo atrás de uma pedra, que por sua vez possui metade de seu tamanho. Se a arma utilizada for uma pistola, não haverá problema, porém se for uma escopeta, a bala deveria atingir a pedra quando utilizada. Para solucionar este problema eles separaram o algoritimo de atirar da parte visual. As balas de todas as armas agora saem de um ponto fixo (próximo ao ombro), baseado somente na posição corrente e postura do Humanoid. O rastro é manipulados pela EntityRepresentation e sai do cano da arma (como na animação) movendo-se na mesma direção. Os dois cálculos, animação e lógico, lentamente convergem para o ponto de impacto.

O Frame Work Completo

O Diagrama abaixo apresenta o framework completo utilizado em SSN67.

Diagrama de Classe demonstrando a relação entre cada objeto

Diagrama de Classe demonstrando a relação entre cada objeto

O EntityManager é um container para todas as Entidades, ele dispara uma atualização para todas elas em um frequência fixa. Todas as Entidades que participam do game devem estar cadastradas no EntityManager, que dentre várias funções, facilita a procura por elas. A equipe definiu que Entidades pudessem ser atualizadas por outras Entidas em alguns casos especiais, onde a ordem de update fosse relevante. Quando um jogador prepara-se para atirar, é fundamental que o player seja atualizado depois da arma. Caso contrário o sistema apresentará um jitter[2]. Nestes casos a arma pode setar uma flag no jogador para que ele não receba atualizações de pulso da EntityManager. O RepresentationManager mantém todas as EntiyRepresentations em uma hierarquia espacial que torna fácil e rápido a definição do que está ou não visível. Ele recebe uma notificação do EntityManager logo que uma Entidade é adicionada ou removida, com isto cria ou destrói a Representação correspondente. Quando recebe um pulso de frame, a RepresentationManager desenha todas as GameViews. A GameView é responsável por desenhar o mundo para um jogador, ela acompanha a câmera ativa e usa a hierarquia espacial da RepresentationManager para desenhar todas EntityRepresentations visíveis, além de desenhar também as Não-Entidades, como o mundo estático e a HUD sobreposta a todos eles. O  SSN67 poderia possuir o modo multiplayer com a tela dividida, porém esta feature não foi desenvolvida por questões de tempo.

[2] Jitter é uma variação, um retardo na entrega de dados criando uma inconsistencia, termo também muito utilizado em redes de computadores.

Conclusão

Eu ouvi falar em Model View Controller pela primeira vez em 2004, nesta época eu já havia desenvolvido o motor que a empresa utilizava para construir nossos Serious Games. Porém quando fiquei a par das vantagens que esta arquitetura traria ao desenvolvimento, não pensei duas vezes, comecei a construir outro Engine do zero utilizando seus conceitos. Atualmente não consigo imaginar como seria desenvolver um game sem utilizar a arquitetura MVC. Fiquei muito contente em saber que na mesma época uma grande empresa como a Guerrilha Games estava pensando a mesma coisa, percebendo as grandes vantagens deste ótimo Padrão de Projeto. Segundo Jorrit Rouwé, esta nova arquitetura inclusive facilitou o gerenciamento de prazos da equipe, já que induziu a divisão das tarefas em blocos de código menores e intuitivos. Eles afirmam que utilizam esta arquitetura em todos seus projetos, inclusive no atual grande sucesso da empresa, o “sucessor” de Gears of War, KillZone 2.

Um abraço e até a próxima matéria da Abrindo o Jogo. Não esqueçam de deixar seus comentários e críticas :)

Ilustrações: Inara Cavichioli
Referências Bibliográficas:
http://www.gamasutra.com/features/20050414/rouwe_01.shtml
http://en.wikipedia.org/wiki/Shellshock:_Nam_%2767
http://en.wikipedia.org/wiki/Guerrilla_Game
 
[polldaddy poll=1520753]
Autor: Everton Vieira Ver todos os posts de
Sou Bacharel em Análise de Sistemas pela Universidade Católica de Pelotas (UCPel) no ano de 1999. Minha paixão por games é de longa data. Porém, em 2003 tornei essa paixão uma profissão. Durante oito anos atuei como Game Designer e Arquiteto de Software em mais de 30 projetos de Serious Games (simuladores) para grandes empresas do país. Atualmente sou sócio-fundador da Izyplay Game Studio, onde exerço o cargo de Diretor de Criação. Além do envolvimento corporativo, também participei da organização da Pós Graduação em Arquitetura e Desenvolvimento de Jogos Digitais na FATEC SENAC Pelotas. Minha área de interesse e especialização é Game Design e Inteligência Artificial.

5 Comentários em "Abrindo o Jogo- Shellshock Nam 67"

  1. kerberus 07/04/2009 at 17:34 - Reply

    Da onde tirasse essas informações?… muito bom achei que ficou um pouco técnico mas acho que é por causa desse tal MVC que eu ainda não gosto muito, aparentemente ele nos da mais trabalho agora para termos menos trabalho depois, mas sera que compensa trocar mais trabalho agora por menos depois ou sera que sai o comido pelo lambido mais veses menos trabalho? bom apesar de estar usando ainda não conheço a fundo todas as vantagens que o MVC pode proporcionar, vo terminar de postar de uma vez porque to postando do serviço e se meu chefe me pega to frito, muito boa ideia essa da abrindo o jogo bem inovador parabeins mais uma vez Everton continua postando.

    • Everton 16/04/2009 at 11:35 - Reply

      Olá Otávio,
      Grande parte das informações foram retiradas de um artigo sobre o game no site GamaSutra (ótimo para quem deseja seguir neste mercado). Busquei algumas informações na wikipedia e outras vieram da experiência que adquiri na área para enriquecer o artigo.

      []‘s

  2. Rafael 23/04/2009 at 22:45 - Reply

    Everton,

    muito boa essa coluna!

    []´s
    Rafael

  3. Iverton 21/09/2009 at 20:41 - Reply

    É possível demonstrar algum exemplo prático (estilo tutorial) em Java para visualizarmos melhor este MVC?

    Abração!

Deixar um Comentário