Arrows Engine – Lições aprendidas em um projeto fracassado de engine de jogos

Aee pessoal,

Como meus progressos no kinect estão lento (estou fazendo refactoring no código, e também estou sem muito saco para programar depois do trabalho), vou postar sobre o que aprendi (em outras palavras, O QUE NAO FAZER) no desenvolvimento abortado da minha engine de jogos.

Antes de mais nada, que fique claro que este post não dá lições de como você criar sua engine, mas lições que podem ser util no processo de desenvolvimento da engine!

O projeto em questão era criar uma engine de jogos 3D, ou seja, tanto o motor como um ambiente de criação de jogos. O nome que eu dei para ela era Arrows Engine, em homenagem à equipe de F1 Arrows.  Abaixo segue uma foto da suíte de criação de jogos:

Suite de criação de Cena - (Clique para ver em tamanho real) Nesse programa era possivel adicionar os modelos na cena a partir da biblioteca de modelos. Era possivel também posiciona-los na cena. Ele compunha a biblioteca com importações de modelos 3DS. Note que a organização da cena, no lado esquero, era para ser feito em celulas, carregadas via streaming pela proximidade (Sonho Meu!!!)

Esse foi um projeto que comecei para saciar meu sonho de produzir um jogo e que abandonei entre 2006 e 2007  inacabado(2º e 3º ano da faculdade). Mas acho que posso passar um pouco de “lições aprendidas” sobre o processo de desenvolvimento de uma engine de jogos que pode ajudar quem quer começar a fazer a sua ou em qualquer projetinho pessoal. Muitas das lições parecem quem contrariam o que aprendemos e lemos sobre desenvolvimento de software, mas utilizei varias delas em meu mestrado e obtive um bom resultado. 😉

Antes, um pouco sobre a engine. Ela estava sendo desenvolvida em C++ e usando o OPENGL para a renderização 3D, tinha um bom código de gerencia e otimização de cena (frustrum culling), colisão 3D (octree e aabbtree), gerencia de recursos, seus próprio tipo de arquivo otimizado, e um programa para gerenciar o desenvolvimento de um jogo utilizando-a. Além disso, fiz 2 POCs, uma de esqueleto (bone e skinning) e da minha própria engine física (sistema massa mola).

Estou assumindo que todos saibam o que uma engine tem que fazer, que em poucas palavras, é cuidar de todos os aspectos do jogo, menu, renderização, física, IA, som, lógica do jogo, etc. Se você estiver com preguiça de ler como cheguei nas 5 lições, meus erros, etc, segue as 5 lições resumidas. Realmente espero que ajude quem estiver pensando em começar a sua. Vou postar algumas imagens e video sobre o assunto ao longo do post a titulo de ilustração.

  1. Decida se o que vc quer é fazer é uma engine ou um jogo.
  2. Faça POCs simples das técnicas antes de sair fazendo sua engine.
  3. Não perca tempo otimizando o código (e complicando-o) na etapa de desenvolvimento
  4. Procure bibliotecas padrões da industria que possam resolver problemas da sua engine antes de sair fazendo a sua.
  5. Foque na Engine e não em um jogo. Não perca tempo criando ferramentas de criação de jogo antes de ter sua engine pronta.

Wireframe de um dos objetos da cena

Primeira lição é: USE UMA ENGINE PRONTA (se criar o jogo for sua motivação fim), ou seja, não faça sua própria engine!. Mas como assim?! Reformulando, faça se você realmente quer conhecer as técnicas de algoritmos usados na criação de jogos (me ajudou muito aprender algoritmos de criação de jogos, ajudou no meu mestrado, na minha formação como cientista da computação, etc.), mas não se está mais preocupado em criar um jogo, ou seja, criar a engine deve ser o fim e não o meio.

Se você estiver pensando em ter o jogo como fim, eu aconselho a utilizar uma das engines disponíveis no mercado, e tem varias (unreal engine, cryengine, ogre, etc). Com elas, você pode focar em usar a programação para criar uma funcionalidade bem especifica do seu jogo, ao invés de ficar cuidando de detalhes básicos, como código para tocar som, código para gerenciar scripts de inteligência artificial, etc.

Antes de mais nada lembre-se que programar uma engine é um dos maiores desafios da ciência da computação (NA MINHA OPINIAO) porque você normalmente busca simular situações reais com o maior nível de detalhe e complexidade em um hardware que normalmente tem um pentolhesimo de poder de processamento para fazer o que você realmente quer. É um desafio cuidar do som, da IA, dos gráficos foto-realistas, dos efeitos, e ainda deixar isso em taxas interativas (tempo real) e é, por causa de desafios, que vi serem criadas muitas técnicas criativas de otimização e simulação de efeitos físicos que, com certeza, deixariam os maiores cientistas da computação de queixo caído.

Outra coisa, lembre-se também que criar uma engine é um trabalho para um time de programadores experientes etc e saiba que, sozinho, vai ser muito, mas muito difícil. As vezes, você pode produzir algo mais relevante fazendo uma biblioteca que ataca um problema bem especifico das engines de jogos (por exemplo, uma biblioteca de matemática e colisão otimizada em SSE, um gerenciador de recursos poderoso) do que tentar fazer uma engine completa.

Engine rodando a cena criada na suite de criação de cenas.

Segunda Lição: IMPLEMENTE ITERATIVAMENTE – depois da primeira lição, ainda quer criar sua engine? Bom, legal, você é um guerreiro! Então, estude bastante sobre o assunto, as técnicas existentes, as soluções mais utilizadas, etc. Depois disso, foque nas funcionalidades como peças de Lego, operações básicas, desenvolvida sobre cenas simples, que depois vão ser utilizadas para montar o todo, ou seja, o código da Engine.

Tente criar um desenvolvimento iterativo, ou seja, escolha algumas funcionalidades e técnicas básicas e desenvolva-as (espécies de POC – Proof of Concept), como por exemplo abertura e renderização de modelos 3D. Depois, escolha mais algumas areas de uma engine, como por exemplo, implementar ou acoplar uma engine de física. Faça essa iterações separadas e sem se preocupar muito com arquitetura de software (esqueça gets e sets e essas coisas que nos fazem perder tempo… afinal, é somente uma POC), sempre focando no resultado e no aprendizado, e você vai ver que seu código vai se refinando ao longo do tempo (vc vai reutilizar o código da poc de renderização na poc de engine física, as vezes até melhora-lo, mas são programas distintos).

Ao longo das versões, vc naturalmente vai juntar todos os pedaços até chegar uma hora que vai parar, pensar na melhor arquitetura (já que vc já implementou e conhece todas as peças necessárias para criara uma engine) e vai desenvolver uma engine de qualidade em pouco tempo. NÃO PERCA TEMPO PENSANDO EM UMA ARQUITETURA  QUE ABRANGERÁ VARIOS MODULOS QUE VC AINDA NÃO SABE COMO IMPLEMENTAR. Esse acho que foi um dos meus piores erros, porque gastava um tempão pensando em uma super arquitetura que já envolvesse todos os aspectos de uma engine para jogos, começava e daí chegava em um ponto que, depois dos estudos para implementar um novo módulo, percebia que minha arquitetura era uma merda e começava tudo denovo. Isso ainda foi agravado por eu estar entre o segundo e terceiro ano da faculdade, praticamente sem experiências em arquiteturas de software. E pior, eu era “otimização freak”, assunto da próxima lição.

POC de Bone e Skinning

Terceira Lição:  FUJA DAS OTIMIZAÇÕES (ou SIMPLIFIQUE), as otimizações são importantes, mas lá no final do desenvolvimento. Eu cai nessa falácia como um pato. Confie na lei de Moore! E pense que no fim, você vai ter uma visão ampla da arquitetura e vai saber o que vale a pena e o que não vale a pena otimizar.

Eu não estou falando para fazer o código de qualquer jeito, mas não perca tempo otimizando, foque no resultado. Segue um exemplo: podemos resumir uma engine como um loop infinito, na qual a cada iteração as mesmas operações vão ser executadas, ou seja, execute os scripts de IA, atualiza e cena com a engine física, renderize a cena, toque o som, etc. Quando estava fazendo, cada IF que eu colocava eu pensava se ele realmente era necessário, já que ia ser repetido infinitas vezes em um loop, as vezes fazendo malabarismo para economizar um IF que prejudicava toda a arquitetura, deixando tudo mais complexo.

Com o tempo aprendi que a chave de uma arquitetura é a máxima “Se está simples, está bom! Se está complexo, está errado!”. Muitos dizem que uma engine DEVE ser em C++, porque que é uma linguagem de alta performance. Eu concordo, mas também acho que os estudos e as primeiras versões podem ser na linguagem que você tem mais prática, ou na que tem mais bibliotecas disponíveis, mesmo se a linguagem for interpretada por exemplo (err, Java, hauha). Isso vai agilizar MUITO o seu aprendizado, a criação dos POCs, etc. Depois, quando vc estiver maduro, vc porta para C++.

Outro erro nesse sentido foi criar meu próprio arquivo para armazenar as informações da cena, modelos, etc etc. Eu odeio ter que esperar em loading infinitos e muitas vezes acredito que isso é falta de otimização na gerencia de recursos. Veja GTA4, pra mim o supra sumo em gerencia de recursos, abre uma cidade, com muitas texturas, pessoas, carros, tudo em tempo real sem loading. Enfim, por causa disso, criei meus próprios arquivos, BINARIOS (pq são lidos mais rápido) e, pior, PAGINADOS (em poucas palavras, vc carrega na memoria uma porção de dados do tamanho do chunck de um HD, normalmente 1024kb – ou seja, 1 pagina –, e depois interpreta os dados da memória, ao invés de ler do HD byte por byte… um livro bom sobre isso é esse aqui). O esquema de arquivos era muito complexo e toda vez que queria adicionar 1 elemento no meu modelo 3D, tinha q implementar uma adaptação, o que CONSUMIA MUITO TEMPO. Olha, quando estiver em etapa de desenvolvimento, utilize arquivos em formato texto (de preferência XML), que vc pode abrir e alterar se precisar, e deixe para criar seu próprio tipo de arquivo binário ultra rápido quando seu jogo for para produção. Pior foi quando encafifei que iria abrir arquivos .3DS, que dá inicio a próxima lição.

POC de simulação massa mola

Quarta lição: NÃO REINVENTE A RODA (ou, novamente, SIMPLIFIQUE). A idéia dessa lição é utilizar o máximo de bibliotecas que estiverem disponíveis para fazer determinada ação e que tenham uma licença que te satisfaz e são praticamente padrões da industria. E isso serve para os tipos de dados também, pelo menos no desenvolvimento.

Claro que isso não pode ser usado em tudo, as vezes você precisa de um controle fino sobre o gerenciador de cena para implementar alguns algoritmos e usar uma biblioteca de gerenciamento de cena pronta pode complicar a implementação dessa funcionalidade especifica (tem q entender o código dos caras, ver se a arquitetura deles prevê evoluções, etc). Agora, se for para tocar musica, é muito normal que você vai utilizar uma biblioteca pronta ao invés de implementar a sua.

Meu maior erro nessa parte foi quanto aos tipos de dados. Além de usar Binário ao invés de Texto (e XML), eu encafifei que queria exportar os modelos .3DS (criados pelo 3DMax). É um arquivo binário que não tem documentação para abertura, já que ele não era um formato aberto. Peguei como ponto de partida umas documentações de engenharia reversa, mas mesmo assim não tinha tudo o que eu queria, não lidava com as instancias de partes do modelo. Daí fui eu perder um PUTA TEMPO fazendo a engenharia reversa até conseguir o que eu queria. Hoje, eu teria usado o formato .obj, que é em formato texto, e mandaria o modelador salvar nesse formato. MUITO MAIS SIMPLES, muito menos dor de cabeça, muito menos tempo perdido.

POC de octree... logo logo vou fazer um post explicando o que é uma octree e como usei ela para fazer frustrum culling

Quinta lição: NÃO PENSE NO JOGO,  PENSE NA ENGINE. Criar uma engine pensando em um jogo e não na engine não é um bom caminho (meio que a primeira lição denovo aqui). Eu queria fazer um jogo, na verdade, um ambiente sandbox estilo GTA,  que representasse o lugar onde eu morava (um conjunto de kitnets e a faculdade, em São Carlos). Logo, eu tinha uma cena em mente, e ela não era simples. Queria que essa fosse a primeira cena da minha engine.

Contudo, criar cenas complexas sem uma ferramenta de criação de cena é quase impossível, fora que eu escolhi ter arquivos binários no desenvolvimento, o que praticamente impossibilitava eu tentar montar uma cena na mão (montar cena não mão significa, por exemplo, editar um arquivo XML descritor de cena no bloco de notas).

Então eu tive a brilhante idéia de criar um programa com interface gráfica para auxiliar na criação do jogo, que me ajudasse a criar a cena, que gerenciasse os recursos que formavam a cena e iam ser gravados no arquivo binário. PIOR COISA QUE EU PODIA FAZER!!! É legal tem um programa assim? É! Mas depois que vc tem uma arquitetura definida, que vc já implementou todas as funcionalidades, que vc acha que realmente vc vai usar o que vc fez. Gastei bastante esforço nesse programa e hoje vejo que ele só ajudou a tirar o foco do que eu realmente devia estar fazendo, que era estudar as técnicas e fazer POCs usando uma CENA SIMPLES (uma caixa, uma esfera, um modelo de personagem).

Resumindo, para você criar sua engine, você precisa ser perseverante (o que eu não fui, desisti para fazer o TCC, Mestrado, etc) e determinado. Todos achavam maluquisse eu tentar fazer minha própria engine, mas aprendi muitas coisas, tanto sobre computação gráfica, desenvolvimento de jogos, como também sobre como lidar com projetos pessoais. Espero que essas dicas possam guiar você no desenvolvimento da engine e dos projetos pessoais de vocês. Se der certo, mandem os resultados 😉

Anúncios

Deixe um comentário

Arquivado em 3D, Computação Gráfica, Desenvolvimento, Desenvolvimento de Jogos, Geek

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s