Eine erweiterte Version von little bee extrahiert derzeit die Frame-Synchronisationslogik in das SDK, siehe Projekt https://github.com/dudu502/littlebee_libs Dies ist ein Beispiel für ein Frame-Synchronisationsspiel, bei dem Hunderte von Objekten und Tausende von Zuständen im Spiel synchronisiert werden Der Hintergrund des Spiels ist ein Schießspiel unter einem Planetensystem. Nachfolgend finden Sie den Videolink.
[Sehen Sie sich das Video an (Youtube)]
[Sehen Sie sich die Wiedergabe des Videos an (Youtube)]
[Sehen Sie sich die Wiedergabe des Videos an (bilibili)]
[Sehen Sie sich die Wiedergabe des Videos an (bilibili)]
Frame-Synchronisation | Zustandssynchronisation | |
---|---|---|
Konsistenz | Die Gestaltungsebene bestimmt die unvermeidliche Konsistenz | Kann Konsistenz garantieren |
Anzahl der Spieler | Eingeschränkte Multiplayer-Unterstützung | Mehrere Spieler haben Vorteile |
Plattformübergreifend | Die Konsistenz von Gleitkommaoperationen muss berücksichtigt werden | Da die Hauptberechnungen auf dem Server erfolgen, gibt es keine plattformübergreifenden Probleme. |
Anti-Cheating | Leicht zu betrügen, aber optimierbar | Kann Betrug sehr gut verhindern |
Trennen und erneut verbinden | Die Umsetzung ist schwierig, aber nicht unmöglich | Sie müssen die Nachricht nur einmal erneut senden, was einfach zu implementieren ist |
Wiedergabeanforderungen | lässt sich perfekt umsetzen | Nicht erreichbar |
Spiel pausieren | Einfach umzusetzen | Nicht einfach umzusetzen |
Netzwerkübertragungsvolumen | relativ klein | relativ groß |
Entwicklungsschwierigkeit | relativ komplex | relativ einfach |
RTS-Spiele | Geeignet | Nicht geeignet |
Kampfspiele | Geeignet | Nicht geeignet |
MOBA-Spiele | Geeignet | Nicht geeignet |
MMO-Spiele | Nicht geeignet | Geeignet |
Nachdem wir die Schwierigkeiten verstanden haben, die im Entwicklungsprozess der Frame-Synchronisation überwunden werden müssen, werden wir als nächstes darüber nachdenken, eine bessere Implementierungsmethode oder ein Entwicklungs-Framework auszuwählen. Da die Entwicklung der Rahmensynchronisation die Trennung von Daten und Leistung erfordert, inwieweit sollte diese getrennt werden? Der Datenberechnungsteil kann sogar in einem separaten Thread platziert werden. Der Vorteil, Logik auf diese Weise zu schreiben, besteht darin, dass der Server auch die Funktion der schnellen Wiedergabe des Spiels erreichen kann. Ich denke, dass nur ECS diesen Grad der Trennung erreichen kann. Frame-Synchronisation plus ECS ist absolut ein perfekter Partner.
Erstens müssen wir ECS einführen. ECS ist keine brandneue Technologie und wurde auch nicht zuerst von Unity vorgeschlagen. Dieser Begriff tauchte schon sehr früh auf und wurde in den letzten Jahren durch Blizzards „Overwatch“ schlagartig populär. Die Server- und Client-Frameworks von „Overwatch“ basieren vollständig auf ECS und weisen eine hervorragende Leistung in Bezug auf Spielmechanik, Netzwerk und Rendering auf. Ehrlich gesagt ist ECS kein Designmuster. Die Designmuster, die wir zuvor verwendet haben, wurden alle unter objektorientiertem Design besprochen, und ECS ist nicht objektorientiert. Unity hat auch ECS. Tatsächlich sind die eigenen Komponenten von Unity auch eine Art ECS, aber sie sind nicht rein genug. ECS eignet sich besonders für Gameplay. Es gibt viele Varianten von ECS, und hier ist ECS mit einigen geringfügigen Modifikationen.
Dies ist eine Funktion von Frame-Synchronisationsspielen. Wenn ein Spiel über ein Wiederholungssystem verfügt, muss das Spiel durch Frame-Synchronisation implementiert werden. Die Wiedergabe kann auch als Videoaufzeichnung bezeichnet werden, sie unterscheidet sich jedoch stark von der Videoaufzeichnung mithilfe von Videodateien, da der Träger normalerweise eine große Datei einnimmt und das Fenster während des Wiedergabevorgangs nicht leicht gestohlen, missbraucht oder böswillig werden kann verändert, komprimiert und in der Qualität verschlechtert, so dass die Videowiedergabe einen großen Nachteil hat. Durch die bildsynchrone Wiedergabe kann die Datei extrem klein werden und kann nicht manipuliert werden. Benutzer können während des Wiedergabevorgangs nach Belieben zwischen den Fenstern wechseln. Man kann sagen, dass das notwendige System für Frame-Synchronisationsspiele das Replay-System ist.
Hier wird RevenantX/LiteNetLib empfohlen. Diese Bibliothek ist sehr leistungsstark und einfach zu verwenden. Sie bietet eine zuverlässige UDP-Übertragung, was genau das ist, was ich möchte. Für die Netzwerkkommunikation stehen viele Datenprotokolle zur Auswahl. Die Hauptfunktionen sind Serialisierung und Deserialisierung. Wie diese PtRoom-Struktur:
//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 ;
}
}
}
}
Dies ist ein Unity-Projekt, das auf Frame-Synchronisierung basiert
Einige Tools: Pt-Strukturgenerierungstool, Excel2Json-Generierungstool, allgemeines Bibliotheksprojekt, ServerDll-Bibliotheksprojekt
Designdokumente: Entwurfsdesigndokumente, Prototypdesigndokumente, Konfigurationstabellen.
Die folgenden drei Abbildungen beschreiben den Einsatz des Frame-Synchronisationssimulators in drei verschiedenen Szenarien.
Die folgende Abbildung zeigt das allgemeine Verhalten von Client und Server gleichzeitig, und die Wiedergabelogik entspricht ebenfalls demselben Verhalten.
Dieses Bild zeigt die Client- und Server-Ausführungslogik in jedem logischen TICK. Der obere Teil ist der Client. Die Logik, die der Client ausführen muss, umfasst den ECSR-Teil, und der untere Teil ist der Serverteil.
Das letzte Bild beschreibt jeden logischen Frame der Wiedergabe.
Mithilfe dieser Bilder und der spezifischen Spieltypen können wir benutzerdefinierte Systeme und Komponenten einrichten, um die zugehörige Logik zu verwalten.
Dies ist ein Service-Sammlungsprojekt, einschließlich WebServer, GateServer, RoomServer usw.