holodepth

Oyun geliştirme · Three + fizik köprüsü

Sabit Timestep & Performans: Accumulator Köprüsü

requestAnimationFrame değişken aralık getirir; fizik motoru sabit adım ister. Bu sayfa accumulator desenini, görsel enterpolasyonu ve kare bütçesi bağlantısını anlatır. Platform FPS dilimi tekrarı değil; oyun fizik köprüsünün zaman sözleşmesidir.

Holodepth bu yaprağı motor içi integrator teorisi veya netcode rollback dersi olarak yazmaz. Web oyun döngüsü Loop & zaman bütçesi yaprağındaki rAF omurgasını fizik adımına bağlar. Çarpışma hook’ları Çarpışma tepkisi köprüsü yaprağında mühürlendi. Ms / jank SLA ve FPS mantığı Platform · FPS yaprağındadır. Deterministik çok oyunculu fizik ve motor içi Hexovian izleğindedir.

Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «rAF değişken dt verir; fizik sabit dt ile accumulator’da adımlanır. Görsel ara kare enterpole edilir. Spiral of death clamp edilir. Platform FPS ile ölçülür. Oyun geliştirme izleği burada kapanır.»

Accumulator deseni ilk bakışta fazladan karmaşıklık gibi görünür; ama tek bir hatalı world.step(frameDt) çağrısının cihazlar arası tutarsızlık üretmesi, bu karmaşıklığın maliyetini genelde birkaç saat içinde geri öder.

Bu sayfanın sınırı · komşu konularla ayrım

Bu sayfa Three + fizikte sabit timestep ve performans köprüsünü anlatır:

  • Accumulator deseni
  • Fixed dt vs variable render
  • Görsel enterpolasyon / extrapolation notu
  • Spiral of death ve clamp

Bilinçli olarak dışarıda bırakılan konular:

Kısa ayrım: Bu sayfa «fizik adımı zamanı nasıl sabitlenir?» · Loop bütçesi «rAF ve oyun fazları» · Platform FPS «ms dilimi ve ölçüm» · Hexovian «replike deterministik sim».

Neden sabit fizik adımı?

Variable dt ile fizik adımı: sekme yavaş cihazda artar, hızlı cihazda azalır; aynı girdi farklı sonuç üretir. Sabit adım (ör. 1/60 s) simülasyonu tekrarlanabilir kılar; render ise monitör hızına göre akar.

Holodepth: «her rAF’te bir world.step(frameDt)» varsayılanı web oyunu için risklidir; accumulator köprüsü üretim standardıdır.

Tekrarlanabilirlik sadece bug ayıklamayı kolaylaştırmaz; oynanış dengesini de korur. 144 Hz bir monitörde oynayan bir oyuncu, 60 Hz'de oynayan bir oyuncudan farklı bir zıplama yüksekliği veya çarpışma hassasiyeti yaşamamalıdır — sabit adım bu garantiyi verir, variable adım vermez.

Render akışkandır; fizik adımı sabittir.

Accumulator deseni

Her karede gerçek süre frameDt accumulator’a eklenir. Accumulator fixed dt’den büyük olduğu sürece fizik adımı çalışır ve accumulator’dan dt düşülür. Render, adımlar bittikten sonra (enterpolasyon ile) yapılır.

Holodepth pseudo-akış: ölç → biriktir → while (acc ≥ dt) step → sync / interpolate → render. Bu sıra mühürlenmezse debug zordur.

Bir karede sıfır fizik adımı çalışması normaldir (yüksek FPS'te accumulator henüz dt'yi doldurmamış olabilir); bunu hata sanıp «her karede en az bir adım» zorlamak, tam da kaçınılmak istenen variable step davranışına geri döner.

rAF köprüsü ve oyun fazları

Loop bütçesi yaprağındaki faz sırası korunur: input → simülasyon (fizik adımları) → senkron → render. Fizik adımı sayısı kare başına değişebilir; input okuma kare başına bir kez tipik kalır.

Çarpışma hook’ları fizik adımı içinde veya hemen sonrasında çalışır; render öncesi state tutarlı olmalıdır.

Girdi bir karede birden fazla fizik adımına yayılıyorsa (ör. 3 adım çalıştı), her adımda aynı input snapshot'ı kullanılmalıdır — adımlar arasında input'u yeniden okumak, tek bir tuş basışının üç kez sayılmasına yol açabilir.

Görsel enterpolasyon

Son fizik durumu ile bir önceki durum arasında alpha = accumulator / dt ile mesh pozisyonu enterpole edilir; hareket pürüzsüz görünür. Holodepth: enterpolasyon görsel içindir; oyun mantığı son tamamlanan fizik adımına bağlanır.

Extrapolation (tahmin) düşük gecikmede kullanılabilir; yanlış pozisyon riski vardır. Web vitrinlerinde enterpolasyon yeterlidir.

Enterpolasyon için önceki ve şimdiki fizik pozisyonunu ayrı alanlarda tutmak gerekir (prevPosition, currentPosition); mesh'e doğrudan motor pozisyonunu yazmak bu iki değeri birbirine karıştırır ve alpha hesaplaması anlamsızlaşır.

Spiral of death ve clamp

Kare süresi uzayınca accumulator çok adım ister; fizik CPU’yu yiyerek bir sonraki kareyi daha da geciktirir. Holodepth: frameDt üst sınırı (ör. 0.25 s) ve kare başına maksimum adım sayısı clamp edilir. Geri kalan accumulator bilinçli drop veya «yavaş çekim» politikası ile yönetilir.

Clamp olmadan sabit adım üretimde çöküş üretir; ölçüm Platform · FPS ile doğrulanır.

maxSteps sınırına ulaşıldığında oyunun «yavaşladığını» hissettirmek, aniden donmasından daha iyi bir kullanıcı deneyimidir — Holodepth önerisi, drop edilen zamanı sessizce yok saymak yerine bir «yavaş çekim» (slow-mo) sinyaline çevirmektir.

Güvenli döngü: simüle accumulator

Örnekler öğretim amaçlıdır; motor step(dt) imzasını sürümünüzde doğrulayın. Sonsuz while döngüsüne karşı maxSteps zorunludur.

Simüle · fixed step game loop (yüzey şekli).

const FIXED_DT = 1 / 60
const MAX_FRAME_DT = 0.25
const MAX_STEPS_PER_FRAME = 5

let accumulator = 0
let lastTime = performance.now()
let previousStates = new Map()
let currentStates = new Map()

export function createFixedStepLoop({ world, syncBodies, render }) {
  function tick(now) {
    let frameDt = (now - lastTime) / 1000
    lastTime = now
    frameDt = Math.min(frameDt, MAX_FRAME_DT)
    accumulator += frameDt

    let steps = 0
    while (accumulator >= FIXED_DT && steps < MAX_STEPS_PER_FRAME) {
      snapshotPrevious(previousStates, currentStates)
      world.step(FIXED_DT)
      syncBodies(currentStates)
      accumulator -= FIXED_DT
      steps += 1
    }

    const alpha = accumulator / FIXED_DT
    interpolateMeshes(previousStates, currentStates, alpha)
    render()
    requestAnimationFrame(tick)
  }

  requestAnimationFrame(tick)
}

function snapshotPrevious(prev, curr) {
  for (const [id, state] of curr) prev.set(id, { ...state })
}

function interpolateMeshes(prev, curr, alpha) {
  for (const [id, now] of curr) {
    const was = prev.get(id)
    if (!was || !now.mesh) continue
    now.mesh.position.lerpVectors(was.position, now.position, alpha)
    now.mesh.quaternion.slerpQuaternions(was.quaternion, now.quaternion, alpha)
  }
}

Simüle · adım sayısı telemetrisi (ölçüm kancası).

// Platform FPS yaprağındaki ms dilimi ile birlikte okuyun.

export function createStepMetrics() {
  const samples = []
  return {
    record(steps, physicsMs) {
      samples.push({ steps, physicsMs, t: performance.now() })
      if (samples.length > 120) samples.shift()
    },
    p99PhysicsMs() {
      if (!samples.length) return 0
      const sorted = samples.map((s) => s.physicsMs).sort((a, b) => a - b)
      const idx = Math.floor(sorted.length * 0.99)
      return sorted[Math.min(idx, sorted.length - 1)]
    },
    avgSteps() {
      if (!samples.length) return 0
      const sum = samples.reduce((n, s) => n + s.steps, 0)
      return sum / samples.length
    },
  }
}

// Holodepth: avgSteps sürekli MAX'e yakınsa clamp veya gövde sayısı gözden geçirilir.

Performans notları

Sabit adım gövde sayısıyla doğrusal ölçeklenir; sleeping, broadphase ve basit collider seçimi motor yüzeyi yaprağıyla birlikte düşünülür. Hook maliyeti adım başına eklenir; stay spam fizikten bağımsız CPU yer.

Worker’da fizik adımı ileri seviye konudur; Holodepth web oyunu köprüsü ana iş parçacığında accumulator ile başlar. Derin paralel sim Hexovian’dadır.

Sabit dt'yi 1/60'tan 1/120'ye düşürmek «daha kararlı» hissettirebilir, ama adım sayısını ikiye katlayarak CPU maliyetini de ikiye katlar — bu değişimi yalnızca ölçümle doğrulanmış bir kararlılık sorunu varsa yapın, varsayılan olarak değil.

Zaman tuzakları

  1. Variable step: her rAF’te frameDt vermek.
  2. Clamp yok: spiral of death.
  3. maxSteps yok: donma riski.
  4. Enterpolasyon yok: titreyen görsel.
  5. Oyun mantığı alpha’da: tutarsız skor.
  6. Ölçüm yok: «hissettim» optimizasyonu.
  7. Netcode determinizm: Hexovian konusu.

Üç zaman profili

Üç profil de aynı accumulator iskeletini paylaşır; ayrışan şey dt büyüklüğü, clamp politikası ve enterpolasyon kalitesidir.

  • 01 · Zaman

    Vitrin fizik

    dt
    1/60 · az gövde
    Interp
    Basit lerp
    Risk
    Variable step tembelliği
  • 02 · Zaman

    Web oyunu

    Clamp
    maxSteps + frameDt cap
    Ölçüm
    Platform FPS
    Risk
    Spiral
  • 03 · Zaman

    Yoğun sahne

    dt
    1/120 veya alt gövde
    Politika
    Drop accumulator
    Risk
    Ölçeksiz adım

Holodepth perspektifleri

Önce ölç, sonra dt oyna

1/120’ye geçmeden önce adım ms ve gövde sayısını yazın; Platform FPS ile doğrulayın.

İzlek kapanışı

Döngü, girdi, entity, fizik yüzeyi, çarpışma tepkisi ve şimdi sabit adım — altı yaprak birlikte web/Three için minimal ama üretime hazır bir oyun köprüsü oluşturur. Daha derin motor ihtiyacı Hexovian sınırında karşılanır.

Teşhis maddeleri

  1. Accumulator var mı?
  2. frameDt clamp ediliyor mu?
  3. maxSteps sınırı var mı?
  4. Görsel enterpolasyon uygulanıyor mu?
  5. Oyun state son adıma mı bağlı?
  6. Fizik ms Platform FPS ile etiketli mi?
  7. Netcode determinizm Hexovian’a kaymış mı?

Holodepth içgörüsü

«Fizik titriyor» çoğu zaman collider değil; variable step veya enterpolasyon eksikliğidir. Önce accumulator okuyun.

İzlek kapanışı: oyun geliştirme 6/6

Three + fizik köprüsü izleği burada kapanır. Döngü, girdi, entity, motor yüzeyi, çarpışma tepkisi ve sabit adım birlikte web Three oyununun zaman ve fizik omurgasını verir. Geniş döngü ve bütçe için Loop & zaman bütçesi yaprağına dönün; motor içi, ECS ve netcode için Hexovian izleğine geçin. Holodepth oyun geliştirme yolu 6/6 tamamlanmıştır.