Mesma lógica de jogo em duas bibliotecas gráficas separadas


11

Que filosofia de código / estrutura de abstração / design de programa permitiria que um jogo fosse usado com gráficos 2D e 3D (separadamente) SEM ter que recodificar a lógica do jogo?

Estamos falando de usar o mesmo código, alterar um mínimo de coisas (por exemplo, trocar nomes de arquivos por recursos 2D com nomes de arquivos por recursos 3D) e talvez conectar algumas especializações de uma classe base por genéricos / modelos.

Para colocá-lo em um contexto real, onde faz sentido: imagine um jogo para vários jogadores da LAN, onde há um cliente 3D de alto nível e sedento de desempenho para os jogadores com algumas plataformas gamer realmente boas e um cliente 2D mais humilde para os antigos caixas empoeiradas que alguém encontrou no sótão. Mas ainda é o mesmo jogo - os mesmos eventos são registrados (alguém pegou uma moeda), o mesmo protocolo de rede é usado, os mundos são proporcionais etc.

Para colocá-lo em um contexto MVC: Os controladores são exatamente os mesmos (pressionar a tecla "Para cima" definirá a aceleração dos jogadores em 3,5 unidades / segundo), as vistas são totalmente diferentes (2D versus 3D) e o modelo é o mesmo exceto por qualquer coisa diretamente relacionada aos gráficos (uma verificação de colisão no ambiente é realizada a cada 5 segundos e usa o mesmo algoritmo. Observe que isso significa que existe uma coordenada Z para todos os objetos do jogo na versão 2D, mas é apenas ignorado ou exibido para o usuário de outra maneira, por exemplo, por uma sombra que é exibida mais à esquerda quando o jogador está no ar).

O que torna esse tópico tão fascinante é que forçaria o desenvolvedor a ter uma idéia muito clara de como seus dados estão estruturados e de como o controle flui. Observe que isso não implica o uso de outra coisa senão uma biblioteca de gráficos como SDL, D3DX ou OpenGL. Não há motores de jogos!

Como essa é uma questão principalmente teórica, deixarei de fora as linguagens de programação, mas se você quiser dar um exemplo, poderá usar qualquer linguagem que desejar, C ++, se quiser fazer o trabalho todo, ou mesmo Brainfuck, se sentir até o desafio (todas as respostas concretas serão apreciadas, bem como as abstratas!).


Não tenho certeza se isso é prático. Tanta lógica de jogo usa matemática vetorial, que você teria que fazer tudo em 3D antes de converter para 2D ou o que quer que seja para renderização, ou teria que abstrair completamente sua biblioteca de vetores - o que certamente seria impraticável?
Dezpn

Procure o termo "Camada de abstração" e se familiarize com ele, porque vocês dois trabalharão juntos por um tempo.
Zaratustra

Respostas:


8

Eu acho que tudo que você precisaria seria uma camada de abstração envolvendo sua biblioteca de gráficos; você precisaria de uma nova para cada biblioteca que usaria e cada uma delas teria exatamente a mesma API externa.

Pense na localização de strings: em vez de codificar a string "Inventory" em seu jogo, você chamaria sua biblioteca de localização (possivelmente personalizada), que faria alguns processos e retornaria uma string adequada, dependendo do contexto de o jogo.

Da mesma forma, todas as chamadas para o seu mecanismo gráfico serão feitas através do seu invólucro.

Ao fazer isso, você limita / restringe quais comandos pode dar ao seu mecanismo gráfico. Aqui estão alguns essenciais:

  1. Desenhar (objeto gráfico) em (local)
  2. Propriedade Modify (alfa, rotação, etc.) de (objeto gráfico)
  3. Mover (objeto gráfico) para (local)
  4. Criar mapa de (nome do nível / estrutura de dados)

E alguns outros, que você encontrará ao trabalhar em seu projeto.

Se você estiver usando uma Linguagem Orientada a Objetos com Tipo Estrito, chamaria os comandos acima da interface que todos os seus wrappers implementarão. De preferência, esses serão os únicos métodos públicos / não protegidos.

Agora, crie um novo wrapper para cada uma das suas bibliotecas gráficas e implemente a API . Quando um comando para desenhar __ at __ é fornecido, você deve usar o código para criar o sprite ou modelo e desenhá-lo em seu ambiente. Isso pode exigir alguns truques, como armazenar cada sprite em um hash para ser acessado novamente em outro momento por um determinado símbolo.

Quanto à construção de mapas, a maneira mais eficiente seria pré-construir cada mapa para cada mecanismo gráfico com antecedência e fazer uma pesquisa. Como alternativa, você pode armazenar o mapa em sua própria estrutura de dados customizada e, em seguida, usar seu wrapper para construir um mapa a partir dessa estrutura de dados.

Espero que isso ajude você a começar =]


2

Construir a arquitetura do seu jogo com um paradigma próximo o suficiente do MVC para permitir a abstração completa do código de exibição provavelmente seria bastante difícil para qualquer projeto grande. No entanto, parece que o maior impedimento para a criação de um jogo que ofereça suporte a um cliente 2D e 3D seria projetar um jogo no qual os dois clientes sejam igualmente capazes.

Seria necessário iniciar o design do seu jogo com a intenção total de criar e dar suporte aos dois clientes, e provavelmente seria mais seguro restringir toda a funcionalidade do jogo ao que faz sentido para o cliente 2D.

Como exemplo de armadilha, se você não estava projetando para um conjunto de funcionalidades restritas, pode criar níveis nos quais informações ou objetos importantes eram visíveis apenas de ângulos específicos. Embora isso seja bom para clientes 3D com liberdade de visualização de 360 ​​graus, a menos que seu cliente 2D suporte explicitamente um ângulo de visão que tenha visibilidade em cada um desses objetos importantes, você prejudicará os usuários do cliente.

Seria melhor definir um número específico de ângulos de visão para o cliente 2D (8 ou 16 ou mais) e desenvolver todo o conteúdo para caber nessas restrições. Infelizmente, se você tiver níveis e objetos projetados para serem visualizados apenas a partir de um conjunto específico de ângulos, pode parecer bastante estranho dentro de um cliente 3D.

Na minha opinião, seria uma má escolha tentar um design de jogo, permitindo que clientes 2D e 3D tenham a mesma capacidade. Eu acho que seria uma melhor utilização dos recursos para projetar opções de jogabilidade assimétricas e permitir que cada cliente jogasse com seus pontos fortes. Por exemplo, se o cliente 2D estivesse focado principalmente em uma perspectiva de nível estratégico no mundo do jogo, com o cliente 3D sendo usado para jogabilidade em nível tático.


0

Eu acho que você respondeu sua própria pergunta:

Para colocá-lo em um contexto de MVC: Os controladores são exatamente os mesmos (pressionar a tecla "Para cima" definirá a aceleração dos jogadores em 3,5 unidades / segundo), as visualizações são totalmente diferentes (2D versus 3D) e o modelo é o mesmo exceto por qualquer coisa diretamente relacionada aos gráficos.

Portanto, fornecendo uma abstração adequada entre entrada, lógica do jogo etc. e gráficos, você terá resolvido o problema.

Esse é basicamente o objetivo do modelo MVC, especialmente no que diz respeito a aplicativos de desktop e web: pode haver vários clientes acessando e manipulando os mesmos dados (uma interface da web, cliente móvel e cliente de desktop por email, por exemplo).


0

Mantenha-o simples, se quiser: - Escreva a lógica do jogo para mover os objetos. Não armazene dados neles relacionados à renderização. - Escreva os renderizadores que têm a chance de examinar o estado dos dados do jogo e desenhá-los.

Você pode usar técnicas de programação mais ou menos complicadas para isso. A única coisa que você precisa é uma maneira de obter dados "extras" que você precisa renderizar para cada objeto do jogo. A maneira mais simples é ter zero dados extras necessários! Se o objeto do jogo for um "Assistente", desenhe um Assistente.

Se você precisar de métodos mais complicados, considere o polimorfismo, o padrão de lembranças, as tabelas de hash, os ponteiros void *, etc.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.