Ana Başlık 3. Fonksiyonlar ve Modüler Kod Yazımı
Amaç: Fonksiyon tanımlama, parametre ve dönüş değeri kavramlarını öğreterek kodu modüler hale getirmek.
Öğrenme Çıktıları:
- Fonksiyon tanımlar ve çağırır.
- Parametreli fonksiyonlarla tekrar kullanılabilir kod yazar.
- return ifadesiyle değer döndürür.
- p5.js'te yardımcı çizim fonksiyonları oluşturur.
- Modüler kod yapısının oyun geliştirmedeki önemini açıklar.
- Global ve yerel değişken kapsamını ayırt eder; parametre ile argüman ilişkisini açıklar.
Anahtar Sözcükler: fonksiyon, parametre, argüman, dönüş değeri, return, modülerlik, yeniden kullanılabilirlik, kapsam, global değişken, yerel değişken, gölgeleme
Giriş
Döngüler tekrarlayan aynı kodu kısaltır; fonksiyonlar ise anlamlı iş parçalarını isimlendirilmiş bloklara ayırır. draw() içinde onlarca satır büyüdüğünde "tahta çiz", "skor yaz", "hedefi güncelle" gibi görevler birbirine karışır. Fonksiyonlar, her görevi ayrı bir isim altında toplayarak okunabilirliği artırır ve aynı işlemi farklı yerlerden tekrar çağırmayı mümkün kılar. Böylece bir değişiklik tek noktada yapılır; kopyalanmış satırlarda unutulan güncellemeler azalır.
p5.js’te setup() ve draw() zaten özel fonksiyonlardır; p5.js bunları belirli zamanlarda otomatik çağırır. mousePressed() de önceki ana başlıklarda benzer biçimde tanıtılmıştır. Bu ana başlıkta kullanıcı tanımlı fonksiyonlar ele alınacak: geliştiricinin kendi adını verdiği, parametre alabilen ve değer döndürebilen bloklar. Parametreler dış veri taşır; return hem erken çıkış hem de hesaplanmış sonuç için kullanılır. Modüler yapı, ileride XOX tahtası çizimi ve Daire Tıklama oyunundaki hedef konumu güncelleme gibi görevlerin düzenlenmesine zemin hazırlar.
Fonksiyonlar yalnızca kod tekrarını azaltmaz; soyutlama sağlar. draw() içinde tahtaCiz() yazmak, «tahtayı çiz» niyetini kodu inceleyene iletir; hücre renginin nasıl seçildiği hucreCiz içinde kalır. Oyun büyüdükçe hangi fonksiyonun ne yaptığını bilmek, hata ayıklamayı hızlandırır: tahta bozuksa önce tahtaCiz ve hucreCiz incelenir, tüm draw() taranmaz.
Modüler yazım aynı zamanda hata ayıklamayı ve ekip çalışmasını kolaylaştırır. Bir oyunda skor hesaplaması hatalıysa, tüm draw() gövdesini satır satır izlemek yerine doğrudan skorArtir gibi anlamlı adlandırılmış fonksiyona bakmak yeterli olur; fonksiyon adı zaten hangi görevi üstlendiğini belirtir. Birden fazla kişi aynı sketch üzerinde çalıştığında da fonksiyonlara bölünmüş kod, kimin hangi parçayı değiştirdiğini ayırt etmeyi kolaylaştırır: biri tahtaCiz üzerinde çalışırken diğeri skorGuncelle üzerinde çalışabilir, iki değişiklik aynı satırlarda çakışmaz.
3.1. Fonksiyon Kavramı ve Sözdizimi
Tanım: Fonksiyon (function) — Belirli bir görevi yerine getiren, isimlendirilmiş ve gerektiğinde tekrar çağrılabilen kod bloğudur.
Matematik dersindeki f(x) = x * x gibi bir fonksiyonu düşünün: dışarıdan bir girdi verirsiniz, içerideki kural çalışır, bir sonuç çıkar. Programlamada da benzer bir bakış yaygındır: çağıran taraf çoğu zaman fonksiyonun içini satır satır bilmek zorunda değildir — adı, girdi ve çıktı yeter; gövde bir kara kutu gibi kalabilir. dist(x1, y1, x2, y2) tam böyle çalışır: mesafe formülünü ezberlemeseniz de sonucu kullanırsınız. Kendi yazdığınız icindeMi veya topla için de aynı alışkanlık geçerlidir: önce «ne alır, ne verir / ne yapar?» sorusunu netleştirin.

Görsel 1 fonksiyonu girdi → kara kutu → çıktı olarak özetler: topla(3, 5) çağrısında önemli olan argümanlar ve dönen 8’dir; kutunun içindeki satırlar çağıran için gizli kalabilir.
Bilgi — Girdi, çıktı ve yan etki: İyi tasarlanmış bir fonksiyon genelde değer alır (parametre) ve çoğu zaman değer üretir (return) veya tek, net bir işi tamamlar. Dosya okuma, ağ isteği, konsola yazdırma gibi girdi/çıktı (I/O) işleri fonksiyon gövdesinde sık sık biriktirilmez; bunlar programın başka katmanlarına bırakılır. Elbette istisna vardır: p5.js’te arkaPlanCiz veya hedefCiz gibi yardımcılar tuvale çizim yapar — bu bir yan etkidir, yine de görevleri tek ve anlaşılırdır. Pratik kural: bir fonksiyon mümkün olduğunca tek, net tanımlanmış bir işe karşılık gelsin; «hem skor hesapla hem dosyaya yaz hem de menüyü çiz» gibi karışık sorumluluklar bakımı zorlaştırır.
Dikkat — dış değişkeni değiştirmek: Burada global, kabaca setup / draw dışında (dosyanın üstünde) tanımlanan değişkendir — örn. let secili = "gunes";. Bir fonksiyonun böyle bir değişkeni güncellemesi (secili = "agac") yan etkidir; ideal olan çoğu zaman return ile sonuç vermektir. Yine de olay fonksiyonlarında bu kalıp sık görülür ve bazen gerekir. Global / yerel ayrımının ayrıntısı 3.6’da; örnek kullanım ise bu ana başlığın sonundaki YZ etkinliğinde.
Bilgi — Ekip çalışması: Fonksiyonlar, işi kişilere bölmeyi kolaylaştırır. Biri tahtaCiz yazarken diğeri skorYaz üzerinde çalışabilir; arayüz (ad, parametre, dönüş) üzerinde anlaşılırsa gövdeler birbirinden bağımsız ilerler. Kara kutu burada da işe yarar: ekip arkadaşınızın yazdığı fonksiyonun satır satır içini bilmeden, «ne aldığını / ne verdiğini / ne yaptığını» biliyorsanız onu çağırabilirsiniz — tıpkı dist gibi.
Temel sözdizimi:
Kod 1.
function fonksiyonAdi() { // gövde — çağrıldığında çalışan satırlar}Çağrı (call): fonksiyonAdi(); — parantezler fonksiyonun şimdi çalıştırılması gerektiğini belirtir.
Tablo 1.
| Kavram | Biçim | Anlam |
|---|---|---|
| Tanım | function hedefCiz() { … } |
Fonksiyonun adı ve gövdesi |
| Çağrı | hedefCiz(); |
Tanımlanan bloğu çalıştırır |
| p5.js yerleşik | setup(), draw() |
p5.js belirli anlarda otomatik çağırır |
Kod bloğu: Basit yardımcı fonksiyon — arka plan rengini sabitleyen arkaPlanCiz.
Kod 2.
function setup() { createCanvas(400, 400);} function draw() { arkaPlanCiz(); ortaCizgiCiz();} function arkaPlanCiz() { background(35, 40, 55);} function ortaCizgiCiz() { stroke(200); strokeWeight(2); line(width / 2, 0, width / 2, height); noStroke();}draw() artık ne yaptığını okunaklı biçimde listeler; ayrıntılar fonksiyon gövdelerinde saklanır. p5.js draw() her frame'de çalıştığı için içinde çağrılan arkaPlanCiz() ve ortaCizgiCiz() de her frame'de yeniden çalışır.
Bilgi: Kendi yazdığınız fonksiyonlarda camelCase örfi kullanılır: hedefCiz, skorGuncelle. setup, draw ve mousePressed ise farklı bir kategoridedir: p5.js bu adları sabit olarak tanır ve sketch çalışırken bu isimdeki fonksiyonları belirli anlarda otomatik çağırır. Örneğin draw yerine cizimYap yazarsanız p5.js her frame'de o fonksiyonu aramaz; tuval güncellenmez. Yani camelCase burada tercih meselesi değil, p5.js'in tanıdığı yerleşik olay adlarıdır; kütüphane dokümantasyonunda bu isimlerle tanımlanır.
Fonksiyon çağrı izi: Aşağıdaki sketch'te draw() çalıştığında çağrı sırası şöyledir:
Tablo 2.
| Adım | Çalışan fonksiyon | Not |
|---|---|---|
| 1 | draw() |
p5.js tarafından tetiklenir |
| 2 | arkaPlanCiz() |
draw() içinden çağrılır |
| 3 | ortaCizgiCiz() |
draw() içinden çağrılır |
| 4 | (frame biter) | Bir sonraki frame'de 1. adıma dönülür |
Fonksiyon iç içe çağrılabilir: tahtaCiz döngü içinde hucreCiz çağırır; her hucreCiz tamamlanınca kontrol tahtaCiz'e döner. Bu «çağrı yığını» (call stack) kavramının basit hâlidir; derin özyineleme (Mayın Tarlası Flood Fill) ileride aynı mantığı kullanır.
Bilgi: JavaScript'te function fonksiyonAdi() { … } biçiminde yazılan tanımlar, dosyanın neresinde durduğuna bakılmaksızın çalıştırılmadan önce tanınır; bu nedenle draw() içindeki arkaPlanCiz() çağrısı, arkaPlanCiz tanımından önce yazılsa da hatasız çalışır. Yine de okunabilirlik açısından ilgili fonksiyonları çağrıldıkları yere yakın veya dosyanın sonunda düzenli biçimde tutmak tercih edilir.
Sıra Sizde: Uzun bir draw() bloğunu en az iki anlamlı fonksiyona bölecek şekilde isimlendirin (ör. arkaplanCiz, skorYaz). Her fonksiyonun tek sorumluluğunu bir satırla yazın.
3.2. Parametreli Fonksiyonlar
Tanım: Parametre (parameter) — Fonksiyon tanımında parantez içine yazılan, dışarıdan alınan değer yer tutucusudur. Çağrı sırasında verilen somut değere argüman (argument) denir.
Kod 3.
function dikdortgenCiz(x, y, w, h, renkR, renkG, renkB) { fill(renkR, renkG, renkB); noStroke(); rect(x, y, w, h);} function draw() { background(20); dikdortgenCiz(50, 50, 80, 60, 255, 100, 100); // kırmızımsı dikdortgenCiz(200, 120, 100, 40, 100, 200, 255); // mavimsi}Aynı fonksiyon farklı argümanlarla birden çok kez kullanılır; kod tekrarı azalır.
Tablo 3.
| Kavram | Tanım yeri | Örnek |
|---|---|---|
| Parametre | function dikdortgenCiz(x, y, w, h) |
x, y, w, h |
| Argüman | Çağrı satırı | 50, 50, 80, 60 |
Dikkat: Parametre sırası önemlidir. dikdortgenCiz(50, 50, 80, 60, …) ifadesinde ilk 50 x'e, ikinci 50 y'ye gider. Argüman sayısı parametre sayısından azsa karşılık gelmeyen parametreler undefined olur; fazlaysa fazladan değerler yok sayılır.
3.3. return ile Değer Döndürme
mousePressed() içinde return; ifadesi fonksiyondan erken çıkış için kullanılır; oyun bittiğinde geri kalan satırlar çalışmaz. return aynı zamanda bir değer üretip çağıran yere iletebilir.
Kod 4.
function acikKareMi(satirSutunToplami) { return (satirSutunToplami % 2 === 0);} function draw() { background(50); for (let satir = 0; satir < 4; satir = satir + 1) { for (let sutun = 0; sutun < 4; sutun = sutun + 1) { if (acikKareMi(satir + sutun)) { fill(230, 220, 200); } else { fill(60, 55, 50); } rect(sutun * 50, satir * 50, 50, 50); } }}Fonksiyon, dama deseninde satır ve sütun toplamının çift olduğu hücreleri açık renge ayırır: acikKareMi(3) çağrısı false, acikKareMi(6) çağrısı true döndürür. Çağıran satır bu boolean değeri if koşulunda kullanır.
Tablo 4.
| return biçimi | Anlam | Örnek |
|---|---|---|
return; |
Değer yok; fonksiyon hemen biter | mousePressed içinde erken çıkış |
return değer; |
Hesaplanan değeri çağıran yere verir | return (a + b); |
Tanım: Dönüş değeri (return value) — Fonksiyonun return ile geri gönderdiği sonuç; çağrı ifadesinin yerine geçer.
Kod 5.
let sonuc = topla(3, 5); // sonuc değişkeni 8 olur function topla(a, b) { return a + b;}Kod bloğu: Oyun mantığında return — mesafe ve «içinde mi» testi (daire çarpışmasında kullanılan dist() ile uyumlu).
Kod 6.
function mesafeHesapla(x1, y1, x2, y2) { return dist(x1, y1, x2, y2);} function icindeMi(fareX, fareY, merkezX, merkezY, yaricap) { let m = mesafeHesapla(fareX, fareY, merkezX, merkezY); return m < yaricap;}icindeMi(mouseX, mouseY, hedefX, hedefY, 40) ifadesi true veya false üretir; if koşulunda doğrudan kullanılabilir. Daire Tıklama oyunundaki dist(...) < hedefYaricap satırı bu yapının satır içi hâlidir; fonksiyona taşımak okunabilirliği artırır.
Sıra Sizde: Bölüm 1 Ana Başlık 3'teki «nokta daire / elips içinde mi?» kontrollerini (renk örneği ve Daire Tıklama) davranışı değiştirmeden yardımcı fonksiyonlara taşıyın; eski yerlerde bu fonksiyonları çağırın. Daire için yukarıdaki icindeMi yeterli olabilir. İsterseniz genişlik ve yüksekliği farklı bir elips için ayrı bir fonksiyon da yazmayı deneyin.
3.4. p5.js'te Yardımcı Çizim Fonksiyonları
Izgara ve şekil çizimini fonksiyonlara ayırmak, draw() gövdesini sade tutar.
Kod bloğu: Parametreli hücre ve tahta çizimi.
Kod 7.
const HUCRE = 50;const SUTUN = 3;const SATIR = 3; function setup() { createCanvas(SUTUN * HUCRE, SATIR * HUCRE); noStroke();} function draw() { background(30, 35, 45); tahtaCiz(0, 0, SATIR, SUTUN, HUCRE); merkezIsaretiCiz(width / 2, height / 2);} function tahtaCiz(baslangicX, baslangicY, satirSayisi, sutunSayisi, hucreBoyutu) { for (let satir = 0; satir < satirSayisi; satir = satir + 1) { for (let sutun = 0; sutun < sutunSayisi; sutun = sutun + 1) { hucreCiz( baslangicX + sutun * hucreBoyutu, baslangicY + satir * hucreBoyutu, hucreBoyutu, satir, sutun ); } }} function hucreCiz(x, y, boyut, satir, sutun) { if ((satir + sutun) % 2 === 0) { fill(240, 235, 220); } else { fill(70, 65, 60); } rect(x, y, boyut, boyut);} function merkezIsaretiCiz(merkezX, merkezY) { fill(255, 80, 80); ellipse(merkezX, merkezY, 12, 12);}tahtaCiz üç kez farklı boyutta çağrılabilir; yalnızca argümanlar değişir. Bu yapı ilerleyen bölümlerdeki XOX oyununun görsel zeminini oluşturur.
Çağrı sırası izlemesi: SATIR = 2, SUTUN = 2 olan daha küçük bir tahtada tahtaCiz çağrısının ürettiği hucreCiz çağrıları sırasıyla şöyledir:
Tablo 5.
| satir | sutun | hucreCiz çağrısı | Hücre rengi |
|---|---|---|---|
| 0 | 0 | hucreCiz(0, 0, 50, 0, 0) |
açık (satir + sutun çift) |
| 0 | 1 | hucreCiz(50, 0, 50, 0, 1) |
koyu |
| 1 | 0 | hucreCiz(0, 50, 50, 1, 0) |
koyu |
| 1 | 1 | hucreCiz(50, 50, 50, 1, 1) |
açık |
Dış döngü satir değerini, iç döngü sutun değerini değiştirir; her ikili için hucreCiz bir kez çağrılır. Toplam çağrı sayısı satirSayisi * sutunSayisi kadardır.
3.5. Modüler Kod ve Oyun Mimarisi
Tanım: Modülerlik — Programın bağımsız, yeniden kullanılabilir parçalara (fonksiyonlara, ileride sınıflara) ayrılmasıdır.
Oyun kodunda yaygın işlev ayrımı:
Tablo 6.
| Fonksiyon görevi | Örnek ad | Ne zaman çağrılır |
|---|---|---|
| Çizim | tahtaCiz, hedefCiz |
draw() içinde her frame |
| Girdi | mousePressed (p5.js olayı) |
Fare tıklanınca |
| Mantık | skorArtir, oyunBittiMi |
Olay veya draw() içinde |
| Yardımcı hesap | rastgeleKonum, icindeMi |
İhtiyaç duyulduğunda |

Görsel 2 draw() fonksiyonunun çizim, tahta ve skor gibi görevleri ayrı fonksiyonlara devretmesini; tahtaCiz içinde hucreCiz gibi iç içe çağrıları gösterir.
Kod bloğu: Daire Tıklama için hedef konumu güncelleme — artık fonksiyon kullanılabilir (bu ana başlıktan sonra refaktör örneği).
Kod 8.
function yeniHedefKonumu() { hedefX = random(50, width - 50); hedefY = random(50, height - 50);} function mousePressed() { if (oyunBitti) { return; } let mesafe = dist(mouseX, mouseY, hedefX, hedefY); if (mesafe < hedefYaricap) { skor = skor + 1; if (skor >= HEDEF_SKOR) { oyunBitti = true; } else { yeniHedefKonumu(); } }}Bu parça, sayı tahmin oyununda satır satır draw() ve mousePressed() içinde yazılmış mantığın modüler hâlidir; yeniHedefKonumu() yalnızca koordinat atamasından sorumludur.
Kod bloğu: XOX taşı çizimi — parametreli tasCiz (ilerleyen bölümlerin 5. ana başlığına hazırlık).
Kod 9.
function tasCiz(satir, sutun, hucre, oyuncu) { let x = sutun * hucre + hucre / 2; let y = satir * hucre + hucre / 2; textAlign(CENTER, CENTER); textSize(hucre * 0.55); fill(30); text(oyuncu, x, y);} function xoxTahtasiniCiz(tahta, hucre) { for (let satir = 0; satir < 3; satir = satir + 1) { for (let sutun = 0; sutun < 3; sutun = sutun + 1) { if (tahta[satir][sutun] !== "") { tasCiz(satir, sutun, hucre, tahta[satir][sutun]); } } }}Boş hücrelerde tasCiz çağrılmaz; dolu hücrelerde "X" veya "O" metni çizilir. Tahta verisi (tahta dizisi) ile görselleştirme (tasCiz) ayrılmış olur.
3.6. Değişken Kapsamı: Global ve Yerel
Fonksiyonlar büyüdükçe «bu x hangisi?» sorusu sık çıkar. Cevap kapsam (scope) kurallarındadır: bir değişkenin adı, yalnızca tanımlandığı bölgede geçerlidir. Yanlış yerde tanımlanan skor frame sonunda yok olur; yanlış adlandırılmış parametre ise global skoru güncellemezmiş gibi görünür.
Tanım: Kapsam (scope) — Bir değişken adının geçerli olduğu kod bölgesidir. Bu bölgenin dışında aynı ad ya tanımsızdır ya da başka bir değişkeni işaret eder.
Global değişkenler
setup() ve draw() dışında, sketch dosyasının üst düzeyinde let / const ile tanımlanan değişkenler global kabul edilir. Bunlara setup, draw, mousePressed ve kullanıcı tanımlı yardımcılardan erişilebilir; değer frame’ler arasında kalır.
Kod 10.
let skor = 0; // global — setup/draw dışındalet hedefX;let hedefY; function setup() { createCanvas(400, 400); hedefX = width / 2; hedefY = height / 2;} function draw() { background(240); text("Skor: " + skor, 20, 30); // global skor okunur circle(hedefX, hedefY, 40);} function skorArtir(artisMiktari) { skor = skor + artisMiktari; // global skor güncellenir}Oyun durumu (skor, hedefX, oyunBitti) bu yüzden üst düzeyde tutulur: draw her frame yeniden çalışsa da global değer silinmez.
Tablo 7.
| Nerede tanımlanır? | Tür | Örnek kullanım |
|---|---|---|
setup / draw dışında (üst düzey) |
Global | skor, hedefX, oyunBitti |
Fonksiyon gövdesinde let / const |
Yerel | Geçici hesap, döngü değişkeni |
| Fonksiyon parametresi | Yerel | dikdortgenCiz(x, y, w, h) içindeki x |
Yerel değişkenler ve draw()
Fonksiyon içinde let x = 5 yazılırsa x yalnızca o fonksiyon gövdesinde geçerlidir; fonksiyon bittiğinde yerel değişken yok olur. Parametreler de yerel kapsamdadır.
Dikkat: draw() her frame bir kez çağrılır ve biter. draw içinde tanımlanan yerel değişken her frame’in başında yeniden yaratılır, sonunda yok olur. Kalıcı oyun durumu için kullanılamaz:
Kod 11.
let skor = 0; // global — doğru yer function draw() { let geciciX = mouseX; // yerel — yalnızca bu frame’de geçerli // let skor = 0; // YANLIŞ: her frame sıfırdan başlar, skor birikmez background(240); text(skor, 20, 30); circle(geciciX, 200, 20);}geciciX her frame fare konumuna göre yeniden hesaplanır; bunu global tutmaya gerek yoktur. Buna karşılık skor birikmeli olduğu için global (veya ileride nesne/dizi) olmalıdır.
Argüman ile parametre aynı şey değildir
Çağrı satırındaki değer argüman, fonksiyon tanımındaki yer tutucu parametredir. İsimler aynı olsa bile bunlar iki ayrı değişkendir: çağrı anında argümanın değeri parametreye kopyalanır.
Kod 12.
function konumYaz(x) { // buradaki x, çağıranın x'i değil — kopya (yerel parametre) x = x + 50; text(x, 20, 40);} function draw() { background(255); let x = 100; // draw'ın yerel x'i konumYaz(x); // argüman: 100 → parametreye kopyalanır text(x, 20, 80); // hâlâ 100 — konumYaz içindeki atama burayı değiştirmez}Tablo 8.
| Ad | Nerede? | Bu örnekte |
|---|---|---|
| Argüman | Çağrı: konumYaz(x) |
draw içindeki x değeri (100) |
| Parametre | Tanım: function konumYaz(x) |
Fonksiyonun kendi yerel x'i (önce 100, sonra 150) |
Ekranda üst satır 150, alt satır 100 görünür. Parametre adı x olsa da çağıranın x'i ile bağlantılı değildir; sayısal değerler kopyalanır. Bu yüzden dikdortgenCiz(x, y, w, h) içindeki x, çağrı sırasında gelen argümanın kopyasıdır — fonksiyon gövdesinde x'i değiştirmek, çağıran taraftaki değişkeni otomatik güncellemez.
Bilgi: İsimler bilerek farklı seçilebilir: function konumYaz(ekranX) { … } ve konumYaz(x);. Davranış aynıdır; okuyan kişi parametre ile çağıran değişkeni daha kolay ayırır.
Gölgeleme (shadowing)
Parametre veya yerel let adı, üst düzeydeki global ile aynı olursa fonksiyon içinde yerel olan kazanır; global o isimle görünmez. Buna gölgeleme (shadowing) denir.
Kod 13.
let skor = 10; // global function skorArtir(skor) { // parametre adı da skor — gölgeleme skor = skor + 1; // yalnızca yerel parametre artar // global skor hâlâ 10} function draw() { skorArtir(skor); // argüman: 10 → yerel parametreye kopyalanır text(skor, 20, 30); // hâlâ 10 — beklenen artış olmaz}Karışıklığı önlemek için parametre adını globalden ayırmak önerilir:
Kod 14.
let skor = 10; function skorArtir(artisMiktari) { skor = skor + artisMiktari; // global skor bilinçli güncellenir} function draw() { // … skorArtir(1);}Dikkat: Global skoru güncelleyecek yardımcıda parametreye skor demek yaygın bir hatadır. Ya parametreyi artisMiktari gibi adlandırın ya da globali doğrudan (parametresiz) güncelleyin; ikisini aynı isimle karıştırmayın.
Örnek Olay: Fonksiyonlara Ayırma Tahmini etkinliği tamamlama süresi: 35–40 dakika.
Senaryo: 3×3 tahta çizen kod tek bir draw() içinde 40 satıra ulaşmıştır; tahta rengi değiştirilmek istendiğinde ilgili satırlar bulunamamaktadır.
Durum Tespiti:
- Hücre rengi, çizgi kalınlığı ve tahta boyutu birbirine karışmıştır.
tahtaCizvehucreCizayrımı bakımı kolaylaştırır.- XOX oyununda taş çizimi ayrı bir
tasCiz(x, y, tur)fonksiyonuna taşınabilir.
Problem Durumu: Tek blok hâlindeki kod, ekip çalışmasında ve hata ayıklamada yavaşlatıcıdır.
Tartışma Soruları:
returnile erken çıkış ilereturn değerarasındaki fark nedir?- Aynı fonksiyonu farklı argümanlarla çağırmak neden kod tekrarını azaltır?
draw()içinde kaç yardımcı fonksiyon çağrısı makul sayılır?- Skor neden
draw()içindeletile tanımlanmamalıdır? - Parametre adı global değişkenle aynı olursa ne olur?
Yapay Zekâ Etkileşimi: Kara Kutu ile Ekipçe Sketch Tahmini etkinliği tamamlama süresi: 40–50 dakika.
Amaç: (1) YZ’den çizim fonksiyonları ve klavye ile secili seçen bir yardımcı almak; (2) sizin tarafınızda yalnızca bildiğiniz mousePressed ile tuvale çizmek; (3) kara kutu, ekip paylaşımı ve «global değiştiren fonksiyon» eleştirisini yaşayarak görmek.
Önemli — klavyeyi henüz işlemedik. keyPressed / key bu kitapta sistematik olarak Bölüm 2’de gelir. Yine de YZ’den (veya bir ekip arkadaşından) «tuşa göre secili değiştir» kodunu alıp içini satır satır bilmeden kullanabilirsiniz — tıpkı Görsel 1’deki kara kutu gibi. Davranış garantisi netse (G → secili === "gunes"), gövdeyi bilmek zorunda değilsiniz.
Adım 1 — Çizim fonksiyonlarını YZ’ye yazdırın.
Örnek İstem:
"p5.js için şu yardımcı fonksiyonları yaz: gunesCiz(merkezX, merkezY), insanCiz(merkezX, merkezY), agacCiz(merkezX, merkezY), evCiz(merkezX, merkezY), kusCiz(merkezX, merkezY). Her fonksiyon yalnızca ellipse, rect, line, triangle gibi temel şekillerle çizsin. Tüm parçalar merkezX / merkezY’ye göre konumlandırılsın; sabit piksel adresleri kullanma."
Üretilen kodu yapıştırın; bir kez gunesCiz(width/2, height/2) ile deneyin.
Adım 2 — Seçim fonksiyonunu YZ’ye yazdırın (klavye — sizin bilmeniz gerekmez). Global secili değişkeni olacak; tuşa göre değeri değişecek.
Örnek İstem:
"p5.js’te global let secili = 'gunes' var. keyPressed yaz: g/G → secili = 'gunes', i/I → 'insan', a/A → 'agac', e/E → 'ev', k/K → 'kus'. Başka bir şey çizme; yalnızca secili’yi güncelle. Kısa yorum ekle."
Bu parçayı da sketch’e ekleyin. Şimdilik keyPressed’in nasıl çalıştığını ezberlemeniz beklenmiyor — sözleşme şu: doğru tuşa basınca secili doğru string olur.
Adım 3 — Sizin işiniz: tıklayınca çiz. Yalnızca Bölüm 1 Ana Başlık 3'ten bildiğiniz fare ile ilerleyin:
Kod 15.
let secili = "gunes"; function setup() { createCanvas(400, 400); background(230); // bir kez} function draw() { // boş — şekiller tıklamayla birikir} function mousePressed() { if (mouseX < 40 && mouseY < 40) { background(230); // temizle return; } if (secili === "gunes") { gunesCiz(mouseX, mouseY); } else if (secili === "insan") { insanCiz(mouseX, mouseY); } else if (secili === "agac") { agacCiz(mouseX, mouseY); } else if (secili === "ev") { evCiz(mouseX, mouseY); } else if (secili === "kus") { kusCiz(mouseX, mouseY); }} // keyPressed — YZ / ekip arkadaşı yazdı; siz içini bilmeden kullanıyorsunuzİş bölümü (ekip analojisi): Biri (burada YZ) «tuş → secili» kutusunu yazar; siz «secili → tuvalde çiz» kutusunu yazarsınız. Ortak dil: secili string değerleri. Bu, fonksiyonların ekip çalışmasındaki faydasıdır — görevler ayrılır, arayüz üzerinde anlaşılır.
Adım 4 — Sahne kurun. Tuşa basın (seçim), sonra tuvale tıklayın (yerleştirme). Birkaç ağaç, bir ev, güneş… Aynı çizim fonksiyonunu farklı (mouseX, mouseY) ile çağırmanın parametre gücünü not edin.
Adım 5 — Eleştirel bakış (iki katman).
- Kara kutu işe yaradı mı? Klavye konusunu bilmeden seçim yapabildiniz mi? Davranış sözü tutulduysa (
G→ güneş seçilir) gövdeyi bilmek zorunda değildiniz — Görsel 1’i hatırlayın. - Global
seciligüncellemesi: Ideal olan çoğu zaman değer alıp değer döndürmektir; burada ise olay fonksiyonu dışarıdaki bir değişkeni değiştiriyor. Bu «en temiz» tasarım sayılmaz — yine dekeyPressed/mousePressedgibi olaylarda sık görülür ve bazen pratik olarak gerekir. Kara kutu kullanmak ile her kara kutunun mükemmel tasarlandığı aynı şey değildir; yine de işe yarar bir paylaşım biçimidir. - YZ gerçekten düzgün çizebiliyor mu? YZ metin ve kod iskeletinde sık işe yarar; görsel şekil üretiminde ise özellikle karmaşık figürlerde (insan, kuş, detaylı ev) sıklıkla zayıf kalır veya saçmalayabilir. Olası sorunlar:
- Merkez parametresini yok sayıp sabit
(100, 100)gibi konumlar kullanmak - Parçaların orantısız veya birbirinden kopuk durması (gövde ile kafa ayrı yerde)
triangle/lineuçlarının yanlış bağlanması; “kuş”un tanınmaz bir karalama olmasıfill/strokeunutulduğu için şekillerin birbirine karışması
Basit güneş (daire + ışınlar) çoğu zaman idare eder; karmaşık silüetlerde YZ çıktısını körü körüne güvenmeyin. En az bir çizim fonksiyonunu kendiniz düzelterek veya sadeleştirerek (ör. insanı daire + iki rect) tekrar deneyin.
Kısa not (3–5 cümle): (a) kara kutu / ekip, (b) global güncellemenin «ideal değil ama bazen gerekir» yanı, (c) hangi şekil bozuldu, neden.
Özet
Fonksiyonlar, adlandırılmış ve gerektiğinde tekrar çağrılabilen kod bloklarıdır. Tanım function ad() { … } biçimindedir; çağrı ad(); ile yapılır — parantezler bloğun o anda çalıştırılacağını belirtir. p5.js’in setup() ve draw() fonksiyonları kütüphane tarafından otomatik çağrılır; mousePressed gibi olay fonksiyonları da benzerdir. Kullanıcı tanımlı fonksiyonlar ise geliştiricinin açıkça çağırdığı yardımcı bloklardır. Modülerlik, uzun draw() gövdelerini çizim, girdi, mantık ve hesap görevlerine ayırarak okunabilirliği ve bakımı artırır; tahta bozuksa tüm draw() yerine tahtaCiz incelenir. Yeniden kullanılabilirlik, aynı yardımcının farklı argümanlarla tekrar çağrılmasından doğar. Parametreler fonksiyona dış veri taşır; çağrı sırasındaki somut değerler argümandır (dikdortgenCiz(50, 80, 100, 40)). Aynı fonksiyon farklı argümanlarla birçok kez kullanılabilir; böylece kopyala-yapıştır azalır. return hem koşul sağlanmadığında erken çıkış (if (oyunBitti) { return; }) hem de topla, acikKareMi, icindeMi gibi yardımcılarda hesaplanmış değer döndürme için kullanılır. Dönüş değeri atama veya koşul ifadesinde tüketilir. Kapsam (scope), bir değişken adının geçerli olduğu bölgedir. setup/draw dışında tanımlanan skor, hedefX gibi değişkenler globaldir; frame’ler arasında kalır ve yardımcılardan okunup yazılabilir. Fonksiyon içindeki let ve parametreler yereldir; fonksiyon (veya draw frame’i) bitince yok olur. Bu yüzden skor draw içinde let skor = 0 ile tanımlanmaz. Argüman ile parametre aynı isimde olsa bile ayrıdır: çağrıda değer kopyalanır; parametreyi değiştirmek çağıranın değişkenini otomatik güncellemez. Parametre adı global ile örtüşürse gölgeleme olur; skorArtir(artisMiktari) gibi ayırt edici adlar tercih edilir. p5.js’te tahtaCiz, hucreCiz, hedefCiz, arkaPlanCiz gibi görevler ayrı fonksiyonlara bölündüğünde draw() kısa ve niyet odaklı kalır; iç içe çağrılar (tahtaCiz → hucreCiz) görev hiyerarşisini yansıtır.
Neler Öğrendik?
Soru 1 Aşağıdakilerden hangisi fonksiyon çağrısıdır?
A) function hedefCiz() { }
B) let x = 10;
C) hedefCiz();
D) return false;
E) if (skor > 0)
Soru 2
function topla(a, b) { return a + b; } tanımında a ve b ne olarak adlandırılır?
A) Argüman
B) Parametre
C) Boolean
D) Yerleşik değişken
E) Döngü değişkeni
Soru 3
mousePressed() içinde if (oyunBitti) { return; } satırının amacı nedir?
A) Oyunu kazanmış olmak
B) Fonksiyondan değer döndürerek skor artırmak
C) Oyun bittiyse fonksiyonun geri kalanını çalıştırmamak
D) draw() fonksiyonunu durdurmak
E) Tuval boyutunu değiştirmek
Soru 4
I. Parametreli fonksiyonlar kod tekrarını azaltır.
II. return a + b; ifadesi toplamı çağıran yere iletir.
III. Modüler kod, görevleri isimlendirilmiş parçalara ayırı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
Neler Öğrendik Yanıt Anahtarı
Soru 1: Doğru Cevap: C
- Çözüm:
hedefCiz();fonksiyonu çalıştırır. A seçeneği tanımdır;returnveifayrı yapılardır. - İlgili Konu: 3.1. Fonksiyon Kavramı ve Sözdizimi
Soru 2: Doğru Cevap: B
- Çözüm: Tanımdaki
avebparametredir.topla(3, 5)çağrısındaki 3 ve 5 argümandır. - İlgili Konu: 3.2. Parametreli Fonksiyonlar
Soru 3: Doğru Cevap: C
- Çözüm:
return;değer döndürmeden fonksiyonu sonlandırır; oyun bittiğinde tıklama işlenmez. - İlgili Konu: 3.3. return ile Değer Döndürme
Soru 4: Doğru Cevap: E
- Çözüm: Üç ifade de modüler fonksiyon kullanımını doğru tanımlar.
- İlgili Konu: 3.5. Modüler Kod ve Oyun Mimarisi
Yararlanılan Kaynaklar
Bu içerik aşağıdaki kaynaklardan derlenerek hazırlanmıştır:
- McCarthy, L., Reas, C., & Fry, B. (2015). Make: Getting Started with p5.js. Maker Media.
- Mozilla Developer Network. (n.d.). Functions. MDN Web Docs. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
- Mozilla Developer Network. (n.d.). return. MDN Web Docs. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return
- Mozilla Developer Network. (n.d.). Scope. MDN Web Docs. https://developer.mozilla.org/en-US/docs/Glossary/Scope
- p5.js Foundation. (n.d.). p5.js reference. https://p5js.org/reference/
- Shiffman, D. (n.d.). Code! Programming with p5.js. The Coding Train. https://thecodingtrain.com/tracks/code-programming-with-p5-js