deV( )id Games | because we're tired of no return;

TAG | Engine

Então, estou aqui hoje para falar sobre a terceira parte dos Fundamentos deVoid(): o framework que estamos desenvolvendo para usar como base em nossos projetos, e também um pouco sobre frameworks em geral e por que eles são uma Boa Idéia.

A idéia por trás de um framework (no contexto de programação) consiste basicamente em ter uma biblioteca (ou, como eu gosto de falar, um “bando”) de código com funcionalidade reutilizável, escrito de forma modular e que possa ser plugado facilmente em “todos” os casos que você precisar de tal funcionalidade. Alguns frameworks (como o nosso) são arquitetados como várias “peças” que podem ser utilizadas, ou não, de acordo com as necessidades de seu projeto (e também são feitas para funcionar em conjunto, é claro); em outros casos, o framework é fixo e o programador deve adequar seu projeto a funcionar com ele da maneira que é esperada. Pessoal que trabalha com Java e/ou fazendo sistemas por aí deve estar acostumado com esse tipo de coisa.

A diferença, é claro, é que no nosso caso a coisa é muito mais divertida.

É fácil perceber que no caso de jogos eletrônicos, muito é reutilizável. Mesmo sem saber a fundo como os jogos são feitos, não demora a perceber, por exemplo, que Sonic e Mario (na era 16-bit) não são tão diferentes assim (exceto pelos jogos do Sonic serem melhores e mais bem feitos, evidentemente). Neste caso, estamos observando um paralelismo de gênero. Os dois jogos são do gênero de plataforma, onde o objetivo (resumindo) é sair pulando por aí atravessando obtáculos e chegar no extremo direito da fase (apesar de que o caminho em algumas fases dos Sonic’s é bem mais interessante e desafiador que isso).

sonic-mario

Correr, pular, esmagar inimigos, a fórmula é a mesma. Não importa se você é um ouriço azul ou um encanador bigodudo.

Tradicionalmente, para explorar este paralelismo de gênero, os desenvolvedores criam engines. De maneira geral, todo jogo é criado em cima de uma engine: o código base que faz o jogo funcionar e define o núcleo de sua mecânica; somando a engine com o conteúdo tem-se pois, um jogo. No caso do Sonic, cada novo jogo da série utilizava uma nova versão da engine desenvolvida ao longo dos anteriores, o que certamente economizou bastante no custo do desenvolvimento.

Vindo mais para perto, o conceito de engine se tornou mais conhecido para o público em geral com os jogos “modáveis”. A idéia por trás de um jogo deste tipo é que o acoplamento entre a engine e o conteúdo é bem definido e é fácil modificar o jogo apenas alterando conteúdo e sem precisar tocar no código da engine (parte do conteúdo que define o jogo pode ser composto de scripts, mas isto é outra história). Obviamente, o caso mais conhecido de mod que se tornou famoso é o Counter-Strike, que é uma modificação (e roda na exata mesma engine) do Half-Life. Novamente, é explorada a idéia de reutilizar a engine para um jogo do mesmo estilo, neste caso, de tiro em primeira pessoa (FPS).

A jogabilidade é praticamente a mesma, mas são os pequenos detalhes no conteúdo que fazem a diferença.

A jogabilidade é praticamente a mesma, mas são os pequenos detalhes no conteúdo que fazem a diferença.

Finalmente, voltando ao nosso caso, o que estamos fazendo no momento não é uma engine porque não contém lógica de jogabilidade, quer dizer, não contém nada que define como um jogo funciona. O objetivo com este framework é criar uma série de ferramentas para serem utilizadas na construção de uma engine. Ou seja, estamos explorando a reutilização de código em um nível mais baixo e explorando o que eu chamo de paralelismo de funcionalidade. Em outras palavras, reutilizamos partes do framework para criar engines, e reutilizamos engines para criar jogos. Isto funciona porque mesmo dentre engines completamente diferentes, digamos, a do Sonic e a do Half-Life, várias funcionalidades de mais baixo nível são as mesmas, citando-se:

  • Leitura de entrada (teclado, mouse, joystick)
  • Comunicação em rede / arquitetura cliente/servidor
  • Máquinas de estados
  • Controle de fluxo de execução
  • Controle do dispositivo gráfico e exibição de imagens na tela (2D ou 3D)
  • Controle do dispositivo de áudio e execução de sons/música
  • Inteligência Artificial (buscas, lógica, redes neurais etc)
  • Mecanismo de scripting

Observando estes itens, percebe-se que a idéia de reutilizá-los (ou a própria necessidade de suas existências) não é trivial ao usuário comum como no caso das engines: é mais uma separação explorada pelo desenvolvedor para facilitar seu trabalho, e como facilita! Como eu disse lá em cima, qualquer desenvolvedor sabe que tarefas de baixo nível devem ser implementadas apenas uma vez, “não reinventar a roda”, e assim por diante. E isso vale desde o sistema da padaria da esquina até o mais novo título milionário da EA ou da Ubisoft 🙂

Por último, vale lembrar que durante o desenvolvimento destas três camadas–framework, engine e jogo–a necessidade de uma funcionalidade em uma camada mais alta pode fazer com que esta seja implementada em outra mais baixa, assim como a criação de uma funcionalidade numa camada mais baixa pode incitar sua utilização nas camadas mais altas. Em parte pela nossa não-tão-grande experiência e pelo aprendizado em si, é mais ou menos assim que estamos levando o nosso desenvolvimento: começamos pelas idéias, pelos objetivos do projeto e propagamos para as camadas mais baixas estas necessidades.

· ·

Theme Design by devolux.nh2.me