Oyun Geliştirme

Sunset Express

İptal Edilmiş Prototip

İptal ettiğimiz bir co-op fizik prototipi — ve çalışan sistemlerle işleyen bir oyun arasındaki farka dair bana öğrettikleri.

Rol
Oyun Tasarımı, Oynanış & Ağ Programlama
Ekip
3 kişilik ekip
Süre
6 hafta
Yıl
2026
Motor
Unity · C#
Araçlar
  • Unity
  • C#
  • FishNet
  • Networked Physics
  • GitHub
  • Ortak rigidbody ile taşıma — tek bir tabut, iki ayrı istemcinin uyguladığı kuvvetlerden çözümleniyor
  • FishNet'in tick döngüsüne hizalanmış, tek bir simülasyon sahibi olan ağ üzerinden fizik
  • Yükün kütle merkezini kaydıran ceset simülasyonu ve okunabilir tutuş kopma uyarıları
  • Dahili Stage 0 his testini geçti; daha sonra tasarım ve mimari gerekçelerle iptal edildi
İçindekiler

Dengesiz bir tabutu taşımak üzerine kurulu, kooperatif bir fizik oyunu — iki oyuncu için geliştirildi, dört oyuncuya ölçeklenecek şekilde tasarlandı. 2026 ortasında, Steam’i hedefleyerek, üç kişi Unity’de yaklaşık altı hafta üzerinde çalıştık. Ağustosta durduk. Nedeni, sonuçtan daha önemli:

Çalışan mekaniklerin bir araya gelmesi, her zaman ilgi çekici bir oyun ortaya çıkarmaz.

Fikir

Dört arkadaş, batmak üzere olan bir cenaze nakliye şirketi işletiyor. Komedinin yazılmış esprilerden değil fizikten doğması gerekiyordu — bu yüzden taşınan nesnenin bir dekor parçası gibi değil, başka bir oyuncu gibi davranması gerekiyordu. Oyunu dört temel ilke yönlendirdi:

  • Fair jank (adil sakarlık) — her düşüş komik ve hak edilmiş olmalı, asla keyfi değil
  • Beşinci oyuncu olarak tabut — değişen kütle merkezi, kayan ceset, açılan kapak
  • Koordinasyon komedisi — tek başına basit, birlikte kâbus olan engeller
  • Küçük kapsam, yüksek cila — etrafına içerik kurmadan önce taşımayı kanıtla

Rolüm

Oynanış ve ağ programlamanın yanında oyun tasarımını da üstlendim. Tabut fiziği, tutma / bırakma / kopma sistemleri, ceset simülasyonu, oyuncu kontrolleri ve kamera, taşıma ve zıplama davranışı ile ağ mimarisi benim sorumluluğumdaydı. Sanat, seviye içeriği ve tasarımın bir kısmı ekibin geri kalanına aitti.

Neler İşe Yaradı

Tek bir ortak gövde, iki istemci. Tabut hiçbir zaman kinematik değildi — gerçek bir kütlesi vardı ve iki farklı oyuncunun uyguladığı kuvvetlerden çözümleniyordu; böylece her taşıyıcı, diğerinin ne yaptığını hissediyordu.

Hareket eden bir yük. Belirli bir eğim eşiğinin ötesinde ceset kayıyor ve tabutun kütle merkezini kaydırıyordu. Panik bir animasyondan değil, kuvvet dengesinden doğuyordu.

Geldiğini görebildiğin başarısızlık. Tutuş kaybı, okunabilir uyarı aşamalarıyla tırmanıyordu. Kaos kabul edilebilirdi; rastgelelik değildi.

Senkronize zıplama. İki oyuncunun birlikte zıplaması başta her tutuşu koparıyordu. Çözüm zıplamaları zayıflatmak değildi: kısa bir zaman penceresi içinde kopma eşiği gevşiyor ve eklem sertleşiyordu; böylece itki, bağlantıyı koparmak yerine tabutu kaldırıyordu.

Tick’e hizalı ağ üzerinden fizik. Unity’nin fiziği kendi başına ilerletmesine izin vermek yerine, Unity’nin simülasyon adımını FishNet’in tick döngüsüne devrettim. Oyuncular istemci tarafında tahmin ediliyor ve sunucuya göre uzlaştırılıyor (reconciliation); tabut ise öyle değil — host tarafından simüle edilip replike ediliyor, çünkü otoriteyi onu kim tutuyorsa ona vermek, iki kişi onu aynı anda tuttuğu anda bozuluyor. İki tarafın da aynı sıralı tick’e ihtiyacı var; pipeline’ın garanti ettiği de tam olarak bu.

Stage 0 Geçildi

Prototipin yazılı tek bir geçiş kriteri vardı: iki oyuncunun boş bir sahnede tabutu yaklaşık on beş dakika taşıması ve hâlâ keyif alması. Bir hata avı değil, bir his testi — ölçüt kahkahaydı ve görsel cila, karara bilerek dahil edilmedi.

Taşıma, döndürme, tutuş gerilimi, kopmanın okunabilirliği, kapak ve ceset davranışı ile senkronize zıplamayı test ettik. Geçiş kriteri karşılandı — temel etkileşim çalışıyordu.

Oyun Testinin Değiştirdikleri

Tabut fazla hafif hissettiriyordu. Kolay çözüm, taşıma sırasında bir hız cezası uygulamaktı. Bunun yerine, tabutun gerçek kütlesi oyuncuları yavaşlatsın diye kuvvet sınırlı bir hareket modeline geçtik. Semptomu maskelemek yerine tasarım kuralını koru.

Cesedin fırlaması fazla aniydi. Eşiğin üzerindeki tek bir kare, cesedin kalıcı olarak fırlamasına yol açabiliyordu. Bunu, koşulun kesintisiz olarak sürmesini gerektirecek şekilde değiştirdik. Kalıcı sonuçların okunabilir nedenleri olmalı.

Kapak hasarı yansıtmıyordu. Hiçbir zaman ortaya çıkamayacak bir sonuç için hasar değerlerini ayarlıyormuşuz — davranışı yöneten menteşe yayı aktif değildi. Parametreleri ayarlamadan önce sistemi teşhis et.

Oyunun Tıkandığı Nokta

Sorun mekaniklerin başarısız olması değildi. Bunların bir bütün oluşturduğuna kendimizi ikna edemememizdi.

Prototip his testimizi geçti, ama proje büyüdükçe etkileşimin planladığımız oyunu taşıyacak kadar derinlik ürettiğinden giderek daha az emin olduk. Hâlâ sürekli karar almayı gerektiren bir yapıya, taşımanın yeniliğinin ötesine geçen bir çeşitliliğe ve oyuncuların kontrat üstüne kontrat tekrarlamak isteyeceği bir döngüye ihtiyacımız vardı.

Tabutla etkileşimin eğlenceli olabileceğini kanıtladık. Onu tekrar tekrar taşımanın bir oyunu ayakta tutmaya yeteceğini kanıtlamadık.

Ragdoll Pivotu

İkinci ders mimariyle ilgiliydi ve daha pahalıya mal oldu.

Co-op temeli çalışır hale gelince karakterleri aktif ragdoll’a dönüştürmeye karar verdik. Gerekçe sağlamdı — taşınan nesne kuvvet tabanlıysa, karakterler de kuvvet tabanlı olmalıydı. Hata, bunun oyunu ayakta tutan mimariyle uyumlu olduğunu varsaymaktı.

  1. Aktif bir ragdoll rig’i kurmak. Dokuz runtime sınıfı. Eklemli yapı, ağ uzlaştırması altında hiçbir zaman deterministik olarak oturmadı. Bırakıldı.
  2. Aynı yaklaşımı daha sıkı ayarlamak. Bir profil asset’i ve bir debug düzeneği ekledim — modeli sorgulamak yerine ayar yüzeyini genişlettim. Bırakıldı.
  3. Çalıştığı bilinen bir referanstan yeniden kurmak. Bu, değişken olarak kendi kodumu izole etti. Çakışma sürdü. Geliştirme durdu.

Tek bir ortak rigidbody’yi iki makinede uyum içinde tutmak haftalar almıştı. Düzinelerce artiküle eklem eklemek bu kısıtı taşımak değildi — onu delip geçmekti; üç kez, her denemede daha fazla kodla.

Bu özellik, oyunu ayakta tutan kısıtla uyumlu mu?

Neden Durduk

İptal etmek bir prodüksiyon kararıydı. Devam etmek, alttaki döngünün ölçeklenmeye değer olduğunu kanıtlamadan önce içeriği genişletmeye ve teknik problemleri çözmeye daha fazla zaman harcamak anlamına gelecekti. Artık güvenmediğimiz bir temele yatırım yapmaya devam etmek yerine durmayı seçtik.

Neyi Farklı Yapardım

  • Yalnızca etkileşimi değil, döngüyü doğrula. İyi geçen otuz saniye, iyi geçecek yirmi dakikanın kanıtı değildir.
  • En riskli varsayımı önce bir spike ile test et. Tek bir izole sahne, tek bir soru: eklemli bir gövdede, rewind sonrasında iki istemci aynı pozu üretiyor mu? Bir “hayır” cevabı iki hafta yerine iki güne mal olurdu.
  • Ayar problemlerini mimari problemlerden ayır. Tekrarlanan parametre değişiklikleri davranışı iyileştirmeyi bıraktığında, şüpheli modelin kendisidir.
  • Rollback branch’ini pivottan önce aç. Bizimkini, işler çoktan ters gittikten sonra açtık.

Teknik zorluk ve tasarım kalitesi farklı problemlerdir. Zorlu mühendislik problemlerini çözdük ve yine de bitirmeye değer bir oyunumuz olmadı.

Dahili çalışma adı ve repository adı: Coffin.