Ana Başlık 4. Oyun Döngüsü, FPS ve frameRate
Amaç: Oyun döngüsü ile FPS/frameRate ilişkisini öğreterek animasyon zamanlamasının temelini kurmak.
Öğrenme Çıktıları:
- Oyun döngüsünün update–draw ritmini açıklar.
- FPS kavramını tanımlar.
- frameRate ile hedef FPS değerini ayarlar.
- Düşük FPS’in harekete etkisini tartışır.
Anahtar Sözcükler: oyun döngüsü, FPS, frameRate, frame, zamanlama
Giriş
Döngü ve fonksiyonlarla sketch modülerleştikten sonra hareketin “ne kadar hızlı?” sorusu belirir. Oyun döngüsü her frame’de güncelleme ve çizimi yineler; saniyedeki frame sayısı FPS’dir. p5.js frameRate ile hedef hızı ayarlar; cihaz meşgulse gerçek FPS düşebilir.
Bu ana başlık döngü–FPS ilişkisini ve frameRate kullanımını kurar. Frame başına sabit piksel eklemenin farklı makinelerde farklı hız üretmesi sorunu bir sonraki ana başlıkta deltaTime ile çözülür. 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. Kod okumada izlenen sıra, veri modelinden başlayıp güncelleme ve çizime doğru ilerler.
4.1. Oyun Döngüsüne Genel Bakış
Tanım: Oyun döngüsü (game loop) — Oyunun çalışma süresince tekrarlanan güncelleme döngüsüdür; tipik adımlar girdi okuma, mantık güncelleme ve çizimdir.
p5.js sketch'inde döngü şu biçimde özetlenebilir:
setup()— tuval boyutu, başlangıç değişkenleri, bir kerelik ayarlar.draw()— her frame'de: arka plan, nesne konumlarının güncellenmesi, çizim.- p5.js, sketch durdurulana kadar 2. adımı sürekli tekrarlar.
Önceki bölümlerdeki numaralı akış bu yapıyı doğrusal biçimde anlatmıştı; burada vurgu, draw() gövdesinin hem güncelleme hem çizim taşıyabileceğidir. Küçük örneklerde ikisi aynı fonksiyonda yazılır; büyük projelerde guncelle() ve ciz() gibi ayrı fonksiyonlara bölünmesi modülerlik sağlar (önceki bölümlerdeki fonksiyon kavramı).
setup() ile draw() arasındaki ayrım yalnızca sözdizimsel değildir; performans açısından da anlamlıdır. createCanvas(), görsel yükleme veya büyük dizi oluşturma gibi maliyetli işlemler setup() içinde bir kez yapılır; aynı işlemler yanlışlıkla draw() içine yazılırsa her frame'de tekrarlanır ve FPS düşer. Bu nedenle bir sketch yavaş çalıştığında ilk kontrol noktası, draw() gövdesinde her frame gerekmeyen bir işlemin bulunup bulunmadığıdır.
Kod bloğu: Her frame'de konumunu sabit adımla ilerleyen basit top.
Kod 1.
let topX = 50;let topY = 200;const TOP_YARICAP = 25; function setup() { createCanvas(500, 300); noStroke();} function draw() { background(30, 35, 50); topX = topX + 3; // Her frame 3 piksel sağa if (topX > width + TOP_YARICAP) { topX = -TOP_YARICAP; } fill(255, 200, 80); ellipse(topX, topY, TOP_YARICAP * 2, TOP_YARICAP * 2);}Bu kod çalışır; ancak hız, saniyede kaç frame üretildiğine bağlıdır. Bir sonraki alt bölümlerde bu bağımlılık ölçülür ve giderilir.
Güncelleme ve çizim ayrımı: Modüler kod yazımında (Bölüm 2'in 3. ana başlığı) draw() gövdesi inceltilir:
Kod 2.
function draw() { background(30, 35, 50); guncelleTop(); cizTop();} function guncelleTop() { topX = topX + 3; if (topX > width + TOP_YARICAP) { topX = -TOP_YARICAP; }} function cizTop() { fill(255, 200, 80); ellipse(topX, topY, TOP_YARICAP * 2, TOP_YARICAP * 2);}«Konum değiştir» ile «ekrana çiz» ayrıldığında hata ayıklama kolaylaşır: top görünmüyorsa cizTop, yanlış hızda gidiyorsa guncelleTop incelenir. deltaTime eklendiğinde yalnızca guncelleTop içindeki formül değişir; çizim aynı kalır.
4.2. FPS ve frameRate()
Tanım: FPS (frames per second — saniyedeki frame sayısı) — Bir saniyede draw() fonksiyonunun kaç kez çalıştığının ölçüsüdür. p5.js bağlamında frame kelimesi geometrik kare anlamında değil, draw() çağrısının bir tekrarı anlamında kullanılır.
p5.js varsayılan olarak hedef frame hızını 60 FPS civarında tutmaya çalışır; donanım ve sketch yükü buna ulaşmayı engelleyebilir. Hedef hız frameRate(saniyeBasinaFrame) ile ayarlanır:
Tablo 1.
| İfade | Anlam | Örnek sonuç |
|---|---|---|
frameRate(60) |
Hedef 60 FPS | Çoğu monitörde akıcı hareket |
frameRate(30) |
Hedef 30 FPS | Daha düşük yük, daha seyrek güncelleme |
frameRate() (argümansız) |
Ölçülen anlık FPS | Ekranda gösterilebilir (ör. 58.2) |
Kod bloğu: FPS değerini ekranda gösterme.
Kod 3.
function setup() { createCanvas(400, 200); frameRate(60);} function draw() { background(40); fill(255); textSize(18); textAlign(LEFT, TOP); text("Olculen FPS: " + nf(frameRate(), 0, 1), 15, 15);}nf(sayi, solBasamak, sagBasamak) p5.js fonksiyonudur; ondalıklı (veya tam) sayıyı biçimlendirilmiş metne çevirir. Üç parametrenin anlamı:
Tablo 2.
| Parametre | Rol | Bu örnekte |
|---|---|---|
sayi |
Biçimlenecek değer | frameRate() → örn. 58.273… |
solBasamak |
Ondalık noktanın solundaki basamak sayısı (gerekirse başa 0 ekler) |
0 → sola sıfır doldurma yok; 58 olduğu gibi kalır |
sagBasamak |
Ondalık noktanın sağındaki basamak sayısı (yuvarlanır) | 1 → tek ondalık: "58.3" |
nf(frameRate(), 0, 1) bu yüzden ekranda 58.273 yerine 58.3 gibi kısa bir metin üretir. Diğer örnekler:
Tablo 3.
| Çağrı | Sonuç (yaklaşık) | Açıklama |
|---|---|---|
nf(58.273, 0, 1) |
"58.3" |
Sağda 1 basamak |
nf(58.273, 0, 0) |
"58" |
Ondalık yok |
nf(7, 3, 0) |
"007" |
Solda 3 basamak; başa sıfır |
nf(3.14159, 1, 2) |
"3.14" |
Sağda 2 basamak |
Argümansız çağrılan frameRate() o anda ölçülen ortalama frame hızını verir; sketch ağırlaştıkça değer hedefin altına düşebilir. nf yalnızca gösterimi düzenler; FPS hesabını değiştirmez.
Bilgi: frameRate() fonksiyonunun iki kullanımı vardır: bir sayı verilerek çağrıldığında (frameRate(60)) yalnızca hedef FPS'i belirler; argümansız çağrıldığında (frameRate()) ise o anki ölçülen değeri döndürür. Gerçek FPS donanıma ve çizim maliyetine bağlıdır; mobil veya düşük güçlü cihazlarda 60 hedefi her zaman tutturulamayabilir; bu nedenle hareket formülünde deltaTime kullanmak daha güvenilirdir.
Ekran, yenileme hızı (Hz) ve FPS
Oyunun ürettiği FPS ile monitörün yenileme hızı aynı şey değildir. Yenileme hızı hertz (Hz) cinsinden ölçülür: ekranın saniyede kaç kez yeni bir görüntü çizdiğini söyler. FPS ise yazılımın (burada draw()’ın) saniyede kaç frame hesapladığını söyler. İkisi yakın olsa da zincirin iki halkasıdır: oyun frame üretir → monitör o frame’leri (veya aralarından seçtiklerini) gösterir.
Tablo 4.
| Kavram | Birim | Ne ölçer? | Tipik değerler |
|---|---|---|---|
| Yenileme hızı | Hz | Monitörün saniyedeki tarama / yenileme sayısı | 60, 75, 120, 144, 165, 240… |
| FPS | frame/s | Oyunun / sketch’in saniyede ürettiği frame sayısı | Hedef 30–60 (p5); oyunlarda 60–240+ |
Çoğu ofis ve dizüstü ekranı hâlâ 60 Hz’tir. Oyun / spor odaklı monitörlerde 120–144 Hz yaygındır; üst segmentte 240 Hz ve üzeri görülür. Telefon ve tablet ekranlarında da 90 / 120 Hz paneller sıklaşmıştır. Tarayıcılar çizimi çoğu zaman monitörün yenileme döngüsüyle eşlemeye çalışır (vsync benzeri davranış): böylece yırtılma (tearing) azalır, fakat oyun FPS’i paneli aşsa bile ekranda o kadar “fazla” frame görünmeyebilir — fazlası atılır veya birleştirilir.
Bu yüzden frameRate(60) masaüstünde sıkça doğal bir hedeftir. Daha yüksek Hz’li monitörde frameRate() çağrılmazsa p5.js daha yüksek FPS’e çıkmaya çalışabilir; frame başına sabit piksel ekleyen hareket o zaman bile farklı tempo üretir. Hedefi açıkça vermek paneller arası farkı azaltır; asıl güvenilir çözüm yine deltaTime’dır (sonraki alt başlıklar).
Bilgi — sinema ve “saniyede 24 kare”: Hareketli görüntünün kültüründe klasik sinema filmi uzun süre yaklaşık 24 fps ile özdeşleşmiştir (sesli dönem standardı; sessiz dönemde 16–18 fps civarı da yaygındı). Televizyonda bölgeler arası farklar vardı (ör. birçok ülkede ~25 veya ~30 fps’lik yayın aileleri). Oyunlar ise etkileşim istediği için genelde sinemadan daha yüksek FPS hedefler: 30 “oynanabilir”, 60 “akıcı”, rekabetçi / yüksek yenilemeli kurulumlarda 120+ sıkça istenir. Yani “kaç fps iyi?” sorusunun cevabı ortama göre değişir — film izlemek ile nişancı oyunu oynamak aynı ihtiyaç değildir.
Oyunlarda FPS neden önemli?
- Akıcılık: Düşük ve dalgalı FPS, hareketi kesik kesik gösterir; özellikle kamera dönünce veya kalabalık sahnelerde rahatsız eder.
- Tepki hissi: Daha sık çizilen frame, fare / dokunuş sonucunun ekranda daha erken görünmesine yardımcı olabilir (giriş gecikmesi yalnızca FPS’e bağlı değildir; yine de düşük FPS gecikmeyi büyütür).
- Adalet ve tutarlılık: Frame’e bağlı fizik / hareket varsa yüksek FPS’li oyuncu avantaj (veya dezavantaj) yaşayabilir — bu ana başlığın asıl teknik kaygısı budur.
- Okunabilirlik: Hızlı nesnelerde (mermi, top) seyrek frame, “nereye gitti?” hissini bozar.
Bilgi — psikoloji / algı (kısa): İnsan gözü “tam olarak X fps’nin üstünü göremez” diye tek bir sihirli sayı yoktur; algı kişiye, sahneye ve önceki deneyime göre değişir. Birçok oyuncu 30 → 60 geçişini belirgin yumuşama olarak tarif eder; 60 → 144 geçişi özellikle fareyle nişan alma ve hızlı kamera hareketinde “daha yapışkan / daha az bulanık” hissedilebilir. Öte yandan çok yüksek FPS peşinde koşmak her zaman aynı oranda fayda getirmez: kazanç azalır, maliyet artar. Önemli olan çoğu zaman istikrardır — sürekli 55–60, bir anda 90’a çıkıp 40’a düşen bir grafikten daha öngörülebilir oynanış verir.
Yüksek FPS ve donanım
Daha fazla frame üretmek CPU/GPU’ya daha çok iş yükler: güç tüketimi ve ısınma artar, dizüstünde batarya daha çabuk biter, fanlar yükselir. Bu yüzden oyunlar sıklıkla FPS sınırı (ör. 60’a kilitleme), dikey senkron, veya “pil / performans” modları sunar. p5.js sketch’inizde gereksiz çizim veya setup’a ait işleri draw içine koymak da FPS’i düşürür — yani “yüksek FPS iyi” demek, sınırsız hedef demek değildir; yeterli ve stabil tempo + doğru hareket formülü (deltaTime) bu dersteki dengedir.
Yapay Zekâ Etkileşimi: FPS Düşüş Senaryosu Tahmini süre: 10–15 dakika.
Amaç: Sabit adım hareketinin FPS’e bağımlılığını görmek.
Adım 1: x += 3 ile giden bir kare düşünün; FPS 60’tan 30’a inince ne olur yazın.
Adım 2: Yapay zekâya aynı senaryoyu sorun; gerekçeyi karşılaştırın.
Adım 3: Bir sonraki ana başlıkta deltaTime’ın bu sorunu nasıl çözdüğünü tek cümleyle tahmin edin.
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
Oyun döngüsü, oyunun çalıştığı süre boyunca yinelenen girdi okuma, mantık güncelleme ve çizim adımlarıdır; p5.js’te bu ritmin görünen yüzü setup’tan sonra sürekli çağrılan draw fonksiyonudur. Küçük sketch’lerde güncelleme ile çizim aynı gövdede yazılabilir; ayrı fonksiyonlara bölündüğünde ise hata ayıklama kolaylaşır, çünkü görünmeyen nesne çizim tarafında, yanlış hızda ilerleyen nesne güncelleme tarafında aranır. Ayrım performans açısından da anlamlıdır: tuval oluşturma veya büyük veri hazırlama gibi maliyetli işler setup içinde bir kez yapılmazsa her frame tekrarlanır ve FPS düşer.
FPS, bir saniyede draw fonksiyonunun kaç kez çalıştığını gösterir; burada frame sözcüğü geometrik bir şekli değil, draw çağrısının tek bir tekrarını anlatır. frameRate(60) yalnızca hedefi bildirir; donanım ve çizim yükü bu hedefin tutturulmasını engelleyebilir. Argümansız frameRate() o anda ölçülen değeri döndürür ve nf ile biçimlendirilerek ekranda gösterilebilir. Monitörün hertz cinsinden yenileme hızı ile sketch’in ürettiği FPS ayrı büyüklüklerdir; tarayıcı çizimi yenileme döngüsüne eşlemeye çalıştığı için fazladan üretilen frame’ler ekrana yansımayabilir. Bu belirsizlik, frame başına sabit piksel ekleyen x += 3 gibi bir hareketin farklı cihazlarda farklı tempo üretmesinin nedenidir; hızı geçen gerçek süreye bağlayan deltaTime bir sonraki ana başlıkta ele alınır.
Neler Öğrendik?
Soru 1 FPS neyi ifade eder?
A) Saniyedeki frame sayısı
B) Tuval genişliği
C) Dosya boyutu
D) Renk kanalı
E) Git commit sayısı
Soru 2
frameRate(30) tipik olarak ne yapar?
A) Hedef FPS değerini yaklaşık 30’a çeker
B) Diziyi 30 elemana sabitler
C) HTML’i siler
D) Sesi kapatır
E) DNS’i yeniler
Soru 3
Sabit x += 5 hareketi düşük FPS’te genelde nasıl görünür?
A) Daha yavaş ilerler
B) Her zaman aynı gerçek hızda kalır
C) setup’ı siler
D) Rengi değiştirir
E) Klavyeyi kilitler
Soru 4 Oyun döngüsünün pedagojik özü nedir?
A) Sürekli güncelle–çiz tekrarı
B) Yalnızca bir kez setup
C) Yalnızca CSS
D) Yalnızca sunucu
E) Yalnızca SQL
Neler Öğrendik Yanıt Anahtarı
Soru 1: Doğru Cevap: A
- Çözüm: Frames per second.
- İlgili Konu: 4.2. FPS ve frameRate
Soru 2: Doğru Cevap: A
- Çözüm: Hedef FPS istenen değere çekilir.
- İlgili Konu: 4.2. FPS ve frameRate
Soru 3: Doğru Cevap: A
- Çözüm: Frame seyrelince sabit adım hareketi yavaşlatır.
- İlgili Konu: 4.1. Oyun Döngüsü
Soru 4: Doğru Cevap: A
- Çözüm: Update–draw ritmi süreklidir.
- İlgili Konu: 4.1. Oyun Döngüsü
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