No meu último post escrevi a respeito do desenvolvimento de uma pequena parte do que estou fazendo. Mesmo sendo uma tarefa simples, a complexidade para atingi-la de acordo com os meus objetivos, de forma portável, me dá a dimensão do trabalho que é.
Isto me fez buscar bibliotecas que dê suporte para programação de jogos abstraindo detalhes do ambiente, porém não me fornecendo abstrações em cima da OpenGL, pois quero aprender tal tecnologia, sendo assim nada melhor do que eu mesmo implementar tais abstrações.
Achei algumas bibliotecas interessantes: SDL, Allegro, PLIB, ClanLib e Orx. Para decidir qual utilizar adotei alguns parâmetros de comparação entre elas:
Jogos implementados
Exemplos
Documentação
Plataformas suportadas
Bindings/Scripts suportados
Logos após ler um pouco mais sobre cada uma das bibliotecas, dispensei a PLIB, pois apesar de ser bastante modular e possui módulos bastante interessantes, já está bastante defasada e sem atualizações. Umas das maiores diversões de participar de projetos de software livre é sua comunidade vibrante, sendo assim, projeto descartado. Vamos aos demais!
As plataformas suportadas pelas restantes são:
Windows
Linux
MacOS X
iOS
Android
Orx
X
X
X
X
X
SDL
X
X
X
-
-
Allegro
X
X
X
X
-
ClanLib
X
X
X
-
-
PixelLight
X
X
-
-
X
Após verificar as funcionalidade de cada uma resolvi fazer um test-drive. Nada melhor do que guiar um pouco o carro para sentir suas vibrações.
Comecei experimentando a Orx, por ser a que roda nas mais diversas plataformas. Logo me decepcionei, não encontrei nenhuma maneira rápida e fácil de executar as coisas pela linha de comando. Depois que achei esse tutorial no site deles desisti de vez. Odeio ficar dependente de ambientes de programação.
Achei bastante interessante as funcionalidades apresentadas pela ClanLib, porém achei a documentação fraca, grande parte dos exemplos não rodam, pois a biblioteca suporta OpenGL 3, sendo que as implementações do Linux em sua maioria suportam a versão 2.1. Além disso, achei a comunidade fechada demais, com poucos canais de comunicação.
Num primeiro momento achei a PixelLigth simples, porém olhando ela com mais calma, percebi que ela também estava bastante próxima das engines Crystal Space 3D e Ogre.
Por último testei a Allegro, que me agradou muito, bastante unix-like. Documentação de fácil acesso, muitos exemplos interessantes, possui o segundo melhor suporte multi-plataforma, compatível com SDL, diversos canais de comunicação e uma comunidade muito grande, com diversos jogos do-it-yourself. Pura diversão! Não deixe de conferir o demo "speed" nos seus fontes. Nem vou dizer que é minha escolha :)
Terminei o que considero a fase de prototipação com algumas ferramentas antes de começar a escrever de forma séria um jogo. Escrevi código de qualquer maneira, sem me preocupar se estava elegante, reutilizável, modular, etc. O que queria fazer era experimentar algumas APIs e ver se elas me permitiam fazer as coisas do jeito que eu queria.
Estas APIs são: OpenGL, Assimp, Bullet e OpenAL. Com estas 4 APIs é possível criar jogos e gráficos em tempo real de alta complexidade, com características similares aos jogos mais modernos da atualidade, porém o meu intuito não é criar nada grande, afinal sou um programador apenas, porém com estas APIs posso me concentrar no que mais me interessa, que é escrever o código de um jogo, sem ter que me dedicar a escrever uma biblioteca de física, de detecção de colisões, de áudio 3D, etc.
Mesmo com todas estas ferramentas a disposição sei que a tarefa de desenvolver um jogo de corrida é bastante complexa, porém adotando estas ferramentas poderei me concentrar mais no que me interessa, que é desenvolver a física dos carros e aprender principalmente a API OpenGL. Com elas fiz o seguinte exemplo:
Utilizei a biblioteca Assimp para carregar o modelo dos dois cubos que foram criados com o Blender e exportados para o formato Collada. Através da Bullet adicionei as informações a respeito dos corpos rígidos e obtive as informações das colisões para reproduzir os sons através da OpenAL. OpenGL foi utilizada para gerar a visualização baseada nos dados de física disponíveis e renderizar informações visuais a respeito da geometria utilizada pela biblioteca de física (uma informação muito útil disponibilizada pela biblioteca Bullet).
Algumas pessoas ao lerem esse post podem se perguntar porque eu não estou utilizando uma engine para escrever meu jogo. A resposta é bem simples, quero aprender OpenGL e também quero aprender a integrar estas ferramentas. Depois de desenvolver este simples exemplo já tenho uma noção muito melhor de como as engines são programadas e entendo muito melhor como utilizá-las. Como quero trabalhar profissionalmente um dia com desenvolvimento de jogos, prefiro botar a mão na massa, eu aprendo muito melhor assim!
Não quero desenvolver um super jogo. Estou pensando simples, pois sei que não tenho recursos para desenvolver um jogo top de linhal, mas sei que tenho todas as condições para desenvolver um jogo divertido como o F1GP de 1993: http://www.simracingworld.com/games/2/ e este é justamente meu objetivo. Fazer um jogo de F1 nos mesmos moldes, porém com a ajuda de todas estas APIs que já comentei.
Não é uma tarefa incrivelmente difícil, mas também não é uma tarefa fácil, sendo assim me preocupo como irei desenvolver. Li já faz algum tempo o livro Design Pattens: Elements of Reusable Object-Oriented Software, porém sempre estou folheando para me inspirar em padrões que possam resolver problemas que estou tendo. Li alguns livros específicos de jogos, como Core Techniques and Algorithms in Game Programming (CTAGP), Game Architecture and Design (GAD) e Beginning OpenGL Game Programming (BOGP). Cada um desses livros tem coisas boas e ruins. O GAD possui bastante material orientado a equipes de desenvolvimento, porém também possui algumas ótimas figuras a respeito da arquitetura de um jogo moderno, coma a figura seguinte que mostra os módulos e a interação entre eles em jogo moderno:
Este livro também contém algumas técnicas úteis para pensar a intereção entre os diversos elementos presentes no jogo. O livro CTAGP é bastante abrangente e por isso não trata muito a fundo os assuntos abordados, servindo apenas de coceira mental para buscar mais informação. O BOGP é um ótimo livro, bastante simples e prático, contém muita informação interessante para quem quer usar OpenGL em jogos.
Acabei de comprar o livro Large-Scale C++ Software Design, que apesar de já ser antigo é um dos poucos livros que trata da organização física dos arquivos de um projeto. Apesar de não querer fazer nada grandioso, tenho certeza que meu jogo não será igual um trabalho de faculdade, será bem maior e mais complexo, considero que será um projeto de médio-porte. Desta forma estou ansioso pela chegada deste livro. Apenas depois de lê-lo vou começar a produziar o código "tracer bullets", como descrito no livro The Pragmatic Programmer, que será um código para me guiar onde pretendo chegar, nada rígido, porém será o esqueleto que trará organização e flexibilidade para poder melhorar o código ao adquirir novos conhecimentos.
Neste meio tempo quero ler alguns livros sobre design de jogos que têm assuntos que me interesseram, sendo eles: 3D Game Engine Architecture, 3D Game Engine Design, 3D Game Engine Programming e 3D Game Programming All In One. Como dá pra perceber vou acabar escrevendo uma engine. Não é meu objetivo, porém grande parte dos seus módules serão "façades" e ou "fábricas" que utilizarão outras APIs, como a Assimp e a Bullet. Quero me concentar mesmo em como desenvolver a física do carro.
Se você quiser baixar o código que desenvolvi clique aqui! Para compilá-lo basta digitar "make" e depois "./sample cubo_simples.dae" para executar. Você vai precisar das bibliotecas de desenvolvimento da sua distribuição e das bibliotecas bullet, freealut, openal, vorbis e vorbisfile. Se não esqueci de nada é isso!
Continuo buscando meios para fazer meu jogo. Já decidi algumas coisas, porém colocar todas as coisas juntas, escrever o código e fazer executar é a coisa mais difícil, ainda mais quando se está aprendendo todas as tecnologias necessárias para isso, no entanto é recompensador cada progresso feito.
Eu decidi que o Blender será meu editor, tendo em vista duas alternativas: escrever meu próprio editor ou utilizar um já disponível. Hoje em dia a quantidade de editores 3D é enorme, sendo que se eu fosse escrever um, até que este chegasse em um nível de maturidade aceitável levaria muito tempo, sendo assim optei por utilizar o Blender, que possui uma comunidade enorme a sua volta e é extensível através de plugins, permitindo customizá-los de forma a obter algumas das facilidade que é possível quando se usa um editor próprio, tal como verificar determinadas propriedades de uma cena criada.
O Blender oferece o suporte para realizar o unwrapping (abrir a malha) de um objeto, criando um mapa de textura UV. Nesta página você pode encontrar mais informações a respeito do que estou dizendo: http://www.blender.org/development/release-logs/blender-234/uv-unwrapping/. Este mapa pode ser exportado e editado em seu aplicativo de edição de imagens preferido.
No meu aprendizado eu fiz algo bem simples, abri a malha de um cubo e com o Gimp pintei cada face de uma cor. Após preparar esta textura voltei ao Blender e a apliquei ao cubo. Pronto, este era o objeto que eu queria renderizar em minha aplicação OpenGL, sendo assim exportei-a para o formato Collada 1.4 através do Blender.
Para carregá-la em minha aplicação utilizei a biblioteca Assimp. Apesar de muitos dizerem que escrever código para carregar um formato específico é bastante simples não queria me ater a esta tarefa, pois o principal motivo para fazê-lo é desempenho e eu por enquanto quero experimentar com as peças que podem me auxiliar e o mais rápido possível :).
Além da Assimp utilizei a bilbioteca DevIL que permite importar diversos formatos de arquivo para memória e serem utilizados como textura em uma aplicação OpenGL. Além disso a Assimp também importa todos os pontos do mapeamento UV, sendo possível dizer em quais locais determinados pontos da textura devem ser aplicados na malha do cubo.
Para fazer tudo isso rodar, ainda era necessário escrever o código para carregar o objeto e renderizá-lo na tela. Para facilitar a vida a biblioteca Assimp traz um código de exemplo: http://assimp.svn.sourceforge.net/viewvc/assimp/trunk/samples/SimpleOpenGL/, porém este não utiliza texturas. Um outro desenvolvedor criou um novo exemplo com suporte a texturas: http://assimp.svn.sourceforge.net/viewvc/assimp/trunk/samples/SimpleTexturedOpenGL/, porém apenas com suporte para compilar no Windows usando o Visual Studio, que eu não pretendo utilizar :). Eu fiz uma mistura dos dois alterando o primeiro exemplo e compilei no GNU/Linux, porém não vou publicar o código que escrevi, pois é algo simples e tenho certeza que você consegue fazer também :).
O resultado final? Olha aí que beleza!!!
Um passo de nada para a humanidade dos programadores de jogos, mas um grande passo para mim :P. Agora prentendo colocar dois cubos na minha tela, cada um girando para lados opostos, sendo que quero criar os dois cubos na mesma cena do Blender e tratá-los separadamente na aplicação (ou como um único objeto). Acredito que esta é uma forma interessante de representar objetos que durante a execução da aplicação possam ser quebrados.
Após isto quero adicionar suporte a princípios físico através da utilização da biblioteca Bullet. Após isto o céu é o infinito!!! Estarei bem armado para escrever meu jogo de Fórmula 1.