RTS Oyun Protokolü


18

Çok oyunculu bir RTS oyunu düşünüyordum. Gezinemediğim kısım, birim hareketini senkronize tutmak. A birimini XY'yi bulmak için taşırsam, bunu diğer istemciye ileten sunucuya geri iletmem gerekir.

İletişimin nasıl görüneceğini merak ediyorum. Sadece A birimini JY'den XY'ye taşıdığım sunucuya iletir misiniz? Belki de hareket koordinatını koordinasyonla iletmeniz gerekir? Birimlerin bir müşteriden diğerine hareketini iletmek için en etkili yöntem nedir?

DÜZENLE

Bu, stackoverflow'un yanıtladığı bir sorudur . Bu sitenin muhtemelen soru için daha iyi bir yer olduğunu buldum.

Bu yazının daha iyi cevaplarından biri:

İstemci-Sunucu ağ paradigmasını kullanmak istediğinizi varsayalım? Bu durumda, istemcilerin birimlerin gerçek konumlandırmasını işlemesine güvenemezsiniz, bu görevi sunucuya devretmeniz gerekir. Daha sonra komut listesini her müşteri başına işaretten alırsınız ve her birimin hareketini hesaplarsınız, bu tamamlandıktan sonra, her bir müşteriyle ilgili her birimin konumunu (tüm harita temelinde veya görüntüleme başına) ve işlemi yeniden başlatın.


2
Cevap gerçekten hangi yöntemi kullanmak istediğinize bağlıdır. İstemci - istemci veya istemci - sunucu. İstemciden sunucuya daha kolay ama güvenilir bir sunucu gerektirir
Cem Kalyoncu

Yanıtlar:


25

Tüm birimlerin konumlarını sunucudan her istemciye senkronize etmek istemezsiniz; O kadar sürecektir yolu ihtiyacınız daha fazla bant genişliği. Ayrıca, enterpolasyon / ekstrapolasyon ünitesi pozisyonları, vb. İle uğraşmak zorunda kalacaksınız .

Bunun yerine, yalnızca oyuncuların komutlarını göndermek istiyorsunuz. Oyuncu tıkladığında birimleri hemen hareket ettirmek yerine, ileride bir noktada yapılacak hareket komutunu sıraya koyacaksınız - genellikle sadece birkaç kare. Herkes emirlerini herkese gönderir. Birkaç kare sonra, herkes tüm komutları yerine getirir ve oyun deterministik olduğu için hepsi aynı sonucu görür.

Dezavantajı, her oyuncunun en yavaş oyuncu kadar yavaş olmasıdır - eğer herkes komutları gönderirken geride kalırsa, herkes yavaşlamak ve onu yakalamasını beklemek zorundadır (Starcraft 2'de, bu "XXX oyunu yavaşlatıyor " iletişim kutusu).


Aslında, genellikle yapılan bir şey daha var: sunucuyu tamamen ortadan kaldırın . Her müşterinin komutlarını diğer tüm istemcilere göndermesini sağlayın. Bu, gecikmeyi azaltır (sizden -> sunucu -> rakibinize gelen bir komut yerine, sadece sizden -> rakibinize gider) ve artık ayrı bir sunucuyu kodlamanız gerekmediğinden kodlamayı kolaylaştırır. Bu tür mimarilere eşler arası (P2P) denir .

Dezavantajı, şimdi çatışmaları çözmenin bir yoluna ihtiyacınız var, ancak oyuncuların komutları çoğu RTS'de birbirinden bağımsız olduğu için, bu genellikle bir sorun değil. Ayrıca, iyi ölçeklenmez - her yeni oyuncu eklediğinizde, her oyuncunun ona komutlarını göndermesi gerekir. P2P kullanarak bir MMO RTS yapmayacaksınız.


Bu kurulum (yalnızca P2P kullanarak komut gönderme) Starcraft, C&C ve AoE dahil çoğu RTS'nin nasıl çalıştığıdır ve AoE'nin 28.8kbps bağlantıda 1500 birimi desteklemesinin tek yolu budur .

(AoE'de ağ oluşturma görüntüsü)

Bir P2P RTS yazmak için birkaç ipucu daha:

  • Belli nedenlerden dolayı, bu kurulum yalnızca oyununuz sabit adım süresi kullanıyorsa çalışabilir - bir hesaplama sonucunun kare hızına bağımlı olmasını istemezsiniz! Sabit adım, çoğu şey için çalışmak daha kolaydır, bu nedenle bu bir sorun olmamalıdır.
  • Bunun çalışması için her komutun sonuçları tamamen belirleyici olmalıdır .
    • Kendinizi tek bir sistemle (32 bit Windows gibi) kısıtlarsanız ve tüm istemcileri aynı yürütülebilir dosyayı kullanmaya zorlarsanız bu genellikle oldukça kolaydır: herhangi bir rasgele sayı üretecinin aynı tona sahip olduğundan ve her zaman aynı sırada çağrıldığından emin olun; sıralanmamış koleksiyonlar üzerinde yineleme yaparken son derece dikkatli olun ; vb.
    • Bu son derece farklı platformlar arasında oyun oynanabilir yapma planı, ya da (genellikle Linux ile olduğu gibi) istemcileri kodu kendilerini derlemeye izin verirse zor. Sadece hemen hemen farklı uygulamalarını kullanmak için garantili farklı sistem kütüphaneleri vardır rand(), cos()vs, ama hemen hemen hepsi kayan nokta matematik söz konusu olamaz (bkz burada , burada ve burada ) ! Bu durumda, istemci-sunucu kullanmak daha iyi olabilir.
  • En azından hata ayıklama sırasında, desync hatalarını tespit etmek için tüm birim konumlarını arada bir göndermek isteyeceksiniz (ki bana güvenin, sahip olacaksınız ). Son oyunda size kalmış olsun - hackleme girişimini tespit etmek için en azından bazı birimleri senkronize ederim (veya bir çeşit sağlama toplamı kullanırım).

İyi yazı. Eklemek için küçük bir şey, aynı derleyiciler bile optimize, hata ayıklama / bırakma ve diğer bayraklar sonucu değiştirebilir. Dikkatli ol!
Peter Ølsted

14

Komutların sonuçları yerine komutların kendilerinden geçtiğim TCP ağlı bir RTS yaptım . Örneğin, bir oyuncu taşıma sırası verir. Taşıma sırası bu istemciye göre geçerliyse, sunucuya gönderilir. Sunucu daha sonra, doğrulayan ve yürüten tüm istemcilere geri gönderir.

Böylece tüm istemci makineler oyunu kendileri çalıştırır, sunucu kodu mesajları kabul eder ve tüm istemcilere geri gönderir. İstemci bir taşıma emri verirse, sunucudan geri alınana kadar yürütmeye başlamaz.

Sunucu, komutun da çalıştırılacağı bir 'onay' numarası gönderir, bu da 'geçerli' onayın birkaç adım ilerisindedir. Bu şekilde tüm komutlar tüm makinelerde aynı 'tik' ile yürütülebilir.

Bu yöntemin bir yararı, komutu doğrulamak için herhangi bir istemci makineye bağımlı olmamasıdır. Hareketin sonuçlarını geçersem, birimlerimi daha hızlı taşımak için onu hackleyebilirim. Tüm istemcilerin aynı komutu yürütmesi gerekir ve bir makine farklı çalıştırırsa, bu açıktır.

Komutun istemci tarafını sunucuya göndermeden önce doğrulamak gerekli değildir, ancak teoride ağ trafiğinden tasarruf eder. UI'ye taşıma işleminin mümkün olduğunu söylemek için aynı doğrulama kodunu kullandım, bu yüzden ekstra kod yazmayı gerektirmedi.

Mesajlar neye benzeyebilir. İlk ağ bağlantılı oyunum olduğu için ultra verimlilikle ilgilenmedim. Komutları dize olarak geçtim. Komutlar şu şekilde biçimlendirilir:"<player_id>:<command>:<parameters>"

Bir yapmacık Örneğin, bir hareket komutu şöyle olabilir: "3:move:522:100:200". Bu Oyuncu'nun ( , ) birimine geçmek 3istediği anlamına gelir . move522100200

Sunucu böyle bağlı bir kene numarası ile, bir kim gönderdi dahil tüm istemciler, üzerine komutu geçirir: "153238:3:move:522:100:200".

Sonra istemcilerin tümü, 153238 tik yürütüldüğünde bu komutu yürütür.


Soruya biraz daha bilgi ekledim. SO'nun cevabı söylediklerinize karşı gibi görünüyor ve daha ince ayrıntıları tartışmak isterim.
Darthg8r

Evet, bunu yapmanın başka bir yolu, ama bana öyle geliyor ki, oyun komutlarının çoğundan ziyade oyun durumunun çoğunu geçmek daha fazla iş olurdu. Oyunum, her şeyin her istemci makinede çalışabileceği kadar basitti. Bir MMO için veya Minecraft gibi bir şey için, tüm simülasyonun istemci tarafında çalışmaması nedeniyle her müşteriyle ilgili bilgileri tek tek aktarırsınız.
Philip
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.