Çok oyunculu oyun durumunu tam durum güncellemelerinden daha verimli bir şekilde nasıl senkronize edebilirim?


10

Daha önce küçük bir oyun ağı kodlaması yaptım, ancak öncelikle gerçek zamanlı ihtiyaçları olmayan oyunlar için TCP ile. Ağa bağlı çok oyunculu 2B Java oyunu üzerinde çalışıyorum. Öğrenmek için, mevcut bir ağ API'sı olmadan bunu kendim yapmak istiyorum.

Bir sunucudan istemcilere gönderilen oyun durumunu nasıl verimli bir şekilde temsil edebilirim? Her oyuncunun konumu, animasyon durumu vb. İle bir tür oyun durumu bağlam nesnesi oluşturmak ve bunu her oyuncuya her güncellemede göndermek olacak en belirgin ama muhtemelen en az etkili yol vardır . Bu, uygulanması çok zor görünmüyor, ancak gerçek zamanlı etkileşime yakın bir şey elde etmek için muhtemelen çok büyük olurdu (elbette bu konudaki deneyimim sınırlıdır, bu yüzden yanlış olabilirim).

Daha önce durum değişikliklerini iletmek için daha önce kullandığınız sağlam bir yol var mı ve performansta ekstra çalışmaya değecek kadar büyük bir eşitsizlik bile var mı?


2
Her kare şeyi tam olarak deneyin ve çok yavaşsa (biraz basit bir 2d oyun için muhtemelen yeterince verimlidir) sonra optimize etmeyi deneyin. İyi çalışıyorsa, o zaman iyi çalışır ve ağınızın daha sonra bir darboğaz olduğunu fark etmedikçe değiştirmeniz gerekmez.
Robert Rouhani

Yanıtlar:


10

Tam oyun durumunu düzenli olarak iletmek genellikle mümkün değildir, ancak oyununuzun karmaşıklığına çok bağlıdır. Küçük bir dünya modeli olan basit bir oyun için işe yarayabilir.

Aşağıdaki modelle şahsen çok daha başarılı oldum:

  • Mekansal veri yapısında (örn. Bir oktree) iyi tanımlanmış bir nesne modelinde saklanan oyun durumu
  • Oyun durumunda (istemcide veya sunucuda) yapılan tüm değişiklikler olaylar olarak tanımlanır. Etkinlik, bir oyun nesnesindeki özellik değişikliği, harita döşemesindeki değişiklik, oyun nesnesinin hareketi vb. Olabilir.
  • Sunucudaki oyun motoru, oyun ilerledikçe bir olay akışı oluşturur. Bunlar doğrudan sunucunun oyun durumuna uygulanır.
  • Olaylar oyunculara da gönderilir, ancak sadece o oyuncu o oyuncu ile ilgili ise (örneğin, olay geçerli pozisyondan görülebilir mi?)
  • Oyuncu görünürlüğündeki değişiklikler, oyuncu hareket ettiğinde olayların haritanın yeni bölümlerini "göstermesine" neden olabilir. Bu, oyuncunun oyuna ilk katıldıklarında ilgili oyun durumunun doğru bir başlangıç ​​görünümünü elde etmesini sağlamak için de kullanılabilir.
  • Oyuncu için oyun durumu aldığı her etkinlikle güncellenir. Bu nedenle, oyun durumunun sadece kısmi bir modeline sahiptir, ancak tüm olayların doğru bir şekilde işlendiği varsayılarak sunucu ile senkronize kalmalıdır.

Bu, oldukça büyük oyun dünyaları ile bile benim için iyi bir performans sağladı.

Başka bir ipucu, istemciye sunucuya başvurmadan animasyon, parçacık efektleri vb. Bunları iletmenin bir anlamı yok - sadece uygun oyun olayları tarafından "tetiklenmeleri" gerekiyor.


6

Senkronizasyon genellikle iki kısma ayrılır: artımlı ve mutlak.

Bazen her şeyi iletmelisiniz, büyüktür, ancak doğru şekilde paketlerseniz bunu birkaç saniyede bir yapabilirsiniz. Artan yenilemelerin hatalarını düzelterek everithing'i yerine koymak iyidir.

Gerçek zamanlı deneyim elde etmek için, bazı değişiklikleri hızlı bir şekilde iletmeniz gerekir, ancak yalnızca değişebilen nitelikleri iletmeniz gerekir. Örneğin, bir roket düz bir çizgide uçarsa, konumu güncellemeniz gerekmez, her müşteri başlangıç ​​noktasından hesaplayabilir. Fakat isabet ettiğinde, bu konuda bir mesaj üretebilirsiniz, böylece her müşteri roketi doğru yerde patlatabilir. Küçük hatalar göz ardı edilebilir.

Elbette, yalnızca müşteriyi etkileyebilecekleri şeyleri güncellersiniz! Ekrandan uzakta bir şey buna değmez. Bazı değerler daha az güncellenebilir. Örneğin, konumların az çok hassas olması önemlidir, olaylar (ölüm, atış, patlama, vb.) Anında gönderilirken, doğrudan önemli olmayan değerlerin, örneğin skorbord, sohbet gibi daha düşük yenileme süreleri olamaz.

Verilerin paketlenmesi de önemlidir. Bir UDP paketinde yaklaşık 1400 bayt (yapılandırmaya bağlı, bu varsayılan değerdir) iletebilirsiniz, genellikle birkaç bayt üstbilgi vardır. Böylece 50-100 ünite konumunu tek bir pakette kolayca güncelleyebilirsiniz.


Tavsiye Matzi için teşekkürler. Hala sunucuyu ve istemciyi uygulamaya çalışıyorum, ancak birkaç gün içinde tekrar kontrol edeceğim ve muhtemelen cevabınızı kabul edeceğim.
Haz

Sana iyi şanslar! ;)
Matzi

1

Oyununuza bağlı olarak, her istemcinin aynı oyunu oynadığı, sadece klavye / joystick girişleri ve zamanlayıcı olayları gibi deterministik olmayan girdileri paylaşarak "senkronize edilmiş yürütme" modelini düşünebilirsiniz. (Her müşterinin yerel simülasyonları çalıştırdığı ve uzak simülasyonlardan sonuçları entegre etmeyi beklediği bir modelle karşılaştırıldığında). Oyun motorunuzun çalışması için genellikle tamamen belirleyici olması gerekir, bu da oyuna bağlı olarak ağır bir yük olabilir. Ancak oyun zaten belirleyici ise, bu daha kolay bir yaklaşım olabilir.

Bu #AltDevBlogADay gönderisi , bu yaklaşımın bazı yönlerini modern bir RTS'de kapsar (özellikle müşterilerinizin "farklı" oyunları çalıştırmaya başladığında nasıl tespit edileceği).

Aksi kanıtlanana kadar basit tutmayı unutmayın. :)


1
Bunlar, bu yaklaşımı kullanan Factorio geliştiricisinden iyi okumalar ve bu yaklaşımın karmaşıklığına işaret ediyor, ancak aynı zamanda geçerli olduğunu gösteriyor: factorio.com/blog/post/fff-76 factorio.com/blog/post/fff -147 factorio.com/blog/post/fff-188
AaronLS
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.