Os sistemas de eventos são incríveis, tornam o código extremamente difícil de manejar e realmente permitem a criação dinâmica de jogos através da fácil comunicação de objetos e do loop do jogo. Estou tendo dificuldades com a eficiência da minha implementação atual. Atualmente, minha pequena otimização de separar as listas de objetos nos eventos aos quais eles respondem fez maravilhas, mas deve haver mais que eu possa fazer.
Atualmente, tenho dois métodos:
Mais simples: todos os objetos são adicionados a um vetor quando um evento é enviado, todos os objetos são enviados ao evento por meio do método handle_event ()
Mais complexo: eu tenho um mapa com string como chave e int como valor. Quando um tipo de evento é adicionado, ele é adicionado a este mapa, com o int simplesmente sendo incrementado (deve haver uma maneira melhor)
do vetor de vetores de objetos e, em seguida, empurra um novo vetor para lidar com esse tipo de evento.
Quando um evento é chamado, ele simplesmente chama o int correspondente no mapa eventTypes para o tipo dentro do vetor de vetores de objetos e envia esse evento para cada objeto que manipula esse tipo de evento.
Esse primeiro método é bastante lento (obviamente) para muitos objetos, mas bastante rápido para muito poucos objetos. Enquanto o segundo método é bastante rápido com objetos grandes que gostariam de lidar com diferentes tipos de eventos, mas mais lento que o primeiro método por objeto com objetos manipulando o mesmo tipo de evento.
Existe uma maneira mais rápida (em termos de tempo de execução)? Existe uma maneira mais rápida de procurar um int do tipo string? (Inicialmente eu tinha um enum, mas não permitia tipos personalizados, necessários por causa do nível de dinamismo desejado).
fonte
Respostas:
Parece que você está dizendo que o grande gargalo de desempenho está pesquisando IDs de eventos (números inteiros) a partir de seus nomes de sequência. Você pode pré-processar os dados do jogo para converter todos os nomes de eventos em números inteiros antes de executar o jogo ou, possivelmente, ao carregar o nível; então você não precisaria fazer conversões durante o jogo.
Se os objetos estão sendo criados e destruídos com frequência, pode haver muita rotatividade nos vetores dos objetos. Nesse caso, você pode se beneficiar usando listas vinculadas em vez de vetores; eles são mais rápidos para inserção e exclusão.
fonte
EventType takeDamageEvent = EventSystem::CacheEventType("takeDamageEvent");
. Torne-o um membro estático das classes e você terá apenas uma cópia flutuando em cada classe que precisar.Bem, vamos resolver as coisas simples primeiro. Você tem isso
map
entre cadeias (o nome do evento, presumivelmente) e números inteiros (o índice dos ouvintes de eventos registrados).O tempo de pesquisa em a
map
é baseado em duas coisas: o número de itens no mapa e o tempo necessário para fazer a comparação entre duas chaves (ignorando problemas de cache). Se o tempo de pesquisa for um problema, uma maneira de lidar com isso é alterar a função de comparação, alterando o tipo de string.Vamos supor que você esteja usando
std::string
eoperator<
para comparação. Isso é altamente ineficiente; faz uma comparação em bytes. Você não se importa com a string real menos que a comparação; você só precisa de algum tipo de comparação que ofereça uma ordem estritamente fraca (porquemap
não funciona de outra maneira).Portanto, você deve usar uma string de comprimento fixo de 32 bytes em vez de
std::string
. Eu os uso para identificadores. Os testes de comparação para essas cadeias fixas não fazem comparações de bytes; eles fazem comparações de 32 bits (ou 64 bits). Ele pega a cada 4 bytes como um número inteiro não assinado e o compara com os 4 bytes correspondentes da outra string. Dessa forma, a comparação leva apenas no máximo 8 comparações. Ele garante uma ordem estritamente fraca, embora a ordem não tenha nada a ver com os dados como caracteres.Armazenar strings com mais de 31 bytes (precisa do caractere NULL) trunca a string (mas a partir do meio, e não das extremidades. Acho que a entropia tende a ser maior no início e no final). E seqüências de caracteres mais curtas do que isso exibem os caracteres restantes
\0
.Agora, você pode abandonar
map
completamente e usar uma tabela de hash. Se você realmente possui mais de 100.000 tipos diferentes de tipos de eventos, pode ser uma boa ideia. Mas não conheço um jogo em que isso seja remotamente razoável.fonte
Para responder à pergunta geral:
Não há nenhum. Tudo o que você pode fazer é identificar as necessidades específicas que você terá para seus sistemas de eventos (pode haver várias diferentes) e, em seguida, usar a ferramenta certa para o trabalho certo.
Eu implementei e tentei generalizar toneladas de sistemas de eventos e cheguei a essa conclusão. Como os tradeoffs são realmente diferentes se você compilar em tempo de compilação ou tempo de execução, se usar hierarquias de objetos ou lousas etc.
A melhor maneira é estudar os diferentes tipos de sistemas de eventos e, em seguida, você terá dicas sobre qual usar.
Agora, se você deseja o sistema realmente mais flexível, implemente um sistema de quadro negro (tempo de execução) com propriedades dinâmicas de eventos e você terá algo muito flexível, mas talvez muito lento.
fonte