Como um mecanismo como o Source processa entidades?


9

No mecanismo Source (e é antecessor, goldsrc, quake's), os objetos do jogo são divididos em dois tipos, mundo e entidades. O mundo é a geometria do mapa e as entidades são jogadores, partículas, sons, partituras, etc. (para o Source Engine).

Toda entidade possui uma função de pensamento , que faz toda a lógica dessa entidade.

Portanto, se tudo o que precisa ser processado vier de uma classe base com a função think, o mecanismo de jogo poderá armazenar tudo em uma lista e, em todos os quadros, percorrê-lo e chamar essa função.

Em um primeiro olhar, essa ideia é razoável, mas pode levar muitos recursos, se o jogo tiver muitas entidades.

Então, como um mecanismo como o Source cuida (processo, atualização, desenho etc.) dos objetos do jogo?


2
Por que isso importa, como <some commercial engine>isso acontece?
The Duck comunista

8
@ The Duck Comunista, acho que a verdadeira questão aqui é mais como um mecanismo bem-sucedido faz isso para que eu possa aprender com eles?
Subb

Respostas:


5

Bem, não há praticamente nenhuma outra maneira de fazer isso - você terá que percorrer e chamarthink() todas as entidades pelo menos uma vez a cada poucos quadros.

Você pode colocar entidades em seu próprio encadeamento, mas terá todo o pesadelo de sincronização de estado, o que definitivamente não vale a pena.

Em um primeiro olhar, essa ideia é razoável, mas pode levar muitos recursos, se o jogo tiver muitas entidades.

É por isso que o mecanismo de origem impõe um limite rígido ao número de entidades que podem existir ao mesmo tempo : 4096 entidades, das quais apenas metade (2048) pode ser conectada em rede. Passe por um desses limites e o jogo travará.

É também por isso que, ao criar um mapa, eles recomendam que você não use mais de 800 entidades.


A função 2 ^ 12 ainda não é um número GRANDE para cada quadro?
JulioC

@ Júlio: Bem, a 60 qps, são 246k chamadas de função por segundo - isso é muito, mas definitivamente possível no hardware atual. Lembre-se, porém, de que esse é o máximo absoluto permitido antes que o mecanismo de origem falhe - normalmente, há muito menos entidades em um mapa.
BlueRaja - Danny Pflughoeft

5
As entidades têm uma próxima vez que pensam, a função think não é chamada de todos os quadros e nem para todas as entidades. Lembro que, para o terremoto 2, o tempo mínimo de reflexão foi de 0,1 (100 ms), apenas 10 fps para o processamento de entidades.
bcsanches

"Você pode colocar entidades em seu próprio encadeamento, mas então terá todo o pesadelo da sincronização de estado, o que definitivamente não vale a pena". Confira estes slides do Killzone 4, se você acha que não vale a pena: de.slideshare.net/jrouwe/…
Tara

3

Essas etapas que você menciona provavelmente são executadas em mecanismos separados. É que os mecanismos de jogo simples geralmente os têm de uma só vez. Sua sequência

for each object
    do physics
    do game logic
    draw

torna-se

call physics subsystem
call game logic subsystem
call drawing subsystem

O Physics Engine cuida de posições e tamanhos.

O Game Logic Engine cuida da interpretação do que o Physics Engine mudou (ele pode obstruir alguns pontos de referência ...), quais objetivos os personagens têm e qual comportamento eles devem estar executando , ele executa scripts agendados (este pensamento função de ).

O Drawing Engine desenha quais objetos são visíveis e ele sabe quais objetos são visíveis porque os mecanismos do Quake meio que trapaceiam aqui (consulte a seção Draw).

Meu conselho para você é estudar melhor como as simulações são feitas, em vez dos mecanismos de jogo. Existe uma enorme cultura pop relacionada ao desenvolvimento de jogos e os mecanismos de jogos são feitos em linguagens imperativas (por causa da tradição e velocidade); então foi mais esclarecedor para mim obter bons livros didáticos (em vez de teoria) e ENTÃO olhar para os motores (prática) do que olhar para os motores e os quebra-cabeças por horas como eles fizeram isso.

Física

A noção completa de iterar todas as entidades e {pensar, desenhar} provavelmente levará a problemas. Haverá conflitos e assim por diante. Acredito que a Valve tenha Havok e acho que Havok cuida da física correta o suficiente.

Pensar

A função Think é executada quando um tempo em um jogo é igual ao tempo no nextthink . Funciona dessa maneira no mecanismo Quake, e o mecanismo Quake é a base dos mecanismos Half Life. NÃO é executado todas as vezes.

Internamente, deve ser uma iteração simples através de uma lista de entidades e verificar se já passou o tempo para chamar a função think. A complexidade do tempo será O (N), onde N é o número de entidades.

Se houver um número muito grande de entidades, você deve medir quanto melhorará os fps. Observe que, devido à lei de Amdahl , é uma aceleração potencialmente invisível. Quero dizer, você apenas percorre todos os itens e diminui e verifica um número.

Eu o aceleraria classificando entidades pelo nextthink (crie uma lista de ponteiros para entidades e classifique-a sempre; não uma matriz de entidades, porque as entidades podem alterar seu nextthink a qualquer momento, portanto, reorganizá-las na matriz leva O (N) em vez de O ( 1) na lista).

Você também deve consultar o planejador O (1) no Linux .

Desenhar

Motor desenha o que é aproximadamente visível da área em que a câmera está. O nível do jogo é particionado em uma árvore e uma área é a folha dessa árvore. Não vou incomodá-lo com detalhes sobre isso ... Então, se uma entidade é visível, ela é colocada em um conjunto de entidades visíveis e elas são desenhadas.

Eles armazenam quais áreas são áreas potencialmente visíveis. É chamado de "conjunto potencialmente visível", PVS, para abreviar. Há visualização do PVS , a cápsula verde é o jogador e ao seu redor é renderizado o que o seu PVS contém.


2

Portanto, se tudo o que precisa ser processado vier de uma classe base com a função think, o mecanismo de jogo poderá armazenar tudo em uma lista e, em todos os quadros, percorrê-lo e chamar essa função.

Em um primeiro olhar, essa ideia é razoável, mas pode levar muitos recursos, se o jogo tiver muitas entidades.

Na verdade, colocar tudo em uma grande lista geralmente é menos do que desejável; se você agrupar as entidades em listas com base, por exemplo, no tipo delas, poderá distribuir melhor o processamento por vários encadeamentos. Por exemplo, se você souber que todas as entidades do tipo Foo nunca interagem com outras entidades durante a fase de simulação, é possível descarregá-las completamente. Se eles estivessem espalhados por toda parte, em uma lista grande e singular, isso seria muito mais difícil de fazer.

Você nem precisa estar derivando tudo de uma classe base comum nesse ponto; A origem é exagerada com o abuso de herança pelo que poderia ser implementado como dados a esse respeito.

Obviamente, você sempre terá um limite superior no número de entidades que pode processar por quadro, mesmo se começar a descarregar o trabalho para outros núcleos. Não há como contornar isso, você só precisa ter uma idéia do que esse limite é na sua implementação e tomar medidas para aliviá-lo (seleção adequada das fases de processamento de objetos que não precisam deles, evitando excesso de granularidade nos objetos, etc. cetera).


1

O que você deve levar em consideração e seguir esta linha de pensamento das respostas anteriores é que seu desempenho também será quando e como você chama essas funções de pensamento.

Olhando para o link que você postou no mecanismo de origem, você também pode ler que pode configurar tempos de reflexão e diferentes contextos de reflexão para cada uma de suas entidades, além do óbvio limite rígido que alguém já apontou, essa será a chave para obter maior desempenho com um número maior de entidades, seja criando atualizações escalonadas que espalham o processamento com fome de desempenho por vários quadros de execução ou eliminando o processamento desnecessário, dependendo do contexto atual (ou seja, entidades que estão muito distantes ou além da percepção do jogador não precisam o mesmo nível de "pensar em detalhes" dos personagens próximos de um jogador simplesmente não vê um personagem a 3 km de distância, mordendo o nariz).

E há outros níveis mais específicos de otimização, dependendo da sua lógica e situação do jogo.


"um jogador simplesmente não vê um personagem a 3 km de distância, mordendo o nariz" Haha! Mas como é que ninguém aponta que o uso de funções virtuais é muito lento?
Tara
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.