Unity Bir Script’ten Başka Bir Script’teki Değişkene Ulaşmak

Yayınlandı: 27 Temmuz 2019 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde

Yeniden merhabalar,

Bu derste, Unity‘de yazdığınız bir C# script’inden başka bir C# script’indeki değişkene ulaşmanın birkaç yolunu göstereceğim:

  • Hedef script’i public bir değişkende tutmak
  • Hedef script’e kod vasıtasıyla ulaşmak
  • Değişkeni static yapmak

Bu konuda sıklıkla soru aldığım için, umarım bu ders akıllardaki bir takım soruları cevaplayacaktır. Hazırsanız derse başlayalım!

Öncelikle, işleri kolaylaştırması adına iki script’e ve ulaşmak istediğimiz değişkene isimler verelim. Ders boyunca, Dusman script’inden Player script’indeki “public Vector3 konum;” değişkenine ulaşmaya çalışacağız. Ulaşmaya çalıştığımız değişkenin ya public olması lazım, ya da o değişkene ulaşmaya yarayan public bir property veya fonksiyonun Player script’inde tanımlı olması lazım. Aksi taktirde bu değişkene ulaşamayız.

Hedef script’i public bir değişkende tutmak

En basit yöntem bu sayılabilir. Dusman script’inde public Player player; değişkeni oluşturun ve Dusman objesinin Inspector’undan Player değişkene değer olarak, Player objesini verin. Artık player.konum şeklinde konum değişkenine ulaşabilirsiniz.

Eğer Dusman script’i bir prefab’da yer alıyorsa ve Player objesi sahnenizde yer alan bir obje ise (yani prefab değilse), Dusman objesinin Player değişkenine Player objesini değer olarak veremezsiniz. Çünkü sahnedeki objeler prefab’ların değişkenlerine değer olarak verilemez. Bu durumda, bahsedeceğim diğer yöntemlere başvurmak zorundasınız.

Hedef script’e kod vasıtasıyla ulaşmak

Oyun esnasında bir objeye veya component’e dinamik olarak erişmek için birkaç fonksiyon mevcut:

GameObject obje = GameObject.Find(“Objenin ismi”): ismi girilen objeyi GameObject olarak döndürür. Aynı isimde birden çok obje varsa, ilk bulunan obje döndürülür. Eğer bu isimde bir obje yoksa null döndürülür

GameObject obje = GameObject.FindWithTag(“Objenin tag’ı”): tag’ı girilen objeyi GameObject olarak döndürür. Aynı tag’e sahip birden çok obje varsa, ilk bulunan obje döndürülür. Eğer bu tag’e sahip bir obje yoksa null döndürülür

Player playerScripti = obje.GetComponent<Player>(): obje’nin Player component’ini döndürür. Eğer objede Player component’i yoksa null döndürülür

Player playerScripti = FindObjectOfType<Player>(): sahnedeki Player component’ine sahip objeyi bulur ve bu objenin Player component’ini döndürür. Eğer birden çok objede Player component’i varsa, ilk bulunan objenin Player component’i döndürülür. Sahnedeki hiçbir objede Player component’i yoksa null döndürülür

Fark edeceğiniz üzere, bu fonksiyonlar vasıtasıyla oyun esnasında sahnedeki herhangi bir objeye dinamik olarak erişebilirsiniz. Ancak bu fonksiyonlar biraz yavaş fonksiyonlardır (özellikle FindObjectOfType ve GameObject.Find), o yüzden bu fonksiyonları Update gibi bir fonksiyonda kullanırsanız bu performans sorunlarına yol açabilir. Onun yerine, ulaşmak istediğiniz objeyi tutacak private bir değişken oluşturup, bu fonksiyonlar yardımıyla Start fonksiyonunda değişkene değerini verebilir ve script’in geri kalanında objeye bu değişken vasıtasıyla ulaşabilirsiniz. Örneğin:

private Player player;

void Start()
{
	// Player objesinin tag'ının Player olması lazım!
	player = GameObject.FindWithTag( "Player" ).GetComponent<Player>();
	
	// veya (daha yavaş)
	player = GameObject.Find( "Player" ).GetComponent<Player>();
	
	// veya (çok daha yavaş)
	player = FindObjectOfType<Player>();
}

void Update()
{
	// Artık değişkene player.konum şeklinde ulaşabiliriz
	Debug.Log( player.konum );
}

Player fonksiyonuna kod vasıtasıyla ulaşmanın daha hızlı bir yolu ise, Player script’ine hızlıca ulaşmaya yarayan bir static değişken oluşturmaktır. Bunun için Player script’inde public static Player instance; şeklinde bir değişken tanımlayıp Awake fonksiyonunda (Awake, Start fonksiyonundan önce çağrılır) instance=this; komutunu çalıştırabilirsiniz:

public static Player instance;

void Awake()
{
	// Player script'i, instance değişkenine değer olarak kendisini (this) veriyor
	instance = this;
}

Bundan böyle Dusman script’inden konum değişkenine Player.instance.konum şeklinde rahatça ulaşabilirsiniz. Bu yöntem, yukarıda bahsettiğim fonksiyonları kullanmaya göre çok daha hızlıdır.

Değişkeni static yapmak

Aslında bu yöntem, bir önceki yöntemde bahsettiğim static instance değişkeni oluşturmakla bayağı benzerdir. Tek fark, static instance değişkeni oluşturmak yerine direkt konum değişkenini static yapmamızdır. Yani public Vector3 konum; değişkenini, public static Vector3 konum; olarak değiştirmek yeterlidir. Artık Dusman script’inden bu değişkene direkt Player.konum şeklinde erişebiliriz.

Bu yöntemin kötü yanı, artık konum değişkenine Inspector’dan değerini veremeyecek olmanızdır çünkü static değişkenler Inspector’da gözükmez. Yani eğer konum değişkenine değerini script’inizden veriyorsanız bu yöntem idealken, konum değişkenine Inspector’dan değer veriyor idiyseniz bu yöntem yerine bir önceki static instance değişkenli yöntemi tercih etmelisiniz.

Bu yöntemle ilgili bilmeniz gereken bir başka husus ise, static değişkenlerin varsayılan değerlerini yalnızca bir kere aldıklarıdır. Bir örnek ile biraz daha açayım: diyelim ki ulaşmak istediğiniz değişken public int skor; (veya public int skor = 0;) olsun. Burada skor değişkeninin varsayılan değeri 0’dır. Bu değişkene sahip script’in olduğu obje her yok olup yeniden oluştuğunda, skor‘un değeri tekrar varsayılan değer olan 0’a döner. Ancak siz bu değişkeni public static int skor; şeklinde static yaparsanız, değişkene ilk kez ulaşırken değişken yine 0 döndürürken, değişkene sahip script’in olduğu obje yok olup yeniden oluştuğunda skor‘un değeri sıfırlanmaz, en son değeri neyse o şekilde kalır. Yani mesela level bitti, ana menüye dönüş yapıldı ve ardından level tekrar başlatıldı diyelim. Bu durumda normalde skorun sıfırlanması beklenirken, en son level’da skor ne idiyse değeri o şekilde devam eder. Her level başında skor’un değeri sıfırlansın isterseniz, skor’un olduğu script’in Awake fonksiyonunda skor = 0; şeklinde değeri elle sıfırlamanız gereklidir.

Böylelikle bu dersin de sonuna geldik, sonraki derslerde görüşmek dileğiyle!

yorum
  1. Arda dedi ki:

    başka bir scriptden başka bir objenin ontriggerenter2d sini nasıl kullanabilirim

  2. Yasin Çakıcı dedi ki:

    Tek bir hedefim var oda mobil oyun için, ama bir türlü c# dilinin mantığını kavrayamadım.
    elinizde varmıdır bir ders veya kaynak?

    Yani demek istediğim C# dilini (mantığını) hiçbir bilgisi olmayan birine nasıl anlatabilirsiniz?

    bu soruya cevap 🙂

    • yasirkula dedi ki:

      Benim önerim C#’ın temellerini Unity’den bağımsız olarak öğrenmeniz çünkü Unity ile C# programlamaya başlamak konusunda Türkçe çok iyi kaynak bulmakta belki zorlanırsınız ama “c# giriş dersleri -visual” diye arama yaparsanız, Türkçe ve kaliteli C# başlangıç dersleri bulabilirsiniz. Bu dersler ile C# ile programlamanın temelini iyice kavradığınıza inandıktan sonra Unity’e geçiş yapabilirsiniz.

      Sadece şuna dikkat edin: C# ile konsol tabanlı ve pencere tabanlı (visual) uygulamalar yapılabilir, siz başlangıç seviyesinde olduğunuz için konsol tabanlı derslere bakın, visual C# yazan derslere hiç bakmayın. Zaten temeli kaptıktan sonra görsel kısmı Visual C# ile değil Unity’de C# kullanarak yapacaksınız. Konsol tabanlı derslerin kodlarında Console.WriteLine gibi satırlar görürsünüz.

  3. ali dedi ki:

    Hocam scripti çağırıyorum çağırdığım scriptten public olmasına rağmen değişkenlere de metotlarada ulaşamıyorum. Sizce sorun ne olabilir ?

  4. Kerem Güneş dedi ki:

    Öncelikle merhaba hocam benimde bir sorum olucaktı Unity 3d ile bir oyun geliştiriyorum bu oyununda başlangıçta eğer daha önceden takım olusturulmadiysa takım oluştur sayfasına geçicek daha önceden takım olusturduysa direk ana menüye geçicek birde takım oluşturduğunda takımın logosu adı felan bunları nasıl ana menüde gösterebilirim bunun ile ilgili bir yazınız varsa linkini atabilirmisiniz yada dili farketmez bir ders varsa atarsanız çok sevinirim ne zamandır googlda arıyorum bir türlü bulamıyorum nasıl arayacagimi da bilemiyorum 😊 bu konuda yardimci olursaniz cok sevinirim.

    • yasirkula dedi ki:

      Kendiniz araştırırken “unity persist data” şeklinde arayabilirsiniz. Unity oyunlarında veri kaydetmenin en kolay yolu PlayerPrefs’tir. PlayerPrefs ile kaydettiğiniz veriler oyun kapansa da değerini korur (ama oyun cihazdan silinirse değerler kaybolabilir). Diğer alternatiflerden bazıları JsonUtility, XMLSerializer ve BinaryFormatter’dır. Bunlarla veriyi bir dosyaya çeşitli formatlarda kaydedebilir, daha sonra veriyi geri yükleyebilirsiniz.

      Takımın adı gibi basit şeyleri PlayerPrefs ile çok hızlı bir şekilde kaydedebilirsiniz ama eğer logoyu kullanıcı kendisi bilgisayarından seçecekse (yani var olan bir kaç logo arasından tercih yapmayacaksa), o zaman bu logonun bir kopyasını Application.persistentDataPath klasöründe tutup onun konumunu PlayerPrefs veya bahsettiğim diğer metotlar ile kaydedebilirsiniz. Daha sonra bu konumdan logoyu Texture2D olarak yüklemek için, Texture2D.LoadImage fonksiyonunu kullanabilirsiniz.

  5. Emir Yılmaz dedi ki:

    Merhaba yasir bey. İyisinizdir umarım 🙂 Bir sorum olacak bu konuyla pek alakası yok ama nereye yazacağımı bilemedim. Ben bir mobil oyun yapıyorum. Oyun başında logo geldikten sonra loading ekranı gelicek. Bu loading ekranı 3-4 saniye tutucam. Bu sürede arkaplanda nesneler objeler yüklenicek. Bir nevi optimizasyon. Bunu nasıl yaparım ? Bir kaynak var mıdır İngilizce türkçe ? Ya da siz daha önce bu konuda makale yazdıysanız link atabilir misiniz ? Bu benim için çok önemli 🙂 İyi günler iyi çalışmalar

  6. Chucklestone dedi ki:

    Yaşadığını öğrendiğimiz için Mutluyuz : D

Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google fotoğrafı

Google hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.