Comment un moteur comme la source traite-t-il les entités?


9

Sur le moteur Source (et son prédécesseur, goldsrc, quake's), les objets du jeu sont divisés en deux types, le monde et les entités. Le monde est la géométrie de la carte et les entités sont des joueurs, des particules, des sons, des partitions, etc. (pour le moteur source).

Chaque entité a une fonction de réflexion , qui fait toute la logique de cette entité.

Donc, si tout ce qui doit être traité provient d'une classe de base avec la fonction think, le moteur de jeu pourrait tout stocker sur une liste et, sur chaque image, la parcourir et appeler cette fonction.

À première vue, cette idée est raisonnable, mais elle peut prendre trop de ressources, si le jeu a beaucoup d'entités.

Alors, comment un moteur comme Source prend-il en charge (traiter, mettre à jour, dessiner, etc.) les objets du jeu?


2
Pourquoi cela importe-t <some commercial engine>-il?
The Communist Duck

8
@ The Communist Duck, je pense que la vraie question ici est plutôt de savoir comment fonctionne un moteur performant pour que je puisse apprendre d'eux.
subb

Réponses:


5

Eh bien, il n'y a pratiquement pas d'autre moyen de le faire - vous devrez parcourir et appeler think()chaque entité au moins une fois toutes les quelques images.

Vous pouvez mettre des entités sur leur propre fil, mais vous avez ensuite tout le cauchemar de synchronisation d'état, ce qui n'en vaut certainement pas la peine.

À première vue, cette idée est raisonnable, mais elle peut prendre trop de ressources, si le jeu a beaucoup d'entités.

C'est pourquoi le moteur Source impose une limite stricte au nombre d'entités pouvant exister à la fois : 4096 entités, dont seulement la moitié (2048) peuvent être mises en réseau. Dépassez l'une de ces limites et le jeu se bloquera.

C'est aussi pourquoi, lors de la création d'une carte, ils vous recommandent de ne pas utiliser plus de 800 entités environ.


La fonction 2 ^ 12 n'est-elle pas toujours un GRAND numéro pour chaque trame?
JulioC

@ Júlio: Eh bien, à 60 images par seconde, cela représente 246 000 appels de fonction par seconde - c'est beaucoup, mais certainement faisable sur le matériel d'aujourd'hui. Rappelez-vous, cependant, que c'est le maximum absolu autorisé avant que le moteur source ne plante - généralement, il y a beaucoup moins d'entités sur une carte.
BlueRaja - Danny Pflughoeft

5
Les entités ont une prochaine réflexion, la fonction think n'est pas appelée everyframe et pas pour toutes les entités. Je me souviens que pour le séisme 2, le temps de réflexion minimum était de 0,1 (100 ms), seulement 10 images par seconde pour le traitement des entités.
bcsanches

"Vous pouvez mettre des entités sur leur propre fil, mais vous avez ensuite tout le cauchemar de synchronisation d'état, ce qui n'en vaut certainement pas la peine." Consultez ces diapositives Killzone 4 si vous pensez que cela n'en vaut pas la peine: de.slideshare.net/jrouwe/…
Tara

3

Ces étapes que vous mentionnez sont probablement effectuées dans des moteurs distincts. C'est juste que les moteurs de jeu simples les ont généralement en un seul passage. Votre séquence

for each object
    do physics
    do game logic
    draw

devient

call physics subsystem
call game logic subsystem
call drawing subsystem

Physics Engine s'occupe des positions et des tailles.

Game Logic Engine s'occupe d'interpréter ce que Physics Engine a changé (il pourrait obstruer certains points de cheminement ...), quels objectifs les personnages ont et quel comportement ils devraient faire , il exécute des scripts programmés (cette fonction de réflexion ).

Drawing Engine dessine quels objets sont visibles, et il sait quels objets sont visibles parce que les moteurs Quake trichent ici (voir la section Draw).

Je vous conseille plutôt d'étudier comment se font les simulations plutôt que les moteurs de jeux. Il existe une énorme culture pop liée au développement de jeux et les moteurs de jeux sont fabriqués dans des langues impératives (en raison de la tradition et de la vitesse); donc c'était plus instructif pour moi d'avoir de bons manuels (plutôt de la théorie) et PUIS de regarder les moteurs (s'entraîner) plutôt que de regarder les moteurs et de réfléchir pendant des heures comment ils l'ont fait.

La physique

Toute notion d'itération de toutes les entités et de {penser, dessiner} entraînera probablement des problèmes. Il y aura des conflits, etc. Je crois que Valve a Havok et je suppose que Havok s'occupe d'une physique suffisamment correcte.

Pense

Pense fonction de est exécutée lorsqu'un temps dans un jeu est égal au temps dans la pensée suivante . Il fonctionne de cette façon dans le moteur Quake, et le moteur Quake est la base des moteurs Half Life. Il n'est PAS exécuté à chaque fois.

En interne, cela devrait être une simple itération à travers une liste d'entités et vérifier si le temps a passé pour appeler la fonction think. La complexité temporelle sera O (N), où N est le nombre d'entités.

S'il y a un très grand nombre d'entités, vous devez mesurer dans quelle mesure cela améliorera les fps. Notez qu'en raison de la loi d' Amdahl, il s'agit d'une accélération potentiellement invisible. Je veux dire, vous venez de parcourir tous les articles et de diminuer et de vérifier un nombre.

Je l'accélérerais en triant les entités par nextthink (créer une liste de pointeurs vers les entités et la trier à chaque fois; pas un tableau d'entités, car les entités pourraient changer leur prochaine pensée à tout moment, donc les réorganiser dans le tableau prend O (N) au lieu de O ( 1) dans la liste).

Vous devriez également regarder le planificateur O (1) sous Linux .

Dessiner

Le moteur dessine ce qui est approximativement visible de la zone où se trouve la caméra. Le niveau du jeu est une partition en arbre, et une zone est une feuille de cet arbre. Je ne vais pas vous déranger avec des détails à ce sujet ... Donc, si une entité est visible, elle est placée dans un ensemble d'entités visibles et elles sont dessinées.

Ils stockent quelles zones sont des zones potentiellement visibles. Il est appelé "ensemble potentiellement visible", PVS pour faire court. Il y a visualisation de PVS , la capsule verte est un joueur et autour de lui est rendu ce que contient son PVS.


2

Donc, si tout ce qui doit être traité provient d'une classe de base avec la fonction think, le moteur de jeu pourrait tout stocker sur une liste et, sur chaque image, la parcourir et appeler cette fonction.

À première vue, cette idée est raisonnable, mais elle peut prendre trop de ressources, si le jeu a beaucoup d'entités.

En fait, tout mettre dans une grande liste est généralement moins que souhaitable; si vous deviez regrouper les entités dans des listes en fonction, par exemple, de leur type, vous pourriez mieux répartir le traitement sur plusieurs threads. Par exemple, si vous savez que toutes les entités de type Foo n'interagissent jamais avec d'autres entités pendant la phase de simulation, vous pouvez les décharger entièrement. S'ils étaient dispersés bon gré mal gré dans une grande liste singulière, ce serait beaucoup plus difficile à faire.

Vous n'avez même pas nécessairement besoin de tout dériver d'une classe de base commune à ce stade; La source va assez loin avec l'abus d'héritage pour ce qui pourrait autrement être mis en œuvre en tant que données à cet égard.

Vous aurez bien sûr toujours une limite supérieure sur le nombre d'entités que vous pouvez traiter par trame, même si vous commencez à décharger le travail vers d'autres cœurs. Il n'y a aucun moyen de contourner cela, vous avez juste besoin d'avoir une idée de cette limite dans votre implémentation et de prendre des mesures pour la réduire (élimination appropriée des phases de traitement sur les objets qui n'en auront pas besoin, en évitant une granularité excessive des objets, et cetera).


1

Ce que vous devez prendre en compte et cela en suivant la réflexion des réponses précédentes, c'est que votre performance dépendra également du moment et de la façon dont vous appelez ces fonctions de réflexion.

En regardant le lien que vous avez publié sur le moteur source, vous pouvez également lire que vous pouvez configurer des temps de réflexion et des contextes de réflexion différents pour chacune de vos entités, en plus de la limite évidente que quelqu'un a déjà signalée, ce sera la clé pour obtenir de meilleures performances avec un nombre plus élevé d'entités, soit en créant des mises à jour progressives qui répartissent le traitement avide de performances sur plusieurs cadres d'exécution, soit en supprimant les traitements inutiles en fonction du contexte actuel (c'est-à-dire les entités qui sont trop éloignées ou au-delà de la perception des joueurs n'ont pas besoin le même niveau de «penser en détail» que les personnages proches, un joueur ne verra tout simplement pas un personnage à 2 miles de là se cueillir le nez).

Et il existe d'autres niveaux d'optimisation plus spécifiques en fonction de la logique et de la situation de votre jeu.


"un joueur ne verra tout simplement pas un personnage à 2 miles de là se cueillir le nez" Haha! Mais comment se fait-il que personne ne souligne que l'utilisation des fonctions virtuelles est très lente?
Tara
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.