Nişancı olmayanlar için hareket tahmini


35

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:

  1. 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.

  2. 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?

  3. 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.

  4. 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?


1
3D veya 2D olan bir oyunun ne tür bir sunucu kullanıyorsunuz ile ne ilgisi var? ve neden bir athoritive server oyununda işe yaramaz?
AttackingHobo

1
@Roy T. bant genişliği değişimleri. Bant genişliği, günümüzün bilgisayar sistemlerinde en değerli kaynaktır.
FxIII

1
Bu sadece doğru değildir, çevrimiçi oyunlara büyük ölçüde yanıt süresi hakimdir, örneğin 10Mbit'lik bir hatta (1.25MB / s) sunucu-istemci arasındaki gecikme süresi 20ms'dir, bir 1.25kb paket gönderilmesi 20ms + 1ms alacaktır. 12.5kb paket gönderilmesi 30ms sürer. İki kat daha hızlı bir hat üzerinde, 1.25kb'lik bir paket 12.kb paket için 20ms + 0.5ms ve 20ms + 5ms alacaktır. Gecikme, bant genişliği değil , sınırlayıcı faktördür . Her neyse, ne kadar veri olduğunu bilmiyorum, ancak 50 vector3'ün (25x pozisyon + 25x döndürme) gönderilmesi yalnızca 600 bayttır, bunu her 20ms'de göndermek 30kb / sn'ye mal olacaktır. (+ paket ek yükü).
Roy T.

2
Quake motorunun ilk versiyonundan beri tahmini var. Deprem tahmini orada ve başka yerlerde açıklanmaktadır. Bunu kontrol et.
user712092 12:11

1
Her pozisyon için bu pozisyonu + = velocity * deltatime paralel olarak mı yapıyorsunuz (zorunlu: kodda 2 Varlığın fiziksel parametresi diziniz var, bir kare ayrı, Eski olanı daha yeni olacak ve değiştireceksiniz)? Thief 1 motorunun temelini oluşturan Sean Barret'in yinelemesinde bazı problemler var .
user712092 12:11

Yanıtlar:


3

Söylenecek tek şey, 2D, izometrik, 3D, bu sorun söz konusu olduğunda hepsinin aynı olduğu. Çünkü birçok 3D örneği görüyorsunuz ve yalnızca anlık olarak hızıyla 2B oktan sınırlı giriş sistemi kullanıyorsanız, son 20+ yıl boyunca gelişen ağ ilkelerini atabileceğiniz anlamına gelmez.

Oyun ilkelerine uyulduğunda tasarım ilkeleri lanetlenir!

Daha önceki ve şimdiyi atarak, sorununuzu çözebilecek birkaç bilgiyi atarsınız. Bu verilere zaman damgası ekleyeceğim ve gecikmeli olarak hesaplayacağım, böylece ekstrapolasyon o oyuncunun nerede olacağını daha iyi tahmin edebilir ve enterpolasyon zaman içindeki hız değişikliklerini daha iyi düzeltebilir.

Yukarıdakiler, sunucuların çok fazla durum bilgisi gönderdiğini ve girdileri denetlememesinin büyük bir nedenidir. Başka bir büyük sebep, hangi protokolü kullandığınıza dayanıyor. UDP kabul edilmiş paket kaybı ve sipariş dışı teslimat ile mi? Güvenli teslimat ve yeniden deneme ile TCP? Herhangi bir protokolle, garip zamanlarda paketleri alacaksınız, etkinlik telaşı içinde birbirlerinin üzerine gecikmeli ya da yığılmış olacaksınız. Tüm bu garip paketlerin bir içeriğe uyması gerekiyor, böylece müşteri neler olduğunu anlayabilir.

Son olarak, girdileriniz 8 yöne sınırlandırılmış olsa da, gerçek değişiklik herhangi bir zamanda olabilir - 250ms'lik bir döngüyü zorlamak hızlı oyuncuları sinirlendirir. 30 oyuncu, herhangi bir sunucunun yönetebileceği büyük bir şey değildir. Binlerce hakkında konuşuyorsanız ... o zaman bile grupları birden fazla kutuya bölünür, bu nedenle tek tek sunucular yalnızca makul bir yük taşır.

Hiç çalışan Havok ya da Bullet gibi bir fizik motorunu profilledin mi? Gerçekten oldukça optimize edilmişler ve çok, çok hızlılar. ABC'nin yavaş çalışacağını ve ihtiyacı olmayan bir şeyi optimize edeceğini varsaymak tuzağına düşüyor olabilirsiniz.


Kesin adaçayı tavsiye burada! Büyük resmi görmek çok kolay. Bu durumda TCP kullanıyorum. "8-yöne" sorunu girdiler açısından bir sorun değil - enterpolasyon ve ekstrapolasyon ile ilgili bir problem. Grafikler bu açılarla sınırlıdır ve hareketli spritelar kullanır - oyuncu normalden çok farklı bir açı veya hızda hareket ederse oyun "tuhaf görünüyor".
ShadowChaser

1

Yani sunucunuz aslında bir "hakem" mi? Bu durumda, müşterinizdeki her şeyin deterministik olması gerektiğine inanıyorum; Her müşterideki her şeyin daima aynı sonucu verdiğinden emin olmanız gerekir.

İlk sorunuz için, yerel oyuncu diğer oyuncuların yönünü aldığında, zaman içindeki hareketini yavaşlatabilmenin yanı sıra çarpışmalar yapabilmek dışında, oyuncunun bir sonraki dönüşte hangi yöne döneceğini nasıl tahmin edebileceğinizi bilmiyorum. 8 yönlü çevre.

Her oyuncunun "gerçek pozisyon" güncellemesini aldığınızda (belki de sunucuda şaşırtmayı deneyebilirsiniz) evet, oyuncunun pozisyonunu ve yönünü enterpolasyon etmeniz gerekecek. "Tahmini" pozisyonu çok yanlış ise (yani oyuncu, son yön paketinin gönderilmesinden hemen sonra yön değiştirdi) çok büyük bir boşluğa sahip olacaksınız. Bu, ya oyuncu pozisyonunu atlar ya da bir sonraki tahmin edilen pozisyona enterpolasyon yapabileceğiniz anlamına gelir . Bu, zaman içinde daha yumuşak bir enterpolasyon sağlayacaktır.

Varlıklar çarpıştığında, determinist bir sistem oluşturabilirseniz, her oyuncu çarpışmayı yerel olarak simüle edebilir ve sonuçları gerçeklikten çok uzak olmamalıdır. Her yerel makine, her iki oyuncu için çarpışmayı simüle etmelidir, bu durumda son durumun bloke olmayacak ve kabul edilebilir olacağından emin olun.

Nesnelerin sunucu tarafı için bir hakem sunucusu, basit bir hile karşıtı mekanizma olarak kullanmak için örneğin bir oyuncunun kısa sürede hızını kontrol etmek için hala basit hesaplamalar yapabilir . Her oyuncuyu aynı anda 1 saniyeden fazla izlemeye devam ederseniz, hile algılamanız ölçeklenebilir, yalnızca hile bulma işlemi daha uzun sürer.


Teşekkürler - bu özellikle sunucu tarafında ihtiyacım olana oldukça yakın geliyor. İlginç bir nokta, oyuncular 8 yöne kilitlenmelerine rağmen, iç hareketlerin 3B vektör olmasıdır. Geçtiğimiz gün bunu biraz daha düşündüm ve enterpolasyonu hiç uygulamamış olduğum için mücadele ediyorum - sadece basit bir hızda ve hızı temel alarak pozisyonu güncelleyerek çok basit bir entegrasyon kullanıyorum. her güncellemeyi vektör.
ShadowChaser

Bunu enterpolasyon veya tahminle nasıl birleştireceğimi bilmiyorum. Pakette gönderilen güncellenmiş pozisyonu almaya, belirli bir zaman diliminde (örneğin, 200ms) entegre etmeye ve o noktaya 200ms'de ulaşmak için gereken vektörü (hız) belirlemeye çalıştım. Başka bir deyişle, oyuncunun müşteri tarafındaki mevcut yanlış konumundan bağımsız olarak, aynı "tahmini doğru konuma" 200ms'de ulaşmaları gerekir. Sonunda karakterimi çılgınca yönlere yolladı - Sanırım 200ms gerçekten bir sonraki pakete gitme zamanıdır, tahmin edemem.
ShadowChaser

Yanlış pozisyonu t + 1'deki tahmin edilen doğru pozisyona entegre etmeden önce doğru pozisyonu ilk önce t - t + 1 ile birleştirdiğinizden emin misiniz ?
Jonathan Connell,

Evet - Orijinal entegrasyon için doğru pozisyonu kullandığımı iki kez kontrol ettim. Aslında bu bir hataydı, ancak düzeltilmesi hala gözle görülür bir iyileşme yaratıyor gibi görünmüyordu. Benim şüphem "+1" - paketler arasındaki süreye çok bağlı olması gerekiyor. İki sorun var: normal (250ms) güncellemelere ek olarak durum değişiklikleri gönder ve bunların ne zaman olacağını tahmin edemiyorum. Ayrıca, belirli bir aralıkta kilitlemek konusunda isteksizim çünkü sunucunun müzikçalardan daha uzakta olan varlıklar için daha az güncelleme göndermesi mantıklı. Paketler arasındaki süre değişebilir.
ShadowChaser

1
Sabit bir zaman aralığı türünü içeren evet, muhtemelen iyi bir fikir değildir. 8 yönlü hareketin dengesizliğinin tahmin edilmesi çok zor olacağından endişeleniyorum. Buna rağmen, t + 1'i tahmin etmek için müşterinin ortalama gecikme süresini kullanmaya çalışabilir ve üzerinde diğer oyuncuları her zaman yeni pozisyonlarına “ışınladığınız” bir eşik değerine sahip olabilirsiniz .
Jonathan Connell

0

Durum değişikliği mesajlarınıza hız ekleyemez ve bunu hareketi öngörmek için kullanamaz mısınız? örneğin, değiştiğini söyleyen bir mesaj alana kadar hızın değişmediğini varsayın. Siz zaten pozisyon gönderiyorsunuz, bu yüzden bir şey "abartıyor" ise, bundan dolayı bir sonraki güncellemeden yine de doğru pozisyona sahip olursunuz. Ardından, güncellemeler sırasında pozisyonları son mesajdaki hızı kullanarak zaten uygulayabilir ve yeni bir pozisyona sahip bir mesaj alındığında pozisyonun üzerine yazabilirsiniz. Bu aynı zamanda eğer pozisyon değişmezse, fakat hız (eğer oyununuzda geçerli bir durum olsa bile) bir mesaj göndermeniz gerekiyor, ama bu bant genişliği kullanımınızı hiç etkilemeyecek anlamına geliyor.

İnterpolasyon burada önemli olmamalı, örneğin , gelecekte bir şeyin nerede olacağını, ne zaman kullandığınızı, hangi yöntemi kullandığınızı vb. Bildiğiniz zaman . Belki de ekstrapolasyon ile karıştırılıyor musunuz? (bunun için tarif ettiğim şey basit, yaklaşımdır)


-1

İlk sorum şu olurdu: Sunucunun yetkisinin bulunduğu bir model kullanmanın nesi yanlış? Ortamın 2D mi yoksa 3D mi olduğu neden önemlidir? Eğer sunucunuz yetkiliyse, hile korumanızı çok daha kolay hale getirirdi.

Örneklerin çoğu, sıkı bir şekilde çift hareket tahminini varlıkların kendileri arasında görmüştü. Örneğin, önceki durumu geçerli durumla birlikte depolamak. Bundan kaçınmak ve varlıkları yalnızca “mevcut durumlarıyla” tutmak isterim. Bununla baş etmenin daha iyi bir yolu var mı?

Tahmini gerçekleştirirken, yetkili durum / delta sunucudan alındığında, istemcinin durumuyla karşılaştırılabilir olması için istemcide birkaç durumun (veya en azından deltaların) tutulması gerekir. düzeltmeler. Fikir gerekli düzeltmelerin miktarını en aza indirmek için mümkün olduğunca belirleyici tutmaktır. Önceki durumları korumazsanız, sunucuda farklı bir şey olup olmadığını bilemezsiniz.

Oyuncu durduğunda ne olmalı? Doğru pozisyona enterpolasyon yapamıyorum, çünkü pozisyonları çok ileride ise geriye doğru veya başka bir tuhaf yöne gitmeleri gerekebilir.

Neden interpolasyona ihtiyacınız var? Yetkili sunucu, herhangi bir hatalı hareketi geçersiz kılmalıdır.

Varlıklar çarpıştığında ne olmalı? Eğer mevcut oyuncu bir şeyle çarpışırsa, cevap basittir - sadece oyuncunun hareket etmesini durdurun. Ancak iki varlık sunucuda aynı alanı kaplarsa ne olur? Yerel tahmin, uzak bir varlığın oyuncu veya başka bir varlıkla çarpışmasına neden olursa - onları da durdururum mu? Tahmin, oyuncuları dolaştığı bir duvarın önüne sokma konusunda talihsizlik yaşadıysa, tahmin hiçbir zaman telafi edilemez ve hata bir kez yükseldiğinde işletme yeni pozisyona geçer.

Bunlar, sunucu ile istemci arasında bir çelişki yaşanacak durumlardır ve bu nedenle, sunucunun hataları düzeltebilmesi için istemcide durumları korumanız gerekir.

Hızlı cevaplar için üzgünüm, yola çıkmalıyım. Bu makaleyi okuyun , atıcılardan bahsediyor ancak gerçek zamanlı ağ bağlantısı gerektiren herhangi bir oyun için çalışmalıdır.


Birkaç cevap: * Eğer sunucunun yetkisi varsa, tüm hareket halindeki varlıkları izlemek ve konumlarını düzenli aralıklarla güncellemekten sorumludur. Başka bir deyişle, pahalı olabilen fizik motorunu çalıştırması gerekir. Ölçeklenebilirlik benim için büyük bir tasarım hedefidir. * İstemci tarafında enterpolasyon yapmam gerekiyor, istemcilere gönderilen her sunucu güncellemesi diğer bilge varlıkların atlamasına neden olacak. Şu anda enterpolasyonum fizik motorunda yapıldı - sadece hızı belirliyor. Devlet veya delta yok.
ShadowChaser

Glenn'in tüm makalelerini okudum, ancak yorumlarında yalnızca atıcılara yönelik olduklarını (yani / yüksek güncelleme frekansları) yazdığını belirtti. Makalelerinden birkaçı, yetkili müşteriler hakkında konuşuyor, ki bunun için uğraşıyorum. Sunucuda herhangi bir enterpolasyon / fizik yapmak istemiyorum, ama gerçekten tek yol buysa fikrimi değiştirmek istiyorum :)
ShadowChaser

1
-1. Yazdıklarınız, yalnızca konu hakkında belli belirsiz dokunuşlar; belirsiz hissediyor. Cevaplar, eldeki makaleden yararlı bilgiler içermediği halde, esasen "bu uzun makaleyi okuduklarında" olduklarında, alt-par hissediyorum.
AttackingHobo

1
@AttackingHobo Seninle aynı fikirdeyim. Acelem olduğunu söylemiştim ama bu bahane değil. Zamanım olmasaydı, onu yalnız bırakmak daha iyi olurdu. Ders öğrenildi.
Gyan aka Gary Buyn 28:11
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.