holodepth

HTML5 Canvas · Render döngüsü

Delta time: kareler arası süre ve simülasyon adımı

Delta time (dt), animasyonlu bir canvas sahnesinde iki ardışık kare arasında geçen gerçek süredir — çoğu uygulama bunu saniye cinsinden tutar ve konum güncellemelerini x += v * dt biçiminde yazar. Böylece ekran 48 Hz ile 120 Hz arasında salındığında çizilen nesnelerin ekran üstündeki hızı yaklaşık sabit kalır; sabit 1/60 çarpanına mahkûm kalmazsınız. Bu sayfa, ölçümü nereden alacağınızı, birim sözleşmesini, ani gecikme ve düşük fps durumunda güvenli sınırları ve isteğe bağlı sabit adım modelini canvas üreticisi gözüyle sabitler.

Kareyi ne zaman planlayacağınız requestAnimationFrame konusunda; pikseli ne zaman sıfırlayıp yeniden boyayacağınız Clear & redraw sayfasında. Burada yalnızca her karede çizim öncesi «ne kadar zaman geçti?» sorusunun tek tip cevabı ön plandadır.

Özet: delta kullanım kalıpları

Kalıp Canvas’ta tipik kullanım Risk
Ölçülen dt (saniye) Hız → konum entegrasyonu; parçacık, kamera takip, veri animasyonu Çok büyük dt tünelleme / patlama; üst sınır gerekir
Sabit 1/60 varsayımı Hızlı prototip; grafik ölçeği sabit fps’e kilitlenir Yenileme farkı hissedilir; profesyonel üründe dt tercih edilir
Clamp edilmiş dt Oyun hissi + sekmeye dönüşte güvenli adım Üst sınır düşükse yavaş hareket «yapışık» görünebilir
Sabit adım + artık Tekrarlanabilir küçük fizik adımları; çoklu step aynı karede Fazladan CPU; ara değerle çizim (interp) ayrı düşünülür

Delta time: canvas simülasyonunda adım süresi

Basit zihinsel model: her requestAnimationFrame geri çağrısı bir «şimdi» zaman damgası taşır; bir önceki şimdi ile farkı alırsınız — işte ham delta. Bu farkı saniyeye bölerseniz (ms / 1000), bir kare içinde dünya durumunu ilerleten fonksiyonlarınız zamandan bağımsız hızlar ( units per second) ile konuşabilir. Canvas üzerinde oklar, ölçek animasyonları, yörünge veya grafik çizgisi kaydırması aynı kalıba girer: görsel nicelikleri dt ile ölçeklersiniz, kare sayısı ile değil.

dt = 0 ilk karede veya zaman damgası sıfırlandığında doğaldır; bu durumda «bir önceki konumu koru» veya fizik adımını atla dersiniz — aksi halde NaN yayan bölümler üretebilirsiniz. Yeniden başlatma (pause → play) sonrası aynı sıfırlama disiplini animasyonun geri sıçramasını azaltır.

Piksel düzeyinde yoğunlaşan çizim maliyeti, dt ile doğrudan telafi edilmez; yavaş cihazda kare süresi uzar, dt büyür, siz de aynı mantıkla daha az sıklıkta ama daha büyük adımla ilerlersiniz — bu, CPU maliyetini düşürmez, sadece simülasyon hızının görsel hızla uyumunu korur. Çizim optimizasyonu başka başlıkların boyasıdır.

Monotonik ölçüm ve ilk kare sözleşmesi

Üretimde tercih, tarayıcının rAF ile verdiği yüksek çözünürlüklü monotonik zaman damgasıdır ( DOMHighResTimeStamp); sistem saatine göre geri alınabilir veya sıçrayabilen Date.now tabanlı farklardan kaçınmış olursunuz. Önceki kare zamanını modül veya bileşen ömrü boyunca saklayın; her turda rawDt = (now - prev) / 1000, ardından prev = now ataması tipik sözleşmedir.

Sekme uzun süre gizlendikten sonra dönüldüğünde ham delta saniyeler mertebesine çıkabilir — bu normaldir ve bir sonraki başlıkta ele alınır. Görünürlük değişiminde prev = 0 veya «ilk kare bayrağı» ile bir sonraki turu sıfır deltada başlatmak, ani sıçrama hissini kullanıcıdan gizler ( rAF · görünürlük ile örtüşür; burada odak ölçüm matematiğidir).

Aynı kare içinde birden fazla alt sistem ayrı «yerel saat» tutuyorsa, hepsine aynı global dt iletmek tutarlılık sağlar; biri kendi içinde performance.now() farkını ayrı ölçüp farklı sonuç üretirse gölgeler ve parçacık katmanları birbirinden kayar.

Birim disiplini: saniye veya milisaniye

Ekip içinde tek karar seçin: ya herkes dt’yi saniye (0.016…) sayar ya da milisaniye (16.6…) — ikisini aynı dosyada karıştırmak, hız sabitlerini on kat yanlış yazdıran sessiz hatalar üretir. Fizik ve oyun motorlarında saniye yaygındır; bazı grafik tween kütüphaneleri ms kullanır: sınırda dönüştürün, canvas çizim katmanına girmeden önce tek tipe indirger.

Açısal hızlar ( rad/s) ve doğrusal hızlar ( px/s veya dünya birimi/saniye) aynı dt ile çarpılır; trigonometrik animasyonlarda radyan birikimi
angle += omega * dt şeklindedir — derece/saniye kullanıyorsanız çevrimi tek yerde yapın.

Zamanı metin olarak ekrana basan hata ayıklama HUD’ları, biçimlendirme için dt’yi ms’e çevirebilir; simülasyon çekirdeği yine saniyede kalmalıdır. Böylece tek kaynak gerçeği korunur.

Üst sınır, düşük fps ve kare sıçraması

Ham dt bir debug sekmesi açıldığında veya ana iş parçacığı kilitlendiğinde yükselir; tünelleme ( tunneling), büyük tek adımda çarpışma atlama veya patlama üretebilir. Bu yüzden üretim canvaslarında üst sınır ( clamp max) yaygındır — örneğin tek karede en fazla ~33 ms ( ~30 fps eşleniği) simüle et; daha uzun gerçek boşlukta dünya «yavaşlar» fakat patlamaz.

Alt sınır da kullanılabilir: aşırı yüksek yenilemede mikroskobik dt bazen sayısal gürültü yaratabilir; çok küçük değerleri bir tabanla ( epsilon) kesmek entegratörleri stabilize eder. İki sınırı sabit kodlamak yerine yapılandırma veya profil anahtarı yapmak A/B karşılaştırmasını kolaylaştırır.

Düşük fps’de görsel akıcılık ile simülasyon doğruluğu trade-off’tur: üst sınır agresifse oyuncu donmuş ekranda «yavaş dünya» görür; gevşekse tek karede büyük sıçrama riski artar — oyun türüne göre ayarlanır; bu sayfa formülü sabitlemez, karar çerçevesini verir.

function clampDtSeconds(raw, minS = 1 / 240, maxS = 1 / 30) {
  if (!Number.isFinite(raw) || raw <= 0) return minS;
  return Math.min(maxS, Math.max(minS, raw));
}

function integrateSprite(sprite, dt) {
  sprite.x += sprite.vx * dt;
  sprite.y += sprite.vy * dt;
}

Sabit zaman adımı ve biriken artık

Bazı canvas projelerinde her karede yalnızca bir kez step(dt_measured) yeterli değildir: çarpışma çözücü veya özel entegrasyon deterministik, sabit küçük adımlar ister. Model: gerçek kareden gelen dt’yi bir birikim değişkenine ekleyin; birikim, sabit adım ( h) büyüklüğünü aştığı sürece döngüde fizik çağırın ve birikimden h düşün. Bir karede iki–üç fizik adımı görülmesi normaldir; ağır sahnede üst tavan koymak «spiral of death» ( infinite catch-up) riskini azaltır.

Çizim tarafı genelde ölçülen veya kalan artığa göre interpole edilmiş ara poz ile yapılır; aksi halde dünya diskret adımlarla zıplar gibi görünür. Bu sayfa interpolasyon matematiğini açmaz — yalnızca fizik çağrı sayısı ile tek rAF çizimi ayrımını hatırlatır ( Update vs render konusuyla örtüşür).

Küçük eğitim demolarında sabit adım yerine doğrudan dt ile tek adım çoğu zaman yeterlidir; proje büyüdükçe tekrarlanabilirlik ve test yazımı sabit adımı zorunlu kılar.

let accumulator = 0;
const FIXED_STEP = 1 / 120;
const MAX_STEPS = 5;

function tickFrame(rawDtSeconds, stepPhysics, drawCanvas) {
  accumulator += rawDtSeconds;
  let steps = 0;
  while (accumulator >= FIXED_STEP && steps < MAX_STEPS) {
    stepPhysics(FIXED_STEP);
    accumulator -= FIXED_STEP;
    steps += 1;
  }
  drawCanvas(accumulator / FIXED_STEP);
}

Zaman ölçekleme ve sunum hızı

Yavaş çekim veya hızlandırılmış demo için efektif delta dt_eff = dt * timeScale kullanılır; timeScale = 0 duraklatma, 0.25 dörtte bir hız gibi. Canvas üzerinde dünya mantığı bu çarpanı paylaşır; kullanıcı arayüzü animasyonlarının gerçek zamanlı kalıp kalmayacağı tasarım tercihidir — HUD sayacı bazen ölçeklenmez.

Ease / tween kütüphaneleri kendi dahili süre değişkenlerini taşıyorsa, onları global timeScale ile beslemek veya dışarıda durdurmak sözleşmeye bağlıdır; iki farklı saat kaynağı çakışırsa nesneler biri geride biri önde görünür.

Kayıt / tekrar ( replay) senaryolarında deterministik sabit adım, wall-clock dt’den ayrı tutulabilir — bu ileri konudur; canvas öğretici içeriği için bilinçli sınır çizgisi yeterlidir.

Anti-kalıplar: entegrasyon ve motor karışması

Çift entegrasyon: Hem konumu dt ile hem de hızı ayrıca yanlışlıkla ikinci kez ölçeklemek — örneğin fizik motoruna dt verip dışarıda yine * dt çarpmak — nesneleri uçurur; her alt sistemde tek adımlık sözleşme yazın.

Kare sayacı = zaman: frameIdx / 60 saniye sanmak, gerçek dt dalgalanmasını gizler; video export veya senkron müzikte sapma birikir.

setInterval dt’si ile rAF çizimi: İki farklı zaman kaynağını birleştirirken hangi saatin «hakem» olduğunu belirtmezseniz ara kareler çift veya eksik güncellenir ( rAF · API ).

Clamp’sız uzun duraklama: İlk karede dev sıçrama; özellikle mobilde arka plana atlayıp dönüşte kullanıcıyı cezalandırır.

Bu sayfanın sınırı

Çok gövdeli ( rigid body) fizik, sürekli çarpışma ve ileri entegratörler ( RK4 vb.) burada işlenmez; odak, Canvas 2D sahnesinde yaygın skaler delta kullanımıdır.

Çok oyunculu ve sunucu otoriteli senaryolarda oyun saati ağ katmanı ile ayrı yönetilir; istemci tarafı interpolation / öngörü bu sayfanın kapsamı dışındadır.

  • Tüm kod tabanı aynı dt biriminde mi (saniye / ms)?
  • Ham delta mı yoksa clamp’lenmiş delta mı fizik çekirdeğine gidiyor?
  • Sekme / duraklatma sonrası prev sıfırlandı mı?
  • Sabit adımda birikim tavanı ve maksimum adım sayısı var mı?
  • Hud veya tween ile dünya saati çakışıyor mu?