Unity 2D Oyun Geliştirme: Karakter Hareket Mantığı
Unity ile 2D oyun geliştirirken en temel ihtiyaçlardan biri karakter kontrolü kurmaktır. Oyuncunun “sağa sola yürümesi” basit gibi görünse de, yanlış kurulan bir hareket sistemi ileride çarpışma problemleri, kayma hissi, zıplama tutarsızlığı ve mobilde FPS dalgalanmaları gibi birçok sorunu beraberinde getirebilir.
2D tarafta en sağlıklı yaklaşım genellikle Rigidbody2D bileşeni ile fizik tabanlı bir hareket sistemi kurmaktır. Böylece Unity’nin fizik motoru (Collider2D, friction, gravity, slope davranışları) ile uyumlu, daha doğal ve akıcı bir kontrol elde edersiniz.
Hedef: Akıcı, Tutarlı ve Fizikle Uyumlu Hareket
İyi bir karakter hareket mantığı şu üç şeye odaklanır:
- Doğru input okuma: Klavye, gamepad, mobil joystick gibi farklı kaynaklarla uyum.
- Fizikle uyum: Çarpışmaların bozulmaması, duvarlardan geçmeme, kayma/itme davranışlarının tutarlı olması.
- Zamanlama: Input okuma ile fizik güncellemesini doğru yerde yapmak (Update / FixedUpdate).
1) Input System Kullanımı
Unity’nin yeni Input System paketi; klavye-mouse, gamepad, mobil dokunmatik ve konsol uyumluluğu açısından daha güçlüdür. Tek bir “Action” tanımıyla farklı cihazlardan gelen input’ları yönetebilirsiniz. Ayrıca rebinding (tuş değiştirme), deadzone ayarları ve çoklu kontrol şemaları gibi özellikler büyük projelerde ciddi avantaj sağlar.
Buna rağmen hızlı prototiplerde veya eğitim amaçlı örneklerde Input.GetAxis("Horizontal") hâlâ iş görür. Önemli olan, projenin ölçeğine göre doğru yaklaşımı seçmektir:
- Prototip / Jam: Input Manager (GetAxis) hızlıdır.
- Ürünleşecek proje: Yeni Input System daha sürdürülebilirdir.
Basit Prototip: Input.GetAxis ile Yatay Hareket
using UnityEngine;
public class PlayerInputOld : MonoBehaviour
{
public float moveX;
void Update()
{
moveX = Input.GetAxis("Horizontal"); // -1 ile +1 arası değer
}
}
Burada dikkat: Input okuma genelde Update içinde yapılır, çünkü Update frame ile senkron çalışır ve input kaçırma ihtimali düşer. Ancak fiziği etkileyecek uygulamalar (velocity gibi) FixedUpdate içinde yapılmalıdır.
2) Fizik vs Transform
Karakteri transform.Translate veya transform.position ile hareket ettirmek ilk başta kolay görünür. Fakat bu yöntem “fizik motorunu bypass” ettiği için iki tip sorun çıkarır:
- Işınlanma hissi: Özellikle hızlı hareketlerde karakter “kayarak/atlayarak” gider.
- Çarpışma tutarsızlığı: Collider2D ile çakışmalar, duvara gömülme veya tünelleme görülebilir.
Bu nedenle Rigidbody2D kullanıyorsanız hareketi fizik üzerinden vermek daha doğrudur. 2D platformer gibi oyunlarda en yaygın iki yaklaşım şunlardır:
- rb.velocity ile kontrol (hız bazlı, basit ve stabil)
- rb.AddForce ile kontrol (daha “ağır” his, ivmelenme isteyen oyunlar)
Neden rb.velocity Daha Sağlıklıdır?
Çünkü velocity ile karakterin hedef hızını net olarak belirlersiniz. Bu da kontrol hissini iyileştirir. Aynı zamanda çarpışmalar ve sürtünme gibi fizik etkileşimleri “doğal” şekilde çalışır.
Örnek: Rigidbody2D ile Basit 2D Yürüyüş Sistemi
Aşağıdaki örnek, input’u Update’de okur, fizik uygulamasını FixedUpdate’de yapar ve hareketi velocity üzerinden verir. Bu yapı çoğu 2D oyunda sağlam bir başlangıçtır.
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerMovement2D : MonoBehaviour
{
[Header("Movement")]
public float moveSpeed = 6f;
private Rigidbody2D rb;
private float moveInput;
void Awake()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
// Input okuma (frame bazlı)
moveInput = Input.GetAxisRaw("Horizontal"); // -1, 0, 1 (daha keskin kontrol)
}
void FixedUpdate()
{
// Fizik uygulama (fixed timestep)
rb.velocity = new Vector2(moveInput * moveSpeed, rb.velocity.y);
}
}
GetAxis mı GetAxisRaw mı?
GetAxis: yumuşatılmış değer verir (0.2, 0.5 gibi ara değerler) → daha “analog” his.GetAxisRaw: direkt -1/0/1 verir → platformer oyunlarda daha “keskin” kontrol.
Yeni Input System ile Hareket Mantığı (Genel Yaklaşım)
Yeni Input System’de amaç, bir Input Action üzerinden “Move” gibi bir aksiyon tanımlamaktır. Örneğin Move aksiyonu Vector2 döndürür (x: yatay, y: dikey) ve siz buradan x değerini alarak yürüyüşü yönetirsiniz.
Basit bir mantık şudur:
- Move action tetiklendikçe input değerini güncelle
- FixedUpdate’de rb.velocity ile uygula
(Not: Yeni Input System örneğini proje yapınıza göre “PlayerInput” bileşeni veya “InputActionAsset” üzerinden iki farklı şekilde kurabilirsiniz. İsterseniz buraya özel, adım adım kurulumlu bir örnek de ekleyebilirim.)
Hareket Kalitesini Artıran Küçük Ama Etkili Detaylar
1) Rigidbody2D Ayarları
- Interpolation: Hareket titriyorsa Interpolate açmak görsel akıcılığı artırır.
- Collision Detection: Hızlı karakterlerde “Continuous” işe yarayabilir (özellikle tünelleme varsa).
- Constraints: 2D karakterin dönmesini istemiyorsanız Z Rotation’ı dondurun.
2) Sürtünme (Friction) Kontrolü
Bazı platformer oyunlarda karakterin durması “kayarak” olur. Bunu düzeltmek için Physics Material 2D ile friction ayarı yapabilir veya dururken velocity’yi daha agresif sıfırlayabilirsiniz.
3) Zemin Üstünde mi? (Ground Check)
Zıplama, koşma, kayma gibi mekanikler ekleyecekseniz bir ground check sistemi şarttır. Bu yazıda yürüyüşe odaklandık ama ileride zıplama eklerken bu kontrol kritik hale gelir.
Sonuç
Unity 2D oyunlarda karakter hareket mantığını doğru kurmak, oyunun “hissiyatını” belirleyen en temel adımdır. Input tarafında yeni Input System uzun vadede daha güçlü bir seçenek olsa da, hareketin fizik motoruyla uyumlu olması için en önemli nokta şudur: Transform ile değil, Rigidbody2D üzerinden (özellikle rb.velocity) hareket ettirin.