Ne göndermek lazım?
Videoda Dr. Julian Onions, yıllar önce üzerinde çalıştığı bir uçuş simülatörünü örnek alıyor. Ona göre uçuş simülatörleri çok oyunculu oyunların en zoru, çünkü her şey üç boyutlu ve harita neredeyse sınırsız.
Bir araba oyununda çoğu zaman X ve Y yeter. Uçakta yükseklik için Z de lazım. Bir de uçağın duruşu var: burnunun sağa sola dönmesi (yaw), yukarı aşağı kalkması (pitch) ve kanatların yatması (roll). İlk akla gelen çözüm basit: Bu altı sayıyı mümkün olduğunca sık herkese gönder.
Bu çalışır, ama pahalıdır. Yirmi oyuncuda ağ, paketten geçilmez hâle gelir.
UDP: Kaybolsun, yenisi gelir
Bu paketler genelde UDP ile gönderiliyor. UDP, paketin ulaşıp ulaşmadığını takip etmiyor. Kaybolan paketi tekrar göndermiyor, sırayı da korumuyor.
Bu bir eksiklik gibi görünse de konum için tam istenen şey. Yarım saniye önceki konum bilgisi geç geldiyse artık işe yaramaz. TCP ise kaybolan paketi bekler ve arkasındaki her şeyi durdurur. Gaffer On Games’in klasik yazısı da aynı sonuca varıyor: Hızlı aksiyon oyunlarında zamana duyarlı veri için TCP’nin bu beklemesi kabul edilemez.
Her pakete bir zaman damgası eklenir. Geç gelen eski bir paket, daha yenisi işlendiyse çöpe atılır.
Ama her şey böyle değil. İniş takımlarının açılması ya da seyir ışıklarının yanması bir kez olan ve kaçırılmaması gereken olaylar. Onları tahmin edemezsin. Videoya göre bunlar için TCP gibi güvenilir bir kanal kullanılıyor.
Tahmin et, sadece yanılınca konuş
Paket sayısını asıl düşüren fikir parakete hesabı (dead reckoning). Denizcilikte GPS’ten önce kullanılan yöntem: Son bilinen konum, hız ve yön biliniyorsa şu anki konumu tahmin edebilirsin.
Konumun yanına hızı da (X, Y ve Z yönünde) gönderirsen, karşı taraf bir sonraki paketi beklemeden uçağı ilerletebilir: yeni konum = eski konum + hız × geçen süre. Uçakların çoğu zaman düz ve sabit hızla uçtuğunu düşünürsen, bu tahmin çoğu zaman tutar.
Asıl hile gönderen tarafta. Gönderen de aynı hesabı kendi için yapıyor: “Karşı taraf beni şu an nerede sanıyor?” Tahmin gerçek konuma yeterince yakınsa hiçbir şey göndermiyor. Uçak dönmeye başlayıp tahmin belli bir eşiği aşınca yeni bir paket yolluyor. Hiç değişiklik olmasa bile arada bir “hâlâ buradayım” paketi atılıyor.
Bu fikir askeri simülasyon dünyasında standartlaşmış durumda. Ağdaki simülatörlerin birbiriyle konuşması için kullanılan DIS (Distributed Interactive Simulation, IEEE 1278) standardı, konum ve duruş için eşikler ve belli aralıklarla tekrarlanan bir “kalp atışı” mesajı tanımlıyor.
Tahmin yanılınca: Zıplama mı, kayma mı?
Bağlantı koparsa, karşıdaki uçak ekranında dümdüz uçmaya devam eder. Sonra yeni bir paket gelir ve gerçek konum bambaşka bir yerdedir. Uçağı oraya bir anda ışınlarsan çirkin görünür. Bu yüzden genelde birkaç kare boyunca yumuşakça kaydırılır.
Bunun da garip yan etkileri var. Onions’ın örneği: Pistte beklerken bazen uçakların yerin içinden yükseldiğini görürsün. Yanlış konumdan doğru konuma kayarken arada toprağın altından geçmişlerdir. Flightradar’da uçakların bazen aniden zıplaması da aynı sebepten: Son bilinen veriden tahmin yapılıyor.
Herkesi aynı dikkatle izleme
Yirmi oyuncunun her biri herkesi tam ayrıntıyla bilmek zorunda değil. Genelde oyuncular birbirine değil bir sunucuya yazıyor. Sunucu her oyuncunun etrafında bir ilgi balonu çiziyor. Balonun içindekiler sık ve ayrıntılı güncelleniyor. Dışındakiler için kaba bir konum ve seyrek bir güncelleme yeterli. Uzaktaki uçağın burnu yukarıda mı aşağıda mı, zaten göremiyorsun.
Bu, grafik tarafındaki ayrıntı seviyesi (level of detail) fikriyle el ele gidiyor: Yakındaki uçak tam modelle, uzaktaki kaba bir şekille, çok uzaktaki tek bir noktayla çiziliyor.
Dünya büyük, sayılar sınırlı
Bir yarış oyununda pistin ortasını sıfır noktası seçer, birkaç kilometrelik bir alanda kalırsın. Uçuş simülatöründe dünyanın öbür ucuna uçabilirsin.
Sorun şu: Bilgisayarlar ondalıklı sayıları kayan noktalı (floating point) biçimde tutuyor ve bu biçimde hassasiyet, sayı büyüdükçe azalıyor. 32 bitlik bir sayıyla, sıfır noktasından binlerce kilometre uzakta konumu artık metre hassasiyetinde tutamıyorsun. Yan yana uçan iki uçak titremeye başlıyor. Çözüm ya 64 bitlik (double) sayılar ya da Onions’ın anlattığı karma yöntem: Birkaç sıfır noktası belirlemek (“1 numaralı nokta Londra”) ve pakette “şu noktaya göre şu kadar uzaktayım” diye göndermek.
Kendin dene
Birkaç nesne için konum ve hız tut, her karede x = x + hız × Δt ile ilerlet, sonra yapay paket kaybı ekleyip tahminin nasıl saptığını izle. Oyunlardaki “lag”in nereden geldiğini en iyi bu gösterir.
Düşün
- Bir haritada kuryeleri canlı gösteren bir uygulama yazsan, hangi bilgiyi UDP gibi “kaybolsa da olur” bir kanalla, hangisini güvenilir bir kanalla gönderirdin?
- Tahminin tutmadığı anı kullanıcıya nasıl gösterirdin: zıplatarak mı, kaydırarak mı?
Videoyu izle
Kaynaklar (4, İngilizce)
- Computerphile: Multiplayer Gaming & Flight Simulation (video) (yeni sekmede açılır)
- Gaffer On Games: What Every Programmer Needs To Know About Game Networking (yeni sekmede açılır)
- Gaffer On Games: UDP vs. TCP (yeni sekmede açılır)
- arXiv: Survey study of the QoS Management in Distributed Interactive Simulation Through Dead Reckoning Algorithms (yeni sekmede açılır)
Kendi cümlelerimizle yazılmış bir özettir, çeviri değildir. Tüm kaynaklar yukarıda.