Bagaimana saya membuat game online saya. Bagian 1: Jaringan



Halo semuanya! Baru-baru ini saya berlibur, dan ada waktu untuk dengan tenang memprogram proyek rumah saya. Karena itu saya ingin membuat game online sederhana saya di Rust. Lebih tepatnya, penembak 2D sederhana. Saya memutuskan untuk membuat bagian jaringan terlebih dahulu, dan di sana sudah akan terlihat apa dan bagaimana. Karena genre melibatkan aksi di semua bidang, jadi saya memutuskan untuk menggunakan protokol UDP. Dia mulai mendesain arsitektur bagian jaringan. Saya menyadari bahwa Anda dapat meletakkan semuanya di perpustakaan terpisah. Saya juga mengunggah pustaka yang dihasilkan ke crates.io, di bawah lisensi MIT, karena: a) Maka akan lebih mudah bagi saya untuk menghubungkannya dari sana ke proyek-proyek saya. b) Mungkin itu akan bermanfaat bagi orang lain dan akan membawa manfaat. Untuk detailnya, selamat datang di kucing.

Referensi


-> Sumber
-> Perpustakaan di crates.io
-> Dokumentasi

Contoh penggunaan


Pelanggan


//   use victorem; fn main() -> Result<(), victorem::Exception> { // ,    11111      127.0.0.1:22222 let mut socket = victorem::ClientSocket::new("11111", "127.0.0.1:22222")?; loop { //    socket.send(b"Client!".to_vec()); //    .             socket.recv().map(|v| String::from_utf8(v).map(|s| println!("{}",s))); } } 

Server


 //   use victorem; use std::time::Duration; use std::net::SocketAddr; //,  .            . struct ClientServerGame; //     Game,         impl victorem::Game for ClientServerGame { //,     .       false,   . fn handle_command(&mut self, delta_time: Duration, commands: Vec<Vec<u8>>, from: SocketAddr) -> bool { for command in commands { String::from_utf8(command).map(|s| println!("{}",s)); } true } //     30 .     ,     .      ,     . fn draw(&mut self, delta_time: Duration) -> Vec<u8> { b"Server!".to_vec() } } fn main() -> Result<(), victorem::Exception> { // ,      ClientServerGame     22222 let mut server = victorem::GameServer::new(ClientServerGame, "22222")?; //       . server.run(); Ok(()) } 

Perangkat internal


Secara umum, jika saya menggunakan soket UDP mentah alih-alih soket UDP mentah untuk bagian jaringan Laminar , maka kode dapat dikurangi dengan faktor 100, dan saya menggunakan algoritma yang dijelaskan dalam seri artikel ini - Pemrograman Jaringan untuk Pengembang Game .
Arsitektur server melibatkan penerimaan perintah dari klien (misalnya, menekan tombol mouse atau beberapa tombol pada keyboard) dan mengirimkan mereka status (misalnya, posisi unit saat ini dan arah yang mereka cari) yang dengannya klien dapat menampilkan gambar kepada pemain.

Di server


 //         u32     ,  0 -  , 1 -   ,      . pub fn get_lost(&self) -> (u32, u32) { let mut sequence: u32 = 0; let mut x = 0; let mut y = self.last_received_packet_id; while x < 32 && y > 1 { y -= 1; if !self.received.contains(&y) { let mask = 1u32 << x; sequence |= mask; } x += 1; } (sequence, self.last_received_packet_id) } 

Di klien


 //      (max_id)         (sequence)  .           fn get_lost(&mut self, max_id: u32, sequence: u32) -> Vec<CommandPacket> { let mut x = max_id; let mut y = 0; let mut ids = Vec::<u32>::new(); //      , ,     ,      . let max_cached = self.cache.get_max_id(); if max_cached != max_id { ids.push(max_cached); } while x > 0 && y < 32 { x -= 1; let mask = 1u32 << y; y += 1; let res = sequence & mask; if res > 0 { ids.push(x); } } self.cache.get_range(&ids) } 

Epilog


Bahkan, lebih mudah untuk membuat algoritma pengiriman perintah. Di server, terima hanya paket yang menerima lebih dari pergi ke paket terakhir yang diterima +1, dan buang sisanya. Kirim klien paket terakhir yang diterima. Di klien, simpan cache semua perintah yang coba dikirim oleh pengguna ke server. Setiap kali negara baru datang dari server dengan id, paket terakhir yang diterima oleh server, hapus dari cache dan semua paket dengan id kurang dari itu. Semua paket yang tersisa dikirim ke server lagi.
Selanjutnya, ketika saya akan membuat game itu sendiri, dalam proses penggunaan saya akan lebih meningkatkan dan mengoptimalkan lib. Mungkin saya akan menemukan beberapa bug lagi.

Saya menemukan di sini proyek server permainan di C # - Networker + di Rust, ada daun, semacam analog server permainan di Go-leaf. Hanya ada perkembangan yang sedang berlangsung.

PS Dear friend, jika Anda seorang pemula dan memutuskan untuk membaca kode saya untuk proyek ini dan melihat tes yang saya tulis di sana. Jadi, inilah saran saya untuk Anda - jangan lakukan seperti yang saya lakukan. Saya mencampur semuanya dalam tumpukan dalam tes dan tidak mengikuti template "AAA" (google apa itu). Anda tidak harus melakukan ini dalam produksi. Tes normal harus memverifikasi satu hal, bukan beberapa kondisi sekaligus, dan harus terdiri dari langkah-langkah:

  1. Anda mengatur variabel Anda;
  2. Anda melakukan tindakan yang ingin Anda uji;
  3. Anda membandingkan hasilnya dengan yang diharapkan.

Sebagai contoh

  fn add_one(x:usize) -> usize { x+1 } #[test] fn add_one_fn_should_add_one_to_it_argument(){ let x = 2; let expected = x+1; ///////////////////////// let result = add_one(x); ////////////////////////////////// assert_eq!(expected,result); } 

Source: https://habr.com/ru/post/id435384/


All Articles