Ana Başlık 1. deltaTime ile Zaman Tabanlı Hareket
Amaç: deltaTime ile frame hızından bağımsız hareketi öğreterek taşınabilir animasyon kurmak.
Öğrenme Çıktıları:
- Frame başına sabit adım sorununu açıklar.
- deltaTime birimini ve kullanımını uygular.
- Hızı saniye başına birim olarak yazar.
- Hareketli top örneğinde zaman tabanlı güncelleme kurar.
Anahtar Sözcükler: deltaTime, zaman tabanlı hareket, hız, taşınabilirlik
Giriş
FPS ve frameRate bilindikten sonra asıl çözüm gelir: hareketi frame sayısına değil geçen süreye bağlamak. deltaTime son frame’den bu frame’e geçen milisaniyeyi verir; x += hiz * (deltaTime / 1000) ifadesi hızı “birim / saniye” yapar. Böylece 30 FPS ve 60 FPS’te top benzer gerçek hızda ilerler.
Bu ana başlık sorunu, formülü ve hareketli top örneğini işler. Sonraki diziler ve klavye kontrolü, bu zaman modelinin üzerine çoklu varlık ve girdi ekler. Bundan sonra gelen alt başlıklarda önce veri modeli, sonra hamle kuralı, en sonda çizim ve etkileşim kurulur. Her yeni fonksiyon mümkün olduğunca küçük bir örnekte çalıştırılır; böylece hatanın kaynağı daha kolay bulunur. Anlatımda önce ilgili yapının ne işe yaradığı açıklanır, ardından kod satır satır okunur. Terimler ilk geçtikleri yerde kısa bir tanımla verilir; gerekirse tablo veya görsel ile desteklenir. Örnek sketch’ler tek bir mekaniğe odaklanır; böylece yan konular okumayı dağıtmaz. Parametreleri değiştirip yeniden çalıştırmak, kuralın sınırını görmenin en hızlı yoludur. Bu ana başlığın çıktısı, sonraki oyunda yeniden kullanılabilecek bir iskelet oluşturur.
1.1. Frame Başına Hareketin Sorunu
Frame başına sabit piksel ekleme (topX = topX + 3) sezgiseldir; fakat hız frame sayısına bağlıdır:
Tablo 1.
| Makine | Yaklaşık FPS | Saniyede +3 ile kayma (60 frame varsayımı vs 30) |
|---|---|---|
| Hedef 60 FPS | ~60 | 60 × 3 = 180 piksel/saniye |
| Hedef 30 FPS | ~30 | 30 × 3 = 90 piksel/saniye |
Aynı kod, farklı frame hızında farklı oyun hızı üretir. Oyuncu deneyimi makineden makineye değişir; fizik tabanlı veya ağ üzerinden senkronize oyunlarda bu kabul edilemez.
Bu etki, hızlı hareket eden nesnelerde daha da görünür olur. Örneğin bir mermi veya ok, frame başına 15 piksel ilerleyen bir formülle hareket ettiriliyorsa, 30 FPS'te saniyede 450 piksel, 60 FPS'te saniyede 900 piksel kat eder — iki kat fark, çarpışma testlerinin bile farklı sonuç vermesine yol açabilir: yüksek FPS'te mermi ince bir engelin üzerinden "atlayarak" geçebilir, düşük FPS'te ise engelle çarpışabilir. Bu tür tutarsızlıklar, oyunun zorluk seviyesini geliştiricinin niyeti dışında değiştirir ve hata ayıklamayı zorlaştırır: bir hata bazı bilgisayarlarda gözlenirken bazılarında hiç ortaya çıkmayabilir.
Çözüm: hareketi frame sayısına değil, geçen süreye bağlamak. p5.js her draw() çağrısında bir önceki frame'den bu yana geçen süreyi milisaniye cinsinden deltaTime değişkeninde sunar.
Tanım: deltaTime — Bir önceki draw() çağrısından bu yana geçen süre (milisaniye). p5.js tarafından otomatik güncellenir; sketch içinde atanması gerekmez.
1.2. deltaTime ile Zaman Tabanlı Hareket
Hızı saniye başına piksel (pixels per second) olarak tanımlamak yaygın bir yöntemdir. Örneğin top saniyede 120 piksel sağa gitsin.
Kritik birim: p5.js’te deltaTime milisaniyedir (ms), saniye değil. 1 saniye = 1000 ms olduğu için formüle sokmadan önce saniyeye çevrilir:
Kod 1.
dtSaniye = deltaTime / 1000 // ör. 16.7 / 1000 ≈ 0.0167 skonumDegisimi = HIZ * dtSaniye // ör. 120 * 0.0167 ≈ 2 px bu frame'deTek satırda yazımı: HIZ * deltaTime / 1000 — / 1000 “ms → saniye” adımıdır; hız birimi (piksel/saniye) ile çarpmak için şarttır.
Tablo 2.
| Değişken | Örnek değer | Anlam |
|---|---|---|
HIZ |
120 | Saniyede 120 piksel |
deltaTime |
~16.7 (ms) | Son frame süresi — henüz saniye değil |
deltaTime / 1000 |
~0.0167 (s) | Aynı süre, saniye cinsinden |
HIZ * deltaTime / 1000 |
~2 piksel | Bu frame'de kayma |
60 FPS'te frame başına ~2 piksel, 30 FPS'te frame başına ~4 piksel olur; saniyede toplam yine ~120 piksel kalır.
Dikkat — sık tuzak: x = x + 100 * deltaTime yazmak (/ 1000 yok) yanlış birimle çarpmaktır. deltaTime ≈ 16.7 iken bir frame’de 100 * 16.7 ≈ 1670 piksel eklenir — top saniyede ~100 değil, on binlerce piksel “uçar”. Doğru olan 100 * deltaTime / 1000 (veya önce let dt = deltaTime / 1000, sonra x = x + 100 * dt).
Birim özeti: HIZ → piksel/saniye; deltaTime / 1000 → saniye; çarpım → piksel. Frame süresi kısalınca (FPS yüksek) frame başına eklenen piksel azalır, frame sayısı artar; süre uzayınca tersi olur — saniyedeki toplam aynı kalır. Bu, deltaTime hareketinin frame hızından bağımsız olmasının temelidir.
Okunabilir alışkanlık:
Kod 2.
let dt = deltaTime / 1000; // bir kez saniyeye çevirtopX = topX + HIZ * dt;Kod bloğu: Aynı top — deltaTime ile hareket.
Kod 3.
let topX = 50;let topY = 150;const TOP_YARICAP = 25;const HIZ = 120; // piksel / saniye function setup() { createCanvas(500, 300); noStroke(); frameRate(60);} function draw() { background(30, 35, 50); let dt = deltaTime / 1000; // ms → saniye topX = topX + HIZ * dt; // HIZ * deltaTime / 1000 ile aynı if (topX > width + TOP_YARICAP) { topX = -TOP_YARICAP; } fill(255, 200, 80); ellipse(topX, topY, TOP_YARICAP * 2, TOP_YARICAP * 2); fill(255); textSize(14); textAlign(LEFT, TOP); text("FPS: " + nf(frameRate(), 0, 1), 10, 10);}HIZ * deltaTime / 1000 tek satırda da yazılabilir; önce dt almak birimi görünür kılar.
Dikkat: deltaTime çok büyük olabilir: tarayıcı sekmesi arka plana alındığında veya bilgisayar uykuya geçtiğinde draw() duraklar; geri dönüldüğünde iki frame arasındaki süre birkaç saniyeye çıkabilir. Bazı oyunlarda üst sınır konur:
Kod 4.
let dt = min(deltaTime, 50) / 1000;topX = topX + HIZ * dt;Tek frame'de en fazla 50 ms sayılır; aksi halde top bir anda ekrandan fırlayabilir. Bu kitabın basit örneklerinde doğrudan deltaTime yeterlidir; tarayıcı sekmesi arka planda uzun süre kalırsa dönüşte ani sıçrama gözlemlenebilir — bu beklenen davranıştır.
Karşılaştırma tablosu (HIZ = 120, yaklaşık değerler):
Tablo 3.
| Yöntem | 60 FPS (dt≈16.7 ms) | 30 FPS (dt≈33.3 ms) | Saniyede toplam |
|---|---|---|---|
topX + 3 |
+3 px/frame | +3 px/frame | 180 px vs 90 px |
topX + 120 * dt/1000 |
+2 px/frame | +4 px/frame | ~120 px (her iki FPS) |
1.3. Hareketli Top Örneği
Aşağıdaki sketch, yatay hareketin yanı sıra dikey salınım ekler; sin() önceki bölümlerde tanıtılmıştır. Hareket güncellemesi deltaTime ile yapılır; çizim aynı draw() içinde kalır.
Oyun kuralları (basit demo):
- Top sürekli sağa hareket eder; tuval dışına çıkınca soldan tekrar girer.
- Dikey konum sinüs eğrisiyle salınır.
- Ekranda anlık FPS gösterilir.
Kod 5.
let topX = 0;const TOP_YARICAP = 22;const HIZ_X = 150; // yatay: piksel / saniyeconst SALINIM_GENISLIGI = 40;const SALINIM_HIZI = 2; // salınım faz hızı (radyan/saniye yaklaşık kullanım) let zaman = 0; // birikimli saniye (salınım fazı için) function setup() { createCanvas(560, 320); noStroke(); frameRate(60);} function draw() { background(25, 32, 48); let dtSaniye = deltaTime / 1000; topX = topX + HIZ_X * dtSaniye; zaman = zaman + dtSaniye; if (topX > width + TOP_YARICAP) { topX = -TOP_YARICAP; } let topY = height / 2 + sin(zaman * SALINIM_HIZI) * SALINIM_GENISLIGI; fill(255, 190, 70); ellipse(topX, topY, TOP_YARICAP * 2, TOP_YARICAP * 2); fill(220); textSize(14); textAlign(LEFT, TOP); text("FPS: " + nf(frameRate(), 0, 1), 12, 12); text("deltaTime: " + nf(deltaTime, 0, 1) + " ms", 12, 32);}Bu örnekte zaman değişkeni her frame'de dtSaniye kadar artırılarak birikimli bir saat gibi çalışır; sin(zaman * SALINIM_HIZI) ifadesi bu saate göre −1 ile +1 arasında salınan bir değer üretir ve SALINIM_GENISLIGI ile çarpılarak piksel cinsinden dikey ofsete dönüştürülür. zaman frame sayısına değil geçen gerçek süreye bağlı olduğu için, salınımın hızı da FPS'ten bağımsızdır — tıpkı yatay harekette olduğu gibi. Eğer bu değişken yerine frameCount (önceki bölümlerde tanıtılan, her frame bir artan sayaç) kullanılsaydı, salınım da frame hızına bağımlı hâle gelir ve yukarıda anlatılan tutarsızlık dikey eksende tekrarlanırdı.
setup() içinde frameRate(30) denendiğinde topun yatay hızı gözle aynı kalmalı; yalnızca hareketin akıcılığı (frame sayısı) değişir. Bu, deltaTime kullanımının amacını doğrular.
Deney önerisi: Aynı sketch'te topX = topX + 5 satırını geçici olarak geri getirin; frameRate(60) ve frameRate(30) arasında topun saniyede kat ettiği yolu gözlemleyin. Ardından HIZ * deltaTime / 1000 formülüne dönün — fark belirginleşir. Bu karşılaştırma, oyun geliştirmede «neden deltaTime?» sorusunun pratik yanıtıdır.
Sıra Sizde: Web Editor’de iki toplu karşılaştırma sketch’i yazın (yukarıdaki hareketli top örneğini temel alabilirsiniz).
İstenenler:
- İki top:
topAframe başına sabit (topAX = topAX + 4),topBzaman tabanlı (topBX = topBX + HIZ * deltaTime / 1000, ör.HIZ = 240). - Tuval dışına çıkınca her ikisi de soldan yeniden girsin; farklı renklerle çizin.
- Ekranda
frameRate()ve kısa bir etiket (A: frame,B: deltaTime) gösterin. setupiçindeframeRate(60)veframeRate(30)’u sırayla deneyin (veya1/2tuşuyla hedef FPS değiştirin). Hangisinin yatay temposu değişiyor, hangisi aynı kalıyor? Bir–iki cümleyle not edin.- (Bonus)
guncellevecizişlerini ayrı fonksiyonlara bölün;drawyalnızca arka plan + çağrı yapsın.
Yapay Zekâ Etkileşimi: İki tempo — sen yaz, YZ ölçüm / cilâ eklesin Tahmini etkinliği tamamlama süresi: 35–45 dakika.
Amaç: Frame vs deltaTime farkını çalışan kodla göstermek; ölçüm (saniye başına piksel) ve küçük bir cilâyı YZ’den isteyip çıktıyı eleştirel okumak.
Adım 1 — Sizin kodunuz: Sıra Sizde’deki iki toplu sketch’i kendiniz yazıp çalıştırın (frameRate 30/60 deneyi dahil). YZ’ye henüz tüm oyunu yazdırmayın.
Adım 2 — YZ’den ölçüm yardımcısı: Sketch’inizi yapıştırıp şunu isteyin:
Örnek istem — saniyede kaç piksel?
"Bu p5.js sketch’te iki top var (biri +4/frame, biri HIZ * deltaTime/1000). Mekaniği bozma. Her iki top için son 1 saniyede kat edilen yatay yolu ölçüp ekranda göster (ör. birikimli dx / geçen süre). frameRate(30) ve frameRate(60) iken A ve B için beklenen farkı kısa tabloyla da yaz. Class kullanma; kısa yorum ekle."
Adım 3 — Kontrol: Ölçülen değerler tablodaki sezgiyle uyuyor mu? A’nın saniyedeki yolu FPS ile değişiyor mu, B’ninki yaklaşık sabit mi? YZ deltaTime’ı yanlışlıkla iki kez mi böldü / 1000’i unuttu mu?
Adım 4 — İsteğe bağlı makyaj: Oyun hissi için YZ’ye (yine tam sketch ile) kısa bir cilâ isteyin — ör. tuşla 30/60 geçişi, min(deltaTime, 50) tavanı, hafif iz. Sonra «neleri değiştirdin, bu ders düzeyinde madde madde açıkla» deyin. Anlamadığınız satırda devam sorusu sorun; şu anki düzeyde ağır gelen parçayı sadeleştirmesini isteyin.
Yapay Zekâ Etkileşimi: Clamp’li deltaTime Tahmini süre: 15–20 dakika.
Amaç: Patolojik büyük deltaTime’ı sınırlamak.
Adım 1: Sekme sonrası deltaTime’ın çok büyümesi senaryosunu yazın.
Adım 2: Yapay zekâdan min(deltaTime, 50) benzeri clamp iskeleti isteyin.
Adım 3: Kendi top örneğinde clamp’li ve clampsiz farkı gözlemleyin.
Pekiştirme: kavramı mini senaryoya bağlama
- Veri: Hangi değişkenler durumu tutuyor?
- Güncelleme: Her frame veya olayda ne değişiyor?
- Çizim: Görünenler hangi alanlardan geliyor?
- Kural: Oyuncu eylemi hangi koşulla kabul/red?
Eksik adımı (sınır, başlangıç değeri, tek seferlik olay) şimdi tamamlamak, sonra büyük sketch içinde aramaktan kolaydır.
Sıra Sizde: Bu ana başlıkta öğrenilenleri sonraki konuya bağlayan tek cümlelik bir köprü yazın: “Şimdi X biliyorum; bundan sonra Y için buna ihtiyacım var.” Cümle kurulamıyorsa eksik kalan alt başlıktaki örnek bir kez daha çalıştırılır.
Bu noktada kurulan kalıbın tek cümlelik bir oyun kuralına bağlanması, kavramın yerleşip yerleşmediğini gösterir; kural yazılamıyorsa ilgili alt başlığa dönülüp örnek bir kez daha çalıştırılır. Küçük bir parametre değişikliğinin çıktıyı nasıl etkilediğini not etmek, sonraki ana başlıktaki birleşik örneğe geçişi kolaylaştırır.
Özet
Sabit x += n FPS’e bağımlıdır; deltaTime ile çarpılan hız ise zamana bağlıdır. Birimler önemlidir: deltaTime milisaniye olduğu için çoğu örnekte 1000’e bölünür. Çok büyük deltaTime (sekme sonrası) teleporta yol açmasın diye üst sınır (clamp) düşünülebilir.
Zaman tabanlı hareket, çarpışma ve klavye ile birleşince mini oyunlar farklı cihazlarda tutarlı oynanır. Bu ana başlık Temel Kavramlar kitabında animasyon taşınabilirliğinin anahtarını verir.
Değişikliğin görünür sonucu, sayıların anlamının değişmesidir. Sabit adım yazımında 5 değeri «her frame beş piksel» demektir ve gerçek hız donanıma göre oynar; zaman tabanlı yazımda aynı hız 300 gibi bir değerle «saniyede üç yüz piksel» olarak ifade edilir. Bu nedenle mevcut bir sketch zaman tabanlı hâle getirilirken bütün hız sabitlerinin yeniden ölçeklenmesi gerekir. Aynı çarpan, hız dışındaki zamana bağlı büyüklüklere de uygulanır: sayaçlar, geri sayımlar ve ömür değerleri de saniye cinsinden tutulur.
Ölçüt basittir: aynı sketch farklı FPS değerlerinde çalıştırıldığında topun tuvali kat etme süresi değişmiyorsa hareket zaman tabanlıdır. Değişiyorsa bir yerde frame sayısına bağlı bir güncelleme kalmış demektir. Aynı ölçüt, hareketin yanı sıra animasyon adımları ve düşman üretim aralıkları için de geçerlidir; zamana bağlanmamış tek bir sayaç bile oyunun temposunu donanıma bağımlı kılar.
Neler Öğrendik?
Soru 1
deltaTime tipik olarak neyi verir?
A) Son frame’den bu yana geçen süreyi (ms)
B) Tuval rengini
C) Dosya adını
D) DNS adresini
E) Git remote’u
Soru 2
x += hiz * (deltaTime/1000) neden tercih edilir?
A) Hareketi gerçek zamana bağlamak için
B) setup’ı silmek için
C) HTML’i kapatmak için
D) Sesi açmak için
E) CSS yazmak için
Soru 3 Frame başına sabit piksel eklemenin riski nedir?
A) Farklı FPS’te farklı gerçek hız
B) Dizinin zorunlu silinmesi
C) Renk körlüğü
D) EPUB bozulması
E) Yazıcı hatası
Soru 4 Hız değişkenini “birim / saniye” tutmanın yararı nedir?
A) deltaTime ile çarpınca anlamın net kalması
B) Klavyenin kapanması
C) Matematiğin kalkması
D) Sunucu zorunluluğu
E) SQL zorunluluğu
Neler Öğrendik Yanıt Anahtarı
Soru 1: Doğru Cevap: A
- Çözüm: p5.js deltaTime ms cinsindendir.
- İlgili Konu: 1.2. deltaTime
Soru 2: Doğru Cevap: A
- Çözüm: Zaman tabanlı entegrasyon.
- İlgili Konu: 1.2. Zaman Tabanlı Hareket
Soru 3: Doğru Cevap: A
- Çözüm: FPS düşünce sabit adım yavaşlar.
- İlgili Konu: 1.1. Frame Başına Hareketin Sorunu
Soru 4: Doğru Cevap: A
- Çözüm: Birim tutarlılığı okunabilirlik sağlar.
- İlgili Konu: 1.3. Hareketli Top Örneği
Yararlanılan Kaynaklar
Bu içerik aşağıdaki kaynaklardan derlenerek hazırlanmıştır:
- McCarthy, L., Reas, C., & Fry, B. (2015). Make: Getting Started with p5.js. Maker Media.
- Nystrom, R. (2014). Game Programming Patterns. gameprogrammingpatterns.com — Game Loop bölümü.
- Nystrom, R. (2014). Game Programming Patterns. Genever Benning. https://gameprogrammingpatterns.com/
- Nystrom, R. (2014). Game loop. In Game Programming Patterns. https://gameprogrammingpatterns.com/game-loop.html
- p5.js Foundation. (n.d.). deltaTime. p5.js Reference. https://p5js.org/reference/p5/deltaTime/
- p5.js Foundation. (n.d.). frameRate. p5.js Reference. https://p5js.org/reference/p5/frameRate/
- Shiffman, D. (n.d.). Code! Programming with p5.js. The Coding Train. https://thecodingtrain.com/tracks/code-programming-with-p5-js