İçeriğe geç

Menü

Berk Akademi
Yorumlar Google yorumları Birebir ders başvurusu Ücretsiz ön görüşme Ana Sayfa

Godot 2D Karakter Hareketi Nasıl Yapılır? Adım Adım Mini Proje

godot-2d-karakter-hareketi-nasil-yapilir
Bu yazıda neler var?
  1. Sahne ağacı nasıl kurulur: CharacterBody2D, Sprite2D ve CollisionShape2D
  2. Input Map'te dört yön eylemi nasıl tanımlanır?
  3. Hareket kodu: Input.get_vector, velocity ve move_and_slide
  4. Konumu doğrudan değiştirmek yerine velocity neden tercih edilir?
  5. Köşegen harekette hız neden artmaz?
  6. Karakter hareket etmiyorsa kontrol edilecek noktalar
  7. Prototipi bir sonraki adımda nasıl genişletirsin?
  8. Sık Sorulan Sorular

Godot'ta 2D karakter hareketi üç parçayla kurulur: fiziksel gövde olarak CharacterBody2D, tuşları adlandıran Input Map eylemleri ve her fizik karesinde velocity değerini belirleyip move_and_slide() çağıran kısa bir GDScript. Bu yazıda klavyeyle dört yöne hareket eden tek bir karakter yapacaksın. Sahneyi kurup tuşları tanımlayacak, ardından çalışan kodu yazacaksın.

Sahne ağacı nasıl kurulur: CharacterBody2D, Sprite2D ve CollisionShape2D

Yeni bir sahne oluştur ve kök düğüm olarak CharacterBody2D ekle. Altına bir Sprite2D ve bir CollisionShape2D çocuk düğümü koy. Ağaç şöyle görünmelidir:

Player (CharacterBody2D)
├── Sprite2D
└── CollisionShape2D

Her düğümün işi ayrıdır:

DüğümGörevi
CharacterBody2DHareket ve çarpışma mantığını taşır, scriptin bağlanacağı yerdir
Sprite2DKarakterin görünüşünü verir
CollisionShape2DFiziksel gövdeyi tanımlar

Sprite2D'in Texture özelliğine projendeki herhangi bir görseli sürükleyebilirsin. Görsel sadece ekranda görünür, fizik motoru onu hesaba katmaz.

Fizik açısından asıl önemli düğüm CollisionShape2D'dir. Şekil atanmamışsa düğümün yanında sarı bir uyarı üçgeni belirir. Çünkü CharacterBody2D'nin çarpışma hesabı yapabilmesi için bir şekle ihtiyacı vardır. Şekil olmadan fizik motoru karakteri bir gövde olarak tanıyamaz ve duvarlarla etkileşim beklediğin gibi çalışmaz.

Düğümü seçip Inspector'daki Shape özelliğine yeni bir şekil ata. Dikdörtgen ya da kapsül bu iş için uygundur. Şeklin boyutunu sprite'ın boyutuna yaklaşık uyacak biçimde ayarla. Birebir olması gerekmez, ama şekil sprite'tan çok küçük ya da büyük olursa karakter duvarlara havada takılıyor ya da içine giriyor gibi görünür.

Scripti kök düğüme, yani CharacterBody2D'ye bağlayacaksın. Düğüm adları ve bu yapı Godot'un 2D fizik düğümleri için bilinen standart düzendir. Farklı bir sürümde editör ayrıntıları biraz değişirse resmî dokümantasyondaki düğüm sayfalarına bakabilirsin.

Input Map'te dört yön eylemi nasıl tanımlanır?

Input Map'te dört yön eylemi nasıl tanımlanır?

Kodda tuşları tek tek ("A'ya basıldı mı?") sormak yerine eylem adlarıyla çalışacaksın. Tuş ataması editörde, kod ise eylem adıyla yapılır. İleride tuşu değiştirmek istersen koda dokunman gerekmez.

  1. Üst menüden Project > Project Settings penceresini aç.
  2. Input Map sekmesine geç.
  3. Üstteki kutuya eylem adını yaz ve Add düğmesine bas.
  4. Eklenen eylemin sağındaki + simgesine tıkla, açılan pencerede istediğin tuşa bas ve onayla.
  5. Her eylem için bir tuş daha eklemek istersen aynı adımı tekrarla.

Dört eylemi şu eşleştirmeyle tanımla:

  • move_left: A ve sol ok, kodda "move_left"
  • move_right: D ve sağ ok, kodda "move_right"
  • move_up: W ve yukarı ok, kodda "move_up"
  • move_down: S ve aşağı ok, kodda "move_down"

Kritik nokta şudur: eylem adları koddaki metinlerle harfi harfine eşleşmelidir. Büyük küçük harf ve alt çizgi dahil her karakter önemlidir. Move_Left ile move_left farklı adlardır. Tek harflik bir fark karakterin hiç tepki vermemesine ya da konsolda hata mesajı görmene yol açar.

Godot'ta hazır ui_left, ui_right, ui_up ve ui_down eylemleri de bulunur ve istersen onları kullanabilirsin. Bu yazıdaki örnekte kendi adlarımızı kullanıyoruz, çünkü eylemin ne işe yaradığı adından okunuyor ve menü gezinmesi için ayrılmış ayarlarla karışmıyor.

Hareket kodu: Input.get_vector, velocity ve move_and_slide

CharacterBody2D düğümüne yeni bir script ekle ve içeriğini şöyle yaz:

extends CharacterBody2D

@export var speed: float = 300.0

func _physics_process(_delta: float) -> void:
    var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
    velocity = direction * speed
    move_and_slide()

Satır satır ne olduğuna bakalım:

  • @export var speed: Hızı Inspector'da görünen bir ayara çevirir. Kodu açmadan değeri değiştirip deneyebilirsin. Birim, saniyede piksel olarak düşünülebilir.
  • Input.get_vector(...): Dört eylemi okuyup x ve y bileşenli bir yön vektörü üretir. Parametre sırası sol, sağ, yukarı, aşağıdır. Hiçbir tuşa basılmıyorsa sonuç sıfır vektördür.
  • velocity = direction * speed: Yönü hızla çarpar. velocity, CharacterBody2D'nin kendi özelliğidir ve karakterin bu kareki hızını tutar.
  • move_and_slide(): Karakteri velocity'ye göre hareket ettirir ve çarpışmaları işler.

Kod _physics_process içinde çalışır, çünkü hareket ve çarpışma hesabı fizik karesinde yürür. Bu fonksiyon sabit aralıklarla çağrılır.

Sahneyi çalıştırdığında şunu görmelisin: bir yön tuşuna basınca karakter o yönde sabit hızla ilerler, tuşu bırakınca durur. İki tuşa birlikte basarsan çapraz hareket eder.

Bu örnek velocity'yi doğrudan bir özellik olarak kullanan yazım biçimidir. Farklı bir Godot sürümü kullanıyorsan move_and_slide ve velocity yazımı değişmiş olabilir. Bu durumda o sürümün resmî dokümantasyonundaki CharacterBody2D sayfasına bakman en doğrusu olur.

Konumu doğrudan değiştirmek yerine velocity neden tercih edilir?

Karakteri hareket ettirmenin en kısa yolu position += direction * speed * delta yazmaktır ve boş bir sahnede çalışır. Sorun, engel girince ortaya çıkar. Konumu doğrudan değiştirdiğinde fizik motoruna "bu hareket çarpışır mı?" diye sormamış olursun. Karakter duvarın içine ışınlanabilir, çarpışma tepkisi de devreye girmez.

velocity ile move_and_slide() akışında ise yalnızca gitmek istediğin hızı söylersin. CharacterBody2D hareketi çarpışmaları hesaba katarak uygular. Karakter bir engele çarpınca durmak yerine engelin yüzeyi boyunca kayabilir. Bu davranış resmî dokümantasyonda move_and_slide() için anlatılan temel işlevdir. Konumu elle değiştirmenin hiçbir yerde işe yaramayacağı anlamına gelmez; ama çarpışan bir karakter için doğru başlangıç velocity'dir.

Aşağıdaki tablo, projedeki üç katmanın nasıl bir zincir kurduğunu gösterir: sahne ağacı (şekil), giriş (eylemler) ve fizik (hareket).

ParçaGöreviEksik ya da yanlışsa belirti
CollisionShape2DKaraktere çarpışma alanı verirKarakter duvarın içinden geçer; editörde düğüm yanında uyarı işareti görünür
Input Map eylemleriTuşları isimli eylemlere bağlarTuşlara basınca yön vektörü sıfır kalır; Output panelinde eylem bulunamadı hatası çıkabilir
get_vector ve velocityYönü üretir, hızla çarpıp hareket isteğine çevirirKarakter yanlış yöne gider ya da beklenenden yavaş ve hızlı hareket eder
_physics_process ve move_and_slideVelocity'yi her fizik adımında çarpışmaya göre uygularVelocity değişir ama karakter yerinden kıpırdamaz

Köşegen harekette hız neden artmaz?

Köşegen harekette hız neden artmaz?

Yatay ve dikey girişi ayrı ayrı okuyup velocity.x ile velocity.y değerlerini 1 ile beslediğinde, sağ ve yukarı tuşları birlikte basılı olduğunda yön vektörü (1, 1) olur. Bu vektörün uzunluğu yaklaşık 1,41'dir. Hız 300 ise karakter çapraz giderken saniyede yaklaşık 424 birim hızla gider, yani köşegen hareket kendiliğinden daha hızlı olur.

Çözüm, yön vektörünü normalleştirmektir: yönü korur, uzunluğunu 1'e sabitler. Elle yazman gerekirse direction.normalized() tam bunu yapar. Input.get_vector() ise dönen vektörün uzunluğunu zaten 1 ile sınırlar. Bu yüzden önceki bölümdeki kodda köşegen harekette ek bir hız artışı olmaz.

Mini deney: Hızı ekrana yazdırıp kendin sına. _physics_process içine tek satır ekle:

func _physics_process(delta):
    var direction = Input.get_vector("sol", "sag", "yukari", "asagi")
    velocity = direction * speed
    print(velocity.length())
    move_and_slide()

Karakter dururken Output panelinde 0 görürsün. Tek yöne giderken de, iki tuşa basıp köşegene giderken de çıktı yaklaşık speed değerini verir (hız 300 ise 300 civarı). Köşegende 424 görürsen yön vektörünü kendin üretiyorsun demektir.

Karakter hareket etmiyorsa kontrol edilecek noktalar

Önce doğru sahnenin çalıştığından emin ol: ana sahne ayarını kontrol et ve Çalıştır tuşuyla karakter sahnesinin açıldığını gör. Sonra şu üç noktaya bak:

  1. Eylem adları eşleşiyor mu? Belirti: karakter hiç kıpırdamaz ya da Output panelinde eylemle ilgili hata çıkar. Input Map'teki adla koddaki dizgeyi harf harf karşılaştır; "sag" ile "sağ" farklı adlardır, büyük ve küçük harf de ayrımı bozar.
  2. Script doğru düğümde mi, fonksiyon adı doğru mu? Belirti: kod hata vermez ama hiçbir şey olmaz. Script'in kök CharacterBody2D düğümüne bağlı olduğunu Sahne panelinde script simgesinden doğrula; fonksiyonun adı da tam olarak _physics_process olmalı.
  3. CollisionShape2D hazır mı? Belirti: karakter hareket eder ama engelleri geçer, ya da editörde uyarı çıkar. Düğümün CharacterBody2D'nin çocuğu olduğunu ve Inspector'da bir şekil (Shape) atandığını kontrol et.

Hâlâ sonuç yoksa sorunu ikiye böl. Output panelindeki kırmızı hata satırını oku; satır numarası genellikle doğrudan ilgili koda götürür. Hata yoksa direction değişkenini hesapladıktan hemen sonra print(direction) yaz. Tuşa basınca ekranda (0, 0) dışında bir değer görüyorsan giriş katmanı çalışıyordur ve sorun fizik tarafındadır; hep (0, 0) görüyorsan Input Map ve eylem adlarına dön.

Bu, hata ayıklamanın genel mantığıdır: büyük bir "çalışmıyor" sorununu küçük, test edilebilir adımlara bölmek. Bu beceriyi dilden bağımsız ölçmek istersen ücretsiz algoritmik düşünme testi ile seviyene bakabilirsin.

Prototipi bir sonraki adımda nasıl genişletirsin?

Elindeki karakter dört yöne hareket ediyor. Aynı projeden çıkmadan, her biri birkaç dakikalık üç küçük deneyle devam edebilirsin.

  1. Hız değerini koddaki sabit sayıdan çıkarıp @export var speed satırıyla tanımla; böylece değeri Inspector panelinden, kodu açmadan değiştirirsin.
  2. Yatay yöne göre Sprite2D'nin flip_h özelliğini ayarla; karakter sola giderken görseli ters dönsün.
  3. Sahneye bir StaticBody2D ekle, altına bir CollisionShape2D koyup şekil ata ve karakteri duvara doğru yürüt.

Üçüncü deneyde beklenen sonuç şudur: karakter duvara dayandığında duvarın içinden geçmez, duvara çapraz yaklaşırsan duvar boyunca kayabilir. Bunu move_and_slide() çarpışma sonrası hareketi kalan yöne doğru uzattığı için görürsün. Oyun geliştirme ve diğer yazılım konularında yeni başlıyorsan blog arşivindeki yazılara da göz atabilirsin.

Sık Sorulan Sorular

Godot'ta karakterim neden duvarın içinden geçiyor?

Önce hem karakterde hem duvarda bir CollisionShape2D bulunduğunu ve ikisine de şekil atandığını kontrol et. Sonra karakteri position değerini doğrudan değiştirerek mi yoksa velocity ile move_and_slide() kullanarak mı hareket ettirdiğine bak; konumu doğrudan değiştirmek çarpışma denetimini atlar. Son olarak iki nesnenin çarpışma katmanı (layer) ve maskesi (mask) ayarlarının birbiriyle eşleştiğinden emin ol.

Hareket hızını editörden nasıl değiştiririm?

Script'in başında @export var speed = 300.0 gibi bir değişken tanımla. Script'i kaydettikten sonra karakter düğümünü seçtiğinde bu değişken Inspector panelinde görünür ve oradan değiştirebilirsin.

Godot'ta karakter hareketi için _process mi _physics_process mi kullanılmalı?

Çarpışma ve move_and_slide() içeren hareket için _physics_process uygundur. Bu fonksiyon fizik motoruyla uyumlu, sabit aralıklarla çağrılır; _process ise çoğunlukla görsel ve arayüz güncellemeleri için kullanılır.

Bu mini projeyle sahne ağacı, Input Map ve velocity mantığını bir arada çalıştırdın. Bundan sonra yeni bir özellik eklerken aynı sırayı izleyebilirsin: önce küçük bir deney kur, sonra davranışı gözlemle.

Bu içerik aradığın cevabı verdi mi?
Yanıtın, hangi yazıları geliştirmemiz gerektiğini anlamamıza yardımcı olur.
Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

Bu konudan sonra ne okuyabilirsin?

Tüm yazılar

İlgili Eğitimler

Berk Keskin, yazılım geliştirici ve eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; İzmir Ekonomi Üniversitesi'ni bölüm birincisi ve yüksek şeref öğrencisi olarak tamamladı. Bugün yalnızca eğitim vermekle kalmıyor, sektörde aktif olarak yazılım projeleri geliştiriyor ve gerçek dünya deneyimini birebir derslerine taşıyor. Ezberden uzak, mühendislik zihniyetini merkeze alan sürdürülebilir öğrenme sistemleri tasarlayarak sorgulayan, üreten ve problem çözebilen yeni nesil yazılımcılar yetiştiriyor.

Sektörel Deneyim & Projeler

  • Ticarify Entegrasyon Yazılım logosu CEO Ticarify Entegrasyon YazılımPazaryerleri ve e-ticaret sitelerine otomatik e-fatura kesimi, sipariş ve kargo takibi hizmetleri sunan e-Dönüşüm platformunun API mimarisini ve yazılım ekibini yönetmektedir.
  • Benim Düğünüm logosu CEO Benim DüğünümDijital etkinlik ve anı paylaşım platformu.
  • Siberdizayn logosu Yazılım Ekibi Lideri SiberdizaynYüksek anlık oyuncu trafiğine sahip oyun kontrol panelleri ve sunucu altyapıları geliştiren yazılım ekibine liderlik etmektedir.
  • MEDYOGRAFYA 360° Dijital Çözümler logosu Dijital Strateji Lideri MEDYOGRAFYA 360° Dijital ÇözümlerŞirketlerin dijital çözümlerde uzun vadede nasıl ilerlemesi gerektiği ve dijital dönüşüm süreçlerinin yönetilmesine destek olmaktadır.
  • İzmir Ekonomi Üniversitesi logosu Danışma Kurulu Üyesi İzmir Ekonomi ÜniversitesiMezun olduğu üniversitesinde, Bilgisayar Programcılığı bölümünün akademik müfredatını güncel sektör ihtiyaçlarına göre şekillendirmek adına Danışma Kurulu'nda görev almaktadır.
WhatsApp Hemen Ara