Versi Lanjutan lebah kecil sedang mengekstraksi logika sinkronisasi bingkai ke dalam SDK, silakan lihat proyek https://github.com/dudu502/littlebee_libs Ini adalah contoh permainan sinkronisasi bingkai, menyinkronkan ratusan objek dan ribuan status dalam permainan .Latar belakang permainan ini adalah permainan menembak di bawah sistem planet.
[Tonton pemutaran videonya (Youtube)]
[Tonton memutar ulang videonya (Youtube)]
[Tonton pemutaran videonya(bilibili)]
[Tonton pemutaran ulang videonya(bilibili)]
Sinkronisasi bingkai | Sinkronisasi negara | |
---|---|---|
konsistensi | Tingkat desain menentukan konsistensi yang tak terelakkan | Dapat menjamin konsistensi |
Jumlah pemain | Dukungan multipemain terbatas | Banyak pemain memiliki kelebihan |
Lintas platform | Perlu mempertimbangkan konsistensi operasi floating point | Karena penghitungan utama dilakukan di server, tidak ada masalah lintas platform. |
Anti-kecurangan | Mudah untuk dicurangi, tetapi dapat dioptimalkan | Bisa sangat baik dalam mencegah kecurangan |
Putuskan sambungan dan sambungkan kembali | Memang sulit untuk diterapkan, namun bukan berarti tidak mungkin | Anda hanya perlu mengirim ulang pesan satu kali, mudah diterapkan |
Persyaratan pemutaran | dapat terwujud dengan sempurna | Tidak dapat mencapai |
jeda permainan | Mudah diterapkan | Tidak mudah untuk diterapkan |
Volume transmisi jaringan | relatif kecil | relatif besar |
Kesulitan pengembangan | relatif kompleks | relatif sederhana |
permainan RTS | Sesuai | Tidak cocok |
permainan pertarungan | Sesuai | Tidak cocok |
permainan MOBA | Sesuai | Tidak cocok |
permainan MMO | Tidak cocok | Sesuai |
Setelah memahami kesulitan yang perlu diatasi dalam proses pengembangan sinkronisasi frame, selanjutnya kita akan mempertimbangkan memilih metode implementasi atau kerangka pengembangan yang lebih baik. Karena pengembangan sinkronisasi frame memerlukan pemisahan data dan kinerja, sejauh mana hal tersebut harus dipisahkan? Bagian penghitungan data bahkan dapat ditempatkan di thread terpisah. Keuntungan menulis logika dengan cara ini adalah juga memungkinkan server berjalan untuk mencapai fungsi memutar ulang game dengan cepat. Saya rasa hanya ECS yang dapat mencapai tingkat pemisahan ini. Sinkronisasi frame plus ECS benar-benar merupakan mitra yang sempurna.
Pertama, kita perlu memperkenalkan ECS. ECS bukanlah teknologi baru, juga bukan yang pertama kali diusulkan oleh Unity. Istilah ini muncul sangat awal, dan tiba-tiba menjadi populer dalam beberapa tahun terakhir karena "Overwatch" dari Blizzard. Kerangka kerja server dan klien "Overwatch" sepenuhnya dibangun berdasarkan ECS, dan memiliki kinerja luar biasa dalam mekanisme game, jaringan, dan rendering. Sejujurnya, ECS tidak seperti pola desain. Pola desain yang kita gunakan sebelumnya semuanya dibahas dalam desain berorientasi objek, dan ECS tidak berorientasi objek. Unity juga memiliki ECS. Faktanya, komponen Unity sendiri juga merupakan sejenis ECS, tetapi tidak cukup murni. ECS sangat cocok untuk Gameplay. Ada banyak varian ECS, dan inilah ECS dengan sedikit modifikasi.
Ini adalah fitur game sinkronisasi frame. Jika suatu game memiliki sistem replay, maka game tersebut harus diimplementasikan melalui sinkronisasi frame. Pemutaran juga bisa disebut perekaman video, tetapi sangat berbeda dengan perekaman video. Pemutaran menggunakan file video sebagai operator biasanya memakan file besar, dan jendela tidak dapat dialihkan selama proses pemutaran. Video mudah dicuri, disalahgunakan, dan disalahgunakan dimodifikasi, dikompresi, dan diturunkan kualitasnya, sehingga pemutaran video memiliki kerugian besar. Pemutaran yang disinkronkan dengan bingkai dapat membuat file menjadi sangat kecil dan tidak dapat diubah. Pengguna dapat berpindah jendela sesuka hati selama proses pemutaran. Dapat dikatakan bahwa sistem yang diperlukan untuk sinkronisasi frame permainan adalah sistem replay.
RevenantX/LiteNetLib direkomendasikan di sini. Pustaka ini sangat kuat dan mudah digunakan. Pustaka ini menyediakan transmisi UDP yang andal, dan itulah yang saya inginkan. Ada banyak protokol data yang dapat dipilih untuk komunikasi jaringan. Saya menggunakan protokol aliran biner buatan sendiri. Fungsi utamanya adalah serialisasi dan deserialisasi. Seperti struktur PtRoom ini:
//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 ;
}
}
}
}
Ini adalah proyek Unity berdasarkan sinkronisasi frame
Beberapa alat: Alat pembuatan struktur Pt, alat pembuatan Excel2Json, proyek perpustakaan umum, proyek perpustakaan ServerDll
Dokumen desain: garis besar dokumen desain, dokumen desain prototipe, tabel konfigurasi.
Tiga gambar berikut menjelaskan penggunaan simulator sinkronisasi bingkai dalam tiga skenario berbeda.
Gambar di bawah menunjukkan perilaku umum klien dan server pada saat yang sama, dan logika pemutaran juga sesuai dengan perilaku yang sama.
Gambar ini menunjukkan klien dan server mengeksekusi logika di setiap TICK logis. Bagian atas adalah klien. Logika yang perlu dijalankan klien mencakup bagian ECSR, dan bagian bawah adalah bagian server.
Gambar terakhir menjelaskan setiap frame logis pemutaran.
Melalui gambar-gambar ini dan jenis permainan tertentu, kita dapat mengatur Sistem dan Komponen khusus untuk menangani logika terkait.
Ini adalah proyek pengumpulan layanan, termasuk WebServer, GateServer, RoomServer, dll.