Unity’de Giriş Tuşlarını Yeniden Atama ve Kontrolcü Desteği

Unity'nin yeni Input System paketi ile oyun içi tuşları yeniden atamayı ve çeşitli kontrolcüleri sorunsuz entegre etmeyi öğrenin. Kapsamlı rehber ve ipuçları.

Modern oyun geliştirme, oyunculara esneklik sunmayı gerektirir. Bu esnekliğin başında, oyun içi kontrolleri kendi tercihlerine göre ayarlayabilme, yani tuşları yeniden atayabilme (Unity Input Rebinding) ve farklı kontrolcü türlerini sorunsuz kullanabilme yeteneği gelir. Unity’nin eski giriş sistemi (Legacy Input Manager) bu konuda yetersiz kalırken, yeni Input System paketi, bu ihtiyaçları çok daha modern ve güçlü bir şekilde karşılamaktadır. Bu makalede, Unity’nin yeni Input System’ini kullanarak tuşları nasıl yeniden atayacağınızı, kontrolcü desteğini nasıl yöneteceğinizi ve bu süreçteki en iyi pratikleri öğreneceksiniz.

Giriş: Neden Yeni Input System?

Unity’nin eski giriş sistemi, basit projeler için yeterli olsa da, modern oyunların karmaşık ihtiyaçlarını karşılamakta zorlanıyordu. Özellikle çoklu platform desteği, gamepad’ler, dokunmatik ekranlar ve VR kontrolcüleri gibi farklı giriş cihazlarının yönetimi, eski sistemle oldukça zahmetliydi. Yeni Input System paketi ise bu sorunlara kökten bir çözüm getiriyor. İşte bazı temel avantajları:

  • Cihaz Agnostik: Klavye, fare, gamepad, dokunmatik ekran veya özel kontrolcüler fark etmeksizin tüm girişleri tutarlı bir şekilde işler.
  • Aksiyon Tabanlı: Tuş basımından ziyade, “Zıpla”, “Ateş Et” gibi aksiyonlar üzerinden çalışır. Bu, kontrol şemalarını değiştirmeyi kolaylaştırır.
  • Asenkron ve Olay Tabanlı: Girişleri olaylar (events) aracılığıyla işleyerek daha performanslı ve tepkisel bir deneyim sunar.
  • Gelişmiş Rebinding: Tuşları yeniden atama (Unity Input Rebinding) ve kontrol şemalarını özelleştirme için güçlü araçlar sağlar.
  • Çoklu Oyuncu Desteği: Aynı anda birden fazla kontrolcüyü ve oyuncuyu kolayca yönetme imkanı sunar.

Input System Kurulumu ve Temelleri

Yeni Input System’i kullanmaya başlamak için öncelikle paketi projenize eklemeniz gerekir:

  1. Unity editöründe Window > Package Manager yolunu izleyin.
  2. Paket yöneticisinde Unity Registry seçeneğini seçin.
  3. Input System paketini bulun ve Install düğmesine tıklayın.
  4. Kurulum tamamlandığında, Unity sizden eski giriş sistemini devre dışı bırakıp yeni sistemi etkinleştirmek isteyip istemediğinizi soracaktır. Bu soruyu kabul edin.

Input Actions Varlığı Oluşturma

Input System’in kalbi, Input Actions varlıklarıdır. Bu varlıklar, oyununuzdaki tüm giriş aksiyonlarını, bunlara atanmış tuşları (bindings) ve kontrol şemalarını (control schemes) tanımlar.

  1. Proje penceresinde sağ tıklayın: Create > Input Actions.
  2. Yeni oluşturulan varlığa çift tıklayarak Input Actions düzenleyicisini açın.
  3. Burada Action Maps (örn: “Player”), Actions (örn: “Move”, “Jump”) ve bu aksiyonlara atanmış Bindings (örn: “W” tuşu, “Space” tuşu) tanımlayabilirsiniz.

Her aksiyon için bir Action Type (örn: Button, Value, Pass-Through) ve beklenen bir Control Type (örn: Vector2, Float) belirlemeniz önemlidir. Örneğin, “Move” aksiyonu genellikle bir Value aksiyonu ve Vector2 kontrol tipi olurken, “Jump” aksiyonu bir Button aksiyonu ve Button kontrol tipi olacaktır.

PlayerInput Bileşeni

Bir GameObject’in girişleri işlemesi için ona PlayerInput bileşenini ekleyebilirsiniz. Bu bileşen, oluşturduğunuz Input Actions varlığına referans verir ve aksiyonları kodunuzda dinlemek için kullanabileceğiniz olayları (events) sağlar.

using UnityEngine; 
using UnityEngine.InputSystem; 

public class PlayerController : MonoBehaviour 
{
    private PlayerInput playerInput;
    private InputAction moveAction;
    private InputAction jumpAction;

    void Awake()
    {
        playerInput = GetComponent<PlayerInput>();
        moveAction = playerInput.actions.FindAction("Move");
        jumpAction = playerInput.actions.FindAction("Jump");

        moveAction.performed += OnMove;
        jumpAction.performed += OnJump;
    }

    void OnMove(InputAction.CallbackContext context)
    {
        Vector2 inputVector = context.ReadValue<Vector2>();
        Debug.Log("Hareket: " + inputVector);
    }

    void OnJump(InputAction.CallbackContext context)
    {
        Debug.Log("Zıplama!");
    }

    void OnEnable()
    {
        playerInput.actions.Enable();
    }

    void OnDisable()
    {
        playerInput.actions.Disable();
    }
}

Unity Input Rebinding: Tuşları Yeniden Atama

Oyuncuların tuşları yeniden atayabilmesi, modern oyunların vazgeçilmez bir özelliğidir. Unity Input System, bu süreci oldukça kolaylaştırır. Temel olarak, bir aksiyonun belirli bir binding’ini interaktif olarak değiştirmek için InputActionRebindingExtensions.PerformInteractiveRebinding() metodunu kullanırız.

İnteraktif Rebinding Uygulaması

Bir tuşu yeniden atamak için aşağıdaki adımları izleyebilirsiniz:

  1. Yeniden atanacak binding’i belirleyin. Bu, bir InputAction içindeki belirli bir InputBinding objesi olabilir.
  2. PerformInteractiveRebinding() metodunu çağırın. Bu metod, kullanıcının yeni bir giriş yapmasını bekleyen bir işlem başlatır.
  3. Kullanıcı bir giriş yaptığında, metod bu girişi yakalar ve binding’in overridePath özelliğini günceller.
using UnityEngine; 
using UnityEngine.InputSystem; 
using UnityEngine.UI; 

public class RebindingManager : MonoBehaviour 
{
    public InputActionAsset actionsAsset;
    public Text bindingDisplayText;
    public Button rebindButton;

    private InputAction rebindAction;
    private int bindingIndex;

    void Start()
    {
        // Yeniden atamak istediğimiz aksiyonu ve binding'i bulalım.
        // Örnek: "Player" action map'indeki "Jump" aksiyonunun ilk binding'i.
        rebindAction = actionsAsset.FindActionMap("Player").FindAction("Jump");
        bindingIndex = rebindAction.bindings.IndexOf(x => x.action == rebindAction.id.ToString());

        UpdateBindingDisplay();
        rebindButton.onClick.AddListener(StartRebind);
    }

    void UpdateBindingDisplay()
    {
        if (rebindAction != null && bindingIndex != -1)
        {
            // Mevcut binding yolunu veya geçersiz kılınmış yolu göster.
            bindingDisplayText.text = InputBindingResolver.ResolveBindingPath(rebindAction, bindingIndex);
        }
    }

    public void StartRebind()
    {
        rebindButton.interactable = false;
        bindingDisplayText.text = "Bekleniyor...";

        rebindAction.PerformInteractiveRebinding(bindingIndex)
            .WithCancelingThrough<Keyboard>() // ESC ile iptal etme
            .WithCancelingThrough<Gamepad>() // Gamepad ile iptal etme
            .OnComplete(operation => 
            {
                operation.Dispose();
                rebindButton.interactable = true;
                UpdateBindingDisplay();
                SaveRebinds(); // Rebinding'i kaydet
            })
            .OnCancel(operation =>
            {
                operation.Dispose();
                rebindButton.interactable = true;
                UpdateBindingDisplay();
            })
            .Start();
    }

    // Rebinding verilerini kaydetme (örnek: PlayerPrefs kullanarak)
    private void SaveRebinds()
    {
        string rebinds = rebindAction.SaveBindingOverridesAsJson();
        PlayerPrefs.SetString("rebinds_jump", rebinds);
        PlayerPrefs.Save();
        Debug.Log("Rebinding kaydedildi: " + rebinds);
    }

    // Rebinding verilerini yükleme
    private void LoadRebinds()
    {
        if (PlayerPrefs.HasKey("rebinds_jump"))
        {
            string rebinds = PlayerPrefs.GetString("rebinds_jump");
            rebindAction.LoadBindingOverridesFromJson(rebinds);
            Debug.Log("Rebinding yüklendi: " + rebinds);
            UpdateBindingDisplay();
        }
    }

    // Bu metodu Start() içinde veya uygun bir yerde çağırın
    void Awake()
    {
        // ... (playerInput ve aksiyonları tanımlama)
        LoadRebinds();
    }
}

// Binding yolunu daha okunabilir hale getirmek için yardımcı sınıf
public static class InputBindingResolver
{
    public static string ResolveBindingPath(InputAction action, int bindingIndex)
    {
        if (action == null || bindingIndex < 0 || bindingIndex >= action.bindings.Count)
        {
            return "N/A";
        }
        var binding = action.bindings[bindingIndex];
        string path = action.GetBindingDisplayString(bindingIndex);

        // Gamepad özel tuşları için daha iyi isimler
        if (binding.path.Contains("gamepad"))
        { 
            if (path.Contains("buttonSouth")) return "Gamepad A";
            if (path.Contains("buttonEast")) return "Gamepad B";
            if (path.Contains("buttonWest")) return "Gamepad X";
            if (path.Contains("buttonNorth")) return "Gamepad Y";
            if (path.Contains("leftTrigger")) return "Gamepad LT";
            if (path.Contains("rightTrigger")) return "Gamepad RT";
            if (path.Contains("leftShoulder")) return "Gamepad LB";
            if (path.Contains("rightShoulder")) return "Gamepad RB";
            if (path.Contains("leftStick")) return "Gamepad Sol Çubuk";
            if (path.Contains("rightStick")) return "Gamepad Sağ Çubuk";
            if (path.Contains("dpad")) return "Gamepad Yön Tuşları";
        }
        return path;
    }
}

Yukarıdaki örnekte, SaveBindingOverridesAsJson() ve LoadBindingOverridesFromJson() metotları, tüm binding geçersiz kılmalarını bir JSON dizesi olarak kaydetmenizi ve yüklemenizi sağlar. Bu, Unity Input Rebinding verilerini kalıcı hale getirmek için kritik öneme sahiptir.

Kontrolcü Desteği ve Çoklu Oyuncu

Input System, kontrolcüleri otomatik olarak algılar ve yönetir. Klavyeden farklı olarak, gamepad’ler genellikle birden fazla oyuncu tarafından kullanılabilir. Input System, bu senaryoyu InputUser ve PlayerInputManager bileşenleri aracılığıyla kolayca yönetmenizi sağlar.

PlayerInputManager ile Çoklu Oyuncu

PlayerInputManager, otomatik olarak yeni kontrolcüler algıladığında yeni oyuncular oluşturabilir ve bunlara PlayerInput bileşenleri atayabilir. Bu, yerel çok oyunculu oyunlar için idealdir.

  1. Boş bir GameObject oluşturun ve ona PlayerInputManager bileşenini ekleyin.
  2. PlayerInputManager bileşeninde, oyuncu prefab’inizi (üzerinde PlayerInput bileşeni olan) Player Prefab alanına atayın.
  3. Join Behavior ayarını (örn: JoinPlayersWhenButtonIsPressed) ve Joining Device Limit gibi diğer ayarları yapılandırın.

Artık yeni bir gamepad bağlandığında veya belirlenen bir tuşa basıldığında, PlayerInputManager otomatik olarak yeni bir oyuncu örneği oluşturacak ve ona uygun kontrolcüyü atayacaktır.

Cihaza Özel Bağlamalar (Device-Specific Bindings)

Bazen belirli bir cihaz türü için farklı tuş atamaları yapmak isteyebilirsiniz. Input System, Control Schemes ve binding’lerdeki device-specific yollar ile bunu destekler. Örneğin, bir binding’i sadece klavye için veya sadece Xbox kontrolcüsü için tanımlayabilirsiniz.

Pratik İpuçları

  1. Görsel Geri Bildirim: Rebinding işlemi sırasında oyuncuya hangi tuşa basması gerektiğini veya işlemin iptal edildiğini gösteren net görsel ve metinsel geri bildirimler sağlayın. Örneğin, “Yeni tuşa basın…” veya “İptal edildi” gibi mesajlar kullanın.
  2. Çakışan Tuş Atamalarını Yönetme: Bir tuşun zaten başka bir aksiyona atanmış olup olmadığını kontrol etmek ve oyuncuyu uyarmak, iyi bir kullanıcı deneyimi için önemlidir. `InputBinding` objelerinin path özelliklerini karşılaştırarak bu kontrolü yapabilirsiniz. Ancak, Input System paketi, çakışan bağlamaları doğrudan yöneten bir mekanizma sunmaz; bu genellikle oyun geliştiricisinin sorumluluğundadır.
  3. Varsayılan Ayarlara Dönme: Oyunculara istedikleri zaman varsayılan tuş atamalarına geri dönme seçeneği sunun. Bunu, kaydedilmiş override’ları temizleyerek (rebindAction.RemoveAllBindingOverrides()) ve ardından oyunun ilk halindeki binding’leri yeniden yükleyerek yapabilirsiniz.

Yaygın Hatalar ve Çözümleri

  1. Input Actions Varlığını Etkinleştirmeyi Unutmak: Aksiyonlarınızın çalışmadığını fark ederseniz, playerInput.actions.Enable() veya belirli bir aksiyon haritası için actionMap.Enable() metodunu çağırdığınızdan emin olun. Genellikle bu, OnEnable() metodunda yapılır.
  2. Yanlış Control Type Seçimi: Bir aksiyon için yanlış Control Type (örn: bir düğme için Vector2) seçmek, girişlerin doğru okunmamasına neden olabilir. Aksiyonunuzun beklediği veri tipine uygun Control Type seçtiğinizden emin olun.
  3. UI Navigasyonunda Sorunlar: Kontrolcülerle UI elementlerinde gezinmek için EventSystem‘in doğru şekilde yapılandırıldığından emin olun. Genellikle Standalone Input Module yerine Input System UI Input Module kullanmanız gerekir.
  4. Rebinding Verilerini Kaydetmemek: Oyuncunun yaptığı tuş atamalarının oyun kapatıldığında kaybolduğunu fark ederseniz, SaveBindingOverridesAsJson() ve LoadBindingOverridesFromJson() metotlarını kullanarak bu verileri kalıcı olarak kaydettiğinizden ve yüklediğinizden emin olun. Bu, Unity Input Rebinding deneyiminin sürekliliği için hayati öneme sahiptir.

Performans ve Optimizasyon Notları

Yeni Input System, eski sisteme göre daha performanslıdır çünkü girişleri daha verimli bir şekilde işler ve gereksiz sorgulamalardan kaçınır. İşte bazı optimizasyon ipuçları:

  • Olay Tabanlı Yaklaşım: Mümkün olduğunca Update() döngüsünde sürekli giriş sorgulamak yerine, aksiyonların performed, started ve canceled olaylarını kullanın. Bu, sadece giriş olduğunda kodunuzun çalışmasını sağlar.
  • Gereksiz Aksiyonları Devre Dışı Bırakma: Bir aksiyon haritası (Action Map) veya belirli bir aksiyon, o anda kullanılmıyorsa (örn: oyun duraklatıldığında veya menüdeyken), bunları Disable() metodu ile devre dışı bırakın. Bu, Input System’in işleyeceği giriş miktarını azaltır.
  • Tek PlayerInput Yöneticisi: Çoklu oyuncu senaryolarında, PlayerInputManager‘ı tek bir yerde yönetmek, giriş akışını merkezileştirir ve potansiyel performans sorunlarını azaltır.

Sonuç

Unity’nin yeni Input System paketi, modern oyunların giriş yönetimi ihtiyaçlarını karşılamak için güçlü ve esnek bir çözüm sunar. Unity Input Rebinding özelliği sayesinde oyunculara kontrol şemalarını özelleştirme imkanı tanımak, kullanıcı deneyimini önemli ölçüde artırır. Bu makalede ele aldığımız temel kurulum, aksiyon tanımlama, interaktif tuş atama, kontrolcü desteği ve pratik ipuçları ile kendi Unity projelerinizde gelişmiş giriş sistemleri oluşturmaya hazırsınız. Unutmayın, iyi tasarlanmış bir giriş sistemi, oyununuzun erişilebilirliğini ve keyfini artırmanın anahtarıdır.

Leave a Reply

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir