Estou no meio do desenvolvimento de um jogo baseado em sprite 2D para o Windows 7 Phone, usando o XNA. O treinamento e os tutoriais disponíveis para ele são bastante úteis, mas o problema que enfrento é que cada um deles aborda seu design de classe de maneira diferente e o código não é particularmente bem-fatorado. Como resultado, tem sido difícil para mim entender bem quais responsabilidades devo dar a uma classe em particular.
Por exemplo, eu poderia ter uma classe de sprite de base BaseSprite
que sabe desenhar, verificar colisões, etc. Eu poderia ter uma AnimatedSprite
classe que saberia como navegar em sua planilha de sprite, uma ExplodingSprite
classe e assim por diante. Essa técnica é demonstrada no exemplo de Space Invaders nos materiais da sessão 2 do Windows 7 Phone Jumpstart .
Como alternativa, eu poderia colocar a maior parte da renderização e executar a responsabilidade do jogo em uma GameScreen
classe; essa classe e suas classes derivadas se comportam mais como formulários ou páginas da Web em termos de suas responsabilidades. As classes Sprite são contêineres mais simples e com muito menos lógica.
Essa é a técnica usada no jogo Alien Sprite do Windows 7 Phone Training Kit e em outros exemplos de gerenciadores de estado de jogos.
Qual é a abordagem correta orientada a objetos para o design de classe no desenvolvimento de jogos?
Nos jogos, o padrão Component é uma solução comum.
fonte
Os Princípios do SOLID se aplicam tanto ao design do código do jogo quanto a qualquer outra profissão - pelo menos até você otimizar, então eu usaria o seu primeiro exemplo como ponto de partida.
Eu iria além, porque o BaseSprite parece ter a tendência de se tornar uma megaclasse. O princípio de responsabilidade única determina que a colisão, a renderização e a navegação devem ser tratadas por componentes, em vez de entradas individuais em uma hierarquia de classes. A classe holding de todos esses componentes deve lidar apenas com empurrar posições mundiais entre eles.
fonte
Nos últimos projetos, eu me inclinei mais para uma abordagem no estilo MVC.
No começo, não tínhamos certeza se isso funcionaria, mas funcionou perfeitamente.
Modelo
Os objetos de dados. Apenas os dados puros. Sem comportamento, sem renderização.
Gerenciador de dados. Apenas manipulando "listas" de objetos de dados. (Também pode ser aprimorado para oferecer suporte ao pool.)
Visão
Nós os chamamos de renderizadores. Para cada tipo de objeto de dados, há um renderizador. Quando chamado com um gerente, ele renderiza todos os objetos nessa lista.
Controlador
O mesmo que os representantes, mas controla o comportamento.
Exemplo
O ShipManager possui uma lista de navios. O ShipController moverá os navios de acordo com seu estado. O ShipRenderer renderizará os navios de acordo com seu estado.
Por quê
Dessa forma, a visão e a lógica são estritamente separadas. Isso facilita bastante a migração para uma nova plataforma. Otimizar o layout de dados dentro do XxxManager também é muito fácil.
fonte