İçeriğe geç

TEKNOLOJİ

Unity ile mobil oyun geliştirme: ölçülen seviyeler, test edilen sistemler

Unity ile geliştirdiğimiz mobil oyunlardan: deterministik seviye üretimi, çözücüyle zorluk ölçümü, okunabilirlik denetimi, sunucuda doğrulanan simülasyon.

KISA CEVAP

AMG Yazılım, Unity ve C# ile mobil bulmaca ve casual oyunlar geliştiriyor. Tilting Jar ve Puzzle Reveal App Store’da yayında; Screwsmith, SUNTHREAD, WARDLIGHT ve BEEing geliştirmede, One Shot ise bir prototip. Seviyeleri deterministik üretiyor, çözücüyle ölçüyor ve raporu depoda tutuyoruz: WARDLIGHT’ta taranan 3200 seviyenin tamamı çözülebilir ve yeniden üretimde bayt bayt aynı.

Hangi Unity oyunlarını geliştirdik, hangisi hangi aşamada?

Mobil oyunlarımızı Unity ve C# ile geliştiriyoruz; Tilting Jar, Puzzle Reveal, SUNTHREAD, WARDLIGHT, Mosquito ve BEEing Unity 6 üzerinde. Durumlarını olduğu gibi yazıyoruz:

  • Tilting Jar: App Store’da yayında. 300 seviye, 15 bölüm, 12 mekanik, 5 dil.
  • Puzzle Reveal: App Store’da yayında, sürüm 1.1.2. 50 elle ayarlanmış seviye ve sonsuz mod.
  • Screwsmith: geliştirmede. 200 pişirilmiş seviye ve 16 makine hazır; 1.0 için gizlilik ve destek sayfası yayında.
  • SUNTHREAD: geliştirmede. 320 seviyenin tamamı doğrulama raporundan sıfır hatayla geçiyor.
  • WARDLIGHT: Hallowmark için müşteri işi, geliştirmede. Ara teslimde sürükleme hissi onaylandı, 34 MB imzalanabilir Android paketi hazır.
  • BEEing: geliştirmede; lansman kış sezonuna planlandı.
  • Mosquito: geliştirmede; 15 seviye, 20 insan varyantı ve mağaza tamamlandı.
  • One Shot: prototip. Oynanabilir dilim uçtan uca doğrulandı; sanat, viral yayılım ve gelir modeli sonraki kilometre taşları.

Bu sayfadaki rakamlar oyunların depolarındaki README, plan, ilerleme ve rapor dosyalarından alındı.

Seviyeleri neden deterministik üretiyoruz?

Herkes aynı seviyeyi oynamıyorsa ne zorluk ayarlanabilir ne de bir hata raporu yeniden açılabilir. Bu yüzden seviye üretimini tekrarlanabilir kuruyoruz:

  • Tilting Jar’da ilk 24 seviye elle yazılmış bir öğretim merdiveni; sonrasında tohum seviye indeksinin kendisi ve 137. seviye her cihazda aynı. Bu, fiziğin her cihazda bit düzeyinde aynı çalıştığı iddiası değil; aynı olan başlangıç koşulları.
  • WARDLIGHT’ta üretici önce geçerli bir Hamilton yolu kuruyor, oklar, duvarlar ve kilitler o yoldan türetiliyor. Seviye yapı gereği çözülebilir; tohum seed = (uint)(level * 2654435761).
  • Screwsmith’te rastgelelik System.Random yerine xorshift32 ile üretiliyor, böylece her platformda ve her Unity sürümünde çıktı aynı.

Determinizmi oyun mantığını motordan ayırarak koruyoruz. Screwsmith.Core ve Wardlight.Core katmanlarında hiç UnityEngine referansı yok ve bunu asmdef zorunlu kılıyor. SUNTHREAD ve WARDLIGHT üreticileri önce Node’da referans olarak yazıldı; C# portu golden fixture’larla bayt bayt karşılaştırılıyor. Screwsmith’te seviye üretimi ve ölçümü -batchmode ile, editör penceresi açılmadan komut satırından koşuyor.

Zorluğu çözücüyle nasıl ölçüyoruz?

Mükemmel oyuna göre ölçülen zorluk yanıltıcı, çünkü neredeyse her seviye mükemmel oyunla geçiliyor. Screwsmith’in çözücüsü bu yüzden iki sayı üretiyor: mükemmel oyunda gereken en az ray yuvası ve makul bir insanın seviyeyi ne sıklıkla kaybettiği. Çözücü her seviyeyi 24 kez sığ bir stratejiyle oynuyor; kayıp oranı zorluk puanının baskın terimi (×11). 200 pişirilmiş seviyenin 157’si hedef banda tam isabet etti, 34’ü bir bant saptı. Eğri kasıtlı: 1–35 arasında ortalama insan kayıp oranı %0,8, seviye 36 bilinçli bir duvar (%37,5), 101–200 arası %34.

SUNTHREAD’de soru farklı: oyuncu gerçekten karar veriyor mu? WARDLIGHT motorunda 400. seviyede hamlelerin %100’ü zorunluydu. SUNTHREAD’in üreticisi beş kapı koyuyor: tek çözüm, silinemeyen ipuçları, yalnız isimlendirilmiş kurallarla ilerleyen insan tarzı bir çözücü, %35–70 bandında zorunlu hamle oranı ve son beş seviyeyle aynı kural kümesini reddeden bir parmak izi. Ölçülen oran 0,44 ile 0,79 arasında, ortalama 0,59.

Puzzle Reveal’da ilk sürümün formülü oyunu üçüncü seviyeden sonra kazanılamaz yapıyordu. 50 seviye elle ayarlandı; zorluk yöneticisi %65 kazanma oranını hedefliyor.

Okunabilirlik ve undo neden otomatik denetleniyor?

Bir seviyenin çözülebilir olması, oyuncunun onu okuyabildiği anlamına gelmiyor. Screwsmith’teki ReadabilityAudit piksel gerçeklerini oyun testinden önce yakalıyor: tahtayı gerçek cihaz çözünürlüğünde bir RenderTexture’a çiziyor ve seviyeyi oynarken her durumda yeniden ölçüyor.

  • Vuruş hedefi ekran genişliğinin en az %8,5’i, yaklaşık 4,7 mm. Seviye 178’de üç vida 0,084 genişlikteydi; denetim yakaladı.
  • Renk mesafesi CIE76 ΔE ile ölçülüyor: normal görüşte en az 11, kırmızı-yeşil renk körlüğü benzetiminden sonra en az 9. Yedinci renk sönük haldeki tabanı kırdığı için palet altı renkte kaldı.
  • HUD altında kalan vidalar aynı döngüde aranıyor.

Undo için de aynı yaklaşım geçerli. Çözücü geri dönerken oyunun kendi undo’sunu kullandığı için buradaki bir hata ölçümleri de bozuyor. UndoAudit.Run 200 seviyenin her birinde 60 hamleye kadar rastgele geçerli hamle yapıyor ve hamle öncesi tahtayı geri alma sonrasıyla karşılaştırıyor. Denetime güvenmeden önce bozuk bir simülasyona karşı başarısız olduğunu UseLegacyCrateUndo ve corruptSnapshot ile gösterdik.

Mosquito’da benzer bir kalite kapısı yedi ekranda ve altı cihaz çözünürlüğünde taşma arıyor.

Sunucuda doğrulanan simülasyon: One Shot hileyi nasıl yakalıyor?

One Shot günde tek atışla oynanan rekabetçi bir fizik bulmacası ve şu an bir prototip. Rekabetin şartı, aynı sahnenin herkeste birebir aynı davranması; kayan noktalı fizik ise motorlar ve derleyiciler arasında sapabiliyor.

Simülasyon çekirdeği UnityEngine’den bağımsız yazıldı ve CI bunu zorunlu tutuyor. Aynı .cs dosyaları üç çalışma zamanında derleniyor: Unity Mono, IL2CPP oyuncu derlemesi ve .NET 10 sunucu. 20 altın fixture üçünde de bayt bayt aynı sonucu veriyor.

Atış, girdi kaydıyla sunucuya gidiyor ve verify-shot onu yeniden simüle ediyor. Dürüst atış geçiyor; sahte bir "1 µm isabet" uyuşmazlık olarak işaretleniyor ve liderlik tablosu sunucunun sayısını tutuyor; imkânsız bir girdi kaydı reddediliyor. shots tablosunda user_id + scene_seed benzersiz, ikinci deneme 409 alıyor; spoiler duvarı Supabase RLS ile kapalı. Görsel smoke testleri sahneyi PNG’ye çizip boş olmadığını denetliyor ve dört gerçek görsel hatayı bu yolla yakaladı.

Son sözü sunucuya bırakma ilkesi başka oyunlarda da var: BEEing’de skor makullük denetimi ve sunucu zamanlı çevrimdışı kazanç, Mosquito’da skor ve kapılar Supabase Edge Function’larında doğrulanıyor.

Yayın zinciri, reklam ve satın alma nasıl kuruluyor?

Unity’den mağazaya giden yolda tek bir eksik ayar, uygulamanın açılışta çökmesi demek. Puzzle Reveal’da 13 numaralı derlemedeki açılış çökmesinden sonra zincir betiklendi: derleme, görsel testler, build numarası, iOS dışa aktarma ve Info.plist kapıları (AdMob kimliği, ATT metni, SKAdNetwork) tek komutta; bir kapı düşerse zincir duruyor. Bu yaklaşım sonraki oyunlarda da kullanılıyor. Tilting Jar’da Unity → Xcode → pod install adımları tek komutta yürüyor ve AdMob kimliği eksikse derleme durduruluyor.

Reklam ve satın alma katmanlarını sağlayıcıdan bağımsız kuruyoruz. Tilting Jar’da anahtar boşken oyun sahte bir mağazayla çalışıyor. WARDLIGHT’ta reklam, satın alma, analitik ve bulut senkron arayüz arkasında; oyun editörde tek SDK olmadan açılıyor. Bulut ve analitik için SDK yerine UnityWebRequest ile REST kullanıldı, çünkü IL2CPP’de güvenli ve paketi şişirmiyor.

Teklif motoru da ölçüme dayanıyor. Tilting Jar’da "reklamları kaldır" ancak beş geçiş reklamı gerçekten görüldüyse öneriliyor, ödüllü reklam hiç engellenmiyor ve ilerleme hiçbir zaman paraya kilitlenmiyor. İndirme, gelir ya da elde tutma garantisi vermiyoruz; ekonomi ve entegrasyon kapsamı ayrıca değerlendiriliyor.

Sık sorulan sorular

Elimizdeki bir prototipi ürüne dönüştürebilir misiniz?

Evet. WARDLIGHT’ta oyna.html prototipindeki seviye üreticisi Node’a birebir çıkarıldı ve altın referans oldu; tek değişiklik, duvar saatine bağlı arama sınırının sabit bir işlem tavanıyla değiştirilmesiydi. C# portu bu referansa karşı EditMode testlerinde karşılaştırılıyor. Prototip aşamasında temel döngüyü, kontrol hissini ve oyuncunun kararlarını değerlendiriyoruz; tam üretime geçiş bu değerlendirmeden sonra kararlaştırılıyor.

Seviyelerin çözülebilir olduğunu nasıl kanıtlıyorsunuz?

Raporla. WARDLIGHT’ta taranan 3200 seviyenin 3200’ü çözülebilir; aynı seviyeler iki kez üretildiğinde çıktı bayt bayt aynı. SUNTHREAD’de 320 seviyenin her biri JSON’dan yeniden kurulup beş adımda test ediliyor ve sonuç sıfır hata. Raporlar depoda duruyor ve istendiği an yeniden koşuyor. Screwsmith’te kazanan her aday, gönderilmeden önce kanıt aramasıyla bir kez daha doğrulanıyor.

Oyuncunun hangi seviyede bıraktığını görebilir miyiz?

Evet; analitik olaylarını sorunuza göre kuruyoruz. WARDLIGHT’ta müşteri tam olarak bunu sordu: uygulama hangi seviyede arka plana atıldı, oyuncu kaçıncı denemede yakalandı. Arka plana geçiş hem OnApplicationPause hem OnApplicationFocus üzerinden dinleniyor, çünkü Run-In-Background açıkken HOME tuşu pause değil focus üretiyor; olay tek kez loglanıyor. level_fail_caught deneme sayısını taşıyor.

Bir Unity oyununun backend’i ne olmalı?

Oyuna göre değişiyor; bazen hiç gerekmiyor. Screwsmith’in Günlük Tezgâhı tarihten tohumlanıyor, sunucu ve hesap istemiyor. Tilting Jar ilerlemeyi iCloud’a yedekliyor ve alan bazında en iyi değerle birleştiriyor. Sunucu kullanan oyunlarımızda Supabase var: BEEing’de 7 migration ve 14 Edge Function skor denetimi, çevrimdışı kazanç ve remote config’i taşıyor; WARDLIGHT Supabase ve Firebase’e SDK yerine REST ile bağlanıyor.

Oyun kaç dilde çıkabilir?

Dil sayısı kapsamın bir parçası olarak belirleniyor. Tilting Jar beş dilde (TR, EN, DE, ES, FR) ve dili otomatik algılıyor. BEEing için mağaza ekran görüntüleri, fragmanlar ve ASO metinleri altı dilde hazır: 8 sahne × 6 dil, telefon ve tablet için ayrı. Screwsmith’in Türkçe ve İngilizce mağaza metinleri Apple’ın karakter sınırlarına göre yazıldı.

Unity projelerinde testleri nasıl çalıştırıyorsunuz?

Motordan bağımsız C# katmanları EditMode’da, oynanış PlayMode’da test ediliyor. WARDLIGHT’ta 40/40 EditMode testi, SUNTHREAD’de 27 EditMode ve 34 PlayMode testi yeşil. BEEing’de 152 EditMode, 123 simülasyon ve 23 kooperatif smoke testi var; bir PolicyBot üç persona ile yedi gün oynayıp değişmezleri kontrol ediyor. Mosquito’da 25 PlayMode testi bir otopilot botuyla koşuyor.

Kaynak kod ve hesaplar kime ait olur?

Size. App Store ve Google Play geliştirici hesapları, sunucu ve servis hesapları sizin adınıza açılır. Teslimde kaynak kodun tamamını, tasarım dosyalarını ve tüm erişimleri size devrederiz.

Hazır şablon veya hazır panel kullanıyor musunuz?

Hayır. Kullanıcı ekranlarını ve yönetim paneli ekranlarını projenize özel olarak tasarlayıp sıfırdan geliştiririz. Böylece panel, sizin iş akışınıza göre çalışır.

İLGİLİ STÜDYO NOTLARI

Aklınızda bir fikir varsa,
konuşalım.

Bir tanışma görüşmesiyle başlarız. Kapsamı ve takvimi birlikte netleştirir, size yazılı bir teklif göndeririz.

hello@amgsoftwarestudio.com