Comment puis-je empêcher le lecteur de dériver en raison de la prédiction d'entrée locale lorsqu'il s'arrête?

14

Je travaille sur un moteur de jeu multijoueur serveur-client 2D (que vous pouvez essayer ici ). Il utilise les WebRTC DataChannel. (Les connexions sont peer-to-peer, mais l'homologue hôte agit toujours comme un serveur.)

Le plus gros problème (en dehors de la connectivité) est la prédiction d'entrée locale. Nous faisons comme d'habitude: à la pression des touches, les joueurs se déplacent instantanément, indiquent à l'hôte quelles touches sont pressées, reçoivent les données de l'hôte et les comparent à la position historique. La position est corrigée dans le temps en cas de différence. Cela fonctionne bien avec une faible perte de paquets ou PDV , même si le ping est élevé.

S'il y a perte ou PDV, l'écart peut être plus important. Je pense que cela est dû au fait que si le premier paquet indiquant un changement d'entrée est retardé ou abandonné, l'hôte le découvre plus tard et commence à changer ce joueur plus tard que ne le montre sa prédiction d'entrée locale.

Si le joueur bouge, nous augmentons le montant de la correction appliquée, car elle est moins perceptible. Cela semble combler les lacunes lors du démarrage et pendant le déplacement. Cependant, toute correction est plus visible si elles s'arrêtent brusquement. Ensuite, si le PDV ou la perte signifie que l'hôte pense qu'il s'est arrêté plus tard, l'hôte dépasse, renvoie des données disant qu'il est un peu plus avancé, et la correction fait dériver un peu le joueur. Sur les connexions instables, les joueurs dérivent souvent de manière notable après s'être arrêtés.

Je ne l'ai pas remarqué dans d'autres jeux. Comment cela peut-il être atténué?

AshleysBrain
la source
3
Un jeu P2P qui a un serveur? Il y a quelque chose de mal ici.
API-Beast
Oups, par «serveur», je veux dire «l'hôte homologue».
AshleysBrain
2
Eh bien, cela ne ressemble pas non plus à un modèle d'égal à égal, simplement parce que l'un des joueurs se présente comme le serveur ne le fait pas d'égal à égal. La technique que vous utilisez est définitivement une technique Client-Serveur. Dans le P2P, vous faites entièrement confiance à tous les clients (par exemple, chaque pair se demande à l'autre pair où se trouve son joueur) ou vous ne faites confiance à aucun (par exemple, vous retardez l'entrée jusqu'à ce que tous les pairs l'aient reçue).
API-Beast
Ah ... c'est un bon point en fait ... je me suis mélangé: les connexions sont peer-to-peer (ce que fait WebRTC), mais le moteur lui-même est serveur-client (l'un des pairs est juste le serveur ). Bon point.
AshleysBrain
2
Ce que cela me fait penser est notre propre Andrew Russell de bâton Ninjas journaux de dev sur YouTube , en particulier celui - ci sur la correction des erreurs de prédiction . La dérive que vous décrivez ressemble beaucoup à ce qui se passe dans cette vidéo et Andrew raconte les détails. Est-ce lié ou peut-être même le même problème?
Anko

Réponses:

8

La couche réseau doit avoir une horloge convenue. Ils peuvent s'entendre sur une valeur d'horloge au début du jeu (et la resynchroniser périodiquement en cas de dérive) afin que l'hôte sache combien de temps un paquet particulier a pris pour arriver réellement et quand le client a fait l'action, et vice versa.

Consultez cet article pour une façon possible de synchroniser les horloges dans les jeux. Il y en a d'autres. Les moyens spécifiques n'ont pas d'importance.

La seconde moitié du problème est que le serveur applique l'entrée après le moment où le client a cessé d'appliquer l'entrée. Cela nécessite un tampon des mouvements passés sur le serveur et une certaine logique sur le client pour ignorer les entrées de mouvement du serveur après le dernier mouvement connu.

Tout d'abord, le tampon du serveur. Le serveur doit garder une trace de l'horodatage de la dernière entrée reçue du lecteur. Il a également besoin de tous les mouvements qu'il applique à un joueur, l'horodatage du mouvement. Si une entrée est reçue, tous les mouvements récents appliqués avec une horloge plus récente que le paquet d'entrée sont supprimés et tout mouvement est réappliqué à partir du paquet d'entrée. Par conséquent, si le serveur sur-déplace le joueur sur la base d'une entrée, l'entrée mise à jour annulera ces mouvements et la nouvelle position du joueur sera basée sur la connaissance d'entrée la plus récente du serveur.

Côté client, le client sait quand il a envoyé la dernière entrée au serveur. Étant donné que chaque mise à jour du lecteur à partir du serveur aurait dû être marquée avec l'horloge de la dernière entrée que le serveur connaissait, le client peut ignorer les mises à jour du serveur qui ont une balise d'entrée expirée et s'en tenir à la prédiction du client. Finalement, de nouvelles mises à jour de serveur arriveront avec une entrée à jour et le client pourra les corriger.

Le serveur doit valider les horloges d'entrée et s'assurer qu'elles ne dérivent pas trop des attentes pour éviter de tricher. L'horloge d'entrée ne doit pas être considérablement plus grande que le temps demi-aller-retour que vous devez calculer. Serrez ceux qui sont dans une plage raisonnable ( [Now-2*RTT,Now]par exemple).

Les clients verront beaucoup de gigue des avatars des autres joueurs si la latence est élevée, car ils obtiendront des mises à jour du serveur en fonction de l'entrée périmée, mais n'auront aucun moyen de savoir qu'elle est périmée, puis le serveur pourrait commencer à envoyer des emplacements assez différents en fonction de l'entrée mise à jour qu'il a reçue (et sa suppression d'une partie de son historique et sa relecture avec la nouvelle entrée). Ce dernier problème avec d'autres joueurs voyant votre gigue d'avatar n'est pas vraiment réparable. La latence est nulle et les joueurs bloqués sur des connexions à haute latence vont voir beaucoup de tremblements des autres joueurs, même si leur propre joueur se déplace en douceur. La seule correction est de jouer sur de meilleures connexions ou avec des pairs / serveurs avec moins de latence.

Sean Middleditch
la source
1

J'ai utilisé des messages UDP fiables pour indiquer les changements d'état des boutons et des messages UDP peu fiables pour la correction de position. Fondamentalement, les articles suivants m'ont beaucoup aidé: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

Il indique la prédiction de mouvement en stockant les états du joueur dans des intervalles de temps constants en fonction de l'arrivée des messages de correction de position pendant environ 20 ou 30 sauvegardes d'état. Il semble donc que vos joueurs distants vivront dans un réel "passé" pas si loin en appliquant constamment une technique de prédiction :) En fonction de la latence nette du message, vous pouvez obtenir la position de votre objet environ à temps lorsque le message vient d'être envoyé par l'hôte.

La position actuelle "à l'écran" peut être ensuite traduite en douceur dans la position prédite en utilisant les calculs Lerp (interpolation linéaire). L'idée est d'interpoler des valeurs dans les intervalles de temps entre les paquets de correction. Il semble donc que l'objet affiché se déplace toujours vers une position prédite. Pour la valeur d'interpolation, je prends le 1 divisé par "latence de message moyenne" divisé par "temps de rendu de trame moyen" pour que le mouvement soit fluide.

Dans ce scénario, le jeu calcule sur tous les clients et le serveur corrige de temps en temps les valeurs telles que la vitesse et la position.

La dernière chose qui aide beaucoup dans ce cas: optimisez votre logique de jeu afin de pouvoir facilement annuler les effets de latence en vous assurant que le serveur et les clients peuvent émuler un comportement presque similaire en fonction de l'entrée du joueur.

J'ai décrit l'ensemble du schéma que j'ai utilisé dans mon projet, j'espère donc que vous trouverez la réponse à votre question.

Alexander Smirnov
la source