Afin d'économiser de la bande passante dans mon jeu multijoueur , je ne mets pas à jour chaque objet à chaque tick du serveur, mais chaque objet a un updateRate qui indique au jeu que cet objet devrait être mis à jour à chaque tick du serveur X.
Lorsque je reçois un message de mise à jour pour un objet, je calcule l'heure à laquelle j'attends la prochaine mise à jour:
origin = serverCurrentPosition
diff = serverNextPosition - origin
arriveTime = now + timeBetweenTicks * updateRate
Lorsque je dessine l'objet, je calcule le temps restant jusqu'à la prochaine mise à jour et interpole la position en conséquence:
step = 100 / timeBetweenTicks * updateRate
delta = 1 - step * ((arriveTime - now) / 100)
position = origin + diff * delta
Cela fonctionne ... mais il y a encore un peu de gigue dans le dessin, bien que dans ma théorie, tout devrait fonctionner correctement, car la mise à l'échelle devrait prendre en charge un certain décalage, non?
Donc la question ici est, est-ce la meilleure approche? Dois-je mettre un retard réel dans le calcul? Si oui, comment ferais-je cela? J'ai fait quelques expériences, mais la gigue n'a fait qu'empirer.
la source
Réponses:
Vous avez de la gigue, car votre décalage est en constante évolution. Cela signifie que, bien que le serveur envoie des mises à jour exactement à chaque
timeBetweenTicks
tick, le client les reçoit après un certain temps variable. Ce temps est probablement proche d'timeBetweenTicks
une bonne connexion, mais pas exactement égal (et d'ailleurs, vous pouvez avoir un décalage de serveur et des vitesses d'horloge différentes sur le serveur et le client).Ainsi, lorsque vous comptez recevoir la mise à jour exactement à l'heure spécifiée, vous arrivez constamment à destination un peu avant / après la mise à jour réelle. Par conséquent, la gigue.
Une approche simple pour réduire la gigue consiste à utiliser des «élastiques», ce que Martin suggère dans une autre réponse. Fondamentalement, lorsque vous recevez une mise à jour, vous ne changez pas immédiatement la position de l'objet. Au lieu de cela, si la position du client et la position du serveur ne diffèrent que légèrement, vous commencez à interpoler la position du client, de sorte qu'après un certain temps (par exemple, à mi-chemin de la prochaine mise à jour), les positions du client et du serveur convergent.
Une autre idée pour réduire la gigue dans votre configuration: puisque vous transmettez les coordonnées "actuelles" et "suivantes", vous pouvez calculer la vitesse de l'objet. Ensuite, lorsque la mise à jour est en retard, vous n'arrêtez pas l'objet à sa destination (c'est-à-dire la position "suivante"), mais continuez à le déplacer avec la même vitesse. Si vos objets ne changent pas brusquement de vitesse, cela améliorera vraiment la fluidité du mouvement sur le client.
la source
J'ai résolu ce problème auparavant avec un certain succès avec une approche que j'appelle "ombres réseau". Je ne sais pas si c'est quelque chose que font les autres, mais ça a toujours fonctionné pour moi.
Chaque entité qui est synchronisée sur le réseau a une entité invisible de réseau invisible. Lorsqu'une mise à jour arrive du réseau, vous téléportez l'ombre directement à la position où le réseau devrait se trouver, puis vous interpolez lentement l'entité visible locale vers l'ombre au fil du temps.
J'ai inclus beaucoup de détails sur cette approche dans ma réponse précédente ici
la source
J'ai écrit un article détaillant une approche légèrement différente, qui produit des résultats très fluides: http://www.gabrielgambetta.com/fpm3.html
la source