Mostrando postagens com marcador Programação. Mostrar todas as postagens
Mostrando postagens com marcador Programação. Mostrar todas as postagens

sexta-feira, 21 de dezembro de 2012

BDD (Behaviour Driven Development): O que é?

O que!!! Eu nem aprendi TDD e já inventaram mais uma técnica de desenvolvimento de software? Calma, na verdade BDD é TDD sobre uma nova nomenclatura.

Se é a mesma coisa, então por que estão reinventando a roda? Faz parte do ser humano tentar melhorar suas ferramentas e conceitos. Com isso, você pode pensar que BDD é melhor, mas como já disse, as duas técnicas permitem atingir o mesmo fim, sendo assim o que vai influenciar sua percepção a respeito de cada uma é sua experiência com testes. Se você já utiliza TDD e se sente confortável, provavelmente não vai perceber grandes diferenças no BDD.

No meu caso, BDD caiu como uma luva. Comecei a aprender TDD e ficava me pergutando se os testes que estava escrevendo faziam sentido e nem sempre conseguia responder isto de forma prática. Analisando este passdo agora, percebo que essa dificuldade surgia da falta de experiência com a técnica, o que me fazia perder o foco do que era essencial: o software em desenvolvimento.

Após ler um pouco sobre BDD, comecei a entender que a técnica é exatamente TDD, porém a utilização de uma nova nomenclatura tornou as coisas muito claras para mim, pois a técnica força com que você pense desde o princípio no comportamento que você espera da sua aplicação, assim fica muito mais fácil pensar se seu teste está fazendo a coisa certa ou não.

BDD força você a pensar no que seu software vai fazer através de três construções bastantes simples:  Dado um determinado contexto; Quando algum evento acontece; Então eu espero uma determinada saída. Esta é a tríade do BDD: Given, When e Then.

Estas três palavras mágicas me ajudaram muito a programar com testes e estou extremamente satisfeito com meu ritmo de desenvolvimento. Nos próximos posts irei falar de algumas ferramentas que dão suporte para a técnica e os benefícios que percebo de sua aplicação.

Até a próxima!

quinta-feira, 6 de setembro de 2012

Nested resources com mesmo nome e visões diferentes

Estou desenvolvendo uma aplicação em Rails e cheguei em um momente que tinha o seguinte problema: renderizar conteúdo diferente para 1 recurso aninhado de outros 2.

Vou utilizar um exemplo real para ilustrar melhor o caso. Digamos que estamos trabalhando numa aplicação parecida com o twitter e nossos 3 modelos são: usuários, postagens e tags. A partir delas eu posso ter as seguintes URLs na minha aplicação:
  • /usuario/1/postagens
  • /tags/1/postagens
Sendo necessário a seguinte configuração no meu arquivo routes.rb para obtê-las:

resources :usuarios do
  resources :postagens
end

resources :tags do
  resources :postagens
end

Sem nenhuma configuração adicional, isso irá fazer com que ambas as URL direcionem suas requisições para o mesmo controlador: PostagensController.

Para modificar este comportamento podemos utilizar namespaces. Para isso podemos criar uma pasta chamada usuario e outra chamada tag dentro do caminho /app/controllers e dentro dela colocar a classe PostagensController com o namespace correto, isto é o topo do arquivo teria que ficar da seguinte forma:
  • class Usuario::PostagensControllers < ApplicationController
  • class Tag::PostagensControllers < ApplicationController
Desta forma separamos o controlador de cada um dos nosso recursos aninhados, mas ainda precisamos instruir o Rails que ao receber uma requisição em um dos dois caminhos anteriores queremos que esta seja redirecionada para um controlador ou outro. Os guias na página do Rails tem uma parte ótima a este respeito: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing

Para o meu caso modifiquei o arquivo routes.rb para o seguinte:

resources :usuarios do
  resources :postagens, :module => "usuario"
end

resources :tags do
  resources :postagens, :module => "tag"
end


Desta forma a URL não é alterada, apenas é feito o roteamento para o controlador no namespace correto.

O maior benefício desta estratégia é poder separar as visões para cada uma das requisições, sendo que o que é geral para as duas pode ser extraída para um template, enquanto os recursos específicos não ficam poluídos com ifs desnecessários e que tornam o entendimento da aplicação mais difícil, pois acaba adicionando detalhes de domínios distintos, podendo levar a distrações durante a leitura do código.

Os arquivos da visão ficariam então no seguinte caminho:
  • app/views/usuario/postagens/index.html.erb
  • app/views/tags/postagens/index.html.erb
A seção "Grouping Controllers into Modules" do livro Agile Web Development with Rails foi de grande ajuda para descobrir como implementar esta abordagem.
Maravilha, não!?!

domingo, 22 de janeiro de 2012

RSpec, factory_girl e transações com o banco de dados

Ontem estava quebrando a cabeça para entender como meus testes estavam rodando, pois para mim, a cada execução destes o meu banco de dados estava limpo. Isso é o que acontence quando se utiliza o Test::Unit, porém utilizando o RSpec é diferente.

Nada como uma boa noite de sono. Hoje pela manhã, com a cabeça fresca, fiz as buscas que realmente interessavam e a documentação está toda lá, no site do RSpec: https://www.relishapp.com/rspec/rspec-rails/docs/transactions

Além disso, quando se utiliza o FactoryGirl o comportando é diferente de quando se utiliza fixtures. Com fixtures, o banco é populado com o conteúdo declarado. Já com FactoryGirl o objeto é criado e salvo quando se faz a chamada Factory(:meu_modelo). Isso acabou me confundindo, pois no começo eu pensava que o FactoryGirl iria me retornar o que estava no banco, pois com uma sintaxe parecido é isso o que o fixtures faz.

O RSpec cria transações no banco para cada bloco it "..." do, sendo assim, caso algum objeto seja salvo fora deste escopo ele é mantido no banco e deve ser limpo manualmente.

sábado, 31 de dezembro de 2011

Bibliotecas para Programação de Jogos

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, PLIBClanLib 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 :)

segunda-feira, 19 de setembro de 2011

Programando com Exceções

Escrevendo uma classe em C++ fiquei com uma dúvida. Como tratar um erro que acontece em um construtor? Imediatamente tive duas ideias, retornar NULL ou configurar uma flag na classe. A primeira logo descobri que não era possível, pois os construtores não permitem retornos. A segunda, apesar de possível, achei deselegante e muito suscetível a erros.

Foi a partir deste momento que me perguntei se exceções seria a forma correta de tratar o problema e após ler alguns livros esta é a forma unânime para se notificar um erro que acontece em um construtor, porém na busca desta resposta encontrei muito mais informações deste mecanismo que acabaram me convencendo que exceções são uma ótima forma de tratar erros de tempo de execução em uma aplicação.

É importante lembrar que alguns erros são de lógica e não deveriam acontecer durante a execução do software. Estes normalmente são falhas do programador, sendo assim, a forma correta de tratá-los é através de chamadas a macro assert, as quais podem ser desabilitadas facilmente em produção definindo a variável NDEBUG durante a compilação.

Através das exceções é possível separar o fluxo de código "normal" daquele que é responsável pelo tratamento do erro, tornando a execução de um determinado fluxo mais limpa e fácil de ler, ou seja, sem distrações. Além disso, um erro, muitas vezes, acontece em um determinado componente do sistema que não possui informações suficientes para saber como este deve ser tratado, pois seu contexto é muito limitado para identificar as condições que o provocaram, impossibilitando qualquer medida para corrigi-lo, neste caso, faz mais sentido lançar uma exceção e deixar uma parte da aplicação que tenha um contexto mais adequado tratar o erro.

Outra questão que tive quando comecei a pensar sobre exceções foi a respeito dos recursos que já haviam sido alocados durante a chamada do construtor. O que iriam acontecer com eles?

Caso uma exceção ocorra durante a execução de um construtor, o destrutor da classe não é chamado, sendo assim, seus recursos não são liberados. A solução para este problema é chamada por "resource allocation is initialization". Ao invés de fazer uma chamada a uma biblioteca específica para se obter um recurso, cria-se uma classe que irá representar este recurso que é inicializado através do construtor. A Wikipédia traz uma ótima descrição a respeito deste assunto: http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

Outro benefício interessante do uso de exceções é a chamada dos destrutores das classes que estão na pilha, pois quando uma exceção é lançada, grosseiramente falando, é como se o seu código fosse executando vários "return" até encontrar uma parte do código que a trate. Isto evita que seus objetos fiquem perdido, causando memory leaks.

Também procurei informações sobre exceções para descobrir alguns conselhos de como utilizá-las, pois também tinha dúvidas se seria um bom recurso para utilizar na programação de jogos, devido ao overhead que adicionam. Pelo que li é totalmente plausível utilizá-las (além disso a engine Ogre3D as utilizam), porém é necessário entendê-las muito bem para conseguir visualizar o impacto que terão durante sua chamada.

Os conselhos apresentados por Bjarne Stroustrup no livro C++ Programming Language são muito bons:
  • Use exceções para tratamento de erros;
  • Não use exceções onde estruturas de controle locais são suficientes;
  • Use a técnica "resource allocation is initialization" para gerenciar recursos;
  • Nem todo programa precisa tratar exceções;
  • Use "resource allocation is initialization" e tratamento de exceções para manter invariantes;
  • Minimize o uso de try-blocks. Use "resource allocation is initialization" ao invés de código de tratamento explícito;
  • Nem toda função precisa tratar todos os erros possíveis;
  • Lance uma exceção para indicar uma falha em um construtor;
  • Evite lançar exceções em destrutores;
Além desses existem muitos outros conselhos, porém acredito que isto já é o bastante para atiçar o apetite de qualquer um que tenha lido até aqui. Os livros que achei mais interessantes sobre o assunto foram:
Ótimas referências!

quinta-feira, 5 de maio de 2011

Model-View-Presenter (MVP) no .NET Compact Framework

Ao contrário de padrões de projetos, padrões arquiteturais dão linhas diretrizes muito vagas e nenhuma sugestão concreta de implementação. Ao tentar aplicar o padrão MVP segui o básico do framework apresentado no paper MVP: Model-View-Presenter. The Taligent Programming Model for C++ and Java, no entanto achei o modelo ineficiente para ser utilizado em uma aplicação Windows Forms, já que neste ambiente temos a disposição componentes que podem ser manipulados visualmente durante a programação da solução.

Utilizando o framework supra-citado, não era possível faz uso do ambiente gráfico para gerar automaticamente o código de criação da tela, desta forma passei a me perguntar se um framework que levasse em consideração estas questões já não existia, pois definir visualmente as telas da aplicação é um recurso muito útil para ser desperdiçado pela adoção do MVP.

Encontrei o framework MVC# que apesar de ser antigo, oferece suporte ao MVP, inclusive no .NET Compact Framework. Além do MVP, ele adota uma idéia de tarefas, onde uma tarefa pode englobar vários pares de views/presenters, sendo que a tarefa se torna um lugar para armazenamento de informações necessárias por view/presenter distintos.

O site criado pelo programador é muito bom e contém uma boa descrição de como ele pensou, projetou e implementou a solução. Além disso, são descritos vários exemplos que vão bem além de uma simples tela.

Apesar de estar satisfeito com este framework, ele ainda pode melhorar, porém para as minhas necessidades atuais me atendeu muito bem, já que minha aplicação era simples. Em uma aplicação mais complexa seria necessária ter um controle melhor em relação as visões e das tarefas (criação/destruição). Uma coisa boa é que o código-fonte do framework é aberto, permitindo modificações e melhorias, sendo assim, caso precise delas tenho chances de implementá-las. Viva a influência do software livre!


terça-feira, 1 de fevereiro de 2011

Game Coding Complete

Comecei a ler os livros 3D Game Engine Architecture, 3D Game Engine Design e 3D Game Programming All In One. Nenhum deles me agradou e parei pouco tempo depois. Pra aguardar a chegada do Large-Scale C++ Software Design resolvi dar uma olhada no livro Game Coding Complete e não é que gostei.

Não vou escrever muito a respeito do livro aqui, pois vou acabar fazendo um post igual ao último. Vou deixar apenas alguns comentários a respeito do livro em geral.

Pra começar é um livro a respeito de programação de jogos como um todo, então os assuntos são muito mais abrangentes do que os tratados no livro 3D Game Engine Programming. Achei que o livro dá uma visão geral muito bacana, mostrando as camadas mais comuns encontradas em um jogo e como separá-las de forma que o o resultado seja flexível, para isso adotando um sistema de envetos, gerenciamento de processos e scripts com Lua.

Esta abordagem diferente permite mostrar como programar um jogo, que é a lógica que executa por trás da engine. Neste aspecto achei o conteúdo apresentado pelo livro muito bom, pois não se restringe apenas a dizer como a estrutura deve ser, mas apresenta código que implementa esta estrutura e utiliza vários aspectos interessantes da linguagem C++ que tornam a programação mais fácil, tal como smart pointers, e os quais o autor tem o cuidado de explicá-los, já que não são próprios da linguagem e sim extensões. Além disso a estrutura apresentada pelo autor é muito flexível, permitindo extender facilmente a lógica do jogo, seja através da escrita de novas classes, seja pela escrita de scripts em Lua.

Achei uma ótima leitura. Agora vou devorar o Large-Scale C++ Software Design!

terça-feira, 18 de janeiro de 2011

3D Game Engine Programming - Review do Livro

Acabei de ler este livro. Ele é escrito com bom-humor, o que deixa sua leitura mais agradável, ainda mais em um campo que é tão complexo como a programação de um engine para jogos 3D, porém em alguns lugares o autor tenta ser engraçado com desleixo, dizendo que escreveu um código em 1 hora porque estava vendo TV, o que para mim não é engraçado e ainda me deixa com uma pulga atrás da orelha.

Um ponto que considerei negativo é que em várias partes o autor diz que o livro tem como audiência programadores avançados, porém em muitas partes o autor entra em detalhes desnecessários, os quais tais programadores já dominam. Estas explicações poderiam ter sido deixadas de fora, abrindo espaço para abordar outros assuntos ou até mesmo para diminuir este monstro de mais de 800 páginas.

Um detalhe importante e que acho que muitas pessoas levam em consideração é que o livro é um pouco antigo, de 2004, porém muitas das informações ainda são relevantes, pois apesar das placas de vídeo terem evoluída bastante de lá pra cá as técnicas para se programar uma engine continuam as mesmas. Em qualquer área da computação se usa técnicas desenvolvidas a muitos anos atrás. Vários algoritmos que foram utilizados em jogos como Doom ainda são muito relevantes. Para a minha pouca experiência nesta área, a leitura foi ótima para entender vários conceitos e iniciar a programação de uma engine simples.

A introdução é bastante interessante e possui diversos pontos de vista que compartilho, alguns deles são:
  • Game Engine: o livro deixa a definição aberta, mas sugere um norte, que seria os blocos que permite criar um jogo de forma "simples", sem ter que lidar com detalhes de hardware. Ela lhe provê funcionalidades para facilitar o desenvolvimento de aplicações em um ambiente 3D e nunca conterá qualquer código que envolva a lógica do jogo.
  • Faz um comparativo entre o modelo de desenvolvimento antigo, quando os computadores tinham pouco memória, poder de processamento e placas gráficas rudimentares e o novo, que permite pensar em um nível mais alto, sem se preocupar tanto com algoritmos, otimizações de código assembly, etc, pois atualmente, em alguns casos, é mais fácil utilizar força bruta e deixar o HW se virar.
  • Coloca o hardware como seu aliado. As coisas têm que ser assim, se você ver o hardware como seu inimigo você sempre vai estar lutando com ele, porém encarando ele como um aliado você tentará tirar o máximo que ele pode lhe oferecer, você conhecerá suas forças e suas fraquezas e saberá utilizar cada uma delas (será que a realidade é assim mesmo?).
  • Nesta parte também é apresentada como o projeto e construção do jogo deve ser encarada e realizada por um time, porém não vou colocar mais detalhes, primeiro porque não li toda esta parte e segundo porque a minha intenção é realizar um desenvolvimento hobbysta e por enquanto não tem time nenhum :).
O livro tem uma tendência a utilizar conceitos do Direct3D / DirectX, pois seu autor é mais inclinado para estas tecnologias, mas o livro tenta ser independente de uma API gráfica em particular, porém o autor deixa o aviso que se alguém tentar implementar as interfaces que ele define utilizando OpenGL vai encontrar alguma dificuldade. É bom ter este tipo de aviso, pois a minha intenção é utilizar OpenGL, então tenho que manter o foco muito mais nos conceitos do que na forma de implementação em específico.

O capítulo 2 trata a respeito do projeto de uma engine e seus principais objetivos são: (1) projetar uma engine de jogo básica; (2) criar engines independente da aplicação que a usa e (3) construir uma engine a partir de partes simples. Era isso mesmo que eu estava procurando, chocolatin!!!

O capítulo começa perguntando qual será o nome da sua engine? A minha será Kodorna, por quê? É um apelido que meu irmão me deu a muito tempo, quando tinha uns 12 ou 13 anos e na época me deixava muito irritado, mas agora já me acostumei e até eu me chamo de Kodorna. Acho que é um nome bacana por ser despretensioso, porém ao mesmo tempo faz parte de uma época bacana da minha vida, onde eu estava amadurecendo ou não, talvez eu ainda continue verde :D

Neste capítulo é apresentado uma visão geral da engine e como ela irá funcionar, mencionando onde aparecerão mais detalhes a respeito de sua implementação. Ótima apresentação!

Não gostei do capítulo 3. Ele não teve uma utilidade imediata para mim, pois quero escrever um jogo em OpenGL na plataforma Linux. Apesar disso ele mostra como isolar o código dependente de API em uma interface, algo que não era novidade para mim, mas que é interessante.

Além disso achei a explicação do código ruim, é apresentada uma parte disso, outra daquilo, daí volta para apresentar um pouco mais do início. Acabou ficando confuso, sendo necessário voltar as páginas para relembrar a relação da nova informação com a antiga, sendo que seria possível explicar todas as coisas a respeito de uma parte uma vez só.

O quarto capítulo é sobre otimização de código e matemática. Ele começa alertando para o fato de não otimizar coisas desnecessárias ("Premature optimization is the root of all evil" - Donald Knuth) e fazer profiles para saber quais partes do código estão com problemas, algo bastante conhecido pelos programadores. O assunto fica interessante quando o autor começa a falar sobre as extensões disponíveis nos processadores para acelerar certas computações, são elas: MMX, SSE, SSE2 e 3DNow!. Acho a discussão interessante, pois pelo que eu saiba os compiladores livres não geram código para estas extensões. Uma biblioteca que nunca utilizei, mas que acredito ser útil para fazer uso destas extensões é a liboil.

Neste capítulo além de introduzir algumas classes básicas para qualquer engine, que são as classes para manipular vetores e matrizes (utilizando as extensões citadas acima claro), também é explicado o conceito de "rays". Este é uma classe para selecionar objetos em sua tela, como em um editor 3D ou em um jogo como "The Sims" e também é utilizado para detectar colisões. Por último o autor trata de quaternions, uma representação matemática que facilita rotações em qualquer um dos eixos. A matemática inclusa no capítulo é ótima, porém não li com muita atenção, pois sua utilização é principalmente para detectar colisões e eu pretendo utilizar a biblioteca Bullet para isso, mas tenho certeza que algumas destas informações ainda me serão úteis. Além disso, o autor deixa referência ao livro Geometric Tools for Computer Graphics, o qual parecer ser uma ótima referência a matemática utilizada em jogos.

O capítulo 5 é ótimo. Trata de luzes, materiais e texturas. Possui uma discussão básica sobre a utilização de luzes, mas suficiente para fazer uso desta tecnologia. Não li muito a respeito deste assunto, pois minha placa de vídeo não suporta luzes, sendo assim não pretendo utilizá-la, sendo que efeitos de iluminação podem ser conseguidos de outras formas, tal como o uso de pixel e vertex shaders. A discussão sobre materiais e texturas é bastante interessante e o código apresentando é bem útil. A classe que carrega as texturas em memória é um flyweight, porém o autor não o chama assim, mas a classe impede que texturas idênticas sejam carregadas mais de uma vez para a memória.

Capítulo 6 terminado e quanta informação! Nesta parte o autor mostra como suportar visões diferentes (ortogonal, perspectiva e 2D), várias viewports, modos de renderização diferentes (wireframe, etc) e como alternar entre esta opções influenciam nos cálculos da matriz de visualização, campo de visão, view frustrum, etc (e como se deve fazer estes cálculos, claro :). Um material muito interessante. Depois disso entra a parte de renderização de vértices e como tornar esta operação rápida. Uma pena que esta parte é inteiramente voltada ao DirectX, a qual não pretendo estudar, porém através do encapsulamento de como as renderizações são feitas não se faz mais necessário acessar a API do DirectX, então o que posso fazer é me inspirar nesta implementação para reescreve-la utilizando OpenGL. Um ótimo exercício. A partir deste ponto a engine já está pronta para ser utilizada em suas primeiras renderizações!

O capítulo 7 foi bem rápido apesar do assunto ser super interessante: Pixel e Vertex Shader! Com estas duas tecnologias recentes é possível programar como a placa irá renderizar os pixels na tela de uma forma muito mais fina e obter diversos efeitos legais, até mesmo efeitos de iluminação. Não pretendo me dedicar muito a shaders no momento e por isso li o capítulo bem rapidamente, só para ter uma idéia geral da coisa, mesmo porque o assunto é muito mais complexo para ser tratado em apenas um capítulo de um livro de programação de engines 3D como o próprio autor comenta. Atualmente existem muitas linguagens para programar shaders que se assemelham a linguagem C, porém o autor mostra a tecnologia em uma linguagem parecida com Assembly, pois considera importante que o leitor saiba o que está por baixo dos panos e realmente é bem interessante, com poucas linhas de código (6 linhas para ser mais preciso) já é possível criar efeitos interessantes. Sim, você não leu errado, poucas linhas em assembly podem fazer grande diferença em suas cenas!

Mais um capítulo rápido. Neste o autor expões uma classe para carregar um modelo 3D com informações de esqueleto e juntas, permitindo animar personagens como monstros, pessoas, e até coisas simples, como máquinas com peças móveis.

Outro capítulo que passei muito rápido (será que todos serão assim daqui pra frente?). O capítulo 9 trata do módulo de entrada, seja ele por teclado, mouse ou joystick. Um capítulo simples, porém totalmente voltada para como fazer as coisas com DirectX e como sei que vou utilizar SDL para esta função passei bem por cima deste capítulo.

Não só passei pelo décimo capítulo muito rapidamente, mas ele também é bem curto e cobre o básico do suporte de som em um jogo, porém introduzindo suporte a som 3D, o que é bem interessante. A API é bem simples e pode facilmente ser implementada utilizando OpenAL, sendo que nesta última já estão disponíveis diversos efeitos de som interessantes na forma de exemplos.

Quase chegando no fim! Décimo primeiro capítulo terminado. Apesar das explicações básicas de vários conceitos de redes, que deixa o capítulo mais digerível para pessoas sem background no assunto, a implementação é bastante interessante, porém a organização do código não é muito boa, deixando o código do cliente e do servidor misturados. Em implementações mais complexas isso tornaria o código mais difícil de manter e estender. Acredito que o padrão state neste caso cairia muito bem. Apesar disso, achei que o código encapsula bem a API WinSocket, que pode ser facilmente substituída pela implementação de Berkley, deixando a complexidade da comunicação entre cliente/servidor fora do código da aplicação que utiliza a engine.  Por fim, o autor escreve duas aplicações simples para utilizar a API especificada, uma de chat e outra de transferência de arquivos. Capítulo bastante interessante.

O capítulo 12 é bastante curto, porém muito interessante. Nele é mostrado código para gerenciar a câmera de suas cenas. O auto apresenta uma classe base e a partir dela escreve uma câmera com 6 graus de liberdade e uma voltada para jogos de tiro em primeira pessoa. Além disso ele também discute aspectos relacionados a jogos que utilizam câmeras em terceira pessoa e também sobre o uso de quaternions para evitar o problema de gimbal lock quando se está manipulando uma câmera com 6 graus de liberdades. Capítulo simples e direto, muito bom!

Cérebro fritando! O capítulo 13 é sobre gerenciamento da cena, ou seja, o que deve e o que não deve ser renderizado na sua tela. Cobre principalmente os algoritmos para renderização de jogos indoor e implementa dois destes algoritmos (BSP e Octree). Tem ainda uma parte nostalgia, onde mostra os precursores dos jogos de tiro em 3D (Doom, Duke Nukem 3D, Castle Wolfstein) que popularizaram as técnicas de gerenciamento de cena. Para quem quer desenvolver jogos outdoor e renderizar terrenos terá que procurar fontes externas. O assunto é bastante vasto e o capítulo é ótimo como uma introdução, além de dar de bandeja os algoritmos supracitados.

O capítulo 14 é enorme e deveras, já que nele é mostrado como implementar um editor de polígonos, ou seja um editor de níveis para o seu jogo sendo capaz das seguintes tarefas:
  • Criar polígonos e objetos simples;
  • Editar polígonos e objetos no nível de vértices;
  • Apagar e copiar objetos;
  • Selecionar e esconder objetos;
  • Agrupar geometria em uma malha;
  • Editar coordenadas de textura;
  • Carregar e salvar um nível;
  • Carregar e salvar partes de uma geometria;
  • Definir pontos de início para os jogadores no jogo;
  • Definir e editar fontes de luz;
  • Marcar objetos que devem projetar sombras;
  • Definir portais para o gerenciador de cena;
Tarefas interessantíssimas! Tudo utilizando a engine desenvolvida no livro, sendo assim, o que você vê na sua tela é como vai aparecer no seu jogo. Apesar disso ainda pretendo utilizar o Blender para criar meus modelos, pois ainda não estou convencido que programar um editor seja produtivo atualmente, sendo que o Blender pode ser estendido com scripts para exportar níveis com informações adicionais que o jogo precisar. Mas só terei certeza disso depois que começar a criar meus modelos.

O último capítulo é a cereja do bolo. Um jogo de deathmatch multiplayer utilizando a engine. O jogo aproveita algumas classes do editor, porém levando em consideração questões como a performance. Faz uso de tudo que foi escrito até o momento, carregando o nível criado no editor do capítulo anterior. O capítulo também introduz classes para calcular sombras e discute (e mostra o código) de como realizar a renderização do nível de forma eficiente.

Gostei muito do livro, possui partes de muito valor, porém não gostei de algumas pequenas coisas, tal como o estilo do código do autor. Além disso, seria interessante ter mais referências, sendo poucos os livros citados pelo autor. O autor também não utiliza padrões de projeto na criação da engine, algo que eu considero interessante, porém só depois que eu começar a criar e utilizar minha própria engine poderei afirmar se vale a pena ou não.

Apesar da engine criada abranger bastante coisa, achei que faltaram duas coisas importantíssimas e fundamental para a criação de qualquer jogo atualmente: uma biblioteca de física e um sistema de partículas. O primeiro item até entendo que tenha sido deixado de fora, afinal o autor quer criar tudo da engine, pois acha importante ter o entendimento do que está acontecendo, sendo assim, seria necessário criar todo o suporte de física, o que é assunto para um livro inteiro. Já o segundo item achei uma falha grave. Hoje em dia qualquer jogo que se preze tem explosões, chuva, neve, fumaça, etc, e todos este efeitos são criados através de um sistema de partículas, que com certeza ficou faltando neste livro.

Tentei deixar meu texto curto, porém o livro tem mais de 800 páginas, então esta tarefa é bastante complicada. Espero que este review sirva para você ter uma noção melhor do que vai encontrar no livro e como ele é escrito. Não sou um programador de jogos, nem um programador avançado de C++. Ainda estou aprendendo muito sobre os dois mundos, principalmente o de jogos, porém escrevo para partilhar do pouco da minha jornada e também para colocar as percepções que tenho do que vou aprendendo, pois estes registros é que vão me guiar no desenvolvimento da minha engine e do meu jogo.

sexta-feira, 7 de janeiro de 2011

Programação de Jogos

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ê gostou deste post, talvez ache interessante este também: http://cerdiogenes.blogspot.com/2010/11/comparacao-entre-metodos-para-evolucao.html. É um artigo que escrevi como trabalho final da minha pós-graduação e aborda o treinamento de carros de corrida utilizando aprendizado de máquina e inteligência computacional.

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!

segunda-feira, 26 de julho de 2010

Upload de arquivos no JSF2 no escopo de conversação

Há algum tempo vinha procurando uma solução para fazer upload de arquivo no JSF2 no escopo de conversação.

Existem vários sites que mostram como fazer upload de arquivo no JSF{1,2}, porém nenhum deles leva em consideração o escopo de conversação: http://forums.sun.com/thread.jspa?threadID=5399669, http://ironicprogrammer.blogspot.com/2010/03/file-upload-in-jsf2.html, http://dominikdorn.com/?p=169, http://balusc.blogspot.com/2009/12/uploading-files-with-jsf-20-and-servlet.html

Além destes sites também vi uma solução no livro Core Java Server Faces 3ª edição, no entanto nesta solução o mesmo problema existia. Ao submeter um arquivo, enquanto no escopo de conversação, o escopo era simplesmente destruído.

Entrei em contato com os diversos autores para verificar se eles me davam uma luz, pois ainda sou bastante cru para mexer com filtros em JSF. Algum tempo depois recebi a resposta do autor do Core Java Server Faces, o Cay Horstmann, que me sugeriu olhar como o Seam resolvia o problema, pois esta foi a tecnologia pioneira do escopo de conversação.

Ele me deu esse conselho no dia 30 de Junho, mas apenas hoje consegui finalizar a implementação.

Primeiro olhei o código do RichFaces, pois ele que contém o componente de file upload e então percebi que ele não implementava o filtro, que é o componente que analisa a requisição e processa os cabeçalhos para extrair o arquivo e os outros elementos da requisição. Descobri que quem fazia isso era o próprio Seam.

Coloquei no liquidificador a implementação do Seam e do Cay Horstmann e o sabor ficou muito bom, um componente de upload de arquivos simples e que funciona no escopo de conversação. Pefeito!

Porém não me peça para explicar porque o filtro do Seam funciona para salvar a conversação, ainda não consegui entender, mas se você souber, ficaria muito satisfeito em ouvir.

O projeto do NetBeans que criei pode ser baixado através do seguinte link: http://sites.google.com/site/cerdiogenes/java/jsf2/fileupload.zip?attredirects=0

Nele não existe nenhum tipo de validação, mas pretendo começar a trabalhar nisso em breve, pois vou precisar integrá-lo em um sistema e os requisitos se tornam mais específicos. Que venham os problemas então! E que sejam fáceis de resolver :D

segunda-feira, 31 de maio de 2010

Configurar Repositório Externo no Subversion

Quando estamos desenvolvendo alguns projetos, as vezes precisamos buscar código-fonte de repositórios externos. Isso é interessante até mesmo no desenvolvimento in house, pois as vezes utilizamos bibliotecas em diferentes projetos. Desta forma conseguimos manter uma base de software para diferentes aplicativos e atualizá-las de forma fácil.

Para configurar os repositórios externos utiliza-se os comandos:
svn propget
svn propset
O comando propget serve para você solicitar uma propriedade configurada em um diretório. Um exemplo de sua utilização é:
svn propget svn:externals .
O ponto do final se refere ao diretório corrente, caso queira pegar a propriedade de outro diretório basta passar um caminho no lugar do ponto.

O comando propset server para setar uma propriedade e sua syntaxe é:
svn propset svn:externals 'dir_local http://endereco.svn.remoto/nome/do/diretorio' .
Repare o ponto no final. Este comando diz que no diretório corrente (o ponto) será criado um diretório com o nome dir_local e seu conteúdo será buscado do repositório http://endereco.svn.remoto/nome/do/diretorio.

Após está mudança, basta fazer um commit e um update das alterações para buscar o repositório externo. Caso você queira criar mais de um repositório externo adicione todas as referência externas em um arquivo da seguinte forma:
dir_local1 http://endereco.svn.remoto/nome/do/diretorio1
dir_local2 http://endereco.svn.remoto/nome/do/diretorio2
dir_local3 http://endereco.svn.remoto/nome/do/diretorio3
E ao utilizar o comando svn propset faça o seguinte:
svn propset svn:externals -F nome_do_arquivo .
Não esqueça depois de setar a propriedade de realizar um commit.

Isso é realmente muito fácil, mas a documentação do SVN deixa bastante a desejar em relação a um recurso tão útil.

terça-feira, 9 de junho de 2009

Compilando CrystalSpace3D (CS) e Crystal Entity Layer (CEL) no Slackware 12.2

Estou brincando com a CS e a CEL por aqui. Se você pretende utilizar esta biblioteca para desenvolver jogos ou qualquer outra aplicação com recursos 3D eu diria para levar em consideração esta mensagem http://sourceforge.net/mailarchive/forum.php?thread_name=742a36470902230603y27874edaid465aec69e0f78fc%40mail.gmail.com&forum_name=crystal-main. No entanto, você é dono do seu sistema, então trabalhe com qualquer versão da biblioteca que você quiser.

Compilar tais bibliotecas é muito fácil, pois a docuemtação é simples, porém espera-se que você já tenha compilado algo, mas não deve fugir de um ./configure, make e make install e em alguns casos jam e jam install. Esta última é a ferramenta utilizada pela CS e CEL para compilar a árvore dos fontes.

A maioria das dependências utilizadas podem ser encontradas em www.slacky.eu e www.slackbuilds.org. Outra ferramenta interessante é a pkgcreate (http://www.din.uem.br/~msambinelli/download/), que facilita bastante o processo de criar pacotes a partir dos fontes.

As informações para compilar e instalar a CS está disponível em: http://www.crystalspace3d.org/docs/online/1.4/manual/Building.html#0

Algumas dependências já vêm instaladas com o Slack, são elas: zlib, libpng, libjpeg, freetype, bibliotecas de desenvolvimento do X e da OpenGL, libogg, libvorbis, libmng. Outras já possuem seus pacotes prontinhos para serem instaladas, são elas:

Jam: http://www.slacky.eu/aadm/pkgs/index.php?ver=6&pkg=658
wxWidgets 2.8.10: http://www.slacky.eu/aadm/pkgs/index.php?ver=6&pkg=1165
libmspack: http://www.slacky.eu/aadm/pkgs/index.php?ver=6&pkg=792 (dependência da wxWidgets acima)
CEGUI 0.6.2: http://www.slacky.eu/aadm/pkgs/index.php?ver=6&pkg=635

Outros possuem SlackBuild's prontos:

ODE 0.8: http://slackbuilds.org/repository/12.1/libraries/ode/ (utilizei a versão para o Slack 12.1 e que funciona muito bem no 12.2, pois esta é a versão recomendada para a CS). Aqui está o link para o pacote que compilei: ode-0.8-i486-1_SBo.tgz

Não instalei algumas dependências, pois não pretendo utilizar, sendo ela a biblioteca Bullet, pois pretendo utilizar a ODE.

Estas bibliotecas compilei utilizando o pkgcreate:

cal3d-0.11.0-i686-1_PKGC.tgz
lib3ds-1.3.0-i686-1_PKGC.tgz
libcaca-0.99.beta13-i686-1_PKGC.tgz (o pacote oficial do Slack deve ser substituído por este, pois esta versão é requerida, porém tal biblioteca é opcional, sendo apenas necessária se você quiser a saída do seu programa em ASCII :-)

Binários da Cg Toolkit podem ser encontrados no site http://developer.nvidia.com/object/cg_toolkit.html. Aqui instalei a versão 2.1, porém a partir do site da CS, qualquer versão acima da 1.4 deve funcionar.

Muito bem, depois de instalado todos esses arquivos, basta compilar a CS. Baixe os fontes através do comando:

svn co https://crystal.svn.sourceforge.net/svnroot/crystal/CS/branches/release/V1.4 CS_1.4

Agora vá tomar um café enquanto os fontes são baixados. Depois disso, acesse o diretório criado e agora digite ./configure e make ou jam (neste caso o make é uma capa para o jam). E vá tomar outro café :-). Após alguns minutos ou horas, dependendo da sua máquina você estará com a CS compiladinha :D. Não irei dizer para você instalar a biblioteca, pois tive problemas ao fazer isso, o sistema de detecção de colisões não funcionou corretamente, então utilize a biblioteca a partir do local onde esta está.

Vamos partir para a CEL agora, que é uma biblioteca de entidades construída sobre a CS que pode ser considerada uma engine para jogos. Assim como a CS, as informações para compilar e instalar a CEL também estão disponíveis online: http://crystalspace3d.org/cel/docs/online/manual-1.2/Building.html#0. Tais informações não são muito completas, mas já é melhor do que nada.

Esta é bem mais fácil para compilar, já que não exige a instalação de muitas dependências, pois python é padrão em qualquer distribuição. Além desta existe um pacote opcional, o HawkNL, caso você queira suporte a redes, o que eu acho uma ótima idéia. Para esta dependência eu não encontrei pacotes e também não consegui gerar o pacote através do pkgcreate e também fui preguiçoso o suficiente para apenas compilá-la e instalá-la, sem criar pacote algum. O site da HawkNL é http://www.hawksoft.com/hawknl/. Outra coisa importante é exportar a variável CRYSTAL com o caminho onde você compilou a CS.

Pronto, feito isso basta rodar o comando "jam" e ir tomar um café. Após isso você já pode utilizar a biblioteca para criar seus próprios programas assim como rodar os vários exemplos que vem com ela. Para rodar os exemplos você deve exportar a variável LD_LIBRARY_PATH para apontar para onde você compilou a CS.