Orta ölçekli çok oyunculu bir izometrik 2D oyun üzerinde çalışıyorum, bir seferde kalıcı bir sunucuya bağlı yaklaşık 20-30 oyuncu. Yerinde iyi bir hareket tahmini uygulaması elde etmekte zorlandım.
Fizik / Hareket
Oyunun gerçek bir fizik uygulaması yok, ancak hareketi uygulamak için temel prensipleri kullanıyor. Sürekli oylama girişi yerine, durum değişiklikleri (yani / mouse down / up / move olayları), oynatıcının kontrol ettiği karakter öğesinin durumunu değiştirmek için kullanılır. Oyuncunun yönü (yani / kuzey-doğu) sabit bir hız ile birleştirilir ve gerçek bir 3B vektöre dönüştürülür - varlığın hızı.
Ana oyun döngüsünde "Güncelle" "Çiz" den önce çağrılır. Güncelleme mantığı, sıfır olmayan bir hıza sahip tüm varlıkları izleyen bir "fizik güncelleme görevini" tetikler, varlıklar konumunu değiştirmek için çok temel bir entegrasyon kullanır. Örneğin: entity.Position + = entity.Velocity.Scale (ElapsedTime.Seconds) (burada "Saniye" kayan nokta değeridir, ancak aynı yaklaşım milisaniye tam sayı değerleri için işe yarar).
Kilit nokta hareket için enterpolasyonun kullanılmamasıdır - ilkel fizik motoru "önceki durum" veya "mevcut durum" kavramına sahip değildir, sadece bir konum ve hızdır.
Durum Değişikliği ve Güncelleme Paketleri
Karakter varlığının hızı oyuncuyu kontrol ederken, varlığın eylem tipini (ayakta durma, yürüme, koşma), yönünü (kuzey-doğu) ve mevcut pozisyonu içeren sunucuya bir "hareketli avatar" paketi gönderilir. Bu, 3D first person oyunlarının çalışma şeklinden farklıdır. 3D oyunda, hız (yön), oyuncu hareket ederken kareyi kare olarak değiştirebilir. Her durum değişikliğini göndermek, çerçeve başına bir paketi etkili bir şekilde iletir ve bu da çok pahalı olur. Bunun yerine, 3D oyunlar durum değişikliklerini görmezden geliyor ve sabit bir aralıkta "durum güncelleme" paketleri gönderiyor gibi görünüyor - her 80-150ms'de bir.
Oyunumda hız ve yön güncellemeleri çok daha az gerçekleştiğinden, her durum değişikliğini göndermekten kurtulabilirim. Her ne kadar tüm fizik simülasyonları aynı hızda gerçekleşse ve deterministik olsa da, gecikme hala bir konudur. Bu nedenle, rutin konum güncelleme paketleri (3B oyuna benzer şekilde) gönderiyorum fakat çok daha az sıklıkla - şu anda her 250ms'de bir, ancak iyi bir tahminle 500ms'ye kolayca yükseltebileceğimi sanıyorum. En büyük sorun şu anda normdan saptığım - diğer tüm belgeler, kılavuzlar ve örnekler çevrimiçi rutin güncellemeler gönderiyor ve iki durum arasında enterpolasyon yapıyor. Mimarlığımla uyumsuz görünüyor ve (çok temel) bir “ağ bağlantılı fizik” mimarisine daha yakın bir hareket tahmin algoritması bulmam gerekiyor.
Sunucu daha sonra paketi alır ve bir betiği temel alarak hareket tipinden oyuncuların hızını belirler (oyuncu çalışabiliyor mu? Hızına sahip olduktan sonra, bir vektör elde etme yönü ile birleşir - varlığın hızı. Bazı hile algılama ve temel doğrulama işlemleri gerçekleşir ve sunucu tarafındaki varlık geçerli hız, yön ve konum ile güncellenir. Temel azaltma, oyuncuların sunucuyu hareket istekleriyle taşmasını önlemek için de yapılır.
Kendi varlığını güncelledikten sonra, sunucu menzil içindeki diğer tüm oyunculara bir "avatar pozisyon güncelleme" paketi yayınlar. Konum güncelleme paketi, uzaktaki istemcilerin istemci tarafı fizik simülasyonlarını (dünyadaki durumu) güncellemek ve tahmin ve gecikme telafisi gerçekleştirmek için kullanılır.
Tahmin ve Gecikme Tazminatı
Yukarıda belirtildiği gibi, müşteriler kendi pozisyonları için yetkilidir. Aldatma veya anormallik durumları haricinde, müşterinin avatarı hiçbir zaman sunucu tarafından yeniden konumlandırılmaz. Hiçbir ekstrapolasyon ( "şimdi hareket ve doğru daha sonra") müşterinin avatar için gereklidir - oynatıcıya görür ise doğru. Ancak, hareket eden tüm uzak varlıklar için bir çeşit ekstrapolasyon veya enterpolasyon gereklidir. Müşterinin yerel simülasyon / fizik motoru içerisinde bir tür tahmin ve gecikme telafisi açıkça istenmektedir.
sorunlar
Çeşitli algoritmalarla mücadele ediyorum ve bir takım soru ve sorunlarım var:
Ekstra mı, enterpolasyon mu yapmalıyım yoksa ikisini birden mi yapmalıyım? Benim “bağırsak hissi” benim hıza dayalı saf ekstrapolasyon kullanmam gerektiğidir. Durum değişikliği müşteri tarafından alınır, müşteri gecikmeyi telafi eden "öngörülen" bir hız hesaplar ve normal fizik sistemi gerisini halleder. Bununla birlikte, diğer tüm örnek kodlara ve makalelere uymadığını hissediyor - hepsi bir dizi durumu saklıyor ve fizik motoru olmadan enterpolasyon yapıyor gibi görünüyor.
Bir paket geldiğinde, paketin konumunu sabit bir süre zarfında paketin hızıyla interpolasyonu yapmaya çalıştım (örneğin, 200ms). Daha sonra enterpolasyonlu pozisyon ile mevcut "hata" pozisyonu arasındaki farkı yeni bir vektör hesaplamak için alıp gönderilen hız yerine varlığa yerleştiririm. Bununla birlikte, varsayım, başka bir paketin o zaman aralığında geleceği ve bir sonraki paketin ne zaman geleceğini "tahmin etmek" oldukça zor - özellikle de hepsi sabit aralıklarla gelmediğinden (yani / durum değişiyorsa). Konsept temelde kusurlu mu, yoksa doğru mu, ancak bazı düzeltmeler / ayarlamalar gerekiyor mu?
Uzak bir oyuncu durduğunda ne olur? Varlığı hemen durdurabilirim, ancak tekrar hareket edinceye kadar “yanlış” noktaya yerleştirilecektir. Bir vektör tahmin edersem veya enterpolasyona girmeyi denersem, bir sorunum var çünkü önceki durumu saklamıyorum - fizik motoru "X konumuna ulaştıktan sonra durmanız gerekir" demenin bir yolu yok. Bu sadece bir hızı anlıyor, daha karmaşık bir şey değil. Temel tasarım ilkelerini ihlal ettiğinden ve ağ kodunu oyun motorunun geri kalanına taşıdığı için, "paket hareketi durumu" bilgilerini varlıklara veya fizik motoruna eklemek konusunda isteksizim.
Varlıklar çarpıştığında ne olmalı? Üç senaryo vardır - kontrol cihazı yerel olarak çarpışır, iki varlık bir konum güncellemesi sırasında sunucuya çarpışır veya bir uzaktan varlık güncellemesi yerel istemcide çarpışır. Her durumda, çarpışmanın nasıl ele alınacağından emin değilim - hile yapmanın yanı sıra, her iki durum da “doğru” ancak farklı zaman aralıklarında. Uzak bir varlık söz konusu olduğunda, onu bir duvardan geçirerek çizmek anlamsızdır, bu yüzden yerel müşteride çarpışma tespitini yapıyorum ve "durmasına" neden oluyor. Yukarıdaki # 2 numaralı noktaya dayanarak, varlığı asla "duvardan" taşımayı deneyen "düzeltilmiş bir vektör" hesaplayabilirim, bu asla başarılı olmaz - uzak avatar hata çok yüksek olana kadar "sıkışıp kalır" konumu. Oyunlar bunun etrafında nasıl çalışır?