Je suis intéressé à évaluer les différentes façons dont le netcode peut "se connecter" à un moteur de jeu. Je suis en train de concevoir un jeu multijoueur maintenant, et jusqu'à présent, j'ai déterminé que je dois (au moins) avoir un thread séparé pour gérer les sockets réseau, distinct du reste du moteur qui gère la boucle graphique et les scripts.
J'avais un moyen potentiel de créer un jeu en réseau entièrement monothread, qui consiste à le faire vérifier le réseau après le rendu de chaque image, en utilisant des sockets non bloquants. Cependant, ce n'est clairement pas optimal car le temps nécessaire pour rendre une trame est ajouté au décalage du réseau: les messages arrivant sur le réseau doivent attendre la fin du rendu de la trame actuelle (et de la logique du jeu). Mais, au moins de cette façon, le gameplay resterait plus ou moins fluide.
Le fait d'avoir un thread séparé pour la mise en réseau permet au jeu d'être complètement réactif au réseau, par exemple, il peut renvoyer un paquet ACK instantanément à la réception d'une mise à jour d'état du serveur. Mais je suis un peu confus quant à la meilleure façon de communiquer entre le code du jeu et le code réseau. Le thread de mise en réseau poussera le paquet reçu dans une file d'attente, et le thread de jeu lira à partir de la file d'attente au moment approprié au cours de sa boucle, nous ne nous sommes donc pas débarrassés de ce délai d'une trame.
En outre, il semble que je souhaiterais que le thread qui gère l'envoi de paquets soit distinct de celui qui vérifie les paquets qui descendent, car il ne pourrait pas en envoyer un lorsqu'il est au milieu de vérifier s'il y a des messages entrants. Je pense à la fonctionnalité de select
ou similaire.
Je suppose que ma question est, quelle est la meilleure façon de concevoir le jeu pour la meilleure réactivité du réseau? De toute évidence, le client doit envoyer l'entrée utilisateur dès que possible au serveur, afin que je puisse faire venir le code net-send immédiatement après la boucle de traitement des événements, à la fois à l'intérieur de la boucle de jeu. Est-ce que cela a un sens?
la source
Non, non.
Cela n'a pas forcément d'importance. Quand votre logique est-elle mise à jour? Il est inutile de retirer des données du réseau si vous ne pouvez pas encore en faire quoi que ce soit. De même, il est inutile de répondre si vous n'avez encore rien à dire.
Si votre jeu est si rapide qu'attendre que la prochaine image soit rendue est un retard important, alors il va envoyer suffisamment de données que vous n'avez pas besoin d'envoyer de paquets ACK séparés - incluez simplement les valeurs ACK dans vos données normales charges utiles, si vous en avez besoin.
Pour la plupart des jeux en réseau, il est parfaitement possible d'avoir une boucle de jeu comme celle-ci:
Vous pouvez dissocier les mises à jour du rendu, ce qui est fortement recommandé, mais tout le reste peut à peu près rester aussi simple, sauf si vous avez un besoin spécifique. Quel genre de jeu faites-vous exactement?
la source
Ce n'est pas vrai du tout. Le message passe sur le réseau pendant que le récepteur restitue la trame actuelle. Le retard du réseau est limité à un nombre entier de trames côté client; oui, mais si le client a si peu de FPS que c'est un gros problème, alors il a de plus gros problèmes.
la source
Les communications réseau doivent être groupées. Vous devez vous efforcer d'obtenir un seul paquet envoyé à chaque tick de jeu (ce qui est souvent le cas lors du rendu d'une trame, mais devrait vraiment être indépendant).
Vos entités de jeu parlent avec le sous-système réseau (NSS). Le NSS regroupe les messages, les ACK, etc. et envoie quelques (espérons-le un) paquets UDP de taille optimale (~ 1500 octets en général). Le NSS émule les paquets, les canaux, les priorités, les renvois, etc. tout en n'envoyant que des paquets UDP uniques.
Lisez le gaffer sur le tutoriel des jeux ou utilisez simplement ENet qui implémente de nombreuses idées de Glenn Fiedler.
Ou vous pouvez simplement utiliser TCP si votre jeu n'a pas besoin de réactions de contraction. Ensuite, tous les problèmes de traitement par lots, renvoyés et ACK disparaissent. Cependant, vous souhaitez toujours qu'un NSS gère la bande passante et les canaux.
la source
N'ignorez pas complètement la réactivité. Il y a peu à gagner à ajouter une autre latence de 40 ms à des paquets déjà retardés. Si vous ajoutez quelques images (à 60 images par seconde), vous retardez le traitement d'une mise à jour de position d'un autre couple d'images. Il est préférable d'accepter les paquets rapidement et de les traiter rapidement afin d'améliorer la précision de la simulation.
J'ai eu beaucoup de succès à optimiser la bande passante en réfléchissant aux informations d'état minimum nécessaires pour représenter ce qui est visible à l'écran. Ensuite, en regardant chaque bit de données et en choisissant un modèle pour cela. Les informations de position peuvent être exprimées sous forme de valeurs delta dans le temps. Vous pouvez soit utiliser vos propres modèles statistiques pour cela et passer des années à les déboguer, soit utiliser une bibliothèque pour vous aider. Je préfère utiliser le modèle à virgule flottante de cette bibliothèque DataBlock_Predict_Float Cela facilite vraiment l'optimisation de la bande passante utilisée pour le graphique de la scène du jeu.
la source