Exécuter une simulation physique sur le client et le serveur?

13

J'implémente un clone d'astéroïdes multijoueur pour en savoir plus sur l'architecture réseau client / serveur dans les jeux. J'ai passé du temps à lire les publications de GafferOnGames et Valve sur leur technologie client / serveur. J'ai des problèmes avec deux concepts.

  1. Actuellement, j'ai un serveur de jeu faisant autorité qui simule la physique avec box2d et envoie l'état du monde aux clients environ 20 fois par seconde. Chaque client garde une trace des derniers instantanés qu'il a reçus et lerps entre deux états pour lisser le mouvement des sprites. Mais ce n'est pas si simple. Il peut être lisse pendant un certain temps, puis saccadé un peu, puis revenir à lisse, etc. J'ai essayé à la fois TCP et UDP, les deux sont à peu près les mêmes. Une idée de mon problème? (Remarque: j'ai d'abord implémenté cela pour le mode solo, et le mouvement des sprites est parfaitement fluide à 60 images par seconde lors de la mise à jour du monde physique seulement 20 fois par seconde).

  2. Afin de résoudre le premier problème, j'ai pensé que le client devrait peut-être également exécuter une simulation box2d et simplement mettre à jour les positions de ses sprites pour correspondre aux instantanés du serveur lorsqu'ils ne correspondent pas. Je pensais que cela pourrait être plus fluide car mon implémentation en mode solo est fluide. Est-ce une bonne idée?

    Même si cela ne résout pas le problème ci-dessus, est-ce nécessaire pour la prédiction côté client? Par exemple, si un joueur tente de déplacer son vaisseau, comment saura-t-il s'il frappe un astéroïde, un mur ou un vaisseau ennemi sans simulation physique? Il semble que leur vaisseau semble traverser l'objet avec lequel il devrait entrer en collision avant de recevoir un instantané du serveur indiquant qu'ils ont heurté l'objet.

Merci!

Venesectrix
la source

Réponses:

10

Exécutez définitivement la simulation sur les clients et le serveur. Le reste a une latence trop longue. Vous devez vous assurer que les simulations correspondent en insérant des objets dans le même ordre, en utilisant un pas de temps fixe et en évitant la comparaison de pointeurs. Je n'ai pas essayé cela avec Box2D mais il est généralement possible d'obtenir le même comportement sur toutes les machines dans une simulation physique. Toutes les mathématiques sont généralement basées sur des flottants binaires32 IEEE 754 et leur comportement est strictement défini pour des opérations telles que +-*/pour n'en nommer que quelques-unes. Vous devez faire attention sin,coset les goûts difficiles, car ils peuvent différer entre les exécutions (cela est particulièrement important lors du développement pour plusieurs plates-formes). Assurez-vous également que vous utilisez un paramètre strict pour les optimisations flottantes dans votre compilateur. Vous pouvez toujours synchroniser des objets en envoyant périodiquement l'état des objets depuis le serveur. Ne mettez pas à jour sauf si la différence est supérieure à un seuil pour éviter un bégaiement inutile.

Un problème qui me vient à l'esprit est la création de nouveaux objets et comment cela va changer la simulation entre les clients. Une façon de résoudre ce problème consiste à laisser le serveur créer tous les objets. Si le pas de temps actuel est t, le serveur planifiera l'ajout d'un objet à t+d. Ainsi, une liste de nouveaux objets, avec des objets à ajouter et quand les ajouter, peut être maintenue sur tous les clients et mise à jour par le serveur bien à l'avance. Si dest assez grand, vous minimisez le risque de résultats différents. Si vous ne pouvez vraiment pas gérer la différence, vous pouvez forcer un client à attendre des informations sur de nouveaux objets pendant un certain pas de temps avant de simuler ce pas de temps.

rasmus
la source
Merci pour votre réponse. Je ne pense pas que box2d soit garanti pour générer les mêmes résultats sur différents processeurs, ce qui serait le scénario pour nous puisque nous écrivons un jeu de bureau. J'espère que les différences seront infimes et facilement corrigibles avec des mises à jour périodiques d'un serveur faisant autorité, mais je ne l'ai jamais essayé.
Venesectrix
Erin Catto pense qu'essayer de garder l'ensemble de l'état de plusieurs mondes Box2D synchronisés est une bataille perdue ( box2d.org/forum/viewtopic.php?f=3&t=8462 )
Pavel
L'instruction «Le comportement des flottants binaires32 IEEE 754 [..] est strictement défini pour des opérations telles que +-*/» est complètement fausse. Toutes ces opérations dans IEEE-754 peuvent varier en fonction de la mise en œuvre. Voir ici et ici pour plus d'informations.
BlueRaja - Danny Pflughoeft
1
Non, c'est tout à fait vrai. Le problème décrit par votre lien est lié aux différents modes du processeur x87 et aux implémentations des transcendantaux. IEEE 754 binary32 est strictement défini pour les opérations de base. C'est à vous de définir les bons modes et d'utiliser les bonnes instructions pour que la norme soit respectée. La simple utilisation des instructions SSE et non du processeur x87 aide beaucoup.
rasmus
4

Cela ne semble probablement pas si bon, car l'interpolation entre eux repose sur le fait d'avoir toujours le prochain ensemble de données à interpoler. Cela signifie que, s'il y a une courte pointe de décalage, tout doit attendre pour rattraper le retard.

Il y a un ancien article sur GameDev sur l'utilisation de splines cubiques pour prédire la position d'un objet au-delà du point où vous aviez pour la dernière fois des données. Vous utilisez ensuite cette position, puis ajustez la spline lorsque vous obtenez de nouvelles données pour tenir compte de sa nouvelle position. C'est aussi probablement beaucoup moins cher que d'exécuter une deuxième simulation physique, et cela signifie que vous n'avez pas à décider à qui vous faites confiance, car vous avez explicitement implémenté le client en le constituant au fur et à mesure. :)

Matt Kemp
la source
Ce pourrait être le cas. Ce que j'essaie de faire, c'est de retarder jusqu'à ce que j'aie reçu 3 instantanés du serveur. Au point je lerp du plan 1 au plan 2. Puis du plan 2 au plan 3. Si à un moment donné je manque un paquet, je peux lerp de 1 à 3, au lieu de 1 à 2, si cela a du sens. Je ne suis peut-être pas encore en train de l'implémenter correctement. Merci pour le lien vers l'article!
Venesectrix
1

J'ai fait des trucs similaires moi-même, et j'ai exécuté Box2D uniquement sur les clients. La façon dont je l'ai fait était de laisser le client exécuter sa propre simulation à peu près de lui-même, en envoyant la vitesse actuelle (et la rotation) sur chaque paquet de synchronisation au serveur. Le serveur envoie ensuite ces informations à d'autres joueurs, qui définissent les vitesses nouvellement reçues aux entités répliquées. C'était très fluide, sans aucune différence notable entre les clients.

Bien sûr, le problème ici est qu'il n'y a pas de contrôle centralisé sur les entités, mais je pense que cela pourrait également être fait côté serveur en faisant une simulation côté physique de la physique

manabreak
la source
Merci pour votre contribution. Nous aurons besoin d'un contrôle centralisé pour éviter la triche, nous devons donc avoir au moins le serveur exécutant une simulation pour savoir si ce que les clients disent qu'ils font est possible ou non.
Venesectrix
1

Je préférerais personnellement exécuter les simulations uniquement sur le serveur et lui faire diffuser les changements sur les vitesses / accélérations linéaires / angulaires des objets impliqués chaque fois qu'ils se produisent. C'est, quand un certain objet, pour une raison quelconque, change l'une de ses propriétés physiques (telles que les vitesses et accélérations susmentionnées), cette modification spécifique sera envoyée du serveur au client, et le client changera son côté de la les données de l'objet en conséquence.

L'avantage de celui-ci sur votre implémentation actuelle est qu'il annulera la nécessité d'interpolations côté client et générera un comportement très fidèle sur les objets. Le problème est que cette méthode est assez vulnérable aux latences, qui deviennent un très gros problème lorsque les joueurs sont géographiquement trop éloignés les uns des autres.

Quant à la question 1, je dis que le problème serait les fluctuations de la latence, car il n'y a aucune garantie absolue qu'il y aura un intervalle de 20 secondes exactement parfait entre chaque réception de l'instantané. Permettez-moi d'illustrer (étant "t" le temps mesuré en millisecondes):

1) À t = 20 depuis le début du jeu, le client a reçu un instantané et a effectué l'interpolation avec succès et en douceur.

2) À t = 40, il y avait une latence entre le serveur et le client, et l'instantané n'arrivait réellement qu'à t = 41.

3) À t = 60, le serveur a envoyé un autre instantané, mais une seconde de la simulation a été gaspillée côté client en raison de la latence. Si l'instantané arrive à t = 60, le client ne fera pas une interpolation des 40 et 60 instants, mais en fait des instants 41 à 60, générant un comportement différent. Cette inexactitude pourrait être à l'origine de la "secousse" éventuelle.

En ce qui concerne la question 2, votre idée pourrait fonctionner si vous implémentez quelque chose qui suivra efficacement si chaque objet est vraiment synchronisé client-serveur sans avoir à envoyer des packages à chaque trame en informant la position des objets. Même si vous le faites à des intervalles discrets, vous exécuterez non seulement le même problème de la question 1, mais vous aurez également de trop grandes quantités de données à transférer (ce qui est une mauvaise chose).

UBSophung
la source
Je ne suis pas sûr de suivre ce que vous dites dans votre premier paragraphe. Si la simulation s'exécute uniquement sur le serveur et que vous diffusez uniquement les changements de vitesse / accélération, alors comment le client sait-il où les sprites doivent être dessinés? Les clients devraient simuler les objets en fonction de la vitesse / accélération reçue afin de les dessiner correctement. Je pense que vous avez peut-être raison de recevoir des instantanés à des intervalles autres que ceux que j'attends. Une idée de comment gérer ça?
Venesectrix
Les clients connaissent les positions, vitesses et accélérations initiales et actuelles des objets et mettront à jour la position qu'il pense que les objets sont (indépendamment du serveur) en conséquence. Le serveur finira par changer ces propriétés sur les clients par le biais de messages, car c'est le serveur qui fait la physique et la détection des collisions (qui sont appelés à changer tôt ou tard la vitesse / accélération et la direction de l'objet donné)
UBSophung