Bölüm 3 — Amaç ve Kapsam

Genel Amaç

Bu bölümün temel amacı, deltaTime ile cihazdan bağımsız hareketi kurmak; dizi koleksiyonlarını oyun verisine bağlamak ve klavye girdisiyle kontrol iskeletini oluşturarak sonraki çarpışma ve durum makinesi konularına zemin hazırlamaktır. Bölüm boyunca her ana başlık kendi içinde amaç, öğrenme çıktıları, örnek kod ve değerlendirme sorularıyla tamamlanır; böylece bir sonraki bölüme geçmeden önce ölçülebilir kazanımlar elde edilir.

Kapsam

Bu bölüm şu ana başlıklar altında ele alınmaktadır:

Ana Başlık 1: deltaTime ile Zaman Tabanlı Hareket

Ana Başlık 2: Dizi Temelleri: Tanım, Erişim ve push/pop

Ana Başlık 3: Sabit Kapasite ve Paralel Dizilerle Mini Sahne

Ana Başlık 4: Klavye Girdisi


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ı:

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.

text
dtSaniye = deltaTime / 1000          // ör. 16.7 / 1000 ≈ 0.0167 skonumDegisimi = HIZ * dtSaniye       // ör. 120 * 0.0167 ≈ 2 px bu frame'de

Tek 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.

javascript
let dt = deltaTime / 1000; // bir kez saniyeye çevirtopX = topX + HIZ * dt;

Kod bloğu: Aynı top — deltaTime ile hareket.

Kod 3.

javascript
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.

javascript
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):

Kod 5.

javascript
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:

  1. İki top: topA frame başına sabit (topAX = topAX + 4), topB zaman tabanlı (topBX = topBX + HIZ * deltaTime / 1000, ör. HIZ = 240).
  2. Tuval dışına çıkınca her ikisi de soldan yeniden girsin; farklı renklerle çizin.
  3. Ekranda frameRate() ve kısa bir etiket (A: frame, B: deltaTime) gösterin.
  4. setup içinde frameRate(60) ve frameRate(30)’u sırayla deneyin (veya 1 / 2 tuşuyla hedef FPS değiştirin). Hangisinin yatay temposu değişiyor, hangisi aynı kalıyor? Bir–iki cümleyle not edin.
  5. (Bonus) guncelle ve ciz işlerini ayrı fonksiyonlara bölün; draw yalnı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

  1. Veri: Hangi değişkenler durumu tutuyor?
  2. Güncelleme: Her frame veya olayda ne değişiyor?
  3. Çizim: Görünenler hangi alanlardan geliyor?
  4. 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

Soru 2: Doğru Cevap: A

Soru 3: Doğru Cevap: A

Soru 4: Doğru Cevap: A

Yararlanılan Kaynaklar

Bu içerik aşağıdaki kaynaklardan derlenerek hazırlanmıştır:


Ana Başlık 2. Dizi Temelleri: Tanım, Erişim ve push/pop

Amaç: Dizi kavramını, indeksle erişimi ve push/pop/length işlemlerini oyun verisi bağlamında öğretmek.

Öğrenme Çıktıları:

Anahtar Sözcükler: dizi, indeks, length, push, pop, paralel dizi

Giriş

Şimdiye kadar çoğu örnekte tekil değişkenler yeterliydi: bir x, bir skor, bir hedef. Oyunlar büyüdükçe aynı türden birçok değer birlikte yönetilir — birden fazla balon konumu, birden fazla engel, tahmin geçmişi. Bunları x1, x2, x3 diye çoğaltmak bakımı bozar; dizi (array) aynı türdeki değerleri tek isim altında, sırayla tutar.

JavaScript’te dizi köşeli parantezle yazılır; elemanlar 0’dan başlayan indekslerle okunur. length uzunluğu verir; push sona ekler, pop sondan çıkarır. Dolaşma çoğu zaman for ile yapılır. Bu ana başlık dizinin sözdizimini ve temel mutasyonlarını kurar; sabit kapasiteli yığın benzeri kullanım ve paralel dizilerle mini sahne bir sonraki ana başlıkta gelir. 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.

2.1. Dizi Kavramı ve Tanımlama

Tanım: Dizi (array) — Köşeli parantez [] ile tanımlanan, indeksle erişilen sıralı veri koleksiyonudur.

Kod 1.

javascript
let skorlar = [10, 25, 40];           // Sayı dizisilet renkler = [255, 120, 80];         // RGB bileşenlerilet mesajlar = ["dogru", "yuksek", "dusuk"]; // Metin dizisilet bosDizi = [];                     // Boş dizi

Tablo 1.

İfade Anlam
[] Boş dizi oluşturur
[a, b, c] Başlangıç elemanlarıyla dizi
dizi[0] İlk eleman (indeks 0)
dizi.length Eleman sayısı

Dikkat: İndeksler 1'den değil 0'dan başlar. skorlar[1] ikinci elemanı verir; skorlar[3] üç elemanlı dizide tanımsızdır (undefined).

Dikkat — boş slot (hole): Olmayan bir indekse yazmak diziyi “delikli” uzatabilir:

Kod 2.

javascript
let a = [1];a[3] = 44;// a.length → 4; a[1] ve a[2] boş (empty); okununca undefined

Konsolda çoğu zaman Array(4) [ 1, <2 empty slots>, 44 ] benzeri görünür. Bu, bilerek yazılan BOS / -1 işaretinden farklıdır: empty slot’ta hücre hiç doldurulmamıştır. push veya 0, 1, 2… sırasıyla atama boşluk bırakmaz; oyun listelerinde bu delikleri oluşturmayın.

Görsel 1. Dizi indeksleri — skorlar = 10, 25, 40
Görsel 1. Dizi indeksleri — skorlar = 10, 25, 40

Görsel 1 her elemanın indeks numarasını (0, 1, 2) ve skorlar[i] erişimini kutularla gösterir. Dördüncü kutu yoktur — skorlar[3] tanımsızdır.

Bilgi: JavaScript dizileri başlangıç düzeyinde farklı türleri aynı listede tutabilir ([1, "iki", true]). Oyun kodunda genellikle tek tür tutulması okunabilirliği artırır.

Dizi okuma izlemesi: let renkler = [255, 120, 80]; tanımı için indeks ve değer eşleşmesi şöyledir:

Tablo 2.

İndeks renkler[indeks] Anlam
0 255 Kırmızı bileşen
1 120 Yeşil bileşen
2 80 Mavi bileşen
3 undefined Dizide karşılığı yoktur

fill(renkler[0], renkler[1], renkler[2]) ifadesi bu üç bileşeni sırayla okuyarak fill(255, 120, 80) ile aynı sonucu verir; dizi, ilgili renk bileşenlerini tek isim altında taşımayı sağlar.

Sıra Sizde: let skorlar = [10, 25, 40]; için kâğıda yazın:

  1. skorlar[0] ve skorlar[2] nedir? skorlar[3] neden sorunlu?
  2. skorlar.length kaçtır? Son geçerli indeks hangisidir?
  3. for ile üç skoru alt alta yazdıracak döngünün koşulunu bir satırda yazın (i < …).

2.2. Dizi Elemanlarına Erişim, Dolaşma ve Paralel Diziler

Eleman okuma ve yazma:

Kod 3.

javascript
let tahminler = [7, 12, 5];tahminler[0] = 8;        // İlk elemanı 8 yaplet ortanca = tahminler[1]; // 12

Kod bloğu: for döngüsüyle dizi elemanlarını ekrana yazma.

Kod 4.

javascript
let tahminler = [7, 12, 5, 9]; function setup() {  createCanvas(400, 300);} function draw() {  background(240);  fill(30);  textSize(18);  textAlign(LEFT, TOP);   for (let i = 0; i < tahminler.length; i = i + 1) {    let metin = (i + 1) + ". tahmin: " + tahminler[i];    text(metin, 20, 20 + i * 28);  }}

i < tahminler.length koşulu, indeksin dizi sınırları içinde kalmasını sağlar. length eleman sayısını verdiği için son geçerli indeks length - 1'dir.

Tablo 3.

i tahminler[i] Ekrandaki satır
0 7 1. tahmin: 7
1 12 2. tahmin: 12
2 5 3. tahmin: 5
3 9 4. tahmin: 9

Dizideki tek bir eleman güncellenebilir: tahminler[2] = 99; yalnızca üçüncü elemanı değiştirir. Son geçerli indeks dizi.length - 1'dir; bu sınırın dışına yazmak beklenmedik sonuçlara yol açabilir.

Paralel diziler — aynı indeks, bir nesne

Tek bir daire için x ve y iki değişken yeter. Ekranda birden fazla hedef varsa her biri için X ve Y gerekir. Bunları iki dizide, aynı indekste tutmak pratik bir çözümdür: hedefXListesi[i] ile hedefYListesi[i] aynı hedefin koordinatlarıdır. Bu modele paralel dizi denir. (İleride nesne veya 2B dizi alternatifleri gelecek; şimdilik paralel dizi yeterlidir.)

Hatırlatma — ellipse: ellipse(x, y, genislik, yukseklik) merkez (x, y) olan bir elips çizer. Genişlik ve yükseklik çaptır (yarıçapın iki katı). Daire için genişlik = yükseklik; oval için ikisi farklıdır. circle(x, y, cap) ise yalnızca daire içindir.

Kod bloğu: Konum listesinden birden fazla hedef çizimi.

Kod 5.

javascript
let hedefXListesi = [80, 200, 320];let hedefYListesi = [100, 150, 200];const YARICAP = 25; function setup() {  createCanvas(400, 300);  noStroke();} function draw() {  background(25, 30, 45);  fill(255, 200, 50);   for (let i = 0; i < hedefXListesi.length; i = i + 1) {    ellipse(hedefXListesi[i], hedefYListesi[i], YARICAP * 2, YARICAP * 2);  }}

Aynı i hem X hem Y’yi okur; döngü bir turda bir hedef çizer.

Görsel 2. Paralel diziler — aynı indekste X ve Y eşleşmesi
Görsel 2. Paralel diziler — aynı indekste X ve Y eşleşmesi

Görsel 2 hedefXListesi[i] ve hedefYListesi[i] çiftinin tuvalde aynı hedef dairesine karşılık geldiğini gösterir.

Sıra Sizde: Aşağıdaki sahnede biz (oyuncu) ve düşmanlar var. Bizim konumumuz tek bir noktadır — bizX, bizY iki değer yeter, dizi gerekmez. Ama düşmanlar çok olduğu için konumları paralel dizilerde tutulur: dusmanX[] ve dusmanY[]. Aynı indeks bir düşmanı verir: (dusmanX[i], dusmanY[i]). Boş / ölü slotta hem X hem Y -1’dir; döngüde atlanır (sahnede çizilmez).

Kod 6.

javascript
let bizX = 200, bizY = 150;let dusmanX = [60, 340, -1, 260, 150];let dusmanY = [60,  80, -1, 240, 200]; // [2] ikisi de -1 → yok

Görsel 3. Düşman konumları — paralel diziler ve 2B sahne
Görsel 3. Düşman konumları — paralel diziler ve 2B sahne

Kağıda yazın:

  1. dusmanX.length kaçtır? Sahnede gerçekten kaç düşman var (-1 slotunu saymayın)?
  2. (dusmanX[0], dusmanY[0]) neresi? İndeks [2] neden sahnede yok?
  3. Bize en yakın düşman hangi indeks? for ile -1 olanları atlayıp dist(bizX, bizY, dusmanX[i], dusmanY[i]) (veya uzaklık karesi) ile en küçüğü bulun.

2.3. push(), pop() ve length

Tanım: push() — Dizinin sonuna eleman ekler; length bir artar.

Tanım: pop() — Dizinin son elemanını çıkarır ve o değeri döndürür; length bir azalır.

Tablo 4.

Metot / özellik Etki Örnek Sonuç
push(değer) Sona ekler liste.push(42) liste [10, 20] iken → [10, 20, 42]
pop() Sondan çıkarır liste.pop() liste [10, 20, 42] iken → 42 döner; liste [10, 20]
length Eleman sayısı liste.length [10, 20] iken → 2

Görsel 4. push() ile sona eleman ekleme ve for ile dolaşma
Görsel 4. push() ile sona eleman ekleme ve for ile dolaşma

Görsel 4 push(9) öncesi ve sonrası diziyi yan yana gösterir; altta for döngüsünün her indekste hangi değeri okuduğu özetlenir.

Kod bloğu: Tahmin geçmişine ekleme.

Kod 7.

javascript
let tahminGecmisi = []; function mousePressed() {  let yeniTahmin = floor(random(1, 11)); // 1–10 arası tam sayı  tahminGecmisi.push(yeniTahmin);}

floor() p5.js'te ondalıklı sayıyı aşağı yuvarlayarak tam sayı üretir; random(1, 11) 1 ile 11 arasında (11 hariç) değer verir.

Tanım: floor() — Verilen sayıyı aşağı yuvarlayan p5.js fonksiyonu; tam sayı elde etmek için random() ile birlikte kullanılır.

Dikkat: pop() boş dizide undefined döndürür. Oyun mantığında dizinin boş olup olmadığı length === 0 ile kontrol edilebilir.

pop() iz örneği: let liste = [10, 20, 42];

Tablo 5.

Adım İşlem liste içeriği Dönüş
Başlangıç — [10, 20, 42] —
1 liste.pop() [10, 20] 42
2 liste.pop() [10] 20
3 liste.pop() [] 10
4 liste.pop() [] undefined

Son satırda dizi boşken pop() güvenli çalışır ancak anlamlı değer vermez; oyun mantığında «son tahmini geri al» gibi özellikler eklenecekse önce length > 0 kontrolü yapılır.

Bilgi — yığın (stack): push ve pop yalnızca «diziyi büyüt / küçült» değil; birlikte kullanıldığında dizi yığın (stack) gibi davranır. Kural LIFO’dur (last in, first out — son giren ilk çıkar): en son eklenen eleman ilk çıkarılır. JavaScript’te ayrı bir Stack sınıfı şart değildir; sıradan bir dizi + push/pop çoğu zaman yeter.

Yığın, programlamada temel bir yapıdır: fonksiyon çağrıları makinede bir çağrı yığını üzerinde tutulur; derleyiciler ve yorumlayıcılar bu modeli kullanır. Oyun geliştirmede de sık görülür — birkaç tanıdık örnek:

Tablo 6.

Bağlam Yığın ne tutar? push / pop hissi
Geri al (Undo) Son hamleler / fırça darbeleri Ctrl+Z ≈ pop; çizim editörleri, Super Mario Maker seviye düzenleyicisi, birçok bulmaca oyunu
Ekran / menü yığını Açık menü katmanları Duraklat → Ayarlar → Kontroller; kapatınca bir üst menüye dönüş (pop) — konsol RPG ve aksiyon oyunlarında klasik
Kart / deste Destenin üstü Solitaire ve benzeri kart oyunlarında desteden çekmek ≈ üstten pop; yeni kart koymak ≈ push
Envanter «son alınan» Son eklenen eşyalar Bazı envanter / crafting akışlarında «son ekleneni geri ver» veya kısa geçmiş

Aşağıdaki mini kule örneğinde GERİ AL ile son kuleyi kaldırmak da aynı fikirdir: geçmiş bir yığındır.

Bilgi: push() çağrısının kendisi de bir değer üretir: eklemeden sonraki yeni eleman sayısını döndürür. let yeniUzunluk = tahminGecmisi.push(7); satırında yeniUzunluk, güncellenmiş tahminGecmisi.length ile aynı değeri taşır. Örneklerde dönüş değeri kullanılmaz, push yalnızca ekleme etkisi için çağrılır; ancak dönüş değerinin var olduğunu bilmek, ileride benzer metotlarla karşılaşıldığında şaşırtıcı olmayacaktır.

Kod bloğu: Dizide en büyük değeri bulma (skor listesi, can değerleri…).

Kod 8.

javascript
function enBuyuk(degerler) {  if (degerler.length === 0) {    return 0;  }  let maks = degerler[0];  for (let i = 1; i < degerler.length; i = i + 1) {    if (degerler[i] > maks) {      maks = degerler[i];    }  }  return maks;}

enBuyuk(skorlar) çağrısı listedeki en yüksek skoru verir; for + karşılaştırma örüntüsü birçok özet istatistikte tekrarlanır.

Kod bloğu: Mini kule savunma — haritaya tıkla, kule kur (push); geri al henüz yok (Sıra Sizde’de pop).

Kod 9.

javascript
let kuleX = [];let kuleY = []; function setup() {  createCanvas(400, 300);} function draw() {  background(210, 230, 205); // yesil harita   // Once buton — metinler ustune binmesin diye saginda / altinda  fill(150, 60, 60);  rect(0, 0, 72, 36);  fill(255);  textAlign(CENTER, CENTER);  textSize(12);  text("GERİ AL", 36, 18);   fill(40);  textSize(13);  textAlign(LEFT, TOP);  text("Haritaya tıkla: kule kur", 80, 6);  text("GERİ AL: son kuleyi kaldır", 80, 22);  text("Kule sayısı: " + kuleX.length, 12, 44);   for (let i = 0; i < kuleX.length; i = i + 1) {    fill(70, 110, 200);    circle(kuleX[i], kuleY[i], 26); // kule govdesi    fill(255);    circle(kuleX[i], kuleY[i], 10); // namlu  }} function mousePressed() {  if (mouseX < 72 && mouseY < 36) {    // GERİ AL — Sıra Sizde'de pop eklenecek  }  kuleX.push(mouseX);  kuleY.push(mouseY);}

Her tıklama harita konumunu her iki diziye push eder; kuleler ekranda birikir. Sol üst GERİ AL kutusuna tıklamak şu hâliyle kaldırma yapmaz; dahası tıklama alttaki push satırına da ulaştığı için o noktaya yeni bir kule eklenir. Kaldırma mantığı ve bu istenmeyen ekleme Sıra Sizde’de birlikte düzeltilir.

Sıra Sizde: Yukarıdaki mini kule savunma kodunu temel alın. GERİ AL’a tıklanınca son kurulan kuleyi kaldırın (kule savunmada yanlış yere konan kuleyi geri almak gibi).

İstenenler:

  1. Kâğıtta: kuleX = [10, 20], kuleY = [30, 40] iken bir kule kurun → push (50, 60), sonra bir geri al — diziler nasıl kalır?
  2. mousePressed içinde GERİ AL dalına: length > 0 ise her iki dizide pop (yalnızca birinde değil — paralel dizi!).
  3. Çalıştırıp birkaç kule kurup geri alın; ekrandaki kule sayısı kuleX.length ile uyumlu olsun.

İpucu: Yalnızca if bloğunun içine pop yazmak yetmez — mousePressed içinde en az bir değişiklik daha gerekir; yoksa GERİ AL’a basınca istenmeyen bir push de tetiklenebilir.

Yapay Zekâ Etkileşimi: Dizi Dolaşma Bug’ı Tahmini süre: 15–20 dakika.

Amaç: Off-by-one hatalarını tanımak.

Adım 1: i <= dizi.length yazan hatalı bir döngü düşünün; ne olur yazın. Adım 2: Yapay zekâya bu bug’ı ve düzeltmesini sorun; kendi gerekçenizle karşılaştırın. Adım 3: Kısa bir diziyle editörde hem hatalı hem doğru sınırı deneyin.

Özet

Dizi, köşeli parantezle tanımlanan ve indeksle erişilen sıralı bir veri koleksiyonudur; let sayilar = [10, 20, 30] üç elemanlı bir listedir. İndeksler sıfırdan başladığı için sayilar[0] ilk elemanı verir ve son geçerli indeks length - 1 olur; bu sınırın dışına çıkan bir okuma undefined üretir. Dolaşma döngüsünün koşulu bu yüzden çoğu zaman i < dizi.length biçiminde yazılır. Var olmayan bir indekse yazmak diziyi boş hücrelerle uzatabilir; bu boşluklar, oyun listelerinde bilinçli olarak konan işaret değerlerinden farklıdır.

Aynı türden birden çok nesnenin özellikleri paralel dizilerde tutulabilir: iki ayrı listede aynı indeks aynı düşmanın x ve y koordinatını gösterir, kullanılmayan hücre ise bir işaret değeriyle atlanır. Tek bir for döngüsü her turda ilgili indeksin iki değerini birden okuyarak sahnedeki nesneleri çizer. Bu model, ileride gelecek nesne ve iki boyutlu dizi alternatiflerinin ön adımıdır.

push diziyi sonundan büyütür, pop son elemanı çıkarıp değerini döndürür ve length her iki işlemde de güncellenir; boş dizide pop çağrısı undefined verdiği için önce uzunluk denetlenir. İkisi birlikte kullanıldığında dizi, son giren ilk çıkar kuralıyla çalışan bir yığın gibi davranır; geri alma, menü katmanları ve kart destesi bu davranışın tanıdık örnekleridir. Sabit kapasiteli kullanım ve mini sahne örneği bir sonraki ana başlıkta bu temele dayanır.

Neler Öğrendik?

Soru 1 JavaScript dizilerinde ilk elemanın indeksi nedir?

A) 1

B) 0

C) -1

D) length

E) undefined

Soru 2 dizi.push(5) ne yapar?

A) İlk elemanı siler

B) 5’i dizinin sonuna ekler

C) Tuvali temizler

D) FPS’i 5 yapar

E) setup’ı yeniden çalıştırır

Soru 3 for (let i = 0; i < dizi.length; i++) neden yaygındır?

A) Çünkü length dışı indekslere güvenli sınır çizer

B) Çünkü rengi değiştirir

C) Çünkü HTML siler

D) Çünkü ses açar

E) Çünkü DNS ister

Soru 4 Paralel diziler ne anlama gelir?

A) İki dizinin aynı indekste ilişkili özellik tutması

B) İki tarayıcının zorunlu açılması

C) Yalnızca string birleştirme

D) CSS grid

E) Git branch

Neler Öğrendik Yanıt Anahtarı

Soru 1: Doğru Cevap: B

Soru 2: Doğru Cevap: B

Soru 3: Doğru Cevap: A

Soru 4: Doğru Cevap: A

Yararlanılan Kaynaklar

Bu içerik aşağıdaki kaynaklardan derlenerek hazırlanmıştır:


Ana Başlık 3. Sabit Kapasite ve Paralel Dizilerle Mini Sahne

Amaç: push/pop olmadan sabit kapasiteli dizi kullanımını ve paralel dizilerle çoklu nesne sahnesini öğretmek.

Öğrenme Çıktıları:

Anahtar Sözcükler: sabit kapasite, tepe, paralel dizi, mini sahne, çoklu nesne

Giriş

Dizi temelleri ve push/pop bilindikten sonra iki pratik yol ayrımı belirir. Birincisi dinamik liste: eleman gelince uzar, gidince kısalır. İkincisi sabit kapasite: dizi boyutu baştan ayrılır, “kaç eleman canlı?” bilgisi ayrı bir tepe/sayaçta tutulur. Bazı oyun iskeletlerinde ikinci model, bellek ve döngü sınırını öngörülebilir kılar.

Paralel diziler aynı indekste konum, hız veya renk gibi özellikleri birlikte taşır. Bu ana başlık sabit kapasite fikrini somutlaştırır ve paralel dizilerle küçük bir sahne kurar. Sayı tahmin veya balon örneği, dizinin yalnızca veri deposu değil oyun kuralının taşıyıcısı olduğunu gösterir. Sonraki bölümlerdeki klavye ve çarpışma, bu çoklu nesne alışkanlığının üzerine binecektir. 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.

3.1. Sabit kapasite: diziyi push / pop olmadan yığın gibi kullanmak

Motivasyon: push ve pop hazır metotlardır; onları bilmek işi kısaltır. Ama yığın mantığı metotlara bağlı değildir: «sona ekle / sondan çıkar» davranışını indeks ve atama ile de kurabilirsiniz. Bu, hem «metotları henüz bilmiyorum» durumunda bir çıkış yolu sunar hem de dizinin nasıl çalıştığını (slot, indeks, doluluk) daha görünür kılar. Birçok dilde ve özellikle makineye yakın ortamlarda hazır push/pop yoktur; sabit boyutta dizi + tepe indeksi klasik çözümdür.

push / pop dizinin gerçek uzunluğunu değiştirir. Alternatif yaklaşım: ihtiyaç duyulacak en fazla eleman sayısını (MAKS) baştan belirlemek; diziyi o uzunlukta oluşturup boş slotları özel bir değerle (BOS, -1, "" …) kodlamak; ekleme ve çıkarmayı push() / pop() çağırmadan slotlara yazarak yapmak. Böylece dizi yığın (stack) gibi kullanılır: length sabit kalır, doluluk bir tepe indeksiyle (veya BOS tarayarak) izlenir.

Fikir:

  1. Üst sınırı sabitle (MAKS).
  2. Diziyi MAKS uzunluğunda BOS ile doldur (geçerli veriden ayırt edilebilir olmalı).
  3. «Ekle» (push benzeri) = yigin[tepe] = deger; tepe++ — push() yok.
  4. «Çıkar» (pop benzeri) = tepe--; değeri oku; slota BOS yaz — pop() yok.

Kod 1.

javascript
const MAKS = 5;const BOS = -1; // geçerli tahmin 1–10 olduğu için -1 «boş» demektir let yigin = [BOS, BOS, BOS, BOS, BOS]; // length her zaman 5let tepe = 0; function yiginEkle(deger) {  if (tepe >= MAKS) {    return false; // yer yok  }  yigin[tepe] = deger;  tepe = tepe + 1;  return true;} function yiginCikar() {  if (tepe === 0) {    return BOS; // boş  }  tepe = tepe - 1;  let eski = yigin[tepe];  yigin[tepe] = BOS;  return eski;}

Tablo 1.

Adım İşlem yigin tepe
Başlangıç — [-1, -1, -1, -1, -1] 0
1 yiginEkle(7) [7, -1, -1, -1, -1] 1
2 yiginEkle(3) [7, 3, -1, -1, -1] 2
3 yiginCikar() → 3 [7, -1, -1, -1, -1] 1

Bu modelde yigin.length her zaman MAKS kalır; dolu eleman sayısı tepe ile aynıdır. Ekrana yazarken yalnızca dolu slotlar çizilir:

Kod 2.

javascript
for (let i = 0; i < tepe; i = i + 1) {  text(yigin[i], 20, 40 + i * 20);}

tepe tutmak istemezseniz «ilk BOS slota yaz / sondan ilk dolu slotu boşalt» diye de tarayabilirsiniz; sonuç aynı fikirdir, yalnızca doluluk hesabı döngüyle yapılır.

Tablo 2.

Yaklaşım Boyut Boş yer Ne zaman uygun?
push / pop length değişir Eleman yoksa slot yoktur Uzunluk baştan bilinmiyor; geçmiş listesi
Sabit kapasite + BOS (+ tepe) length === MAKS sabit Slot var, değer BOS Envanter, can, sabit düşman havuzu, yığın/geri al

Bilgi — JavaScript’te dinamik dizi: Bu kitapta kullandığımız JavaScript / p5.js dizileri dinamiktir: push ile büyür, pop ile küçülür; length çalışma sırasında değişebilir. Bu yüzden «doğru boyutu baştan seçmek» JS’te çoğu zaman zorunluluk değil, tasarım tercihidir (örneğin envanterde tam 5 slot istiyorsanız).

Dikkat — bazı dillerde boyut sabit kalır: C, C++ sabit dizileri, Pascal dizileri veya gömülü / makineye yakın ortamlarda dizi boyutu çoğu zaman tanım anında belirlenir ve sonradan büyütülemez. Boyutu çok küçük seçmek taşmaya (overflow) ve hatalı bellek yazımına yol açabilir; çok büyük seçmek ise kullanılmayan slotlar yüzünden bellek israfına yol açar. Bu yüzden o dünyada «ihtiyacı doğru tahmin etmek» kritik bir mühendislik kararıdır. Sabit kapasite + tepe modeli, hem o kısıtı yansıtır hem de JS’te bile «maksimum N» kuralını açıkça kodlar.

Bilgi: 2.3’teki yığın fikri burada da aynıdır — fark yalnızca sözdizimidir: push/pop yerine tepe ve BOS ile LIFO davranışı elle kurulur. Gerçek oyun motorlarında da «maksimum N kayıtlı geri al» veya «en fazla N açık menü» gibi üst sınırlar sıkça sabittir; taşmayı engellemek için kapasite baştan kesilir.

Dikkat: Boş işaretçisi geçerli bir oyun değeriyle çakışmamalıdır. Tahmin aralığı 1–10 iken BOS = -1 uygundur; skor 0 da anlamlıysa 0 boş anlamına gelemez. String listelerinde sıkça "" veya "BOS" kullanılır.

Kule kurma ve skor geçmişi gibi örnekler push / pop ile yazılır (kısa ve okunaklıdır). Sabit slot / yığın modeli, metot bilmeden yığın kurmak, «maksimum N yer» kuralını gömmek veya sabit boyutlu dizi zorunluluğu olan dilleri anlamak için bilinmelidir.

Ne isteniyor? (kısa): push / pop kullanmadan «aynı işi başka sözdizimiyle yaz» demek değil. Yukarıdaki sabit slot + tepe modeli zaten yiginEkle / yiginCikar ile duruyor. Sıra Sizde’de bu modeli çalışan bir mini sketch’te göreceksiniz; sizin göreviniz listenin görselini Görsel 1’deki gibi slot kutularına çevirmek.

Görsel 1. Sabit envanter — slotlar ve tepe
Görsel 1. Sabit envanter — slotlar ve tepe

Kod bloğu: Mini envanter — tıkla ekle / sol üstten çıkar (push/pop yok).

Kod 3.

javascript
const MAKS = 5;const BOS = ""; let envanter = [BOS, BOS, BOS, BOS, BOS]; // length her zaman 5let tepe = 0;let esyalar = ["kilic", "iksir", "anahtar", "kalkan", "harita"]; function setup() {  createCanvas(520, 200);  textAlign(CENTER, CENTER);} function draw() {  background(245);  fill(40);  textSize(14);  textAlign(LEFT, TOP);  text("Sol tık: eşya ekle | Sol üst kutu: çıkar | length = " + envanter.length, 12, 10);  text("tepe = " + tepe, 12, 32);   // Sol üst: çıkar  fill(120, 80, 80);  rect(0, 160, 40, 40);  fill(255);  textAlign(CENTER, CENTER);  textSize(11);  text("ÇIKAR", 20, 180);   // Şimdilik yalnızca metin listesi — Sıra Sizde'de bunu Görsel 1 gibi slotlara çevireceksiniz  textAlign(LEFT, TOP);  textSize(14);  fill(30);  for (let i = 0; i < MAKS; i = i + 1) {    let yazi = envanter[i];    if (yazi === BOS) {      yazi = "(boş)";    }    text("[" + i + "] " + yazi, 60, 70 + i * 20);  }} function mousePressed() {  if (mouseX < 40 && mouseY > 160) {    yiginCikar();    return;  }  // Sıradaki eşyayı ekle (döngüsel)  let ad = esyalar[tepe % esyalar.length];  yiginEkle(ad);} function yiginEkle(deger) {  if (tepe >= MAKS) {    return false;  }  envanter[tepe] = deger;  tepe = tepe + 1;  return true;} function yiginCikar() {  if (tepe === 0) {    return BOS;  }  tepe = tepe - 1;  let eski = envanter[tepe];  envanter[tepe] = BOS;  return eski;}

Sketch’i çalıştırın: birkaç kez tıklayın, ÇIKAR ile geri alın. Konsolda veya ekranda envanter.length’in hep 5 kaldığını görün — push/pop olmadığı için dizi büyüyüp küçülmez; doluluk tepe ile izlenir.

Sıra Sizde: Yukarıdaki mini envanter kodunu temel alın. draw içindeki metin listesini kaldırıp Görsel 1’e benzer 5 yan yana dikdörtgen slot çizin.

İstenenler:

  1. Dolu slot (envanter[i] !== BOS): dolu kutu + eşya adı.
  2. Boş slot: soluk / kesik çizgili çerçeve + «BOS» (veya boş bırakın).
  3. tepe indeksinin altına küçük bir üçgen veya ok koyun (sonraki boş slotu göstersin; tepe === MAKS iken en sağda veya «dolu» yazın).
  4. yiginEkle / yiginCikar ve mousePressed mantığına dokunmayın — yalnızca çizimi değiştirin. envanter.length hâlâ 5 olmalı.

3.2. Paralel dizilerle mini sahne — balonlar

2.2’de paralel diziler ve ellipse hatırlatması yapıldı; 2.3’te push / pop ile liste büyüyüp küçüldü. Bu alt başlıkta ikisini birleştirip oval balon sahnesi kurulur: konum için balonX / balonY, boyut için ayrı balonRX / balonRY (yatay ve dikey yarıçap) — hepsi aynı indekste.

Hatırlatma: ellipse(x, y, genislik, yukseklik) — genişlik = 2 * rx, yükseklik = 2 * ry. Daire istiyorsanız rx === ry (veya circle); Görsel 2’deki gibi oval balonlar için rx ile ry farklıdır.

Sık karşılaşılan dizi hataları:

Tablo 3.

Belirti Olası neden Çözüm
undefined ekranda Geçersiz indeks (d[3] üç elemanlı dizide) i < dizi.length koşulunu kontrol et
Döngü hiç çalışmıyor i <= length sınır aşımı i < length kullan
push sonrası liste görünmüyor draw() içinde dolaşma yok for ile ekrana yazdır
Tüm balonlar üst üste / garip boyut Paralel dizide indeks kayması Aynı i ile X, Y, RX, RY oku
Bir balon «kaybolmuş» gibi Yalnızca bir diziye push / pop Ekleme-çıkarma tüm paralel dizilerde birlikte

Dikkat: Paralel dizilerde push yalnızca bir listeye uygulanırsa listeler farklı uzunlukta kalır. balonX.push(mouseX) yapıp balonY / balonRX / balonRY unutulursa döngü undefined okur. Ekleme ve çıkarma her listede birlikte yapılmalıdır.

Sıra Sizde: Paralel dizilerle bir balon sahnesi çizin. Hedef görünüm:

Görsel 2. Hedef — paralel dizilerle oval balonlar (rx, ry)
Görsel 2. Hedef — paralel dizilerle oval balonlar (rx, ry)

İstenenler:

  1. balonX, balonY, balonRX, balonRY (isteğe bağlı renk dizisi) — aynı indekste bir balon.
  2. for içinde ellipse(balonX[i], balonY[i], balonRX[i] * 2, balonRY[i] * 2) (ip için kısa bir line bonus).
  3. Kâğıtta: yalnızca balonX.push(...) yapıp diğer üç diziyi unutan bir arkadaşın ekranında ne bozulur? Bir cümleyle yazın.

Örnek Olay: Kule yığını Tahmini etkinliği tamamlama süresi: 20–25 dakika.

Senaryo: Mini kule sketch’inde üç kule kurulmuş, sonra bir kez GERİ AL’a basılmıştır. Dizilerde ne kalır, ekranda kaç kule görünür?

Tartışma Soruları:

Yapay Zekâ Etkileşimi: Balon Patlat — sen yaz, YZ yardımcı fonksiyon yazsın Tahmini etkinliği tamamlama süresi: 45–60 dakika.

Amaç: Oyun mekaniğini (siz yazın); nokta–elips testi, çakışmasız yeni balon ve uyumlu renk gibi yardımcı fonksiyonları YZ’den isteyin; en sonda çalışan oyunu YZ ile makyajlayın (patlama / belirme efektleri). Boş slot / -1 yok — ekleme push, silme splice (veya sondaysa pop).

splice (kısa): dizi.splice(i, 1) indeksi i olan elemanı çıkarır (length bir azalır). pop() yalnızca sondan çıkarır; ortadaki balonu patlatmak için splice gerekir. Paralel dizilerde aynı i için her listede splice(i, 1) çağrılır.

Oyun fikri (kısa): Oval balonlar (balonX, balonY, balonRX, balonRY; isteğe bağlı balonR, balonG, balonB). Tıklama bir balonun içindeyse o indeks tüm dizilerden splice ile çıkar, skor artar. Değilse YZ’nin ürettiği yardımcılarla yeni, diğerlerine değmeyen bir balon push edilir.

Adım 1 — Sizin kodunuz (oyun mekaniği): Web Editor’de şunları kendiniz yazın:

Adım 2 — YZ’den üç yardımcı fonksiyon: Aşağıdaki istemleri ayrı ayrı (veya tek seferde üç fonksiyon diye) verin. Dönüş için dizi kullanın — bu ana başlıkta nesne literal ({ x: … }) henüz yok; [x, y, rx, ry] yeter ([0]→x, [1]→y, [2]→rx, [3]→ry).

Örnek istem A — nokta elips içinde mi? "p5.js için fonksiyon yaz: noktaElipsIcindeMi(px, py, cx, cy, rx, ry) → boolean. (px,py) noktası, merkezi (cx,cy), yatay yarıçap rx, dikey yarıçap ry olan elipsin içinde mi? Elips denklemi kullan. Kısa yorum ekle. Class / nesne literal yok."

Örnek istem B — çakışmasız yeni balon: "Fonksiyon: yeniBalonOlustur(balonX, balonY, balonRX, balonRY, tuvalW, tuvalH). Rastgele konum ve rx/ry üret; balon tamamen tuval içinde kalsın; mevcut balonlardan hiçbirine değmesin (elips–elips veya güvenli daire yaklaşımı). Birkaç deneme yapsın; yer bulamazsa null dönsün. Dönüş: dizi [x, y, rx, ry] — nesne literal kullanma. Parametre olarak mevcut paralel dizileri ve tuval boyutlarını alsın."

Örnek istem C — uyumlu renk (isteğe bağlı): "Fonksiyon: uyumluBalonRengi() → [r, g, b] (0–255). Pastel / birbirine uyumlu canlı renkler üretsin (ör. sabit doygunluk, rastgele ton). color() nesnesi yerine sayı dizisi dön."

Adım 3 — Birleştirme (siz): YZ fonksiyonlarını sketch’e yapıştırın. mousePressed içinde örneğin:

Kod 4.

javascript
// iskelet — indeksi siz bulun, splice / push siz yazınlet vurus = -1;for (let i = 0; i < balonX.length; i = i + 1) {  if (noktaElipsIcindeMi(mouseX, mouseY, balonX[i], balonY[i], balonRX[i], balonRY[i])) {    vurus = i;    break;  }}if (vurus >= 0) {  // tüm paralel dizilerde splice(vurus, 1); skor++} else {  let b = yeniBalonOlustur(balonX, balonY, balonRX, balonRY, width, height);  if (b !== null) {    // b[0]..b[3] → push; renk için uyumluBalonRengi()  }}

Adım 4 — Kontrol / eleştirel bakış:

Oyun mekanik olarak çalışıyorsa (patlat / ekle / skor) Adım 5’e geçin. İsterseniz süzülme (balonY[i] = balonY[i] - 0.5) gibi ufak bir mekaniği de kendiniz ekleyebilirsiniz.

Adım 5 — Makyaj (YZ): Mantık bittikten sonra çalışan sketch’in tamamını yapıştırıp görsel + ses cilasını YZ’ye bırakın. Amaç oyunu yeniden yazmak değil; patlama / belirme hissi ve kısa geri bildirim sesleri katmak.

Örnek istem — efektli makyaj (+ ses + açıklama): "Aşağıdaki p5.js Balon Patlat sketch’im çalışıyor (paralel diziler, splice/push, skor). Mekaniği bozma; class kullanma; paralel dizi modelini koru.

Yapılacaklar:

  1. Balon patlayınca hemen splice etme — kısa kaybolma animasyonu (küçülme ve/veya alfa; parçacık/halka bonus olabilir).
  2. Yeni balon eklenince büyüme veya fade-in ile belirsin.
  3. Patlamada ve yeni balon eklenince kısa ses efekti (p5.sound veya basit sentez / Oscillator; Web Editor’de çalışacak şekilde; dosya yoksa sentez tercih et).

Ayrıca yanıtında şunları iste:

A) Önce sözel olarak: balon patlatma için kaç farklı efekt türü düşünülebilir? (ör. küçülerek kaybolma, alfa solma, parçacık saçılma, genişleyen halka, titreme…) Her türü 1–2 cümleyle anlat.

B) Her tür için bu sketch’e uygun, kısa örnek kod parçası yaz (hepsini birden uygulamana gerek yok; birini seçip tam koda entegre et, diğerlerini örnek olarak göster).

C) En sonda: benim orijinal koda göre neleri değiştirdin / ekledin listesini yaz. Her maddeyi bu ders düzeyinde açıkla (dizi, for, push/splice, fonksiyon — henüz bilmediğimiz class/nesne jargonundan kaçın).

Kod:"

(Ardından kendi sketch’inizi yapıştırın.)

YZ’nin önerdiği animasyon için çoğu zaman ekstra diziler gerekir (ör. balonOlcek, balonAlfa veya «patlıyor» durumu). Bunları eklerken indekslerin hâlâ birlikte push / splice edildiğini kontrol edin. Ses için ek kütüphane / userStartAudio() gibi satırlar gelebilir — Play’e bastıktan sonra ilk tıklamada sesin açılması normaldir. Efekt abartılıysa sadeleştirin; skor ve tıklama mantığı bozulmamalı.

Adım 6 — Önce fikir, sonra (isterseniz) kod: YZ’nin Adım 5’teki «neleri değiştirdim» listesini okuyun. Anlamadığınız bir satır varsa devam sorusu sorun (ör. «Şu eklediğin balonAlfa dizisini, bu dersteki paralel dizi diliyle tekrar açıkla.»).

Ardından oyunu daha ileri taşımak için önce yalnızca fikir isteyin — henüz kod istemeyin:

Örnek istem — başka nasıl makyajlarız? (yalnızca fikir) "Bu Balon Patlat oyununu (paralel diziler, patlat/ekle, skor) daha eğlenceli yapmak için 6–8 makyaj / cilâ fikri öner. Görsel, ses, arayüz ve hafif oyun hissi karışık olsun. Her fikir için kısa sözel açıklama ve zorluk (kolay/orta) yaz. Kod yazma; yalnızca fikir kataloğu."

Beğendiğiniz bir (veya birkaç) fikri uygulamaya dökmek isterseniz, mevcut sketch’inizi yapıştırıp uygun bir prompt yazın; yapılan makyajın kodunu sizin şu anki bilgi düzeyinizde açıklamasını isteyin. Anlamadığınız noktalarda devam soruları sorun.

Örnek istem — seçilen fikri uygula + açıkla: "Şu makyaj fikrini mevcut koda ekle: [fikri buraya yaz]. Mekaniği bozma. Bitince: (1) eklediğin/değiştirdiğin yerleri madde madde listele, (2) her maddeyi dizi, for, push/splice, fonksiyon dilinde, yeni başlayan düzeyinde açıkla. Kod:"

Hatırlatma: YZ bazen bu derste henüz görmediğiniz yapılara (ör. daha ileri animasyon, ses API’si, alışık olmadığınız sözdizimi) kayabilir. Bir parçayı «şu anki düzeyimde anlamıyorum, daha basit anlat veya o kısmı sadeleştir» diyerek geri itmek doğaldır; her satırı hemen kavramak zorunda değilsiniz. Anladığınız katmanı tutup, kalanını sonraki konulara bırakabilirsiniz.

Yapay Zekâ Etkileşimi: Paralel Diziden Nesneye Tahmini süre: 15–20 dakika.

Amaç: Paralel dizilerin nesne literaline eşlenmesini görmek.

Adım 1: x[i], y[i], r[i] için bir nesne şekli ({x,y,r}) tasarlayın. Adım 2: Yapay zekâdan paralel dizi ↔ nesne dizisi dönüşüm iskeleti isteyin; henüz sınıf kullanmayın. Adım 3: Hangi modelin bu aşamada daha okunur olduğunu bir cümleyle not edin.

Özet

Sabit kapasitede dizi, baştan istenen sayıda eleman içerecek biçimde (ör. [BOS, BOS, BOS, BOS]) tanımlanır; canlı eleman sayısı tepe benzeri bir değişkenle izlenir. Ekleme tepeye yazar ve tepeyi artırır; silme tepeyi azaltır — push/pop yerine indeks aritmetiği vardır. Bu model, nesne havuzu düşüncesine de köprüdür.

Paralel x[], y[], r[] dizileri aynı i ile bir balonu veya hedefi tanımlar. draw içinde i < tepe (veya length) kadar dolaşıp güncelleme ve çizim yapılır. Mini sahne, diziyi görünür oyun davranışına bağlar: çoklu konum, basit kural, okunabilir döngü. Bu alışkanlık olmadan sonraki çarpışma ve klavye kontrollü çoklu varlıklar zorlaşır.

İki modelin maliyeti farklıdır. Dinamik listede silme işlemi kalan elemanları kaydırdığı için indeksler değişir; döngü içinde eleman çıkarmak, atlanan eleman gibi ince hatalara yol açar. Sabit kapasitede ise dizi hiç küçülmez, yalnızca tepe değeri oynar; bu yüzden indeksler kararlıdır ve döngü sınırı her frame'de aynı biçimde okunur. Kapasitenin dolması ayrı bir karardır: yeni eleman ya reddedilir ya da en eskisinin üzerine yazılır. Bu seçim, oyunun kuralına göre baştan belirlenir.

Neler Öğrendik?

Soru 1 Sabit kapasite modelinde tepe tipik olarak neyi tutar?

A) Tuval rengini

B) Canlı / geçerli eleman sayısına giden sınırı

C) DNS adresini

D) CSS sınıfını

E) EPUB kapak adını

Soru 2 Paralel x ve y dizilerinde aynı indeks ne anlama gelir?

A) İki farklı oyunun skoru

B) Aynı varlığın ilişkili özellikleri

C) Rastgele iki tarayıcı

D) Zorunlu ses kanalı

E) Git commit

Soru 3 Mini sahnede diziyi draw içinde dolaşmanın amacı nedir?

A) Her varlık için güncelleme ve çizimi tekrarlamak

B) setup’ı silmek

C) HTML’i kapatmak

D) Renk körlüğü testi

E) Yazıcıya göndermek

Soru 4 push/pop yerine sabit kapasite seçmek ne sağlar?

A) Üst sınırın ve döngünün öngörülebilir kalması

B) Matematiğin kalkması

C) Farein kapanması

D) Zorunlu 3B

E) Sunucu kurulumu

Neler Öğrendik Yanıt Anahtarı

Soru 1: Doğru Cevap: B

Soru 2: Doğru Cevap: B

Soru 3: Doğru Cevap: A

Soru 4: Doğru Cevap: A

Yararlanılan Kaynaklar

Bu içerik aşağıdaki kaynaklardan derlenerek hazırlanmıştır:


Ana Başlık 4. Klavye Girdisi

Amaç: Klavye olaylarını (keyIsDown, key, keyPressed()) öğreterek oyuncu kontrollü hareket sağlamak.

Öğrenme Çıktıları:

Anahtar Sözcükler: klavye girdisi, keyIsDown, keyPressed, key, keyCode, oyuncu kontrolü, ASCII, Unicode

Giriş

Önceki ana başlıkta top deltaTime ile kendi kendine hareket ediyordu; oyuncu yalnızca izliyordu. Oyunlarda karakter, araç veya imleç çoğu zaman klavye (ve fare) ile yönlendirilir. Klavyenin en tanıdık kullanımı tek seferlik olaydır: bir tuşa basıldığı anda tek bir iş yapılır, örneğin R ile tur yeniden başlatılır. Gerçek zamanlı kontrolde ise tuş basılı tutulduğu sürece hareket devam etmelidir: WASD veya ok tuşlarıyla kareyi gezdirmek buna tipik örnektir.

p5.js, fare girdisinde olduğu gibi klavye için de iki katman sunar: draw() içinde her frame okunan durum (keyIsDown) ve tuşa basıldığı anda bir kez çalışan olay fonksiyonu (keyPressed). Bu ana başlıkta her iki yöntem sistematik biçimde ele alınacak; hareket deltaTime ile birleştirilerek önceki ana başlıktaki frame bağımsız hız korunacaktır.

Bu iki katmanlı yaklaşım, klavyenin fiziksel doğasından kaynaklanır: bir tuş, oyuncu parmağını kaldırana kadar "basılı" kalır ve bu süre boyunca aynı tuşa ait sayısız draw() çağrısı gerçekleşebilir. Programın bu süreklilikten haberdar olması için her frame'de tuşun anlık durumunu sorgulaması gerekir; bu da keyIsDown() fonksiyonunun görevidir. Buna karşılık "tuşa basıldı" bilgisinin yalnızca bir kez işlenmesi istenen durumlar da vardır — bir menüde seçim yapmak, bir mermi ateşlemek gibi; bu tür senaryolarda p5.js'in tuş basışını olay olarak bildirdiği keyPressed() daha uygundur. İki katmanı doğru yerde kullanmak, klavye kontrollü bir oyunun hem tepkisel hem öngörülebilir olmasını sağlar.

Türkiye'de okul laboratuvarlarında QWERTY klavye yaygındır; WASD ve ok tuşları birlikte desteklenirse farklı alışkanlıklara sahip oyuncular aynı sketch'i kullanabilir. Tuval odaklıyken tuşlar sketch'e gider — önizleme paneline bir kez tıklamak gerekir; aksi halde girdi tarayıcıya veya editöre yönlenebilir.

4.1. Klavye Olayları ve p5.js Örüntüsü

Tanım: Klavye girdisi — Oyuncunun tuş basmasıyla programa ilettiği kontrol bilgisidir.

p5.js'te yerleşik olay fonksiyonları (önceki bölümlerde setup, draw, mousePressed ile tanıtılan örüntü):

Tablo 1.

Fonksiyon Ne zaman çalışır Tipik kullanım
keyPressed() Tuşa basıldığı frame'de bir kez Zıplama, ateş, menü seçimi, tur yenileme
keyReleased() Tuş bırakıldığı frame'de bir kez Tuş bırakılınca eylem tetikleme (ör. şarj biriktirip bırakınca ateş etme)
draw() + keyIsDown() Tuş basılı olduğu sürece her frame Sürekli yürüme, hızlanma

Bilgi: keyPressed adını taşıyan fonksiyon, p5.js'in otomatik çağırdığı yerleşik olay adıdır; setup ve draw gibi tam yazım gerekir. Kendi fonksiyon adınız farklı olursa p5.js o kodu tuş olayı için çalıştırmaz.

Fare ile karşılaştırma (önceki bölümler):

Tablo 2.

Girdi Sürekli (basılı tutma) Tek seferlik olay
Fare mouseIsPressed, mouseX / mouseY mousePressed()
Klavye keyIsDown(...) keyPressed()

4.2. keyIsDown ile Sürekli Hareket

Tanım: keyIsDown(key) — p5.js fonksiyonu; verilen tuş o frame'de basılıysa true, değilse false döndürür. draw() içinde çağrılır.

Ok tuşları için p5.js sabitleri kullanılabilir: LEFT_ARROW, RIGHT_ARROW, UP_ARROW, DOWN_ARROW. Harf tuşlarında keyIsDown sayı ister: 65 (A), 68 (D).

Kod bloğu: Ok tuşlarıyla yatay hareket — deltaTime ile hız.

Kod 1.

javascript
let kareX = 200;let kareY = 150;const KARE_BOYUT = 40;const HIZ = 180; // piksel / saniye function setup() {  createCanvas(500, 300);  noStroke();} function draw() {  background(35, 40, 55);   let dt = deltaTime / 1000;   if (keyIsDown(RIGHT_ARROW)) {    kareX = kareX + HIZ * dt;  }  if (keyIsDown(LEFT_ARROW)) {    kareX = kareX - HIZ * dt;  }   fill(100, 200, 255);  rect(kareX, kareY, KARE_BOYUT, KARE_BOYUT);}

Birden fazla if kullanıldığında koşullar bağımsızdır; çapraz hareket (ör. sağ + yukarı) aynı frame'de birleşebilir. else if yalnızca tek yön seçilecekse uygundur.

Çapraz hareket ve hız: Sağ ve yukarı aynı anda basılıyken kare hem X hem Y değişir; frame başına kat edilen mesafe HIZ * dt ile her eksende ayrı uygulanır. Köşegen hareket biraz daha hızlı görünebilir (Pisagor bağıntısı); rekabetçi oyunlarda hız normalize edilir. Örneklerde basit bağımsız if blokları kullanılır; çapraz hızı eşitlemek istenirse X ve Y bileşenleri birim vektöre göre ölçeklenip (normalize edilip) tekrar HIZ ile çarpılır.

Tablo 3.

Tuş kombinasyonu X değişimi Y değişimi Görsel etki
Yalnızca RIGHT + 0 Yatay
Yalnızca UP 0 − Dikey
RIGHT + UP + − Çapraz sağ-üst

Dikkat: Tuş kodunu yalnızca keyPressed() içinde okursanız basılı tutma ile sürekli hareket üretilemez; draw() döngüsünde keyIsDown gerekir.

Bu hata sık görülür çünkü keyPressed() sezgisel olarak "tuşla ilgili her şeyin buraya yazılacağı" fonksiyon gibi algılanabilir. Ancak keyPressed() yalnızca tuşa basılma anında bir kez tetiklenir; oyuncu tuşu birkaç saniye basılı tutsa da fonksiyon gövdesi tek seferlik çalışır. Bu nedenle keyPressed() içine kareX = kareX + HIZ * dt gibi bir satır yazmak, karenin yalnızca her basışta bir kez ve sabit miktarda ilerlemesine yol açar — akıcı hareket değil, adım adım sıçrama görünür. Sürekli hareket her zaman draw() içindeki bir koşulla, yani keyIsDown() ile sağlanmalıdır.

Dikey hareket için UP_ARROW ve DOWN_ARROW aynı örüntüyle eklenir:

Kod 2.

javascript
  if (keyIsDown(DOWN_ARROW)) {    kareY = kareY + HIZ * dt;  }  if (keyIsDown(UP_ARROW)) {    kareY = kareY - HIZ * dt;  }

4.3. keyPressed ve Tek Seferlik Eylemler

Turu yeniden başlatan R tuşu, keyPressed() ile şu biçimde yazılır:

Kod 3.

javascript
function keyPressed() {  if (key === "r" || key === "R") {    // turu sıfırla  }}

Tanım: key — Basılan tuşun karakter değerini tutan p5.js değişkeni ( 'a', 'R', ' ' boşluk vb.). Yalnızca olay fonksiyonu çalıştığı frame'de anlamlıdır.

keyPressed() ile mousePressed() aynı mantığı izler: olay bir kez tetiklenir. Zıplama, tek atış veya menüde seçim gibi "her basışta bir eylem" senaryolarına uygundur.

Kod bloğu: Boşluk tuşuna basınca karenin rengini değiştirme (toggle).

Kod 4.

javascript
let kareRengi; function setup() {  createCanvas(400, 300);  kareRengi = color(100, 200, 255);} function draw() {  background(30);  fill(kareRengi);  rect(width / 2 - 30, height / 2 - 30, 60, 60);} function keyPressed() {  if (key === " ") {    if (red(kareRengi) > 200) {      kareRengi = color(100, 200, 255);    } else {      kareRengi = color(255, 120, 80);    }  }}

red() p5.js renk bileşenini okur; renk kavramı önceki bölümlerdeki fill(r, g, b) ile uyumludur.

Bilgi: Tek seferlik eylem için draw() içinde keyIsDown + bayrak değişkeni kullanmak yerine doğrudan keyPressed() tercih edilir; kod niyeti daha net iletilir.

Alternatif olarak draw() içinde keyIsDown ile birlikte bir "önceki durum" bayrağı tutulup tek seferlik eylem simüle edilebilir (tuş bu frame basılı, önceki frame basılı değildi ise eylemi çalıştır). Bu teknik bazı ileri senaryolarda (örneğin aynı frame'de birden çok girdi kaynağını birleştirirken) gerekebilir; ancak ek bir değişken ve karşılaştırma gerektirdiği için kodu karmaşıklaştırır. p5.js'in kendisi bu karşılaştırmayı keyPressed() aracılığıyla otomatik yaptığından, basit ve orta düzey oyunlarda doğrudan keyPressed() tercih edilmelidir.

keyReleased(): Tuş bırakıldığı anda bir kez çalışır. keyPressed() basma anını, keyIsDown() basılı tutmayı, keyReleased() ise bırakma anını yakalar. Örneğin SPACE basılıyken şarj dolup bırakılınca ateş etmek için keyIsDown ile şarj, keyReleased ile ateş ayrılabilir.

Kontrol şeması örneği (uzay gemisi):

Tablo 4.

Tuş Yöntem Eylem
Ok / WASD keyIsDown + draw() Sürekli hareket
SPACE keyPressed() Tek mermi
R keyPressed() Tur sıfırlama
ESC keyPressed() Menüye dön (önceki bölümlerin 4. ana başlığı)

4.4. key ve keyCode

Bazı tuşların tek karakterle temsil edilmesi zordur veya ok tuşları farklı klavyelerde farklı karakter üretebilir. Bu durumda keyCode kullanılır.

Tanım: keyCode — Basılan tuşun sayısal kodu. Ok tuşları için p5.js sabitleri keyCode ile eşleşir.

key ve keyCode arasındaki fark, "hangi karakter" ile "hangi fiziksel tuş" sorularının ayrımına dayanır. Harf ve rakam tuşlarında key doğrudan okunabilir bir karakter döndürür ('a', '5'); bu, ekrana metin yazdırma veya karakter karşılaştırma için pratiktir. Ok tuşları, SHIFT, CTRL gibi tuşlarda ise yazdırılabilir bir karakter yoktur — bu tuşlar keyCode üzerinden sayısal bir kimlikle temsil edilir. p5.js, sık kullanılan ok tuşları için LEFT_ARROW, RIGHT_ARROW, UP_ARROW, DOWN_ARROW adlı sabitleri önceden tanımlayarak bu sayısal kodları ezberlemeyi gereksiz kılar; geliştirici keyCode === 37 yazmak yerine keyCode === LEFT_ARROW yazabilir, kod hem okunur hem hataya daha az açık olur.

37 nereden geliyor? ASCII, Unicode ve tuş kodları

keyCode === 37 yazıldığında 37 «rastgele bir sabit» değildir; bilgisayarların karakter ve tuşları sayılarla temsil etme geleneğinden gelir. «Bu sayı tablonun neresinde?» sorusu için üç katmanı ayırmak yeterlidir.

1. ASCII (American Standard Code for Information Interchange)
Erken bilgisayarlarda harf, rakam ve bazı denetim karakterleri 0–127 aralığında numaralandırıldı. 0–31 denetim kodlarıdır (görünmez); 32–126 yazdırılabilir karakterlerdir. Görsel 1 bu yazdırılabilir aralığı gösterir; renkler rakam, büyük harf ve küçük harf bloklarını ayırır.

Görsel 1. ASCII tablosu — yazdırılabilir karakterler (32–126)
Görsel 1. ASCII tablosu — yazdırılabilir karakterler (32–126)

Tablo 5.

Aralık ASCII / Unicode Anlam
48 … 57 '0' … '9' Rakamlar
65 … 90 'A' … 'Z' Büyük harfler
97 … 122 'a' … 'z' Küçük harfler
32 boşluk Space

Harf ve rakam gibi yazdırılabilir tuşlarda key değişkeni doğrudan bu karakteri verir ('A', 'w'). JavaScript’te bir karakterin numarasını görmek için charCodeAt kullanılabilir: 'A'.charCodeAt(0) → 65.

Bilgi: Tam ASCII listesi ve tarihçesi için ASCII (Wikipedia) veya ASCII Table kaynaklarına bakılabilir. Bu kitaptaki Görsel 1, oyun kodunda en çok kullanılan yazdırılabilir dilimi özetler.

Yazdırılamayan (denetim) karakterler: \n, \t

Görsel 1’de görünmeyen 0–31 aralığı denetim kodlarıdır; ekranda bir «harf» gibi basılmaz, ama programda kaçış dizisi (escape sequence) ile yazılır. Oyun ve arayüz metinlerinde en sık kullanılan ikisi:

Tablo 6.

Yazım (string içinde) ASCII Adı Ne yapar?
\n 10 LF (line feed) Yeni satır (satır sonu)
\t 9 TAB (sekme) Yatay sekme; genelde birkaç boşluk kadar ilerler
(boşluk tuşu) 32 Space Görünür boşluk (yazdırılabilir)

JavaScript string’inde backslash (\) «sonraki karakter özel anlam taşır» demektir: "Merhaba\nDunya" içinde \n iki karakter (\ ve n) gibi yazılır ama bellekte tek satır-sonu karakterine dönüşür.

p5.js text() bu kaçışları işler; HUD (skor / can) gibi çok satırlı yazılar için \n pratiktir:

Kod 5.

javascript
function draw() {  background(30);  fill(255);  textSize(18);  textAlign(LEFT, TOP);  text("Skor: 3\nCan: 5", 24, 40);   // iki satır  text("A\tB\tC", 24, 100);            // sekme ile aralık}

Görsel 2. `\n` ve `\t` — text() kaynak kodu ve tuval çıktısı
Görsel 2. `\n` ve `\t` — text() kaynak kodu ve tuval çıktısı

Görsel 2 solda string içindeki kaçışları, sağda tuvalde oluşan satır kırılmasını ve sekme boşluğunu gösterir.

Bilgi: console.log("skor\t" + skor) konsolda sütun gibi hizalama için de \t kullanır. Tuvalde sütunlar kritikse \t yazı tipine göre farklı genişlik verebilir; o zaman ayrı text(..., x, y) çağrıları veya sabit x ofsetleri daha öngörülebilirdir.

Dikkat: Kaynak kodda girinti için kullanılan boşluk ve Tab da aynı ASCII karakterleridir (32 ve 9). Bunlar string içindeki \n / \t ile karıştırılmamalıdır: biri editörde satırı içeri almak, diğeri metin içeriğinde satır kırmak / sekme koymaktır. Girintinin okunabilirlikteki rolü önceki bölümlerde if ve for bloklarıyla birlikte vurgulanır.

2. Unicode
ASCII yalnızca Latin alfabesinin dar bir dilimini kapsar. Unicode, dünyadaki yazı sistemlerini (Türkçe ğ, ş, emoji, vb.) tek bir numara uzayında toplayan daha geniş standarttır. Unicode’un ilk 128 kodu ASCII ile aynıdır; yani 'A' hem ASCII’de hem Unicode’da 65’tir. Bu kitapta oyun girdileri çoğunlukla Latin harf ve ok tuşlarıyla sınırlıdır; yine de metinleri bilgisayarın «harf = sayı» diye sakladığını bilmek, ileride dosya, ağ veya farklı dillerle çalışırken işe yarar.

Bilgi: Unicode’un resmi özeti: The Unicode Standard. Karakter arama için Unicode Character Table kullanışlıdır. JavaScript kaynak dosyaları UTF-8 ile saklandığında Unicode karakterler metin içinde kullanılabilir.

Dikkat: JavaScript (ve dolayısıyla p5.js sketch’leri) Unicode destekler; teknik olarak let skorŞuAn = 0; veya function çizTop() { … } gibi Türkçe karakterli tanımlayıcılar çoğu modern tarayıcıda çalışır. Yine de bu kitaptaki örneklerde ve önerilen alıştırmalarda değişken / fonksiyon adlarında ASCII harfler (skorSuAn, cizTop) tercih edilir: (1) farklı editör ve yazı tipi kombinasyonlarında karakter bozulması riski azalır; (2) İngilizce kaynaklar ve hata mesajlarıyla eşleşmek kolaylaşır; (3) takım çalışmasında klavye düzeni farkları az sorun çıkarır. Oyuncuya gösterilen metinlerde (text("Skor: " + skor), "Kazandınız!") Türkçe karakter kullanmak ise doğaldır ve teşvik edilir — kısıt tanımlayıcı adlarındadır, ekran yazılarında değil.

3. keyCode ve ok tuşları (37, 38, 39, 40)

Dikkat: Ok tuşlarının ASCII kodu yoktur. ASCII (ve Görsel 1) yazdırılabilir / denetim karakterleri içindir (A, %, satır sonu…). Sol oka basınca metin kutusuna % yazılmaz; key de genelde tek bir yazdırılabilir harf vermez. Oklar «karakter» değil, özel tuştur.

O zaman 37 nereden geliyor? Tarayıcıların eski klavye API’sinin (p5.js’in keyCode ile yansıttığı) ayrı bir tuş-numara listesinden. Bu liste ASCII tablosu değildir; tesadüfen sol oka 37 denmiştir. Aynı şekilde yukarı 38, sağ 39, aşağı 40’tır:

Tablo 7.

Tuş keyCode (sayı) p5.js sabiti ASCII’de karşılığı?
Sol ok 37 LEFT_ARROW Yok (← diye bir ASCII karakteri yok)
Yukarı ok 38 UP_ARROW Yok
Sağ ok 39 RIGHT_ARROW Yok
Aşağı ok 40 DOWN_ARROW Yok

«Ama ASCII 37 = % değil mi?» Evet — ama o başka bir sözlükteki 37’dir. İki farklı numaralandırma aynı rakamı kullanabilir; bu bir çakışma veya çelişki değil, tesadüftür. (İki farklı apartmanda «daire 37» olması gibi: aynı numara, farklı binalar.) Sol ok ≠ %. % tuşuna basınca key === "%" olur; sol oka basınca keyCode === LEFT_ARROW (yani 37) bakılır — farklı olaylar.

Bu yüzden keyCode === 37 ile keyCode === LEFT_ARROW aynı karşılaştırmadır; LEFT_ARROW yalnızca o tuş kimliğinin okunabilir adıdır. Harf tuşlarında keyCode çoğu ortamda büyük harfin ASCII/Unicode numarasına yakındır (ör. A → 65); yine de harf kontrolünde key === "w" / key === "W" daha doğrudan ve güvenilirdir. Ok, SHIFT, ENTER gibi özel tuşlarda keyCode (veya LEFT_ARROW sabiti) kullanılır — ASCII tablosundan ok aramayın; orada yoktur.

Dikkat: Ok / SHIFT sayılarını ezberlemeyin; ASCII’den «okun kodu» diye satır aramayın. Kodda her zaman LEFT_ARROW / RIGHT_ARROW / UP_ARROW / DOWN_ARROW yazın. console.log(keyCode) yalnızca merak veya hata ayıklama içindir.

Dikkat: LEFT / RIGHT / UP / DOWN sabitleri hizalama içindir (textAlign(LEFT) …) ve değerleri string’dir ('left'). keyIsDown(LEFT) bu yüzden «Number bekleniyor, string geldi» uyarısı üretir ve ok tuşunu yakalamaz. Oklar için LEFT_ARROW kullanın. keyIsDown harf için de sayı ister: keyIsDown(65) (A), 68 (D), 87 (W), 83 (S).

Tablo 8.

Tuş p5.js sabiti Tipik kullanım
Sol ok LEFT_ARROW keyIsDown(LEFT_ARROW) veya keyCode === LEFT_ARROW
Sağ ok RIGHT_ARROW keyIsDown(RIGHT_ARROW)
Yukarı UP_ARROW keyIsDown(UP_ARROW)
Aşağı DOWN_ARROW keyIsDown(DOWN_ARROW)
Harf keyCode sayısı keyIsDown(65) (A); olaylarda key === "w"

Kod bloğu: keyPressed() içinde ok tuşu ile mesaj — önceki bölümlerde tanıtılan console.log() ile tuşa basıldığı alt konsolda görülür (tuvalde değil).

Kod 6.

javascript
function keyPressed() {  if (keyCode === UP_ARROW) {    console.log("Yukari ok");  }  if (key === "w" || key === "W") {    console.log("W tusu");  }}

WASD ve ok tuşlarını aynı hareket için birleştirmek yaygındır:

Kod 7.

javascript
  if (keyIsDown(LEFT_ARROW) || keyIsDown(65)) {    kareX = kareX - HIZ * dt;  }  if (keyIsDown(RIGHT_ARROW) || keyIsDown(68)) {    kareX = kareX + HIZ * dt;  }

4.5. Klavye ile Kontrol Edilen Kare

Aşağıdaki sketch, ok tuşları ve WASD ile hareket eden bir kareyi tuval sınırları içinde tutar. Hareket deltaTime ile hesaplanır; ekranda basılı tuş bilgisi gösterilir.

Kontrol özeti:

Kod 8.

javascript
let oyuncuX;let oyuncuY;const BOYUT = 44;const HIZ = 200; function setup() {  createCanvas(560, 360);  noStroke();  oyuncuX = width / 2 - BOYUT / 2;  oyuncuY = height / 2 - BOYUT / 2;} function draw() {  background(28, 32, 48);  let dt = deltaTime / 1000;   if (keyIsDown(LEFT_ARROW) || keyIsDown(65)) {    oyuncuX = oyuncuX - HIZ * dt;  }  if (keyIsDown(RIGHT_ARROW) || keyIsDown(68)) {    oyuncuX = oyuncuX + HIZ * dt;  }  if (keyIsDown(UP_ARROW) || keyIsDown(87)) {    oyuncuY = oyuncuY - HIZ * dt;  }  if (keyIsDown(DOWN_ARROW) || keyIsDown(83)) {    oyuncuY = oyuncuY + HIZ * dt;  }   oyuncuX = constrain(oyuncuX, 0, width - BOYUT);  oyuncuY = constrain(oyuncuY, 0, height - BOYUT);   fill(90, 180, 255);  rect(oyuncuX, oyuncuY, BOYUT, BOYUT);   fill(220);  textSize(14);  textAlign(LEFT, TOP);  text("Ok / WASD: hareket  |  R: merkeze sifirla", 12, 12);  text("Fare: " + floor(mouseX) + ", " + floor(mouseY), 12, 32);} function keyPressed() {  if (key === "r" || key === "R") {    oyuncuX = width / 2 - BOYUT / 2;    oyuncuY = height / 2 - BOYUT / 2;  }}

Tanım: constrain(deger, min, max) — p5.js fonksiyonu; değeri verilen alt ve üst sınır arasında tutar. Kare tuval dışına taşmaz. Bu, tuval sınır çarpışmasının pratik kısayoludur; bir sonraki ana başlıkta sınır testinin if ile açık yazımı ve sekme tepkisi ayrıca ele alınır.

Tanım: color(r, g, b) — p5.js fonksiyonu; Önceki bölümlerdeki RGB modeliyle (0–255 bileşenler) renk değeri üretir ve değişkende saklanabilir. red(), green(), blue() bu değerden ilgili bileşeni okur. Doğrudan fill(r, g, b) ile aynı sayı aralığı kullanılır; fark, rengin bir kez üretilip yeniden kullanılabilmesidir.

Tanım: floor(n) — Ondalıklı sayıyı aşağı yuvarlayarak tam sayıya indirger; ekranda koordinat göstermek için kullanılmıştır (önceki bölümler, diziler ana başlığındaki floor(random(...)) örneğiyle aynı işlev).

Tuval odaklıyken tuşlar sketch'e gider; tarayıcı sekmesinin odak dışı kalması durumunda girdi alınmayabilir — önizleme paneline tıklamak gerekir.

Hata ayıklama ipuçları:

Tablo 9.

Sorun Olası neden Denenecek
Tuşlar hiç çalışmıyor Tuval odak dışı Önizlemeye tıkla
Hareket çok yavaş/hızlı HIZ veya deltaTime HIZ * dt formülünü kontrol et
R tuşu yanıt vermiyor keyPressed tanımsız Fonksiyon adının doğru yazıldığını doğrula
Kare ekrandan çıkıyor constrain eksik Sınır satırını ekle
Çapraz hareket beklenenden hızlı X ve Y aynı anda değişiyor Basit oyunlarda sorun oluşturmaz; hız normalize edilerek düzeltilebilir
Bir tuş bazen çalışıyor bazen çalışmıyor Klavye düzeni (harf/sembol) farkı keyCode veya büyük/küçük harf kontrolünü gözden geçir

Bu tablo, klavye kontrollü bir sketch'te karşılaşılan sorunların çoğunun ya odak (tuvalin girdi almaması) ya da hangi p5.js aracının (durum mu, olay mı) kullanıldığıyla ilgili olduğunu gösterir. Hata ayıklarken ilk soru her zaman "bu davranış sürekli mi yoksa tek seferlik mi olmalı?" olmalıdır; yanıt keyIsDown ile keyPressed arasındaki seçimi belirler.

Yapay Zekâ Etkileşimi: Kontrol Şeması Tasarlama Tahmini etkinliği tamamlama süresi: 25–30 dakika.

Amaç: Klavye girdisini oyun eylemleriyle eşleştirmek.

Adım 1: Basit bir oyun fikri seç (ör. uzay gemisi, top, kare). Adım 2: Hangi tuşların sürekli (keyIsDown), hangilerinin tek seferlik (keyPressed) olacağını tabloya yaz. Adım 3: Yapay zekâ sohbet robotuna şu istemi gir: "p5.js için [oyun] kontrol tablom: [tablo]. Her tuş için keyIsDown mu keyPressed mi kullanmalıyım? Kısa gerekçe ver." Adım 4: Öneriyi yukarıdaki kare örneğiyle karşılaştır.

Yapay Zekâ Etkileşimi: Klavye Girdisi Tahmini etkinliği tamamlama süresi: 20–25 dakika.

Adım 1: keyIsDown (sürekli) ile keyPressed (tek sefer) farkını tabloya yazın. Adım 2: Ok tuşları için LEFT_ARROW kullanımını not edin. Adım 3: Yapay zekâ sohbet robotuna sorun: «p5.js keyIsDown keyPressed keyCode ne zaman kullanılır?» Adım 4: Yanıtı bu ana başlıktaki kontrol tablosu ile karşılaştırın.

Sıra Sizde: Bir oyunda sürekli basılı tutulan hareket (WASD) ile tek seferlik eylem (SPACE ile ateş / zıplama) için hangi klavye API’sini seçerdiniz? İkisini tablo gibi iki satırda yazın.

Özet

Klavye girdisi, oyuncunun gerçek zamanlı kontrolünü sağlar. p5.js'te iki temel katman ayırt edilir: keyIsDown() tuş basılıyken her frame true döndüğü için draw() içinde sürekli hareket üretir; keyPressed() ise basış anında bir kez çalışır. Sürekli harekette hız deltaTime ile çarpılarak Bölüm 2 Ana Başlık 4'teki frame bağımsız tempo korunur; çapraz hareket için bağımsız if blokları birleşir. WASD ve ok tuşları birlikte desteklenebilir; böylece farklı alışkanlıklara sahip oyuncular aynı sketch'i kullanır. Ok tuşları için LEFT_ARROW, RIGHT_ARROW, UP_ARROW, DOWN_ARROW sabitleri; keyIsDown ile harf tuşları için 65 / 68 gibi keyCode sayıları kullanılır. keyPressed() zıplama, ateş, tur yenileme ve renk değiştirme gibi tek seferlik eylemler için uygundur. key harf ve sembol tuşlarını, keyCode ok tuşları gibi özel tuşları tanımlamada kullanılır; key === "r" veya keyCode === LEFT_ARROW gibi koşullar olay gövdesinde yazılır. Yazdırılabilir karakterler ASCII (ve onu kapsayan Unicode) numaralarıyla saklanır ('A' → 65); ok tuşları ise ASCII’de yoktur — keyCode 37/38/39/40 gibi özel sayılardır ve p5.js bunları LEFT_ARROW / UP_ARROW / RIGHT_ARROW / DOWN_ARROW sabitleriyle adlandırır. Ham sayı yerine sabiti kullanmak okunabilirliği artırır. Denetim karakterleri \n (satır sonu) ve \t (sekme) string içinde kaçış dizisi olarak yazılır; text() ile çok satırlı HUD üretilebilir. constrain() ile nesne tuval sınırları içinde tutulur — bu, konumu sınırda kilitleyen bir engellemedir; duvara çarpınca yön değiştiren sekme tepkisi sonraki ana başlıkta açık if ve hız tersine çevirme ile ele alınır. Fare ile karşılaştırıldığında sürekli basılı tutma mouseIsPressed / keyIsDown, tek seferlik olay ise mousePressed() / keyPressed() eşleşmesine karşılık gelir.

Neler Öğrendik?

Soru 1 Sürekli yürüme hareketi için en uygun yapı hangisidir?

A) Yalnızca keyPressed() içinde konum artırmak

B) draw() içinde keyIsDown() ile konum güncellemek

C) Yalnızca setup() içinde keyIsDown() kullanmak

D) background() ile tuş okumak

E) createCanvas() her frame çağırmak

Soru 2 key === "r" ifadesi ne zaman anlamlıdır?

A) Her frame otomatik true olur

B) keyPressed() veya keyReleased() çalıştığında basılan tuşu kontrol eder

C) Yalnızca fare tıklanınca

D) Tuval genişliğini verir

E) Dizi uzunluğunu döndürür

Soru 3 [Kod okuma] HIZ = 200, deltaTime ≈ 16.7 ms iken aşağıdaki blok bir frame'de kareX değerini yaklaşık ne kadar artırır? Kod 9.

javascript
if (keyIsDown(RIGHT_ARROW)) {  kareX = kareX + HIZ * deltaTime / 1000;}

A) 200 piksel

B) Yaklaşık 3.3 piksel

C) 16.7 piksel

D) 0 piksel

E) 1000 piksel

Soru 4 constrain(oyuncuX, 0, width - BOYUT) satırının amacı nedir?

A) FPS artırmak

B) Oyuncu konumunu tuval sınırları içinde tutmak

C) Klavye olayını silmek

D) Diziye eleman eklemek

E) R tuşunu devre dışı bırakmak

Neler Öğrendik Yanıt Anahtarı

Soru 1: Doğru Cevap: B

Soru 2: Doğru Cevap: B

Soru 3: Doğru Cevap: B

Soru 4: Doğru Cevap: B

Yararlanılan Kaynaklar

Bu içerik aşağıdaki kaynaklardan derlenerek hazırlanmıştır:


Bölüm 3 — Ek Sorular

Her ana başlık için 10 çoktan seçmeli değerlendirme sorusu. Bölüm sonu sınav veya pekiştirme amaçlıdır.


Ana Başlık 1 için 10 Soru

SORU 1: Aşağıdaki yaklaşımlardan hangisi oyun sketch’inde daha sağlam bir geliştirmedir?

A) Konu dışı teknolojiye (biçim/dil dışı) sapıp temel kuralı atlamak

B) Öğrenilen p5.js API’si ile ölçülebilir bir oyun kuralı eklemek

C) draw içinde createCanvas tekrarlamak

D) Skoru her frame koşulsuz artırmak

E) Hata ayıklamadan uzun kodu olduğu gibi bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme, öğrenilen araçlarla kural eklemeyi hedefler; alandan kopuk şıklar elenir. İlgili Konu: Pekiştirme


SORU 2: Aşağıdaki yaklaşımlardan hangisi oyun sketch’inde daha sağlam bir geliştirmedir?

A) Konu dışı teknolojiye (biçim/dil dışı) sapıp temel kuralı atlamak

B) Öğrenilen p5.js API’si ile ölçülebilir bir oyun kuralı eklemek

C) draw içinde createCanvas tekrarlamak

D) Skoru her frame koşulsuz artırmak

E) Hata ayıklamadan uzun kodu olduğu gibi bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme, öğrenilen araçlarla kural eklemeyi hedefler; alandan kopuk şıklar elenir. İlgili Konu: Pekiştirme


SORU 3: Aşağıdaki yaklaşımlardan hangisi oyun sketch’inde daha sağlam bir geliştirmedir?

A) Konu dışı teknolojiye (biçim/dil dışı) sapıp temel kuralı atlamak

B) Öğrenilen p5.js API’si ile ölçülebilir bir oyun kuralı eklemek

C) draw içinde createCanvas tekrarlamak

D) Skoru her frame koşulsuz artırmak

E) Hata ayıklamadan uzun kodu olduğu gibi bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme, öğrenilen araçlarla kural eklemeyi hedefler; alandan kopuk şıklar elenir. İlgili Konu: Pekiştirme


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

Doğru cevap: A

Genel açıklama: Bu soru ana başlık kazanımını ölçer. İlgili Konu: 1.4


SORU 5: «deltaTime ile Zaman Tabanlı Hareket» bağlamında hangisi daha iyi bir sonraki adım geliştirmedir?

A) Konu dışı bir CSS animasyonu eklemek

B) Mevcut sketch’e ölçülebilir bir kural (skor, sınır, durum) eklemek

C) Tuvali silip boş bırakmak

D) setup’ı tamamen kaldırmak

E) Rastgele sözdizimi hatası bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme mevcut öğrenilen API ile kural ekler. İlgili Konu: 1.uygulama


SORU 6: Aşağıdaki hangi seçenek tipik bir çeldirici bug senaryosudur?

A) dist ile isabet, ardından skoru bir kez artırmak

B) draw içinde koşulsuz skor artışı

C) createCanvas’ı setup içinde bir kez çağırmak

D) background ile frame temizlemek

E) keyIsDown ile sürekli hareket

Doğru cevap: B

Genel açıklama: Koşulsuz artış her frame şişer — görünür bug. İlgili Konu: 1.uygulama


SORU 7: Kod okuma: if (x > width) { x = 0; } ne yapar?

A) Y’yi sıfırlar

B) X tuval sağını aşınca sola sarar

C) FPS’i sıfırlar

D) Fareyi kilitler

E) Diziyi temizler

Doğru cevap: B

Genel açıklama: Yatay sarma (wrap) kalıbı. İlgili Konu: 1.uygulama


SORU 8: Bu ana başlıkta (deltaTime ile Zaman Tabanlı Hareket) hangi uygulama en uygundur?

A) Öğrenilen API’yi bilinçli yok sayıp rastgele hazır kütüphane çağırmak

B) Anlatılan kavramı küçük bir sketch’te görünür çıktıyla denemek

C) Konuyu yalnızca okuyup hiç kod yazmamak

D) Tuval boyutunu her frame rastgele değiştirmek

E) Hata ayıklamadan uzun kod kopyalamak

Doğru cevap: B

Genel açıklama: Seçenek konu başlığıyla örtüşür; diğerleri alandan kopuk. İlgili Konu: 1.uygulama


SORU 9: console.log ayıklamada asıl faydası nedir?

A) Tuval çözünürlüğünü artırır

B) Ara değerleri görüp yanlış varsayımı yakalamayı sağlar

C) Otomatik çarpışma ekler

D) draw’ı durdurur

E) Kaynakça üretir

Doğru cevap: B

Genel açıklama: Gözlemlenebilir ara durum. İlgili Konu: 1.uygulama


SORU 10: Bir fonksiyonu parametreli yazmanın faydası?

A) FPS’i kilitlemek

B) Aynı mantığı farklı argümanlarla yeniden kullanmak

C) setup’ı kaldırmak

D) HTML’i silmek

E) Rengi yasaklamak

Doğru cevap: B

Genel açıklama: Modülerlik ve yeniden kullanım. İlgili Konu: 1.uygulama


Ana Başlık 2 için 10 Soru

SORU 1: JavaScript dizilerinde ilk elemanın indeksi nedir?

A) 1

B) 0

C) -1

D) length

E) undefined

Doğru cevap: B

Genel açıklama: Bu soru ana başlık kazanımını ölçer. İlgili Konu: 2.1


SORU 2: dizi.push(5) ne yapar?

A) İlk elemanı siler

B) 5’i dizinin sonuna ekler

C) Tuvali temizler

D) FPS’i 5 yapar

E) setup’ı yeniden çalıştırır

Doğru cevap: B

Genel açıklama: Bu soru ana başlık kazanımını ölçer. İlgili Konu: 2.2


SORU 3: Aşağıdaki yaklaşımlardan hangisi oyun sketch’inde daha sağlam bir geliştirmedir?

A) Konu dışı teknolojiye (biçim/dil dışı) sapıp temel kuralı atlamak

B) Öğrenilen p5.js API’si ile ölçülebilir bir oyun kuralı eklemek

C) draw içinde createCanvas tekrarlamak

D) Skoru her frame koşulsuz artırmak

E) Hata ayıklamadan uzun kodu olduğu gibi bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme, öğrenilen araçlarla kural eklemeyi hedefler; alandan kopuk şıklar elenir. İlgili Konu: Pekiştirme


SORU 4: Paralel diziler ne anlama gelir?

A) İki dizinin aynı indekste ilişkili özellik tutması

B) İki tarayıcının zorunlu açılması

C) Yalnızca string birleştirme

D) CSS grid

E) Git branch

Doğru cevap: A

Genel açıklama: Bu soru ana başlık kazanımını ölçer. İlgili Konu: 2.4


SORU 5: «Dizi Temelleri: Tanım, Erişim ve push/pop» bağlamında hangisi daha iyi bir sonraki adım geliştirmedir?

A) Konu dışı bir CSS animasyonu eklemek

B) Mevcut sketch’e ölçülebilir bir kural (skor, sınır, durum) eklemek

C) Tuvali silip boş bırakmak

D) setup’ı tamamen kaldırmak

E) Rastgele sözdizimi hatası bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme mevcut öğrenilen API ile kural ekler. İlgili Konu: 2.uygulama


SORU 6: Aşağıdaki hangi seçenek tipik bir çeldirici bug senaryosudur?

A) dist ile isabet, ardından skoru bir kez artırmak

B) draw içinde koşulsuz skor artışı

C) createCanvas’ı setup içinde bir kez çağırmak

D) background ile frame temizlemek

E) keyIsDown ile sürekli hareket

Doğru cevap: B

Genel açıklama: Koşulsuz artış her frame şişer — görünür bug. İlgili Konu: 2.uygulama


SORU 7: Kod okuma: if (x > width) { x = 0; } ne yapar?

A) Y’yi sıfırlar

B) X tuval sağını aşınca sola sarar

C) FPS’i sıfırlar

D) Fareyi kilitler

E) Diziyi temizler

Doğru cevap: B

Genel açıklama: Yatay sarma (wrap) kalıbı. İlgili Konu: 2.uygulama


SORU 8: Bu ana başlıkta (Dizi Temelleri: Tanım, Erişim ve push/pop) hangi uygulama en uygundur?

A) Öğrenilen API’yi bilinçli yok sayıp rastgele hazır kütüphane çağırmak

B) Anlatılan kavramı küçük bir sketch’te görünür çıktıyla denemek

C) Konuyu yalnızca okuyup hiç kod yazmamak

D) Tuval boyutunu her frame rastgele değiştirmek

E) Hata ayıklamadan uzun kod kopyalamak

Doğru cevap: B

Genel açıklama: Seçenek konu başlığıyla örtüşür; diğerleri alandan kopuk. İlgili Konu: 2.uygulama


SORU 9: console.log ayıklamada asıl faydası nedir?

A) Tuval çözünürlüğünü artırır

B) Ara değerleri görüp yanlış varsayımı yakalamayı sağlar

C) Otomatik çarpışma ekler

D) draw’ı durdurur

E) Kaynakça üretir

Doğru cevap: B

Genel açıklama: Gözlemlenebilir ara durum. İlgili Konu: 2.uygulama


SORU 10: Bir fonksiyonu parametreli yazmanın faydası?

A) FPS’i kilitlemek

B) Aynı mantığı farklı argümanlarla yeniden kullanmak

C) setup’ı kaldırmak

D) HTML’i silmek

E) Rengi yasaklamak

Doğru cevap: B

Genel açıklama: Modülerlik ve yeniden kullanım. İlgili Konu: 2.uygulama


Ana Başlık 3 için 10 Soru

SORU 1: Aşağıdaki yaklaşımlardan hangisi oyun sketch’inde daha sağlam bir geliştirmedir?

A) Konu dışı teknolojiye (biçim/dil dışı) sapıp temel kuralı atlamak

B) Öğrenilen p5.js API’si ile ölçülebilir bir oyun kuralı eklemek

C) draw içinde createCanvas tekrarlamak

D) Skoru her frame koşulsuz artırmak

E) Hata ayıklamadan uzun kodu olduğu gibi bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme, öğrenilen araçlarla kural eklemeyi hedefler; alandan kopuk şıklar elenir. İlgili Konu: Pekiştirme


SORU 2: Paralel x ve y dizilerinde aynı indeks ne anlama gelir?

A) İki farklı oyunun skoru

B) Aynı varlığın ilişkili özellikleri

C) Rastgele iki tarayıcı

D) Zorunlu ses kanalı

E) Git commit

Doğru cevap: B

Genel açıklama: Bu soru ana başlık kazanımını ölçer. İlgili Konu: 3.2


SORU 3: Aşağıdaki yaklaşımlardan hangisi oyun sketch’inde daha sağlam bir geliştirmedir?

A) Konu dışı teknolojiye (biçim/dil dışı) sapıp temel kuralı atlamak

B) Öğrenilen p5.js API’si ile ölçülebilir bir oyun kuralı eklemek

C) draw içinde createCanvas tekrarlamak

D) Skoru her frame koşulsuz artırmak

E) Hata ayıklamadan uzun kodu olduğu gibi bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme, öğrenilen araçlarla kural eklemeyi hedefler; alandan kopuk şıklar elenir. İlgili Konu: Pekiştirme


SORU 4: push/pop yerine sabit kapasite seçmek ne sağlar?

A) Üst sınırın ve döngünün öngörülebilir kalması

B) Matematiğin kalkması

C) Farein kapanması

D) Zorunlu 3B

E) Sunucu kurulumu

Doğru cevap: A

Genel açıklama: Bu soru ana başlık kazanımını ölçer. İlgili Konu: 3.4


SORU 5: «Sabit Kapasite ve Paralel Dizilerle Mini Sahne» bağlamında hangisi daha iyi bir sonraki adım geliştirmedir?

A) Konu dışı bir CSS animasyonu eklemek

B) Mevcut sketch’e ölçülebilir bir kural (skor, sınır, durum) eklemek

C) Tuvali silip boş bırakmak

D) setup’ı tamamen kaldırmak

E) Rastgele sözdizimi hatası bırakmak

Doğru cevap: B

Genel açıklama: Geliştirme mevcut öğrenilen API ile kural ekler. İlgili Konu: 3.uygulama


SORU 6: Aşağıdaki hangi seçenek tipik bir çeldirici bug senaryosudur?

A) dist ile isabet, ardından skoru bir kez artırmak

B) draw içinde koşulsuz skor artışı

C) createCanvas’ı setup içinde bir kez çağırmak

D) background ile frame temizlemek

E) keyIsDown ile sürekli hareket

Doğru cevap: B

Genel açıklama: Koşulsuz artış her frame şişer — görünür bug. İlgili Konu: 3.uygulama


SORU 7: Kod okuma: if (x > width) { x = 0; } ne yapar?

A) Y’yi sıfırlar

B) X tuval sağını aşınca sola sarar

C) FPS’i sıfırlar

D) Fareyi kilitler

E) Diziyi temizler

Doğru cevap: B

Genel açıklama: Yatay sarma (wrap) kalıbı. İlgili Konu: 3.uygulama


SORU 8: Bu ana başlıkta (Sabit Kapasite ve Paralel Dizilerle Mini Sahne) hangi uygulama en uygundur?

A) Öğrenilen API’yi bilinçli yok sayıp rastgele hazır kütüphane çağırmak

B) Anlatılan kavramı küçük bir sketch’te görünür çıktıyla denemek

C) Konuyu yalnızca okuyup hiç kod yazmamak

D) Tuval boyutunu her frame rastgele değiştirmek

E) Hata ayıklamadan uzun kod kopyalamak

Doğru cevap: B

Genel açıklama: Seçenek konu başlığıyla örtüşür; diğerleri alandan kopuk. İlgili Konu: 3.uygulama


SORU 9: console.log ayıklamada asıl faydası nedir?

A) Tuval çözünürlüğünü artırır

B) Ara değerleri görüp yanlış varsayımı yakalamayı sağlar

C) Otomatik çarpışma ekler

D) draw’ı durdurur

E) Kaynakça üretir

Doğru cevap: B

Genel açıklama: Gözlemlenebilir ara durum. İlgili Konu: 3.uygulama


SORU 10: Bir fonksiyonu parametreli yazmanın faydası?

A) FPS’i kilitlemek

B) Aynı mantığı farklı argümanlarla yeniden kullanmak

C) setup’ı kaldırmak

D) HTML’i silmek

E) Rengi yasaklamak

Doğru cevap: B

Genel açıklama: Modülerlik ve yeniden kullanım. İlgili Konu: 3.uygulama


Ana Başlık 4 için 10 Soru

SORU 1: Sürekli yürüme hareketi için en uygun yapı hangisidir?

A) Yalnızca keyPressed() içinde konum artırmak

B) draw() içinde keyIsDown() ile konum güncellemek

C) Yalnızca setup() içinde keyIsDown() kullanmak

D) background() ile tuş okumak

E) createCanvas() her frame çağırmak

Doğru cevap: B

Genel açıklama: Basılı tutma draw() döngüsünde keyIsDown ile okunur. İlgili Konu: 2.2. keyIsDown ile Sürekli Hareket


SORU 2: Zıplama veya tek atışlı ateş gibi eylem için hangi olay fonksiyonu daha uygundur?

A) draw() içinde sürekli keyIsDown

B) keyPressed()

C) setup()

D) background()

E) createCanvas()

Doğru cevap: B

Genel açıklama: keyPressed() bir basışta bir kez tetiklenir; tekrarlayan hareket için uygun değildir. İlgili Konu: 2.3. keyPressed ve Tek Seferlik Eylemler


SORU 3: Ok tuşları için genelde hangi değişken kullanılır?

A) mouseX

B) keyCode

C) frameCount

D) deltaTime

E) push()

Doğru cevap: B

Genel açıklama: Ok tuşları gibi özel tuşlar keyCode ile (LEFT_ARROW, RIGHT_ARROW vb.) okunur. İlgili Konu: 2.4. key ve keyCode


SORU 4: [Kod okuma] HIZ = 200, deltaTime ≈ 16.7 ms iken aşağıdaki blok bir frame'de kareX değerini yaklaşık ne kadar artırır? Kod 1.

javascript
if (keyIsDown(RIGHT_ARROW)) {  kareX = kareX + HIZ * deltaTime / 1000;}

A) 200 piksel

B) Yaklaşık 3.3 piksel

C) 16.7 piksel

D) 0 piksel

E) 1000 piksel

Doğru cevap: B

Genel açıklama: 200 × 0.0167 ≈ 3.3 piksel; hız saniye başına tanımlıdır. İlgili Konu: 2.2 (deltaTime ile birleşim)


SORU 5: constrain(oyuncuX, 0, width - BOYUT) satırının amacı nedir?

A) FPS artırmak

B) Oyuncu konumunu tuval sınırları içinde tutmak

C) Klavye olayını silmek

D) Diziye eleman eklemek

E) R tuşunu devre dışı bırakmak

Doğru cevap: B

Genel açıklama: constrain değeri min–max aralığına sıkıştırır; kare ekran dışına çıkmaz. İlgili Konu: 2.5. Klavye ile Kontrol Edilen Kare


SORU 6: key === "a" ifadesi ne zaman anlamlıdır?

A) Her frame otomatik true olur

B) keyPressed() veya keyReleased() çalıştığında basılan tuşu kontrol eder

C) Yalnızca fare tıklanınca

D) Tuval genişliğini verir

E) Dizi uzunluğunu döndürür

Doğru cevap: B

Genel açıklama: key olay anındaki karakter tuşunu verir; sürekli okuma için keyIsDown kullanılır. İlgili Konu: 2.3 ve 2.4


SORU 7: WASD ve ok tuşlarını birlikte desteklemek neden tercih edilir?

A) FPS düşürmek için

B) Farklı klavye alışkanlıklarına erişilebilir kontrol sunmak için

C) Diziyi silmek için

D) Çarpışma testini kapatmak için

E) Tuvali küçültmek için

Doğru cevap: B

Genel açıklama: İki kontrol şeması aynı hareketi farklı tuşlarla sağlar. İlgili Konu: 2.5. Klavye ile Kontrol Edilen Kare


SORU 8: [Kod okuma] Aşağıdaki kodda keyIsDown(LEFT_ARROW) || keyIsDown(65) ifadesi ne zaman true olur?

A) Yalnızca SPACE basılıyken

B) Sol ok veya A tuşundan en az biri basılıyken

C) Yalnızca fare tuval üzerindeyken

D) draw() hiç çalışmıyorken

E) setup() tamamlandıktan sonra bir kez

Doğru cevap: B

Genel açıklama: || en az bir koşul true ise true döner. İlgili Konu: 2.5


SORU 9: I. keyIsDown() her frame kontrol edilebilir.
II. keyPressed() tek basışta bir kez çalışır.
III. Klavye girdisi tuval odak dışındayken her zaman alınır.

Hangileri doğrudur?

A) Yalnız I

B) I ve II

C) Yalnız III

D) II ve III

E) I, II ve III

Doğru cevap: B

Genel açıklama: I ve II doğru. III yanlış; önizleme panelinin odakta olması gerekir. İlgili Konu: 2.1–2.3


SORU 10: Klavye ile hareket eden kare örneğinde hız neden deltaTime ile çarpılır?

A) Dizi indeksini hesaplamak için

B) Frame hızından bağımsız tutarlı hareket için (Ana Başlık 1)

C) Tuval rengini değiştirmek için

D) mousePressed() tetiklemek için

E) Kazanan kontrolü yapmak için

Doğru cevap: B

Genel açıklama: Ana Başlık 1'deki zaman tabanlı hareket klavye girdisiyle birleştirilir. İlgili Konu: 2.2 ve 2.5



Ana Başlık 1 — Açık Uçlu

A1. «deltaTime ile Zaman Tabanlı Hareket» konusundaki merkezi kavramı kendi cümlelerinizle açıklayın ve bunu somut bir mini oyun / sketch örneğine bağlayın.

A2. «deltaTime ile Zaman Tabanlı Hareket» için küçük bir varyasyon tasarlayın (yeni kural, sınır durumu veya görsel geri bildirim). Hangi fonksiyonlar değişir? Madde madde yazın.

A3. Bu ana başlıkta sık yapılan bir yanlış varsayımı (yanlış indeks, sıra, durum veya veri modeli) seçin; neden hatalı olduğunu ve doğru yaklaşımı iki–üç cümleyle yazın.


Ana Başlık 2 — Açık Uçlu

A1. «Dizi Temelleri: Tanım, Erişim ve push/pop» konusundaki merkezi kavramı kendi cümlelerinizle açıklayın ve bunu somut bir mini oyun / sketch örneğine bağlayın.

A2. «Dizi Temelleri: Tanım, Erişim ve push/pop» için küçük bir varyasyon tasarlayın (yeni kural, sınır durumu veya görsel geri bildirim). Hangi fonksiyonlar değişir? Madde madde yazın.

A3. Bu ana başlıkta sık yapılan bir yanlış varsayımı (yanlış indeks, sıra, durum veya veri modeli) seçin; neden hatalı olduğunu ve doğru yaklaşımı iki–üç cümleyle yazın.


Ana Başlık 3 — Açık Uçlu

A1. «Sabit Kapasite ve Paralel Dizilerle Mini Sahne» konusundaki merkezi kavramı kendi cümlelerinizle açıklayın ve bunu somut bir mini oyun / sketch örneğine bağlayın.

A2. «Sabit Kapasite ve Paralel Dizilerle Mini Sahne» için küçük bir varyasyon tasarlayın (yeni kural, sınır durumu veya görsel geri bildirim). Hangi fonksiyonlar değişir? Madde madde yazın.

A3. Bu ana başlıkta sık yapılan bir yanlış varsayımı (yanlış indeks, sıra, durum veya veri modeli) seçin; neden hatalı olduğunu ve doğru yaklaşımı iki–üç cümleyle yazın.


Ana Başlık 4 — Açık Uçlu

A1. Bir oyun için kontrol tablosu oluşturun: hangi tuşlar keyIsDown, hangileri keyPressed ile okunmalı? Gerekçe yazın.

Örnek yanıt unsurları: WASD sürekli; SPACE/R tek seferlik.
Değerlendirme: Tuş–olay eşlemesi tutarlı mı?

A2. constrain() ile manuel sınır if testi arasında ne zaman hangisini tercih edersiniz?

Örnek yanıt unsurları: constrain engelleme; sekme için açık if + hız tersi.
Değerlendirme: Ana Başlık 2–3 köprüsü kurulmuş mu?

A3. Tuval odak dışıyken klavye çalışmıyorsa kullanıcıya ne önerirsiniz?

Örnek yanıt unsurları: Önizleme paneline tıklama.
Değerlendirme: Pratik çözüm var mı?