Unity 3D Editör Scripti Yazmak – 1 – OnInspectorGUI, ContextMenu ve MenuItem

Yayınlandı: 11 Ocak 2016 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde
Etiketler:, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

Hepinize merhabalar,

Bu derste Unity 3D için basit editör scriptleri yazmayı göreceğiz. Unity’i editör scriptleri ile daha da işlevselleştirmek bazen karmaşık projelerinizde işinizi oldukça rahatlatabilir.

Editör scripti yazmak için Unity’nin gerçekten çok fazla fonksiyonu mevcut ve bunların hepsini ele almak benim için mümkün değil. Ben sıklıkla kullanılan fonksiyonlardan ve attribute‘lardan bahsetmeye çalışacağım. Bu derste OnInspectorGUI fonksiyonu ile ContextMenu ve MenuItem attribute’larını göreceğiz. Dersi C# ile anlatacağım ve bir miktar kod yazma bilginiz olduğunu varsayacağım.

Hazırsanız başlayalım…

Editör scriptleriyle çalışırken bu scriptleri projenizde Editor isminde bir klasöre kaydetmeniz gerekmekte. Bu yüzden Project panelinde Editor isminde bir klasör oluşturun. Ardından bu klasör içerisinde “EditorScript1” adında yeni bir C# scripti oluşturup içeriğini şöyle değiştirin:

using UnityEngine;
using UnityEditor;

public class EditorScript1 : Editor
{
	// Kısayol: Yok
	[MenuItem( "CONTEXT/Transform/Yukari Git" )]
	static void TransformYukariTasi( MenuCommand mc )
	{
		// Yukari Git komutunun çalıştırıldığı Transform'u değişkene kaydet
		Transform tr = (Transform) mc.context;
		
		// Transform'u ellemeden önce Undo desteği sağla
		Undo.RecordObject( tr, "Yukari Git" );
		
		// Transform'u 1 birim yukarı taşı
		tr.position += new Vector3( 0f, 1f, 0f );
	}
	
	// Kısayol: Control + G
	[MenuItem( "GameObject/Buyuk Kup Olustur %g", false, 10 )]
	static void BuyukKupYap( MenuCommand mc )
	{
		// Yeni bir küp oluştur
		GameObject go = GameObject.CreatePrimitive( PrimitiveType.Cube );
		
		// Eğer bir obje seçili ise küpü o objenin child'ı yap
		GameObjectUtility.SetParentAndAlign( go, (GameObject) mc.context );
		
		// Küpü büyüt
		go.transform.localScale = new Vector3( 5f, 5f, 5f );
		
		// Küp oluşturma işlemini Undo yapabilmeyi sağla
		Undo.RegisterCreatedObjectUndo( go, "Buyuk Kup Olustur" );
		
		// Yeni oluşan küpü seçili hale getir 
		Selection.activeObject = go;
	}
	
	// Kısayol: H
	[MenuItem( "Benim Menum/Secili Objeleri Yukari Tasi _h" )]
	static void IsimsizFonksiyon()
	{
		// Hierarchy'deki seçili objelerin listesini al
		Transform[] seciliObjeler = Selection.transforms;
		
		// Eğer en az bir obje seçili ise
		if( seciliObjeler.Length > 0 )
		{
			// (Olası) birden çok obje için Undo desteği sağla
			Undo.RecordObjects( seciliObjeler, "Secili Objeleri Ziplat" );
			
			// Seçili objeleri 1 birim yukarı taşı
			for( int i = 0; i < seciliObjeler.Length; i++ )
			{
				seciliObjeler[i].position += new Vector3( 0f, 1f, 0f );
			}
		}
	}
}

Bu kod üç farklı işe yarıyor:

  • Transform component’ine “Yukari Git” adında bir komut ekliyor. Bu komuta, herhangi bir objeyi seçip Transform’unun sağ üstündeki dişli çarka tıklayarak erişebilirsiniz. Eğer “Yukari Git” seçeneğini seçerseniz obje 1 birim yukarı ışınlanıyor.

1

  • Unity’nin üstteki araç çubuğundaki GameObject menüsüne “Buyuk Kup Olustur” adında bir buton ekliyor ve bu butona tıklayınca sahnede 5x5x5 ebatlarında bir küp oluşturuyor. Ayrıca CTRL+G kısayolu ile de bu fonksiyon çağrılabiliyor.

2

  • Yukarıdaki araç çubuğuna “Benim Menum” adında bir sekme ekliyor ve bunun içerisine “Secili Objeleri Yukari Tasi” adında bir buton koyuyor. Bu butona tıklayınca sahnedeki seçili tüm objeler 1 birim yukarı taşınıyor. Bu fonksiyon H kısayolu ile de çağrılabiliyor.

3

Peki bu işlevselliği Unity’e nasıl kazandırdık? Öncelikle scriptimizin MonoBehaviour class’ı yerine Editor class’ını extend etmesini sağladık: “public class EditorScript1 : Editor”. Eğer Javascript kullanıyor olsaydık da orası “public class EditorScript1 extends Editor” olacaktı. Editor class’ı UnityEditor package‘ında olduğu için o package’ı “using UnityEditor;” komutuyla import ediyoruz (Javascript’te buna gerek yok).

Unity’de bir fonksiyonu araç çubuğundan çağırabilmek için MenuItem attribute‘ü kullanılır. Bu attribute parametre olarak fonksiyonu çağırmaya yarayan butona giden yolu (bir string olarak) alır. Örneğin IsimsizFonksiyon isimli üçüncü fonksiyonumuzun başına koyduğumuz MenuItem’a parametre olarak “Benim Menum/Secili Objeleri Yukari Tasi _h” verdik ve bu sayede bu fonksiyonu araç çubuğundan Benim Menum-Secili Objeleri Yukari Tasi yolunu izleyerek çağırabiliyoruz.

NOT: C#‘ta MenuItem’ı [ ve ] işaretleri arasına sararken Javascript‘te attribute’ın başına bir tane @ koymamız yetiyor.

String’in en sonundaki “_h” kısmı, bu butona bir kısayol tuşu atayabilmemize yarıyor. Bu kısayol tuşunu belirlemeden önce bir karakter boşluk bırakıyoruz. Kısayol tuşumuz CTRL tuşunu içersin istiyorsak % işareti, Shift tuşunu içersin istiyorsak # işareti, Alt tuşunu içersin istiyorsak da & işareti kullanıyoruz. Örneğin ikinci fonksiyon olan BuyukKupYap fonksiyonunun kısayolu “%g“, yani CTRL+G. Bu kısayolun CTRL+ALT+G olmasını isteseydik kısayol olarak “%&g” yazacaktık. Eğer CTRL, Alt veya Shift tuşlarından hiçbiri kısayolda yoksa o zaman kısayol tuşunun başına _ işareti koyuyoruz. Örneğin kısayolumuz “_g” olsaydı bu durumda sadece G tuşuna basınca o fonksiyon çalışırdı.

İsterseniz ilk fonksiyondan başlayarak kodu daha detaylı inceleyelim. TransformYukariTasi isimli ilk fonksiyonumuzun MenuItem attribute’u parametre olarak “CONTEXT/Transform/Yukari Git” almış. Burada özel bir durum söz konusu. Eğer Inspector‘dan belli bir component’in sağ üstündeki dişli ikona tıklayınca orada kendi yazdığımız bir seçeneğin gözükmesini istiyorsak o zaman en başa “CONTEXT” yazıyoruz, ardından hangi component’e buton koyacağımızı yazıyoruz (Transform) ve son olarak butonun ismini giriyoruz (Yukari Git).

MenuItem ile çağırdığımız fonksiyonlar static olmak zorunda. Bu static fonksiyona istersek MenuCommand türünde bir parametre verebiliyoruz. CONTEXT ile çalışıyorsak MenuCommand parametresine, hangi component’in dişli ikonunu kullanarak o fonksiyonu çağırdıysak o component değer olarak veriliyor. Örneğin Main Camera‘nın Transform‘undaki dişliye tıklayıp “Yukari Git” seçeneğini seçersek MenuCommand’e değer olarak Main Camera objesinin Transform component’i gider. MenuCommand’den bu Transform’a erişmek için MenuCommand’in context değişkenini Transform’a typecast yapıyoruz (ilk satırda). Editör scriptiyle çalışırken yaptığınız değişiklikler normalde Undo-Redo desteklemez, bu özelliği sizin elle sağlamanız lazım. Bunun içindir ki bir sonraki satırda “Undo.RecordObject( tr, “Yukari Git” );” fonksiyonunu çağırıyoruz. Bir obje üzerinde yapacağımız değişikliğin Undo desteklemesini istiyorsak değişiklik yapmadan önce Undo.RecordObject fonksiyonunu çağırıp ilk parametreye objeyi veriyoruz. İkinci parametreye ise yaptığımız değişikliğin ufacık bir açıklamasını giriyoruz (bu açıklama Edit-Undo seçeneğinin yanında gösteriliyor). Artık Undo desteklediğimize göre son satırda transform‘un y pozisyonunu 1 birim artırarak fonksiyonu sonlandırıyoruz.

TransformYukariTasi’yı test etmek için kameraya “Yukari Git” işlemi uygulayın ardından “Edit-Undo Yukari Git” (veya CTRL+Z) ile bu işlemi geri alabildiğinizi teyit edin.

Gelelim ikinci fonksiyona. Bu fonksiyonu çağırmaya yarayan butonun GameObject menüsü altında gözükmesini istiyoruz. Unity dökümanında yazdığına göre eğer GameObject menüsüne bir buton koyacaksak o zaman o MenuItem‘ın sonuna false ve 10 şeklinde iki parametre daha eklememiz gerekiyormuş. Bende bu sebepten ötürü ikinci fonksiyonun MenuItem attribute’unun sonuna bu iki parametreyi veriyorum. Bu fonksiyonun kısayolu “%g“, yani CTRL+G.

Fonksiyonun içinde öncelikle GameObject.CreatePrimitive fonksiyonu ile sıradan bir küp oluşturuyoruz. Sonraki satırda yaptığımız şey ise şu: eğer Hierarchy‘de bir objeye sağ tıklarsak GameObject menüsünün bir kopyası orada da gözüküyor ve bu yolla bir obje oluşturursak oluşturulan obje, seçtiğimiz objenin otomatik olarak bir child‘ı oluyor. Örneğin Hierarchy’den Main Camera’ya sağ tıklayıp menüden “Buyuk Kup Olustur“u seçin (bu durumda oluşan 5x5x5’lik küp otomatik olarak Main Camera’nın bir child’ı olacak):

4

Bu otomatik olarak child’ı olma olayını işte ikinci satırda yapıyoruz. Eğer Hierarchy’de bir objeye sağ tıklayıp “Buyuk Kup Olustur” demişsek, üzerine sağ tıkladığımız obje MenuCommand parametresine değer olarak veriliyor. GameObjectUtility.SetParentAndAlign isimli fonksiyon ise bu parent etme olayını (ve belki başka bir takım şeyleri daha) ayarlayıp bizim işimizi kolaylaştırıyor. Üçüncü satırda localScale ile küpün boyutunu 5x5x5 yaparken 4. satırda ise Undo.RegisterCreatedObjectUndo fonksiyonu ile bu yeni oluşturduğumuz küpün Undo yaparsak yok edilebilmesini sağlıyoruz. Az önce Undo.RecordObject yaparken niye şimdi farklı bir Undo fonksiyonu kullandık diyebilirsiniz haklı olarak. Şöyle ki, Unity editöründe bazı özel operasyonların Undo fonksiyonu da farklı oluyor. Yeni bir obje oluşturduysak bunun Undo desteklemesi için RegisterCreatedObjectUndo kullanmak zorundayız. Hangi durumda hangi Undo’yu kullanacağınızı öğrenmenin en iyi yolu Unity Script Reference‘de Undo sayfasına erişip oradaki açıklamaları okumak. Fonksiyonun en sonunda “Selection.activeObject = go;” yapıyoruz. Bu komutun tek yaptığı şey “go” değişkeninde tutulan GameObject‘i otomatik olarak seçili hale getirmek. Böylece yeni bir büyük küp oluşturunca o oluşan küp otomatik olarak seçili hale geliyor.

Sanırım artık IsimsizFonksiyon isimli üçüncü fonksiyonu inceleyebiliriz. Kısayol “_h“, yani sadece H tuşu. İlk satırda Selection.transforms ile Hierarchy‘deki seçili objelerin Transform component’lerini bir Transform array‘ine atıyoruz (çünkü bu fonksiyon seçili olan tüm Transform’ları etkileyecek). Eğer en az 1 obje seçili ise, seçtiğimiz (olası) birden fazla obje üzerinde yapacağımız değişikliklerin topluca Undo desteklemesi için Undo.RecordObjects fonksiyonunu kullanıyoruz ve ardından seçimdeki tüm Transform’ları y ekseninde 1 birim yukarı taşıyoruz. İşte bu kadar basit!

Şimdi daha basit bir script ile yolumuza devam edelim. Project panelinde Editor klasörünün dışında istediğiniz bir yerde “ContextMenuTest” isminde yeni bir C# script oluşturun. Bu scriptin Editor klasörü içerisinde olmasına gerek yok çünkü kendisi gerçekte bir Editor scripti değil. Scriptin içeriğini şu şekilde güncelleyin:

using UnityEngine;

public class ContextMenuTest : MonoBehaviour
{
	public int sayi = 1;
	public float sayi2 = 1.11f;
	
	[ContextMenu( "Degerleri Ikiye Katla" )]
	void DegerleriKatla()
	{
		sayi = sayi * 2;
		sayi2 = sayi2 * 2;
	}
}

Gördüğünüz üzere bu script ne UnityEditor‘ü import ediyor ne de Editor class’ını extend ediyor. Yani scriptin normalde yazdığımız scriptlerden hiçbir farkı yok. Scriptte iki tane değişken var ve bir de DegerleriKatla isminde basit bir fonksiyon. Bu fonksiyonun tek yaptığı değişkenleri 2 ile çarpmak. Burada dikkatinizi çeken tek şey ContextMenu attribute‘ü olsa gerek. Bu attribute de parametre olarak bir string alıyor. Kamera objesine ContextMenuTest’i component olarak eklersek ve Inspector‘da component’in sağ üstündeki dişli çarka tıklarsak bu isme sahip bir buton karşımıza geliyor:

5

CONTEXT parametresine sahip MenuItem attribute’ü de aynı şeyi yapıyordu diyebilirsiniz. Aradaki fark şu ki CONTEXT’li MenuItem ile istediğimiz component’e bir buton ekleyebiliyoruz ancak Editor class’ını extend etmemiz gerekiyor. ContextMenu’de ise buton sadece o component’e etki ediyor ve Editor class’ını extend etmemiz de gerekmiyor. Eğer “Degerleri Ikiye Katla” butonuna basarsanız Inspector’da iki değişkeninde ikiye katlandığını görebilirsiniz.

Bu ufacık scripti de hallettiğimize göre geriye son scriptimiz kaldı. Editor klasörü içerisindeEditorScript2” adında yeni bir C# script oluşturup içeriğini değiştirin:

using UnityEngine;
using UnityEditor;

// Bu editör scripti, ContextMenuTest scriptini düzenlemeye yarayacak
[CustomEditor( typeof( ContextMenuTest ) )]
public class EditorScript2 : Editor 
{
	// ContextMenuTest component'inin Inspector'dakini görünümünü kişiselleştir
	public override void OnInspectorGUI()
	{
		// Seçili objedeki ContextMenuTest component'ine eriş
		ContextMenuTest scr = (ContextMenuTest) target;
		
		// Inspector'a basit bir mesaj kutusu çizdir
		EditorGUILayout.HelpBox( "Inspector'un Normal Hali", MessageType.Info );
		
		// Unity'e bu component'in Inspector'unu kendi bildiği yoldan çizmesini söyle
		DrawDefaultInspector();
		
		// Basit bir mesaj kutusu daha çizdir
		EditorGUILayout.HelpBox( "Inspector'un Degistirilmis Hali", MessageType.Info );
		
		// Component'teki sayi değişkeninin değerini değiştirmeye yarayan bir field ekle
		scr.sayi = EditorGUILayout.IntField( "Sayi:", scr.sayi );
		
		// **sayi'yı değiştirirmenin bir başka yolu** //
		// GUILayout.EndHorizontal görene kadarki tüm içeriği tek bir satıra sığdırmaya çalış
		GUILayout.BeginHorizontal();
		
		// Inspector'a "Sayi: " şeklinde bir yazı (label) yazdır
		GUILayout.Label( "Sayi: " );
		
		// Inspector'a bir - butonu çizdir ve butona basılırsa sayi'yı 10'a böl
		if( GUILayout.Button( "-" ) )
			scr.sayi = scr.sayi / 10;
			
		// sayi değişkeninin değerini değiştirmeye yarayan bir field ekle
		// (bu sefer string parametresi vermedik)
		scr.sayi = EditorGUILayout.IntField( scr.sayi );
		
		// Inspector'a bir + butonu çizdir ve butona basılırsa sayi'yı 10'la çarp
		if( GUILayout.Button( "+" ) )
			scr.sayi = scr.sayi * 10;
		
		// Tek satıra sığdırma işlemini bitir
		GUILayout.EndHorizontal();
		// **** //
		
		// sayi2 değişkeninin değerini bir slider ile değiştirmeyi sağla (min:0, max: 250)
		scr.sayi2 = EditorGUILayout.Slider( "Sayi2:", scr.sayi2, 0f, 250f );
		
		// Eğer sayi değişkeni 75'ten büyükse Inspector'a bir mesaj kutusu çizdir
		if( scr.sayi > 75 )
			EditorGUILayout.HelpBox( "Sayi epey büyük!", MessageType.Warning );
		
		// Inspector'a bir buton çizdir (GUILayout da işe yarıyor)
		// Butona basılırsa Degerleri3IleCarp fonksiyonunu çağır
		if( GUILayout.Button( "Degerleri 3'le Carp" ) )
			Degerleri3IleCarp();
	}
	
	// ContextMenuTest component'indeki değerleri 3 ile çarp
	void Degerleri3IleCarp()
	{
		// Seçili objedeki ContextMenuTest component'ine eriş
		ContextMenuTest scr = (ContextMenuTest) target;
		
		// Değişkenleri 3 ile çarp
		scr.sayi = scr.sayi * 3;
		scr.sayi2 = scr.sayi2 * 3;
		
		// Kendi yazdığımız bir scriptteki değerleri bir editör scriptinden
		// elle değiştirince, bu değerlerin düzgünce kaydedildiğinden
		// emin olmak için EditorUtility.SetDirty fonksiyonundan faydalan
		EditorUtility.SetDirty( scr );
	}
	
	// Kısayol: CTRL + Shift + G
	[MenuItem( "Benim Menum/Secili Objeye ContextMenuTest Ekle %#g" )]
	static void ComponentEkle()
	{
		// Eğer bir obje seçili ise
		if( Selection.activeTransform != null )
		{
			// Seçili objeye ContextMenuTest component'i ekle ve bu işlemin Undo desteklemesini sağla
			Undo.AddComponent<ContextMenuTest>( Selection.activeTransform.gameObject );
		}
	}
}

Bu script de ilk script gibi Editor class’ını extend ediyor ve UnityEditor package’ını kullanıyor. Gözünüze ilk çarpan şey muhtemelen CustomEditor attribute‘üdür. Eğer bir component’in Inspector‘daki görünümünü değiştirmek istiyorsak onun için bir editör scripti yazmalı ve onun OnInspectorGUI fonksiyonunu değiştirmeliyiz. Buradaki “onun için bir editör scripti yazma” olayı CustomEditor ile oluyor. Bu attribute ile bu editör scriptinin belli bir component’i etkilemesini sağlayabiliyoruz. Bizim durumumuzda bu ContextMenuTest component’i oluyor. Artık bu script içerisinde OnInspectorGUI fonksiyonu oluşturursak bu fonksiyon içerisinde yazdığımız arayüz kodu direkt olarak ContextMenuTest component’inin Inspector’daki görünümünü etkileyecek. Biz de öyle yapıyoruz ve scriptin en başına bir OnInspectorGUI fonksiyonu koyuyoruz. Bu fonksiyonun başına özellikle bir “override” keyword’ü koymak zorundayız.

Fonksiyonun en başında, üzerinde çalıştığımız ContextMenuTest component’ini scr isimli bir değişkene atıyoruz: “ContextMenuTest scr = (ContextMenuTest) target;“. Buradaki target değişkeni havadan gelmiş gibi durabilir ama aslında bu değişken, extend ettiğimiz Editor class‘ından geliyor (eğer Editor’u Unity Script Reference’dan araştırırsanız bir takım faydalı örnek kodlar da bulabilirsiniz).

OnInspectorGUI ile arayüz çizdirmek için karşımızda iki seçenek var: GUILayout veya EditorGUILayout. Eski Unity sürümlerinde GUI ve GUILayout class’larını kullanarak kod vasıtasıyla arayüz oluşturuyorduk, o sürümleri kullananlarınız GUILayout’a biraz aşina olabilir. GUILayout ile kabataslak bir şekilde yazılar, butonlar, slider’lar vb. oluşturabiliyorduk. Aynı şeyi burada da yapabiliyoruz. Ancak editör scriptlerinde arayüz oluştururken öncelikle aradığınız fonksiyonun EditorGUILayout’ta bir karşılığı var mı diye araştırın, eğer yoksa o zaman GUILayout’a geçiş yapın. Zira adından da anlaşılacağı üzere EditorGUILayout class’ı özellikle editör için arayüz oluşturmak için yazılmış bir class. Unity Script Reference‘den bakarsanız bu class’ın içinde yer alan pek çok hazır fonksiyonu da görebilirsiniz ve emin olun bu fonksiyonlar basit arayüzlerde işinizi görmeye yetiyor.

Editör ekranında GUILayout veya EditorGUILayout kullanırsanız oluşturduğunuz içerik yukarıdan aşağıya doğru çizdirilir. OnInspectorGUI‘de öncelikle EditorGUILayout.HelpBox ile basit bir kutucuğun içerisine “Inspector’un Normal Hali” yazısı yazdırıyoruz. İkinci parametre olan MessageType sadece bu kutucuğun yanında yer alacak olan ikonu etkiliyor, yani önemli birşey değil. Kutucuğu çizdirdikten sonra DrawDefaultInspector() fonksiyonunu çağırıyoruz. Bu fonksiyon, Editor class’ı içerisinde halihazırda yazılmış olan kullanıma hazır bir fonksiyon. Bu fonksiyonu çağırdığımızda; ContextMenuTest için editör scripti yazmasaydık varsayılan olarak o component’in Inspector‘u nasıl çizilecek iseydi işte o varsayılan (default) çizimi editör scriptli haline de uygulayabiliyoruz. Bu fonksiyonu çağırmak zorunda değiliz; ben sadece göstermek istedim:

5_1

Biraz devam edince HelpBox ile yeni bir kutucuk daha çizdiriyoruz ve ardından şu kodu çalıştırıyoruz: “scr.sayi = EditorGUILayout.IntField( “Sayi:”, scr.sayi );“. Hatırlarsanız scr değişkenine, üzerinde çalıştığımız ContextMenuTest component‘ini değer olarak vermiştik. Burada yaptığımız şey ise o scriptteki sayi değişkeninin değerini değiştirebilmek için Inspector’da bir integer field‘ı çizdirmek. Bu field’ı kullanarak sayi değişkeninin değerini değiştirebiliriz:

6

Varsayılan olarak arayüz elemanları yukarıdan aşağı dizilir demiştim. Ancak bu spesifik örnek için ben arayüz elemanlarının bir kısmını soldan sağa dizmek istiyorum. Bu durumda GUILayout.BeginHorizontal() ile GUILayout.EndHorizontal() fonksiyonları arasına ne yazarsam, yazdığım bu arayüz elemanları soldan sağa dizilir. GUILayout kullanıyorum çünkü BeginHorizontal’ın EditorGUILayout’ta karşılığı yok. Yapmak istediğim şey şöyle birşey:

7

Öncelikle “Sayi:” şeklinde bir string bastırmak, sonra bir “” butonu çizdirmek, sonra bir int field ve son olarak da bir “+” butonu çizdirmek. String’i yazdırmak için GUILayout.Label, int field’ı çizdirmek için ise yine EditorGUILayout.IntField kullanıyorum. Butonları ise GUILayout.Button ile çizdiriyorum. Eğer Button fonksiyonunu bir if‘in içine alırsanız, bu butona tıklayınca if koşulunun içindeki kod çalıştırılır. Ben de “-” butonuna basınca sayıyı 10’a bölüyor, “+” tuşuna basınca sayıyı 10 ile çarpıyorum. GUILayout.EndHorizontal() ile de arayüz elemanlarını yatay yerleştirmeye bir son veriyorum.

ContextMenuTest‘teki sayi2 float değişkeninin değerini değiştirmek için “scr.sayi2 = EditorGUILayout.Slider( “Sayi2:”, scr.sayi2, 0f, 250f );” kodunu kullanıyoruz. Bu kod ekrana bir slider çiziyor ve slider’ı 0 ile 250 sayıları arasında tutuyor. Bir sonraki satırda, eğlence amaçlı, eğer sayi değişkeni 75’ten büyükse bir başka mesaj kutucuğu daha çizdiriyorum:

8

Son olarak en alta bir buton daha çizdiriyorum ve butona basılırsa Degerleri3IleCarp fonksiyonunu çağırıyorum. Bu fonksiyonda ContextMenuTest component’inin değişkenlerini 3 ile çarpıyorum. Sonra ise “EditorUtility.SetDirty( scr );” fonksiyonunu çağırıyorum. Bu fonksiyonun tam olarak ne zaman kullanılması gerektiğini bilmiyorum ancak eğer Unity’nin kendi component’lerinden biriyle değil de kendi yazdığınız bir component ile (ContextMenuTest) uğraşıyorsanız ve bu component’in bir değişkenini bir EditorGUILayout fonksiyonu ile değil de direkt elle değiştiriyorsanız ( “scr.sayi = scr.sayi * 3;” ) bu değişikliğin Unity tarafından kaydedildiğini garanti altına almak için SetDirty fonksiyonunu çağırmak isteyebilirsiniz. Çünkü bu fonksiyon, içine parametre olarak girilen component’in değerlerinin düzgünce kaydedilmesini sağlıyor.

EditorScript2’nin en sonunda ComponentEkle isimli static bir fonksiyon var ve MenuItem attribute’ü ile bu fonksiyonu “Benim Menum/Secili Objeye ContextMenuTest Ekle” yolunu izleyerek veya CTRL+Shift+G kısayolunu “%#g” kullanarak çağırabiliyoruz. Bu fonksiyon ile Hierarchy‘de seçili olan objeye ContextMenuTest component’i ekleyebiliyoruz. Undo’nun farklı işler için farklı fonksiyonları olduğundan bahsetmiştim, component eklemek için ise AddComponent isimli generic bir fonksiyonu varmış ve ben de gördüğünüz üzere ondan faydalandım. Böylece yaptığım değişikliği Undo diyerek geri alabiliyorum.

Yazdığımız tüm bu kodları test etmek için CTRL+G ile sahnede yeni bir 5x5x5’lik küp oluşturabilir, CTRL+Shift+G‘yi iki kere kullanarak bu küp objesine iki adet ContextMenuTest component‘i ekleyebilir ve H diyerek küpü biraz yukarı taşıyabilirsiniz. Herhangi bir anda CTRL+Z veya Undo ile herhangi bir değişikliği geri alabilirsiniz. Küpte iki tane ContextMenuTest olunca fark edeceğiniz üzere her component için EditorScript2 scripti ayrı ayrı çalışıyor ve iki component’in değişkenlerinin değerleri birbiriyle karışmıyor. Ayrıca sayi değişkenini değiştirince ona bakan tüm editor field’ları da otomatik olarak güncelleniyor.

Bu derslik de bu kadar. Biraz uzunca ve biraz sıkıcı bir yazı oldu ancak umarım işinize yaramıştır. Dediğim gibi, çok fazla editör class’ı ve fonksiyonu mevcut; bunların hepsini bilmeniz mümkün değil ancak editör scripti yazmak ile ilgili tutorial izleyerek, Google’a sorular sorarak veya sırf Unity Script Reference’de oradan oraya zıplayarak bile kendinizi oldukça geliştirebilirsiniz. Bir sonraki derste görüşmek üzere!

yorum
  1. Seyit Mustafa Adem KANDEMİR dedi ki:

    Gerçekten uzun süredir aradığım bir konuydu çok teşekkürler Süleyman Yasir Bey

  2. yakup dedi ki:

    Benimde beklediğim bir konuydu çok teşekkürler.Geçen buildbox adlı bir oyun motoru gördüm bu oyun motoruyla ilgili tanıtım yaparsanız çok iyi olur çünkü 1-2 örnek video izledim ve tek satır kod yazmadan oyunlarını gerçekleştirdiler.Açıkçası 2D oyunlar geliştirmek için oldukça pratik görünüyor .Bu işe yeni girişecek arkadaşlar için çok faydalı olabilir.

    • yasirkula dedi ki:

      İlginiz için teşekkür ediyorum. Belirsiz bir süre için daha Unity üzerine odaklanmayı planlıyorum.

      • cenker dedi ki:

        üst yorumlarla alakalı değil biliyorum fakat kendi yazdığım kodda sıkıntı çekiyorum
        duvara düz zıplayınca sorun yok sadece çaprazlama zıplayınca yavaşlama oluyor,
        3d ortamda yeri control ediyormuş gibi duvarlarıda kontrol ediyorum karakterin spaceworldaki gidiş vectorunu alarak spherecast yapıyorum yani gittiği yöne doğru fakat rigidbodynin moviposition kullanarak yani fizik var işin içinde ve duvara doğru zıpladığında y yönündeki velocityde yavaşlama oluyor normal zıpladığından az zıplıyor duvarı olup olmadığını kontrol edebiliyorum fakat hangi değeri 0lamam gerek bilmiyorum
        sorun duvara çarptığında halen fizik uygulaması biliyorum
        ondan dolayı bir yavaşlama oluyor

        * KOD UZUN OLDUĞU İÇİN TEMİZLENDİ *

      • yasirkula dedi ki:

        Sıkıntı duvara doğru zıplarken karakterin yerden yükselmesinin azalması ise iki kere MovePosition yapmayı deneyin; birisi dimdik yukarı yönde olsun, öbürünün ise y değeri 0 olsun.

        Attığınız kodu da okudum. Duvar çapraz olmadığı sürece duvarın normali çapraz olmaz, sadece x veya z ekseninde değere sahip olur. Onun da dışında kod biraz kafamı karıştırdı, koda yardımcı olabileceğimi sanmıyorum.

      • cenker dedi ki:

        Kafamda dusundum yerdeyken capraz raycasti yapmasina izin vermiyordum gecici cast ile bos yonu bulup oraya asıl casti yaptirtiyordum.bi sefer havada iken ayni gecici cast gibi duvari olcucek ama bos yerine duvar varsa diye ve duvar varsa artik x yonunde ise x 0 olucak z yonunde ise z sifir olucak yani duvar yonune dogru moveposition uygulamicak kod halinin yazmadim halen yazinca atiyim mi

      • yasirkula dedi ki:

        Çok uzun olmazsa paylaşmanız güzel olur elbette.

  3. Suat dedi ki:

    Adamsın 🙂 Uzun zaman olmuştu , biraz daha sık unity hakkında bilgi paylaşabilirsen daha çok faydalı olacak bize.Senin sayende bir şeyler öğreniyoruz.

  4. Yusuf dedi ki:

    Çok iyi oldu bu konu teşekkürler

  5. emrahatalay dedi ki:

    Çok Güzel bir ders olmuş eline sağlık.

    http://atalayemrah.com

  6. ahmet dedi ki:

    Hocam Merhabalar.Bir sorum olacaktı.Hocam unity içinde 3 tane sahne yaptım ve 1.sahneden 2.sahneye geçerken normalde 2.sahne aydınlık directionlight’ tı ışığı falan herşey tamam ama geçişte sahne karanlık görünüyor.2.sahnede normal ışıklar falan var sahne ikiyi çalıştıryorum sahnede benim istediğim gibi aydınlık ama sahneleri birbirine bağladığımda geçişlerde sahne karanlık oluyor.Problem nedir acaba.Şimdiden teşekürler.

  7. ahmet dedi ki:

    tamam hocam auto lightining seçeneği of olursa ve instentity seçeneğini birden 2.5 gibi bir değer yaptım tam iyi oldu

  8. ahmet dedi ki:

    Hocam Merhabalar.Hocam Kusura bakmayın sürekli soru sorup duruyorum.Hocam Ben unity sahnesinde küplerden bir oda yaptım ve içinde dolaşıyorum ama kamera küplerin yanına geldiğinde dış ortamıda gösteriyor.Ben duvar olarak verdiğim o küplerin dışının gösterilmesini istemiyorum.Bunu nasıl yapabilirim.Şimdiden teşekürler.

  9. İbrahim dedi ki:

    Hocam iyi çalışmalar : sorum şu Vuforia da (Artılrılmış Gerçeklikte) Game ekranından objeleri mouse ile nasıl hareket ettiririz.

    • yasirkula dedi ki:

      Oyunu webcam ile test ediyorsunuz sanırım. Benim webcam’imi Vuforia kabul etmediği için ben böyle test edemedim. Yine de aklınızda tasarladığınız hareket sisteminin nasıl bir şey olduğunu söylerseniz belki yardımcı olabilirim.

  10. İbrahim dedi ki:

    Ben size bir şey soracağım tekrar 🙂 Bu unity de ses komutunu nasıl kontrol ediyoruz.Gelene ses efekti almamız lazım.

  11. Kimex dedi ki:

    Ders için teşekkürler ama 2 soru kafama takıldı.Birincisi bunun 2. bir dersi var mı çünkü başlıkda -1- diye yazmışsınız.İkincisi kendi editor penceremizi ( Game,Scene,Inspector gibi ) yaptığımızda liste,gameobject nasıl eklenir onu çözemedim siz biliyor musunuz ?Teşekkürler.

    • Kimex dedi ki:

      Birde bu gameobjenin resmini eklemek istiyorum ama bir türlü bulamadım 😦

    • yasirkula dedi ki:

      İkinci ders henüz yok ama ileride büyük olasılıkla yazarım diye -1- koydum bu derse. Kendi editör pencerenizde EditorGUI veya EditorGUILayout ile arayüz elemanları oluşturabilirsiniz. Örneğin sizin aradığınız fonksiyon EditorGUILayout.ObjectField olabilir.

      GameObject’in resminden kastınız Preview ekranı ise açıkçası bu konuda bir bilgim yok.

Bir Yanıt Bırakı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. Log Out / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Log Out / Değiştir )

Connecting to %s