Existem duas classes no meu jogo que são realmente úteis, mas lentamente se tornando uma dor. Mensagem e propriedade (a propriedade é essencialmente um componente).
Ambos derivam de uma classe base e contêm um ID estático, de modo que os sistemas podem prestar atenção apenas àqueles que desejam. Está funcionando muito bem ... exceto ...
Estou constantemente criando novos tipos de mensagens e propriedades à medida que estendo meu jogo. Cada vez que eu preciso escrever 2 arquivos (hpp e cpp) e uma tonelada de clichê para obter essencialmente um classID e um ou dois tipos de dados padrão ou um ponteiro.
Está começando a fazer com que brincar e testar novas idéias seja uma tarefa real. Desejo que, quando desejar criar uma nova mensagem ou tipo de propriedade, queira poder digitar algo como
ShootableProperty: int gunType, float shotspeed;
ItemCollectedMessage: int itemType;
em vez de criar um arquivo de cabeçalho e cpp, escrever um construtor, incluindo a classe pai, etc.
São cerca de 20 a 40 linhas (incluindo guardas e tudo) apenas para fazer o que logicamente são 1 ou 2 linhas em minha mente.
Existe algum padrão de programação para contornar isso?
E quanto aos scripts (dos quais eu não sei nada) ... existe uma maneira de definir um monte de classes quase iguais?
Aqui está exatamente como uma classe se parece:
// Velocity.h
#ifndef VELOCITY_H_
#define VELOCITY_H_
#include "Properties.h"
#include <SFML/System/Vector2.hpp>
namespace LaB
{
namespace P
{
class Velocity: public LaB::Property
{
public:
static const PropertyID id;
Velocity(float vx = 0.0, float vy = 0.0)
: velocity(vx,vy) {}
Velocity(sf::Vector2f v) : velocity(v) {};
sf::Vector2f velocity;
};
} /* namespace P */
} /* namespace LaB */
#endif /* LaB::P_VELOCITY_H_ */
// Velocity.cpp
#include "Properties/Velocity.h"
namespace LaB
{
namespace P
{
const PropertyID Velocity::id = Property::registerID();
} /* namespace P */
} /* namespace LaB */
Tudo isso apenas para um vetor 2D e um ID que espera um vetor 2D. (Concedido, algumas propriedades têm elementos mais complicados, mas é a mesma ideia)
Respostas:
C ++ é poderoso, mas é detalhado . Se o que você deseja são muitas classes polimórficas pequenas, todas diferentes, então sim, será necessário muito código-fonte para declarar e definir. Não há realmente nada a fazer sobre isso.
Agora, como ltjax disse, o que você está fazendo aqui não é exatamente polimorfismo , pelo menos para o código que você forneceu. Não vejo uma interface comum que oculte a implementação específica de subclasses. Exceto, talvez, o ID da classe, mas isso é realmente redundante com o ID da classe real: é o nome. Parece ser apenas um monte de classes contendo alguns dados, nada realmente complicado.
Mas isso não resolve o seu problema: você deseja criar muitas mensagens e propriedades com a menor quantidade de código. Menos código significa menos erros, portanto, é uma decisão sábia. Infelizmente para você não existe uma solução única. É difícil dizer o que melhor atenderia às suas necessidades sem saber exatamente o que você pretende fazer com essas mensagens e propriedades . Então deixe-me expor suas opções:
Use modelos C ++ . Os modelos são uma ótima maneira de deixar o compilador "escrever código" para você. Está se tornando cada vez mais proeminente no mundo C ++, à medida que a linguagem evolui para suportá-los melhor (por exemplo, agora você pode usar um número variável de parâmetros de modelo ). Existe toda uma disciplina dedicada à geração automatizada de código por meio de modelos: metaprogramação de modelos . O problema é: é difícil. Não espere que os não programadores possam adicionar novas propriedades se planejarem usar essa técnica.
Use macros C simples . É da velha escola, fácil de abusar demais e propenso a erros. Eles também são muito simples de criar. As macros são apenas pastas de cópias glorificadas executadas pelo pré-processador; portanto, elas são realmente adequadas para criar toneladas de coisas quase iguais, com pequenas variações. Mas não espere que outros programadores o amem por usá-los, pois as macros costumam ser usadas para ocultar falhas no design geral do programa. Às vezes, porém, são úteis.
Outra opção é usar uma ferramenta externa para gerar o código para você. Já foi mencionado em uma resposta anterior, então não vou expandir isso.
Existem outros idiomas que são menos detalhados e permitem criar classes com mais facilidade. Portanto, se você já possui ligações de script (ou planeja tê-las), definir essas classes no script pode ser uma opção. Acessá-los a partir do C ++ será bastante complicado, e você perderá a maior parte dos benefícios da criação simplificada de classes. Portanto, isso provavelmente é viável apenas se você planeja executar a maior parte da lógica do jogo em outro idioma.
Finalmente, por último, mas não menos importante, você deve considerar o uso de um design orientado a dados . Você pode definir essas "classes" em arquivos de texto simples usando um layout semelhante ao que você se propôs. Você precisará criar um formato e um analisador personalizados para ele ou usar uma das várias opções já disponíveis (.ini, XML, JSON e outros enfeites). Então, no lado do C ++, você precisará criar um sistema que suporte uma coleção desses diferentes tipos de objetos. Isso é quase equivalente à abordagem de script (e provavelmente requer ainda mais trabalho), exceto que você poderá adaptá-lo com mais precisão às suas necessidades. E se você simplificar o suficiente, os não programadores poderão criar coisas novas sozinhos.
fonte
Que tal uma ferramenta de geração de código para ajudá-lo?
por exemplo, você pode definir seu tipo de mensagem e membros em um pequeno arquivo de texto e fazer com que a ferramenta de geração de código o analise e grave todos os arquivos C ++ padrão como uma etapa de pré-construção.
Existem soluções existentes, como ANTLR ou LEX / YACC, e não seria difícil criar as suas próprias, dependendo da complexidade de suas propriedades e mensagens.
fonte
Aconselho você a pesquisar sobre os buffers de protocolo do Google ( http://code.google.com/p/protobuf/ ). Eles são uma maneira muito inteligente de lidar com mensagens genéricas. Você apenas precisa especificar as propriedades em um padrão de estrutura e um gerador de código faz todo o trabalho de gerar as classes para você (Java, C ++ ou C #). Todas as classes geradas possuem analisadores de texto e binários, o que as torna boas para inicialização e serialização de mensagens baseadas em texto.
fonte