La version avancée de Little Bee extrait actuellement la logique de synchronisation de trame dans le SDK, veuillez consulter le projet https://github.com/dudu502/littlebee_libs Il s'agit d'un exemple de jeu de synchronisation de trame, synchronisant des centaines d'objets et des milliers d'états dans le jeu. L'arrière-plan du jeu est un jeu de tir sous un système planétaire. Voici le lien vidéo.
[Regardez la vidéo (YouTube)]
[Regardez la vidéo en replay (YouTube)]
[Regarder la vidéo(bilibili)]
[Regarder la rediffusion de la vidéo(bilibili)]
Synchronisation des trames | Synchronisation d'état | |
---|---|---|
cohérence | Le niveau de conception détermine l’inévitable cohérence | Peut garantir la cohérence |
Nombre de joueurs | Prise en charge multijoueur limitée | Plusieurs joueurs ont des avantages |
Multiplateforme | Nécessité de prendre en compte la cohérence des opérations en virgule flottante | Étant donné que les principaux calculs sont effectués sur le serveur, il n’y a aucun problème multiplateforme. |
Anti-triche | Facile à tricher, mais peut être optimisé | Peut être très efficace pour empêcher la tricherie |
Déconnecter et reconnecter | C’est difficile à mettre en œuvre, mais ce n’est pas impossible | Il vous suffit de renvoyer le message une seule fois, facile à mettre en œuvre |
Exigences de lecture | peut être parfaitement réalisé | Impossible d'atteindre |
mettre le jeu en pause | Facile à mettre en œuvre | Pas facile à mettre en œuvre |
Volume de transmission du réseau | relativement petit | relativement grand |
Difficulté de développement | relativement complexe | relativement simple |
Jeux RTS | Approprié | Ne convient pas |
jeux de combat | Approprié | Ne convient pas |
Jeux MOBA | Approprié | Ne convient pas |
Jeux MMO | Ne convient pas | Approprié |
Après avoir compris les difficultés qui doivent être surmontées dans le processus de développement de la synchronisation de trames, nous envisagerons ensuite de choisir une meilleure méthode de mise en œuvre, ou un cadre de développement. Étant donné que le développement de la synchronisation de trames nécessite la séparation des données et des performances, dans quelle mesure doit-elle être séparée ? La partie calcul des données peut même être placée dans un thread séparé. L'avantage d'écrire la logique de cette manière est qu'elle permet également au serveur de fonctionner pour réaliser la fonction de relecture rapide du jeu. Je pense que seul ECS peut atteindre ce niveau de séparation. La synchronisation de trames et ECS sont absolument un partenaire parfait.
Tout d’abord, nous devons introduire ECS. ECS n’est pas une toute nouvelle technologie et n’a pas non plus été proposé pour la première fois par Unity. Ce terme est apparu très tôt, et il est devenu soudainement populaire ces dernières années grâce à « Overwatch » de Blizzard. Les frameworks serveur et client de « Overwatch » sont entièrement construits sur la base d'ECS et offrent d'excellentes performances en termes de mécanique de jeu, de réseau et de rendu. Franchement, ECS n'est pas comme un modèle de conception. Les modèles de conception que nous avons utilisés auparavant ont tous été discutés dans le cadre de la conception orientée objet, et ECS n'est pas orienté objet. Unity a également un ECS. En fait, les propres composants de Unity sont également une sorte d'ECS, mais ils ne sont pas assez purs. ECS est particulièrement adapté au Gameplay. Il existe de nombreuses variantes d'ECS, et voici ECS avec quelques légères modifications.
Il s'agit d'une fonctionnalité des jeux à synchronisation d'images. Si un jeu dispose d'un système de relecture, alors le jeu doit être implémenté via la synchronisation d'images. La lecture peut également être appelée enregistrement vidéo, mais elle est très différente de la lecture utilisant des fichiers vidéo, car le support occupe généralement un fichier volumineux et la fenêtre ne peut pas être commutée pendant le processus de lecture. Les vidéos sont facilement volées, mal intentionnées ou malveillantes. qualité modifiée, compressée et dégradée, la lecture vidéo présente donc un gros inconvénient. La lecture synchronisée par image peut rendre le fichier extrêmement petit et ne peut pas être falsifié. Les utilisateurs peuvent changer de fenêtre à volonté pendant le processus de lecture. On peut dire que le système nécessaire aux jeux de synchronisation d'images est le système de relecture.
RevenantX/LiteNetLib est recommandé ici. Cette bibliothèque est très puissante et simple à utiliser. Elle fournit une transmission UDP fiable, ce qui est exactement ce que je souhaite. Il existe de nombreux protocoles de données parmi lesquels choisir pour la communication réseau. J'utilise un protocole de flux binaire créé par moi-même. Les fonctions principales sont la sérialisation et la désérialisation. Les champs de la structure sont facultatifs. Comme cette structure PtRoom :
//Template auto generator:[AutoGenPt] v1.0
//Creation time:2021/1/28 16:43:48
using System ;
using System . Collections ;
using System . Collections . Generic ;
namespace Net . Pt
{
public class PtRoom
{
public byte __tag__ { get ; private set ; }
public uint RoomId { get ; private set ; }
public byte Status { get ; private set ; }
public uint MapId { get ; private set ; }
public string RoomOwnerUserId { get ; private set ; }
public byte MaxPlayerCount { get ; private set ; }
public List < PtRoomPlayer > Players { get ; private set ; }
public PtRoom SetRoomId ( uint value ) { RoomId = value ; __tag__ |= 1 ; return this ; }
public PtRoom SetStatus ( byte value ) { Status = value ; __tag__ |= 2 ; return this ; }
public PtRoom SetMapId ( uint value ) { MapId = value ; __tag__ |= 4 ; return this ; }
public PtRoom SetRoomOwnerUserId ( string value ) { RoomOwnerUserId = value ; __tag__ |= 8 ; return this ; }
public PtRoom SetMaxPlayerCount ( byte value ) { MaxPlayerCount = value ; __tag__ |= 16 ; return this ; }
public PtRoom SetPlayers ( List < PtRoomPlayer > value ) { Players = value ; __tag__ |= 32 ; return this ; }
public bool HasRoomId ( ) { return ( __tag__ & 1 ) == 1 ; }
public bool HasStatus ( ) { return ( __tag__ & 2 ) == 2 ; }
public bool HasMapId ( ) { return ( __tag__ & 4 ) == 4 ; }
public bool HasRoomOwnerUserId ( ) { return ( __tag__ & 8 ) == 8 ; }
public bool HasMaxPlayerCount ( ) { return ( __tag__ & 16 ) == 16 ; }
public bool HasPlayers ( ) { return ( __tag__ & 32 ) == 32 ; }
public static byte [ ] Write ( PtRoom data )
{
using ( ByteBuffer buffer = new ByteBuffer ( ) )
{
buffer . WriteByte ( data . __tag__ ) ;
if ( data . HasRoomId ( ) ) buffer . WriteUInt32 ( data . RoomId ) ;
if ( data . HasStatus ( ) ) buffer . WriteByte ( data . Status ) ;
if ( data . HasMapId ( ) ) buffer . WriteUInt32 ( data . MapId ) ;
if ( data . HasRoomOwnerUserId ( ) ) buffer . WriteString ( data . RoomOwnerUserId ) ;
if ( data . HasMaxPlayerCount ( ) ) buffer . WriteByte ( data . MaxPlayerCount ) ;
if ( data . HasPlayers ( ) ) buffer . WriteCollection ( data . Players , ( element ) => PtRoomPlayer . Write ( element ) ) ;
return buffer . Getbuffer ( ) ;
}
}
public static PtRoom Read ( byte [ ] bytes )
{
using ( ByteBuffer buffer = new ByteBuffer ( bytes ) )
{
PtRoom data = new PtRoom ( ) ;
data . __tag__ = buffer . ReadByte ( ) ;
if ( data . HasRoomId ( ) ) data . RoomId = buffer . ReadUInt32 ( ) ;
if ( data . HasStatus ( ) ) data . Status = buffer . ReadByte ( ) ;
if ( data . HasMapId ( ) ) data . MapId = buffer . ReadUInt32 ( ) ;
if ( data . HasRoomOwnerUserId ( ) ) data . RoomOwnerUserId = buffer . ReadString ( ) ;
if ( data . HasMaxPlayerCount ( ) ) data . MaxPlayerCount = buffer . ReadByte ( ) ;
if ( data . HasPlayers ( ) ) data . Players = buffer . ReadCollection ( ( rBytes ) => PtRoomPlayer . Read ( rBytes ) ) ;
return data ;
}
}
}
}
Il s'agit d'un projet Unity basé sur la synchronisation de trames
Quelques outils : outil de génération de structure Pt, outil de génération Excel2Json, projet de bibliothèque générale, projet de bibliothèque ServerDll
Documents de conception : documents de conception générale, documents de conception de prototypes, tableaux de configuration.
Les trois figures suivantes décrivent l'utilisation du simulateur de synchronisation de trame dans trois scénarios différents.
La figure ci-dessous montre le comportement général du client et du serveur en même temps, et la logique de lecture correspond également au même comportement.
Cette image montre le client et le serveur exécutant la logique dans chaque TICK logique. La partie supérieure est le client. La logique que le client doit exécuter inclut la partie ECSR et la partie inférieure est la partie serveur.
La dernière image décrit chaque image logique de la lecture.
Grâce à ces images et aux types spécifiques de jeux, nous pouvons configurer un système et un composant personnalisés pour gérer la logique associée.
Il s'agit d'un projet de collecte de services, comprenant WebServer, GateServer, RoomServer, etc.