xkcd'nin "Machine" Geliştirme Notları
İlk fikir
- Mart sonuna kadar fikir üzerinde düşündükten sonra Nisan başında karar verilen fikir
- "Something Awful kullanıcılarının yaptığı blueball GIF'i gibi döşeme tabanlı dev bir düzenek yapabilir miyiz? Herkes küçük bir kareye katkıda bulunacak."
- Başta fikir tam olarak şekillenmiş gibi geliyordu, ancak gerçekten konuşmaya başlayınca hâlâ verilmesi gereken çok sayıda karar olduğunu fark ettiler
- Topun nereden çıkacağı, herkesin aynı makineyi görüp görmediği, amacın ne olduğu, oyuncuların nasıl etkileşime gireceği gibi temel noktalarda farklı düşüncelere sahiptiler
Önceki denemelerden öğrenilenler
- Kullanıcı üretimi içerik odaklı interaktif çizgi roman yapma deneyimi vardı
- Lorenz: Okurların panel metinlerini yazarak şakayı ve hikâyeyi geliştirdiği bir exquisite corpse çalışması (çok eğlenceliydi)
- Collector's Edition: Okurların xkcd arşivine gizlenmiş çıkartmaları bulup paylaşılan tuvale kalıcı olarak yapıştırdığı bir oyun (istenen sonucu vermedi)
- Başta boş bir merkez haritayla başlamak kaosa yol açtı
- Çıkartma yerleştirme konusunda teşvik az olduğundan, bireysel davranışlarla olay örgüsünü ilerletmek zordu ve sadece basit desenler oluştu
- Genel bir hikâye ya da hedef yoktu ve çıkartmaların birbirleriyle ilişkisi de belirsizdi
- Ortak bir tuvalin başarılı olması için insanlara neler yapılabileceğini örneklerle göstermek ve paylaşılan bir bağlam ile amaç sağlamak gerekiyor
Kısıtların tasarlanması
- Büyük bir bilye düşürme makinesi yapmaya karar verdikten sonra fazla sayıda seçenekle karşı karşıya kaldılar
- 100x100 boyutunda bir grid kullanmaya karar verdiler
- İstemci tarafında 10 bin döşemeyi gerçek zamanlı simüle etmek riskli görünüyordu
- Oyuncuların doğrudan iletişim kurmadan karmaşık bir makinenin alt bölümlerini nasıl yapacağı ve ayrık döşemeler birleştirildiğinde bunun çalışıp çalışmayacağı belirsizdi
- Birçok düşünce deneyi sonunda 3 temel ilke belirlendi:
1. Doğruluğu feda etme pahasına bile oyuncu ifadesini en üst düzeye çıkarmak
- Makine ne kadar öngörülebilir olmalı?
- Tüm sistemi sunucuda çalıştırmak ya da tek tek döşemeleri doğrulamak da düşünüldü, ancak prototip editörde kaotik bilye çarpışma düzenlerini kolayca üretmenin mümkün olduğu görüldü
- Bilyeler engellenmeden düz çizgide hareket etmiyorsa öngörülemez makineler üretmek kolaylaşıyordu
- Makinenin öngörülebilirliğini artırmak, oyuncu özgürlüğüyle çelişiyordu
- Sıkışık geliştirme takvimi de daha az tahmin/simülasyon gerektiren yaklaşımı tercih etmelerine yol açtı
- Son derece deterministik olmayan ya da bozuk makineler dahil, oyunculara çok esnek bir üretim özgürlüğü vermeye karar verdiler
- Kısıtların karşılanıp karşılanmadığını denetlemek ve uygunsuz içeriği kaldırmak için aktif moderasyon gerekiyordu
2. Uyumlu ve değiştirilebilir makineleri teşvik eden katı kısıtlar sağlamak
- Moderasyon gerekliliği ve öngörülemez oyuncu makineleri, tersine daha fazla düzen ihtiyacını doğurdu
- Başta giriş/çıkışları tamamen serbest biçimli düşünmüşlerdi, ancak moderasyon sürecinde ilk döşemelerin değiştirilmesinin büyük çaplı arızalara yol açabileceğini fark ettiler
- Aynı döşeme alanında birden fazla oyuncunun uyumlu tasarımlar yapabilmesi için yeterince güçlü kısıtlar tasarlandı
- Robustness ilkesi uygulandı: "Gönderdiğinde tutucu ol, aldığında hoşgörülü ol"
- Giriş/çıkış kısıtları koyabilmek için baştan tüm makine haritasına ihtiyaç vardı
- Harita üretimiyle makinenin zorluk seviyesi ayarlanabildi (basit 1 giriş 1 çıkıştan karmaşık 4 giriş 4 çıkış birleşmelerine kadar)
- Gerçek zamanlı geri bildirim vermek için döşemelerin aldıklarına yakın bir hızda bilye çıkarması şart koşuldu
- Bilyeleri yutan ya da geciktiren makineler kısıtlandı
- Döşemeler rastgele giriş hızlarıyla kaos testine tabi tutuldu
- "Makineyi bir süre çalıştır ve ortalamada kısıtları karşılayıp karşılamadığını kontrol et" ilkesi benimsendi
3. Makine ilk 30 saniye içinde kararlı duruma ulaşmalı
- Moderatörün ne kadar süre izlemesi gerektiği sorusu ortaya çıktı
- Tüm makinenin moderasyon süresini hesapladılar (10 bin döşeme için 83,3 saat)
- 30 saniye içinde kararlı duruma geçmesi yönünde keyfi bir karar aldılar
- Bilyelerin 30 saniye sonra kaybolması sağlandı
- Başta zaman aşımı yoktu, bu yüzden oyuncular oyunu öğrenirken bilyeler birikiyor ve ekranı dolduruyordu
- Etkin rigid body sayısı arttıkça fizik simülasyonu yavaşlıyordu
- Bilyeler eğlenceden çok engel hâline geliyordu
- Bilye süre sonu sayesinde makine zamanla hata biriktirmez oldu
- Moderatör yalnızca 30 saniye izleyerek çoğu bilyenin nereye gidebileceğini anlayabiliyordu
Simülasyon ve hipergerçeklik
- Machine mimarisindeki iki büyük zorluk:
- Yukarıdaki tasarım kısıtlarıyla farklı döşemeleri birbirine bağlayıp bütün bir makine oluşturmak işe yarayacak mı?
- Bunu doğrulamak için birkaç küçük harita üretip çözdüler
- Devasa makineyi sunucuda ya da istemcide gerçek zamanlı çalıştırmak mümkün değilse, bunu nasıl gösterecekler?
Kaydırırken tek bir bilyeyi takip etmeyi mümkün kılmak hedefleniyordu
- Tüm makine simüle edilmese bile, oyuncunun gördüğü alanın çevresi simüle edilmeliydi
- Başta sonsuz haritada yalnızca görünen alanı simüle etmeyi denediler
- Oldukça iyi çalıştı, ancak kaydırma sırasında döşemeler simülasyona boş başlangıç durumuyla giriyor ve akışta boşluklar oluşuyordu
- Boş döşemeler yerine, sanki hâlihazırda etkinlik varmış gibi görünmesi gerekiyordu
İkinci zorluk: döşemelerin anlık görüntüsünü yalnızca kararlı duruma ulaştıktan sonra almak ve bunların yalnızca kaydırmayla görünmeden hemen önce var olmasını sağlamak
- Son çizgi romanda görüntü kırpmayı kapatılmış görünüm (CSS overflow:hidden, contain:paint devre dışı):
- Anlık görüntüleri fark ettiniz mi? Özellikle dikkat etmezseniz fark etmek zor
- Yalnızca render edilen döşemeler fizik simülasyonunda gerçekten var
- Görüntü optimizasyonu: Sadece görünüm alanındaki bilyeler gösteriliyor, ama simülasyon tüm döşeme aralığında yürütülüyor
- Makinenin üst kısmını taklit etmek için simülasyonun en üst satırında bilyeler oluşturulup besleniyor (giriş kısıtlarının beklenen hızına göre)
- Moderasyon UI'ına anlık görüntü oluşturma eklendi
- Moderatör, bir döşemeyi onaylamadan önce en az 30 saniye beklemek zorunda
- Onay düğmesine basıldığında anlık görüntü oluşturuluyor
- Moderatör isterse makine iyi görünene kadar biraz daha bekleyebiliyor
- Anlık görüntü yaklaşımı beklenenden de iyi çalıştı
- Makinede biriken hataları sıfırlamak gibi olumlu bir etkisi oldu
- Kaydırırken görülen döşemelerin ilk izlenimi, moderatörün beğendiği temiz ve iyi bir durum oluyor
- Gerçekte uzun süre izlendiğinde birçok makine bozulabiliyor ya da dağıtabiliyor, ancak keşfetmeye devam ettikçe yeni anlık görüntülere girildiğinden bunu görmek gerekmiyor
- Çizgi romandaki kaydırılan makine gerçek değil. Hipergerçek
- Tümü aynı anda simüle edilmiyor, ama bu aslında daha iyi bir sonuç veriyor
React ve DOM ile binlerce bilye render etmek
- Rapier fizik motoru üzerine kuruldu
- Güçlü dokümantasyonu, kullanışlı temel yapı taşları için temiz API'si ve Rust implementasyonu (tarayıcıda WASM olarak çalışıyor) sayesinde etkileyici performans sundu
- Başta Rapier'in determinizm garantisi cazip gelmişti, ancak sunucu tarafı simülasyon yapılmadı
- Rapier üstüne özel bir React context olan
<PhysicsContext> yazıldı
- Rapier fizik nesnelerini oluşturup React component lifecycle içinde yönetti
- Fizik ya da çarpışma yüzeyi olan, yerleştirilebilir her nesne için "widget" component'leri geliştirmeyi kolaylaştırdı
- React burada basit ve kirli bir scene graph görevi gördü
- Görünüm kaydırılırken döşeme yükleme/boşaltma basitleşti: bir döşeme unmount edildiğinde tüm fizik ve DOM temizleniyor
- Bonus olarak hot reloading'i fast refresh'e bağlamak kolaylaştı (çarpışma şekillerini ayarlamak için gerçekten çok iyiydi)
- React context yaklaşımının bir başka avantajı:
- Fizik hook'ları
<PhysicsContext> içinde değilse noop oluyor
- Bu sayede moderasyon UI'ında statik döşeme önizlemeleri render etmekte kullanılabildi
- Rapier nesnelerini oluşturmak için hook yerine component kullanmış olmayı isterdi (
react-three-rapierın yaptığı yaklaşım)
- React diffing ile daha iyi uyuşuyor (bağımlılıklar değiştiğinde
useEffect, önceki instance'ı kaldırıp yeniden oluşturuyor)
- Machine tamamen DOM kullanılarak render edildi
- Geliştirmenin başlarında performans açısından DOM render etmenin sınırlarına dayanma endişesi vardı
- Fazla yavaşlarsa PixiJS ya da canvas'a geçmeleri bekleniyordu, ancak DOM ile ne kadar ileri gidilebileceğini görmek istediler
- Render performansı optimizasyonu:
- Frame loop, fizik simülasyonu olan widget'lara doğrudan stil uyguluyor
- React'in diff işlemi yalnızca scene graph üzerinde yapısal değişiklik olduğunda çalışıyor
- Başta bilyeleri React ile
1 yorum
Hacker News yorumu
Çeşitli yorumlar bir araya getirildiğinde, özetle şu içerik ortaya çıkıyor:
Rapierfizik motoru kullanıldı, ancak özyinelemeli bir hata nedeniyle çökmeler de yaşandı