Bölüm 3 · Sunum 4

Klavye: kontrol oyuncuya geçiyor

Basılı tutunca yürümek, bir kez basınca zıplamak. İkisi aynı şey değil.

keyIsDownkeyPressedkey ve keyCodeASCIIKontrol edilen kare

Bir oyunda yürümek ile zıplamak arasında klavye açısından ne fark var?

Sağ oka basılı tutuyorsunuz: karakter yürümeye devam ediyor. Boşluğa basılı tutuyorsunuz: karakter durmadan zıplıyor mu?

İki katman: durum ve olay

Klavye girdisiOyuncunun tuşa basarak programa ilettiği kontrol bilgisidir.
GirdiSürekli (basılı tutma)Tek seferlik (basma anı)
FaremouseIsPressed, mouseX / mouseYmousePressed()
KlavyekeyIsDown(…)keyPressed()

Tanıdık bir ayrım: Daire Tıklama’da skoru mouseIsPressed ile değil mousePressed() ile saymıştık. Klavyede de aynı iki katman var.

Üç araç, üç farklı an

AraçNe zaman çalışır?Tipik kullanım
draw() + keyIsDown()Tuş basılı olduğu sürece, her frameSürekli yürüme, hızlanma
keyPressed()Tuşa basıldığı an, bir kezZıplama, ateş, menü seçimi, turu yenileme
keyReleased()Tuş bırakıldığı an, bir kezŞarj biriktirip bırakınca ateş etme
Adlar sabitkeyPressed ve keyReleased, p5.js’in kendisinin çağırdığı olay fonksiyonlarıdır. setup ve draw gibi tam olarak böyle yazılmalıdır.

Önce tuvale tıklayın, sonra bir tuşa basın

Tuşlar çalışmıyorsaTuval “odakta” değildir. Önizlemeye bir kez tıklayın; yoksa tuşlar tarayıcıya ya da editöre gider.

keyIsDown(): şu an basılı mı?

keyIsDown(tuş)Verilen tuş o frame’de basılıysa true, değilse false döndürür. draw() içinde çağrılır.
TuşYazımı
Sol okkeyIsDown(LEFT_ARROW)
Sağ okkeyIsDown(RIGHT_ARROW)
Yukarı okkeyIsDown(UP_ARROW)
Aşağı okkeyIsDown(DOWN_ARROW)
Harf (A, D)keyIsDown(65), keyIsDown(68)

Ok tuşları için hazır sabitler var. Harf tuşlarında keyIsDown bir sayı ister; nedenini birazdan göreceğiz.

Ok tuşlarıyla yatay hareket

Tuvale tıklayıp sağ ve sol oka basılı tutun. Hız yine deltaTime ile: saniyede 180 piksel.

Aynı satırı keyPressed() içine yazarsak kare nasıl hareket eder?

Sağ oka basılı tutuyorsunuz…

Akıcı yürümez; her basışta bir adım sıçrar

Tuşa basılı tutuyorum, neden yürümüyor?
😤
oyuncu
Bana bir kez haber verildi. Bir adım attım.
🧍
keyPressed()
Sık yapılan hatakeyPressed() “tuşla ilgili her şeyin yazıldığı yer” gibi görünür. Ama yalnızca basma anında bir kez tetiklenir.
KuralSürekli hareket her zaman draw() içinde, keyIsDown() ile.

Dikey hareket ve çapraz gitmek

Dört ayrı if birbirinden bağımsızdır. Sağ ve yukarı aynı anda basılıysa ikisi de çalışır: kare çapraz gider. else if yalnızca tek yön seçilecekse uygundur.

Basılı tuşlarxyEtki
Yalnızca →+0Yatay
Yalnızca ↑0−Dikey
→ ve ↑+−Çapraz, sağ üst

Çapraz koşmak neden daha hızlı?

HIZHIZ ≈ 1.41 × HIZ

İki eksende de HIZ kadar ilerleyince köşegen, Pisagor’a göre √2 ≈ 1.41 kat daha uzun olur.

Doom 1993Hem ileri hem yana basarak koşmak (strafe-running) düz koşmaktan belirgin biçimde hızlıydı. Hız rekortmenleri hâlâ bu yöntemi kullanır.

Rekabetçi oyunlarda hız normalize edilir: iki bileşen birim vektöre göre ölçeklenir, sonra HIZ ile çarpılır. Basit örneklerimizde buna gerek yok.

keyPressed() ve key

keyBasılan tuşun karakter değerini tutan değişken: 'a', 'R', ' ' (boşluk). Yalnızca olay fonksiyonu çalıştığı anda anlamlıdır.

"r" ile "R" farklı karakterlerdir. Caps Lock açık olabilir; ikisini de kontrol edin.

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

Boşluk tuşu: rengi değiştir

Tuvale tıklayıp boşluğa basın. Basılı tutsanız da renk bir kez değişir. red() bir rengin kırmızı bileşenini okur.

keyReleased(): basılı tut, şarj et, bırak, ateşle

Mega Man’in şarjlı atışı gibi: basılı tutma keyIsDown, bırakma anı keyReleased. Mermiler de bir dizide duruyor.

Kontrol şeması: bir uzay gemisi

TuşYöntemEylem
Ok / WASDkeyIsDown + draw()Sürekli hareket
SPACEkeyPressed()Tek mermi
RkeyPressed()Turu sıfırla
ESCkeyPressed()Menüye dön
WASD nereden geldi?1990’ların sonunda Quake oyuncuları sol eli WASD’ye, sağ eli fareye koymaya başladı. Düzeni yaygınlaştıran isim, turnuva şampiyonu Dennis “Thresh” Fong’du. Bugün neredeyse her PC oyununun varsayılanı.

Ok tuşlarını da WASD’yi de birlikte desteklerseniz farklı alışkanlıklara sahip oyuncular aynı oyunu oynayabilir.

Tek seferlik eylem için neden keyPressed()?

Doğrudan keyPressed()Niyet açıkça görünür: “bu tuşa basılınca şu olsun.” p5.js, “önceki frame’de basılı değildi, şimdi basılı” karşılaştırmasını sizin yerinize yapar.
Alternatif: keyIsDown + bayrakdraw() içinde bir “önceki durum” değişkeni tutarak aynı şey elle yapılabilir. Bazı ileri senaryolarda gerekir; ama fazladan değişken ve karşılaştırma ister.

Basit ve orta düzey oyunlarda doğrudan keyPressed() tercih edilir.

keyIsDown(65) yazınca A tuşu algılanıyor. 65 nereden geliyor?

Bilgisayar “A” harfini aslında nasıl saklıyor olabilir?

Her karakterin bir numarası var: ASCII

ASCII tablosu: yazdırılabilir karakterler 32–126
ASCII: American Standard Code for Information Interchange. 0–31 görünmeyen denetim kodları, 32–126 yazdırılabilir karakterler.

Tabloyu okumak

AralıkKarakterlerAnlamı
48 … 57'0' … '9'Rakamlar
65 … 90'A' … 'Z'Büyük harfler
97 … 122'a' … 'z'Küçük harfler
32boşlukSpace

Harf ve rakam tuşlarında key doğrudan karakteri verir: 'A', 'w'. Numarasını görmek için charCodeAt.

Küçük bir ayrıntıRakam '5' ile sayı 5 aynı şey değil: karakterin numarası 53.

key mi, keyCode mu?

keyHangi karakter?Harf, rakam ve sembol tuşlarında okunabilir bir karakter verir: 'a', '5', ' '.
keyCodeHangi fiziksel tuş?Basılan tuşun sayısal kodu. Ok tuşları, SHIFT, CTRL gibi karakteri olmayan tuşlar bununla tanınır.

Harf için key === "w"; ok tuşu için keyCode === LEFT_ARROW. p5.js ok tuşlarının sayılarını ezberlemeyin diye sabitleri hazır verir.

Sol okun keyCode’u 37. ASCII tablosunda 37 ise % işareti.

Sol oka basınca ekrana % mi yazılıyor? Bu bir çelişki mi?

Aynı numara, farklı binalar

TuşkeyCodep5.js sabitiASCII’de?
Sol ok37LEFT_ARROWYok
Yukarı ok38UP_ARROWYok
Sağ ok39RIGHT_ARROWYok
Aşağı ok40DOWN_ARROWYok

Ok tuşları birer karakter değil, özel tuştur; ASCII’de karşılıkları yoktur. 37, tarayıcıların ayrı bir tuş-numara listesinden gelir.

Benzetmeİki farklı apartmanda “daire 37” olabilir. Aynı numara, farklı binalar. Sol ok ≠ %.
EzberlemeyinKodda her zaman LEFT_ARROW yazın. console.log(keyCode) yalnızca merak ve hata ayıklama içindir.

LEFT ile LEFT_ARROW aynı şey değil

keyIsDown(LEFT) çalışmazLEFT, RIGHT, UP, DOWN hizalama sabitleridir: textAlign(LEFT). Değerleri metindir ('left'). keyIsDown ise sayı bekler.

Harfler için de sayı gerekir: A 65, D 68, W 87, S 83.

TuşTipik kullanım
OklarkeyIsDown(LEFT_ARROW) ya da keyCode === LEFT_ARROW
Harf, süreklikeyIsDown(65)
Harf, olaydakey === "w" || key === "W"

Olayda ok ve harf: konsola bakın

Gri tuvale tıklayın, sonra ↑ ve W’ye basın. Mesajlar tuvalde değil, altındaki konsolda görünür.

WASD ve okları birleştirmek

|| ile “sol ok ya da A basılıysa” deriz. İki alışkanlık, tek hareket.

Görünmeyen karakterler: \n ve \t

YazımıASCIIAdıNe yapar?
\n10LF (line feed)Yeni satıra geçer
\t9TAB (sekme)Yatayda birkaç boşluk kadar ilerler
boşluk32SpaceGörünür boşluk
Kaçış dizisi (escape sequence)Ters eğik çizgi \ “sonraki karakter özel anlam taşıyor” demektir. \n iki karakterle yazılır ama bellekte tek bir satır sonu karakteridir.

0–31 arasındaki denetim kodları ekrana harf gibi basılmaz; programda böyle yazılır.

Çok satırlı HUD yazısı

Ters eğik çizgi n ve t: text kaynak kodu ve tuval çıktısı
Solda kaynak kod, sağda tuvaldeki sonuç. Skor ve can gibi alt alta yazılar için \n pratiktir.

İki küçük uyarı

Sütunlar önemliyse\t’nin genişliği yazı tipine göre değişir. Tuvalde düzgün sütun için ayrı text(…, x, y) çağrıları daha öngörülebilirdir. Konsolda console.log("skor\t" + skor) iş görür.
Girinti ile karıştırmayınKodda satırı içeri almak için bastığınız boşluk ve Tab da aynı karakterlerdir (32 ve 9). Ama onlar editördeki düzen içindir; metnin içindeki \n ve \t ise ekrana yazılan içeriktir.

Unicode: ASCII’nin ötesi

  • ASCII yalnızca Latin alfabesinin dar bir dilimini kapsar.
  • Unicode, dünyadaki bütün yazı sistemlerini (ğ, ş, emoji…) tek bir numara uzayında toplar.
  • İlk 128 kodu ASCII ile aynıdır: 'A' ikisinde de 65.
Türkçe karakterli değişken adılet skorŞuAn = 0; çoğu tarayıcıda çalışır. Yine de adlarda ASCII harfleri tercih ediyoruz (skorSuAn): karakter bozulması riski azalır, İngilizce kaynaklarla eşleşmek kolaylaşır, klavye düzeni farkı sorun çıkarmaz.
Oyuncuya gösterilen yazılardaTürkçe karakter doğaldır: text("Kazandınız!"). Kısıt ekran yazılarında değil, adlardadır.

Klavye ile kontrol edilen kare (1/2)

Klavye ile kontrol edilen kare (2/2)

Hareket draw içinde ve sürekli; R ile sıfırlama keyPressed içinde ve tek seferlik. İki katman aynı sketch’te.

Bu örnekteki yardımcılar

constrain(deger, min, max)Değeri alt ve üst sınır arasında tutar. Kare tuvalin dışına taşmaz.
color(r, g, b)Bir renk değeri üretir; değişkende saklanır. red(), green(), blue() bileşenlerini okur.
floor(n)Aşağı yuvarlar. Burada fare koordinatını tam sayı göstermek için.

constrain, konumu sınırda kilitleyen bir engeldir. Duvara çarpınca yön değiştiren sekme tepkisini bir sonraki bölümde açık if ile yazacağız.

Bir şey çalışmıyorsa

SorunOlası nedenDenenecek
Tuşlar hiç çalışmıyorTuval odakta değilÖnizlemeye tıkla
Hareket çok yavaş ya da hızlıHIZ ya da deltaTimeHIZ * dt formülünü kontrol et
R tuşu yanıt vermiyorkeyPressed tanımsızFonksiyon adının yazımına bak
Kare ekrandan çıkıyorconstrain eksikSınır satırını ekle
Çapraz hareket fazla hızlıx ve y birlikte değişiyorBasit oyunda sorun değil; istenirse normalize et
Bir tuş bazen çalışıyorKlavye düzeni, büyük/küçük harfkeyCode ya da iki harfi birden kontrol et

İlk soru hep aynı: bu davranış sürekli mi olmalı, tek seferlik mi?

Tarihin en ünlü tuş dizisi: Konami Kodu

1986’da Gradius’un NES sürümünde ortaya çıktı; Contra’da 30 can verdiği için efsaneleşti. Kodu bir dizide, keyPressed içinde tek tek kontrol ediliyor.

Yapay zekâyla: kontrol şeması tasarlayın

  1. Basit bir oyun fikri seçin: uzay gemisi, top, kare.
  2. Hangi tuşlar sürekli (keyIsDown), hangileri tek seferlik (keyPressed) olacak? Tabloya yazın.
  3. Tablonuzu yapay zekâya verin: “Her tuş için keyIsDown mu keyPressed mi kullanmalıyım? Kısa gerekçe ver.”
  4. Öneriyi az önceki kare örneğiyle karşılaştırın.

İki satırlık karar

  1. Sürekli basılı tutulan hareket (WASD) ile tek seferlik eylem (SPACE ile ateş ya da zıplama) için hangi aracı seçerdiniz? Tablo gibi iki satırda yazın.
  2. Ok tuşları için LEFT_ARROW kullanımını not edin.
  3. Yapay zekâya sorun: “p5.js’te keyIsDown, keyPressed ve keyCode ne zaman kullanılır?” Yanıtı bugünkü kontrol tablosuyla karşılaştırın.

Kod zamanı

  1. Kare örneğinde Shift basılıyken hız iki katına çıksın. İpucu: keyIsDown(SHIFT).
  2. Sayılara basınca karenin rengi değişsin: 1 kırmızı, 2 yeşil, 3 mavi.
  3. Ateş: boşluğa her basışta karenin üstünden bir mermi çıksın ve yukarı gitsin. Mermileri bir dizide tutun; ekrandan çıkanı silin.
  4. Zorlu: çapraz giderken hız artmasın. İki yön birden basılıysa hızı 0.707 ile çarpın.

Oyuncu boşluğa 2 saniye basılı tuttu. zipla() kaç kez çağrılır?

  1. 1
  2. 2
  3. Yaklaşık 120
  4. 0

60 FPS × 2 saniye. Zıplama tek seferlik bir eylemdir; yeri keyPressed().

Hangisi sol ok tuşunu doğru yakalar?

  1. keyIsDown(LEFT)
  2. key === "left"
  3. keyIsDown(LEFT_ARROW)
  4. keyIsDown("%")

LEFT hizalama sabitidir. Ok tuşlarının karakteri yoktur; keyCode ve LEFT_ARROW ile tanınırlar.

text("A\nB\tC", 20, 40) tuvalde nasıl görünür?

  1. Tek satırda: A\nB\tC
  2. İki satır: üstte A; altta B, biraz boşluk, C
  3. Üç satır: A, B, C

\n satır kırar, \t yatayda sekme boşluğu bırakır.

Merak edenler için kaynaklar

Bölüm 3’ü bitirdik

  • keyIsDown() basılı olduğu her frame doğrudur: sürekli hareket, draw içinde.
  • keyPressed() basma anında, keyReleased() bırakma anında bir kez çalışır.
  • key karakteri, keyCode tuşun sayısal kodunu verir.
  • Oklar için LEFT_ARROW gibi sabitler; LEFT hizalama içindir.
  • Karakterler sayılarla saklanır: ASCII ve onu kapsayan Unicode. \n satır kırar, \t sekme koyar.
  • constrain değeri iki sınır arasında tutar.

Sıradaki bölüm

Bölüm 4: Çarpışmalar ve oyun durumları

Top duvardan sekecek, oyun menüden başlayacak.