ECS? Na verdade, sugiro que talvez não seja prematuro pensar muito no lado orientado a dados do design e comparar diferentes representantes, pois isso pode afetar seus designs de interface , e é muito caro mudar tarde no final. o jogo. Além disso, o ECS exige muito trabalho e pensamento antecipado, e acho que vale a pena utilizar parte desse tempo para garantir que isso não traga luto por desempenho no nível de design mais adiante, considerando como ele estará no coração de sua empresa. mecanismo todo enlouquecido. Esta parte me brilha:
unordered_map<string,[yada]>
Mesmo com otimizações de string pequenas, você tem um contêiner de tamanho variável (strings) dentro de outro contêiner de tamanho variável (unordered_maps). Na verdade, as pequenas otimizações cordas realmente pode ser tão prejudicial quanto útil, neste caso, se a tabela é muito escassa, uma vez que a pequena otimização corda implicaria que cada índice não utilizado da tabela de hash ainda vai usar mais memória para a otimização SS ( sizeof(string)
seria ser muito maior) até o ponto em que a sobrecarga total de memória da sua tabela de hash pode custar mais do que o que você está armazenando nela, especialmente se for um componente simples como um componente de posição, além de gerar mais falhas de cache com grande avanço para passar de uma entrada na tabela de hash para a próxima.
Estou assumindo que a string é algum tipo de chave, como uma identificação de componente. Nesse caso, isso já torna as coisas dramaticamente mais baratas:
unordered_map<int,[yada]>
... se você quiser os benefícios de poder ter nomes fáceis de usar que os scripts podem usar, por exemplo, as seqüências internas podem oferecer o melhor dos dois mundos aqui.
Dito isto, se você pode mapear a string para um intervalo razoavelmente baixo de índices densamente usados, poderá fazer isso:
vector<[yada]> // the index and key become one and the same
A razão pela qual não considero prematuro é porque, novamente, isso pode afetar seus designs de interface. O objetivo do DOD não deve ser o de tentar apresentar as representações de dados mais eficientes imagináveis de uma só vez na IMO (que geralmente devem ser alcançadas iterativamente, conforme necessário), mas pensar nelas o suficiente para projetar interfaces no topo para trabalhar com isso. dados que deixam espaço suficiente para o perfil e a otimização sem alterações de design em cascata.
Como um exemplo ingênuo, um software de processamento de vídeo que combina todo o seu código com isso:
// Abstract pixel that could be concretely represented by
// RGB, BGR, RGBA, BGRA, 1-bit channels, 8-bit channels,
// 16-bit channels, 32-bit channels, grayscale, monochrome,
// etc. pixels.
class IPixel
{
public:
virtual ~IPixel() {}
...
};
Não vai chegar muito longe sem uma reescrita potencialmente épica, já que a ideia de abstrair no nível de pixel único já é extremamente ineficiente (a vptr
própria custaria muitas vezes mais memória que o pixel inteiro) em comparação com a abstração no nível da imagem (o que geralmente representam milhões de pixels). Então, pense bastante em suas representações de dados com antecedência, para que você não precise enfrentar um cenário de pesadelo e, idealmente, não mais, mas aqui acho que vale a pena pensar sobre essas coisas desde que você não queira criar um mecanismo complexo em torno do seu ECS e descubra que o próprio ECS é o gargalo de maneiras que exigem que você mude as coisas no nível do design.
Quanto às falhas de cache do ECS, na minha opinião, os desenvolvedores geralmente se esforçam demais para tornar seus ECS compatíveis com o cache. Começa a render muito pouco esforço para tentar acessar todos os seus componentes de maneira perfeitamente contígua e geralmente implica em copiar e embaralhar dados em todo o lugar. Geralmente, é bom o suficiente, digamos, apenas modificar índices de componentes de classificação antes de acessá-los, para que você os acesse de uma maneira em que pelo menos não esteja carregando uma região de memória em uma linha de cache, apenas para despejá-la e carregá-la. tudo de novo no mesmo loop apenas para acessar uma parte diferente da mesma linha de cache. E um ECS não precisa fornecer eficiência incrível em todos os aspectos. Não é como se um sistema de entrada se beneficiasse tanto quanto um sistema de física ou renderização, então eu recomendo apontar para "bom" eficiência global e "excelente" apenas nos locais onde você realmente precisa. Dito isto, o uso deunordered_map
e string
aqui são fáceis o suficiente para evitar.