Unity Editor’da Selection.objects ile Çoklu Seçim Yönetimi

Unity Editor'da birden fazla obje üzerinde işlem yapmak için Selection.objects nasıl kullanılır? Gelişmiş Editor araçları ve otomasyon ipuçlarını keşfedin.

Unity Editor’da Selection.objects ile Çoklu Seçim Yönetimi

Unity geliştiricileri olarak, Editor içinde tekrarlayan görevleri otomatikleştirmek ve iş akışımızı hızlandırmak isteriz. Özellikle sahnede veya proje penceresinde birden fazla obje üzerinde aynı anda işlem yapmamız gerektiğinde bu otomasyon hayati önem taşır. İşte tam da bu noktada Unity’nin `Selection` sınıfı ve özellikle `Selection.objects` özelliği devreye girer. Bu makalede, Unity çoklu seçim işlemleri için `Selection.objects`’ı derinlemesine inceleyecek, nasıl kullanılacağını, pratik ipuçlarını, yaygın hataları ve performans optimizasyonlarını öğreneceksiniz.

Selection Sınıfı ve Temelleri

Unity Editor’da herhangi bir obje seçtiğinizde, bu seçili objelere `UnityEditor.Selection` sınıfı aracılığıyla erişebilirsiniz. Bu sınıf, Editor penceresinde (Hierarchy, Project) o an seçili olan objeler hakkında bilgi sağlar. Genellikle tek bir objeye odaklanmak için `Selection.activeGameObject` veya `Selection.activeObject` kullanılırken, birden fazla objeyi hedeflemek için `Selection.objects` veya `Selection.gameObjects` gibi özellikler tercih edilir.

Selection.objects Nedir?

`Selection.objects`, Editor’da seçili olan tüm objeleri içeren bir `Object[]` dizisi döndürür. Bu, sahnede seçili olan `GameObject`’lerden, proje penceresinde seçili olan `Material`, `Texture`, `ScriptableObject` gibi Asset’lere kadar her şeyi kapsar. `Object` temel sınıfı olduğu için, bu dizi farklı türdeki objeleri bir arada tutabilir. Bu özelliği, çok çeşitli Editor araçları geliştirmek için inanılmaz derecede esneklik sağlar.

Örneğin, seçili tüm objelerin adlarını konsola yazdırmak için basit bir Editor script’i şöyle yazılabilir:

using UnityEditor;
using UnityEngine;

public class SelectionInfoTool : EditorWindow
{
    [MenuItem("Tools/Selection Info")]
    public static void ShowWindow()
    {
        GetWindow("Selection Info");
    }

    void OnGUI()
    {
        GUILayout.Label("Seçili Objeler:", EditorStyles.boldLabel);
        if (Selection.objects.Length == 0)
        {
            GUILayout.Label("Hiç obje seçili değil.");
        }
        else
        {
            foreach (Object obj in Selection.objects)
            {
                GUILayout.Label($"- {obj.name} ({obj.GetType().Name})");
            }
        }
    }
}

Bu kod bloğu, seçili olan her objenin adını ve türünü bir Editor penceresinde listeler. Bu sayede Unity çoklu seçim özelliğinin temel kullanımını görebilirsiniz.

Selection.gameObjects ve Selection.transforms

Bazı durumlarda, sadece sahnede bulunan `GameObject`’ler veya onların `Transform` bileşenleri üzerinde işlem yapmak isteyebilirsiniz. `Selection` sınıfı bu senaryolar için daha spesifik özellikler sunar:

  • `Selection.gameObjects`: Sadece sahnede seçili olan `GameObject`’leri içeren bir `GameObject[]` dizisi döndürür. Proje penceresindeki Asset’leri içermez.
  • `Selection.transforms`: Sahnede seçili olan `GameObject`’lerin `Transform` bileşenlerini içeren bir `Transform[]` dizisi döndürür.

Bu özellikler, özellikle sahne manipülasyonu yapan Editor araçları için çok daha kullanışlıdır. Örneğin, seçili tüm `GameObject`’lerin pozisyonunu sıfırlamak için `Selection.transforms` kullanmak daha doğrudan bir yaklaşımdır:

using UnityEditor;
using UnityEngine;

public class ResetPositionTool
{
    [MenuItem("Tools/Reset Selected Positions")]
    public static void ResetPositions()
    {
        if (Selection.transforms.Length == 0)
        {
            Debug.LogWarning("Pozisyonu sıfırlanacak GameObject seçili değil.");
            return;
        }

        foreach (Transform t in Selection.transforms)
        {
            Undo.RecordObject(t, "Reset Position"); // Geri alma desteği için
            t.position = Vector3.zero;
            EditorUtility.SetDirty(t); // Değişiklikleri kaydetmek için
        }
        Debug.Log($"{Selection.transforms.Length} adet GameObject'in pozisyonu sıfırlandı.");
    }
}

Gelişmiş Çoklu Seçim İşlemleri

Unity çoklu seçim yeteneklerini daha da geliştirmek için `Selection.GetFiltered` metodunu kullanabiliriz. Bu metod, belirli bir türdeki objeleri veya belirli bayraklara sahip objeleri filtrelemek için harikadır.

Selection.GetFiltered Kullanımı

`Selection.GetFiltered(System.Type type, SelectionMode mode)` metodu, seçili objeler arasından sadece belirtilen `type`’a uyanları döndürür. `SelectionMode` ise aramanın kapsamını belirler (örn: `Assets`, `Deep`, `ExcludePrefab`).

Örneğin, seçili objeler arasından sadece `MeshRenderer` bileşenine sahip olanları bulup renklerini değiştirmek isteyebilirsiniz:

using UnityEditor;
using UnityEngine;

public class ChangeMeshColorTool
{
    [MenuItem("Tools/Change Selected Mesh Color/To Red")]
    public static void ChangeToRed()
    {
        ChangeColor(Color.red);
    }

    [MenuItem("Tools/Change Selected Mesh Color/To Blue")]
    public static void ChangeToBlue()
    {
        ChangeColor(Color.blue);
    }

    private static void ChangeColor(Color newColor)
    {
        Object[] selectedRenderers = Selection.GetFiltered(typeof(MeshRenderer), SelectionMode.ExcludePrefab);

        if (selectedRenderers.Length == 0)
        {
            Debug.LogWarning("Hiç MeshRenderer'a sahip obje seçili değil.");
            return;
        }

        foreach (MeshRenderer renderer in selectedRenderers)
        {
            if (renderer.sharedMaterial != null)
            {
                Undo.RecordObject(renderer.sharedMaterial, "Change Material Color");
                renderer.sharedMaterial.color = newColor;
                EditorUtility.SetDirty(renderer.sharedMaterial);
            }
        }
        Debug.Log($"{selectedRenderers.Length} adet MeshRenderer'ın rengi {newColor} olarak değiştirildi.");
    }
}

Bu örnek, `Selection.GetFiltered` kullanarak sadece `MeshRenderer` bileşenine sahip `GameObject`’leri hedef alıyor ve prefab’leri dışarıda bırakıyor. Bu sayede istenmeyen değişikliklerin önüne geçilmiş olur.

Pratik İpuçları

  1. Undo Sistemi Entegrasyonu: Editor araçları geliştirirken, kullanıcıların yanlışlıkla yaptıkları değişiklikleri geri alabilmelerini sağlamak çok önemlidir. `Undo.RecordObject(object, name)` veya `Undo.RegisterCompleteObjectUndo(object, name)` metodlarını kullanarak Unity’nin geri alma sistemine entegre olun. Herhangi bir objede değişiklik yapmadan önce bu metotları çağırmayı unutmayın.

    // Örnek: Pozisyon değişikliğini geri alınabilir yapma
    Undo.RecordObject(myGameObject.transform, "Move GameObject");
    myGameObject.transform.position += Vector3.up;
  2. Editor Menüsüne Ekleme (`[MenuItem]`): Geliştirdiğiniz araçlara kolayca erişmek için `[MenuItem(“Path/To/Your/Tool”)]` niteliğini kullanın. Bu, Unity Editor’ın üst menüsüne özel seçenekler eklemenizi sağlar ve iş akışınızı büyük ölçüde hızlandırır. Yukarıdaki örneklerde gördüğünüz gibi, bu sayede tek bir tıklama ile karmaşık işlemleri tetikleyebilirsiniz.
  3. Değişiklikleri Kaydetme (`EditorUtility.SetDirty`): Editor script’leri aracılığıyla bir obje veya Asset üzerinde değişiklik yaptığınızda, Unity bu değişiklikleri otomatik olarak kaydetmeyebilir. Değişikliklerin kalıcı olması ve Editor’da doğru şekilde güncellenmesi için `EditorUtility.SetDirty(Object obj)` metodunu çağırmalısınız. Özellikle Asset’ler üzerinde yapılan değişiklikler için bu çok kritiktir.

    // Örnek: Materyal değişikliğini kaydetme
    Material myMaterial = AssetDatabase.LoadAssetAtPath("Assets/MyMaterial.mat");
    myMaterial.color = Color.blue;
    EditorUtility.SetDirty(myMaterial); // Değişikliğin kaydedilmesini sağlar

Yaygın Hatalar ve Çözümleri

Unity çoklu seçim ile çalışırken karşılaşılabilecek bazı yaygın hatalar ve bunların çözümleri şunlardır:

  • Yanlış Tür Varsayımı (`Selection.objects` vs. `GameObject[]`): `Selection.objects` bir `Object[]` dizisidir, `GameObject[]` değildir. Bu yüzden doğrudan `foreach (GameObject go in Selection.objects)` şeklinde döngüye girmek hata verebilir veya beklediğiniz gibi çalışmayabilir (eğer seçili Asset’ler varsa). Çözüm olarak, `foreach (Object obj in Selection.objects)` kullanın ve döngü içinde `obj as GameObject` ile tür kontrolü yapın veya sadece `GameObject`’leri hedeflemek için `Selection.gameObjects` veya `Selection.GetFiltered` kullanın.
  • Undo Kullanmayı Unutmak: Kullanıcıların yaptığınız değişiklikleri geri alamaması kötü bir kullanıcı deneyimi yaratır. Her zaman `Undo.RecordObject` veya `Undo.RegisterCompleteObjectUndo` kullanarak geri alma sistemini entegre edin.
  • Asset’leri Göz Ardı Etmek: `Selection.objects` sadece sahnede görünen objeleri değil, proje penceresinde seçili olan tüm Asset’leri de içerir. Editor aracınızın sadece `GameObject`’ler üzerinde çalışmasını istiyorsanız `Selection.gameObjects` veya `Selection.GetFiltered` kullanın. Aksi takdirde, beklenmedik Asset değişiklikleri veya null referans hataları alabilirsiniz.
  • Değişikliklerin Kaydedilmemesi: Editor script’leri ile yapılan değişikliklerin Editor’da kalıcı olması için `EditorUtility.SetDirty` kullanmayı unutmak, sıkça karşılaşılan bir durumdur. Özellikle Asset’ler üzerinde çalışırken bu adıma dikkat edin.

Performans ve Optimizasyon Notları

Büyük projelerde veya çok sayıda obje üzerinde işlem yaparken performans sorunları yaşanmaması için bazı noktalara dikkat etmek gerekir:

  • Büyük Seçimlerde Döngü Maliyeti: Binlerce obje üzerinde işlem yapıyorsanız, her bir obje için yapılan her işlem (örneğin, GetComponent çağrısı) toplamda önemli bir maliyet oluşturabilir. Mümkünse, döngü içinde pahalı işlemleri tekrarlamaktan kaçının.
  • `Selection.objects`’ın Yeni Bir Dizi Döndürmesi: `Selection.objects` özelliği her çağrıldığında yeni bir `Object[]` dizisi oluşturur. Eğer aynı diziyi birden fazla yerde kullanacaksanız, diziyi bir değişkene atayarak gereksiz bellek tahsisini önleyebilirsiniz: `Object[] selected = Selection.objects;`.
  • İlerleme Çubuğu (`EditorUtility.DisplayProgressBar`): Uzun süreli işlemler için kullanıcıya geri bildirim sağlamak amacıyla `EditorUtility.DisplayProgressBar` kullanın. Bu, Editor’ın kilitlenmediği izlenimini verir ve kullanıcı deneyimini iyileştirir.

    // Örnek: Uzun süreli işlemde ilerleme çubuğu
    float progress = 0;
    foreach (Object obj in Selection.objects)
    {
        EditorUtility.DisplayProgressBar("İşlem Sürüyor", $"Objeler işleniyor: {obj.name}", progress / Selection.objects.Length);
        // İşlemlerinizi burada yapın
        progress++;
    }
    EditorUtility.ClearProgressBar(); // İşlem bitince çubuğu kapatın

Unity Editor’da Unity çoklu seçim yeteneklerini kullanarak verimli ve güçlü araçlar geliştirmek, iş akışınızı büyük ölçüde hızlandırabilir. `Selection.objects` ve ilgili metotları doğru bir şekilde anlamak ve uygulamak, Unity geliştiricileri için vazgeçilmez bir beceridir. Bu makaledeki bilgilerle kendi özel Editor araçlarınızı oluşturmaya başlayabilir ve geliştirme sürecinizi optimize edebilirsiniz.

Leave a Reply

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