Unity UI (Arayüz) Sistemi

Yayınlandı: 21 Ocak 2015 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde

GÜNCELLEME (30.12.2019): Kod C#’a çevrildi.

Hepinize yine ve yeniden koca bir merhaba,

Yazılarımın giriş cümlesi o kadar klişe hale geldi ki her derste girişi nasıl değişik bir hale sokabilirim diye düşünmüyor değilim. Ama bir saniye; konumuz bu değil! Bu dersimizde Unity 4.6 sürümü ile gelen yeni UI (user-interface)(arayüz) sistemini inceleyeceğiz.

Twitter’da da bolca dile getirdiğim üzere yeni sistemi gerçekten çok sevdim. Sistemin güzel yanları daha az draw call harcaması, multi-touch desteklemesi, 3 boyutlu arayüz yapmayı mümkün kılması ve görsel olarak düzenlenebilmesi. Yani yeni sistemle birlikte artık arayüzü çizdirirken kod yazmanıza gerek yok.

Hazır mısınız? Harika! O halde derse başlıyorum.

NOT: Ders boyunca yapacağımız örnek uygulamaları içeren örnek projeyi indirmek için tıklayın: https://www.dropbox.com/s/b64v7wsvbpnth05/UI%20Ders.rar?dl=0

UI sistemi çeşitli elemanlardan oluşmakta: canvas, panel, button, slider vb. Her bir eleman, adından da anlaşılacağı üzere farklı işlevselliğe sahip. Dersimize en temel UI elemanı ile başlayacağız: canvas!

Canvas

Canvas’ın iki mühim görevi vardır:

1- Diğer UI elemanlarını içinde barındırır. Yani diğer tüm arayüz elemanları canvas’ın child’ı olmak zorundadırlar.

2- UI sisteminin 2D mi yoksa 3D mi olacağını belirler. 2 boyutlu arayüz, şimdiye kadar kullandığımız OnGUI ve GUITexture‘ler ile aynıdır: arayüz oyun ekranının üzerine çizilir. 3 boyut desteği ise UI sistemi ile yeni gelen bir özellik ve bu özellik sayesinde oluşturduğunuz arayüz 3D uzayda bir konuma ve eğime sahip olabiliyor. Bu derste her iki boyutu da göreceğiz.

Button

Bu elemanın nolduğunu isminden de çıkarırsınız. Kendisi tıklanabilir (interaktif) bir buton rolünü üstlenir.

Bu elemanın özelliklerinden bahsetmeden önce birlikte bir canvas ve birkaç butondan oluşan basit bir arayüz oluşturmayı uygun buldum. Böylece yeni sistemle birlikte nasıl hiç kod yazmadan arayüz oluşturabildiğimizi görecek ve bazı önemli terimlerle tanışacaksınız: anchor ve pivot.

Unity’de boş bir sahne (scene) açın. Bu sahnede UI sistemini test edeceğiz.

Az önce UI sisteminin en temel biriminden bahsetmiştik: canvas. Butonlardan oluşan bir arayüz istiyoruz ancak bu butonlar bir canvas’ın child’ı olmak zorunda. Bu durumda canvas’ı iki şekilde oluşturmamız mümkün:

1- GameObject-UI-Canvas yolunu izleyerek elle oluşturabiliriz.

2- Direkt GameObject-UI-Button ile bir buton oluştururuz ve yeni bir canvas bizim için otomatik olarak oluşturulur.

Ben 2. yolu tercih edeceğim. GameObject-UI-Button yolunu izleyin. Hierarchy panelinizde bir canvas bir de button belirecek:

1

Canvas bizim için otomatik olarak oluşturuldu. Bu yetmezmiş gibi otomatik olarak bir de EventSystem oluşturuldu. EventSystem napar? Oluşturduğunuz arayüzün hem PC’de hem de mobil cihazlarda çalışabilmesini sağlar. Yani arayüzün mobil cihazlarda çalışması için ekstra bir efor sarf etmiyorsunuz, bu işi EventSystem vasıtasıyla Unity sizin için yapıyor.

Eğer Scene paneline bakacak olursanız devasa bir dikdörtgensel alan ve bu alanın içine yerleştirilmiş ufak bir buton göreceksiniz. İşte bu dikdörtgensel alan bizim canvas’ımız. Şu anda canvas 2D modunda, yani canvasın içinde oluşturduğumuz arayüz elemanları direkt oyun ekranının üzerine çizilecekler.

Peki arayüzü nasıl düzenleyeceğiz? Bunun en kolay yolu 2D moduna geçiş yapmak. 2D modunda Z ekseni kaybolur; sadece X ve Y eksenleri ile çalışırız. 2D moduna geçiş yapmak için Unity arayüzünün tepesinde yer alan 2D butonuna basmanız yeterli:

2

Şimdi canvas’ın içinde yer alan buton objesine tıklayarak onu seçin. Ardından klavyeden T tuşuna tıklayın veya araç çubuğundan Rect Handles aracını seçin:

2_2

Bu tool (araç) UI elemanlarını düzenlerken işe yarar. Neden ayrı bir tool kullanıyoruz derseniz çünkü UI elemanları Transform component’ine değil, Rect Transform component’ine sahiptirler ve bu component, Transform component’inin sahip olduğu değişkenlerden farklı değişkenlere de ev sahipliği yapar.

Butonu seçince karşımıza birkaç yeni gizmo çıkmış durumda:

3

Resimde de gördüğünüz üzere bu gizmo’lar pivot noktası ile anchor‘u temsil ediyor. Normalde butonun üzerinde Button yazıyordu ama pivot’un görünürlüğünü azalttığı için o yazıyı sildim.

Pivot

Açıkçası ben pivot’un bir faydasını görmedim. Pivot’un yerini bence hiç oynamayın. Pivot’un tek bir konuda çok işe yaradığını gördüm, o da arayüz elemanını döndürürken (rotate). UI elemanları pivotun etrafında döner ve pivotun konumunu değiştirirseniz objelerin dönme şekilleri de farklı olur.

Bir UI elemanını pivot etrafında döndürmek için, o elemanı saran dikdörtgensel hattın uçlarında yer alan mavi noktalardan herhangi birinin biraz dışına fare imlecini getirmeniz yeterli. Bu durumda fare imlecinin şekli değişecek ve sol mouse tuşuna basılı tuttuğunuz sürece o arayüz elemanı pivot etrafında dönecek:

4

Eğer pivotun yerini değiştirmediyseniz buton, kendi merkezi etrafında dönecektir. Ancak biz butonun kendi sol üst noktası etrafında dönmesini istiyoruz diyelim. O zaman yapmamız gereken şey pivotu tutup sürükleyerek butonun sol üst noktasına taşımak. Sonrasında butonu tekrar döndürün. Artık buton sol üst noktası etrafında dönecek:

5

Anchor

Pivot’u aradan elediğimize göre geldik en baba konuya: anchor. Arayüz elemanlarını yerleştirirken anchor’dan bolca faydalanacaksınız. Ekranın çözünürlüğü değiştikçe arayüz elemanlarının nasıl davranacaklarını belirleyen birkaç eleman var; bunlardan önemli bir tanesi de anchor.

Anchor’u, canvas üzerinde 4 üçgenin bir araya gelmesiyle oluşmuş bir ikon olarak görebilirsiniz (öncesinde buton objesini seçmeniz lazım). İşin ilginç yanı şu ki aslında her UI elemanının bir değil tam dört tane anchor’u vardır. O dört üçgenin her biri bir anchor’u temsil etmektedir. Eğer bu üçgenlerden herhangi birini tutup sürüklerseniz dört anchor birbirinden ayrılır:

6

Anchor’ların çok ama çok önemli bir özelliği var: her bir anchor aslında bağlı olduğu UI elemanının bir köşesiyle iletişim halindedir. Sıradaki cümleye lütfen dikkatinizi verin çünkü kritik nokta burası: Bir anchor ile o anchor’un bağlı olduğu köşe arasındaki uzaklık, ekranın çözünürlüğü ne kadar değişirse değişsin “daima” aynı kalacaktır. Mesela:

7

Bu örnekte iki farklı durumu göstermeye çalıştım. 1 numaralı durum bir önceki resimle aynı. Burada hangi anchor’un hangi köşeyle bağlantılı olduğuna (sol üst anchor butonun sol üst köşesiyle bağlantılı vs. vs.) ve anchor ile bağlantılı olduğu köşe arasındaki uzaklığa dikkat edin.

Ben bu butonun, genişliği daha az olan bir ekranda nasıl görüneceğini merak ettim ve Scene panelinin genişliğini epeyce azalttım. Anchor’lar da ekranla birlikte hareket etti (bu konuya değineceğim) ve 2 numaralı durumla karşılaştım. 2 numarada anchorlar birbirine daha bir yakınlaştı ama her iki durumda da anchor’lar ile köşeler arası uzaklıklar aynı kaldı. Harika!

Bu sistemi daha iyi anlamak için kendi canvas’ınızda biraz pratik yapmanızı şiddetle öneririm. Butonun anchorlarını birbirinden ayırıp istediğiniz noktalara dikin. Anchorlar ile bağlı oldukları köşeler arası uzaklığı dikkatlice gözlemleyin. Ardından Scene panelinin ebatlarıyla oynayın. Anchor’lar hareket edecek ve butonun da boyutu değişecek ama anchor’lar ile butonun köşeleri arasındaki uzaklık daima sabit kalacaktır.

Şimdi anchor’ların neye göre otomatik olarak konumlandırıldığını görelim. Bir önceki resimdeki 1 ve 2 numaralı durumların farkı sol ve sağdaki anchor’ların 2 numarada birbirine daha yakın olmasıydı. Bunun sebebi de ikinci durumda ekranın genişliğinin daha küçük olmasıydı.

Anchor’lar konumlandırılırken % sistemi ile hareket edilmekte. Bunu bir örnek üzerinden anlatacağım:

8

Unity’de anchor’ları konumlandırırken ekranda, resimde görüldüğü gibi çeşitli % ifadeler belirir. Bunlar, ilgili anchor’un ekranın kenarlarından ne kadar uzakta olacağını belirlemektedir.

Örneğin sol alttaki anchor’u ele alalım. Bu anchor her zaman için canvas’ın solundan, canvas’ın genişliğinin %17’si kadar uzakta yer alacak. Benzer şekilde, canvas’ın alt noktasından ise canvas’ın yüksekliğinin %25’i kadar uzakta yer alacak (yani 1/4’ü kadar). Biz ekranın (yani dolaylı olarak canvas’ın) yüksekliğini ne kadar değiştirirsek değiştirelim anchor’daki bu oranlar asla değişmeyecektir. Ekranın çözünürlüğü 100×100 iken sol alt anchor’un canvas’ın sol alt köşesine uzaklığı (17,25) pixel olurken ekranın çözünürlüğü 200×60 iken (34,15) pixel olacaktır. Umarım konsept anlaşılmıştır.

O halde anchor’larla ilgili bilmemiz gereken iki önemli bilgi var:

  • Bir anchor ile o anchor’un bağlı olduğu köşe arasındaki uzaklık daima aynıdır. Yani siz arayüzü tasarlarken bu uzaklık (10,20) pixel ise ekranın çözünürlüğünü ne kadar ellerseniz elleyin; uzaklık daima (10,20) pixel olarak kalacaktır.
  • Bir anchor’un canvas’ın kenarlarına olan % cinsinden uzaklığı, ekranın çözünürlüğünü ne kadar ellerseniz elleyin daima aynı kalır.

Sıra geldi bu öğrendiğimiz bilgileri hazır sıcakken pratiğe dökmeye. Mesela canvas’ın içindeki butonun sol kenarıyla canvas’ın sol kenarı arasındaki uzaklığın daima 50 pixel olmasını istiyoruz diyelim. Benzer şekilde, sağ kenarlar arası mesafe ise daima 70 pixel olsun istiyoruz diyelim. Burada referans noktası olarak canvas’ın sağ ve sol kenarlarını alıyoruz. O halde ilk işimiz, butonun sol anchor’larını canvas’ın sol kenarına dayamak, sağ anchor’larını ise canvas’ın sağ kenarına dayamak olmalı. Yani şu şekilde:

9

Artık sol anchor’lar (canvas’ın sol kenarı) ile butonun sol köşeleri arası uzaklık sabit hale geldi. Biz bu uzaklığın sol tarafta 50 pixel, sağ tarafta 70 pixel olmasını istiyoruz. Burada iki farklı yol izleyebiliriz:

A) Butonu Elle Konumlandırmak

Yapmamız gereken şey, butonun sol kenarına fare imlecini getirmek ve sol mouse tuşu basılıyken butonun sol noktasını çekiştirmek. Bu işlemi, butonun sol kenarı ile canvas’ın sol kenarı arası uzaklık 50 pixel olana kadar yapmalıyız:

10

Farkedeceğiniz üzere bu metot biraz zahmetli çünkü tam istediğiniz uzaklığı elde etmek için ince ayar yapmanız gerekebiliyor. Ancak elbette ki imkansız değil.

B) Butonu Rect Transform Vasıtasıyla Konumlandırmak

Bu metot öncekine nazaran çok daha kolay. Nasıl mı? Butonu seçiyorsunuz ve Rect Transform‘daki “Left” değerini 50 yapıyorsunuz:

11

İşte bu kadar! “Right“ı da 70 yaptığınız zaman artık sağ anchor’lar (canvas’ın sağ kenarı) ile butonun sağ köşeleri arası uzaklık 70 pixel olacak. Buradaki “Top” değerinin üst anchor’lar ile butonun üst köşeleri arası dikey uzaklık, “Bottom“un ise alt anchor’lar ile butonun alt köşeleri arası dikey uzaklık olduğunu kendiniz anlamışsınızdır herhalde.

Artık yaptığımız sistemi test edebiliriz. Bunu yapmanın kısa yolu Hierarchy‘den Button objesini seçmek ve ardından Canvas‘ın kenarlarından tutarak canvas’ı yeniden boyutlandırmak. Canvas’ı yeniden boyutlandırma işlemi sadece önizleme (preview) amaçlıdır ve elinizi sol mouse tuşundan çektiğiniz anda canvas eski haline dönecektir. Eğer herşeyi düzgün yapmışsanız canvas’ın genişliğini değiştirdiğinizde butonun genişliği artacak/azalacak ama butonla canvas’ın kenarları arası mesafe asla değişmeyecektir.

Burada bilmeniz gereken önemli bir nokta var: eğer canvas’ın genişliğini 120 pixelden daha küçük yaparsanız buton kırmızı bir çarpı işaretine dönüşecektir ve artık görünmeyecektir; çünkü butonun kenarlara olan uzaklığı 50+70=120 pixel. Bu da demek oluyor ki eğer oyunu 120 pixelden daha ufak genişliğe sahip bir ekranda oynarsak buton ekranda gözükmeyecek. Böyle ufak bir ekran genişliği yoktur elbet; o yüzden şu anki durumda bir sıkıntı yok ama siz butonun kenarlara olan uzaklığını belirlerken bu bilgiyi unutmayın zira uzaklığı elle artırdıkça o butonun ekranda görünmesi için gerekli minimum ekran genişliği de artacaktır.

Peki şimdi şöyle birşey yapalım: ekranda üç buton olsun. Bu butonların ekranın sol ve sağ kenarlarına olan uzaklığı 50’şer pixel olsun. Butonlar alt alta dizili olsun ve iki buton arası dikey uzaklık 60 pixel olsun. Bu üç butonun yükseklikleri ise birbirine eşit olsun. Bunu kendiniz yapmaya çalışın. En son elde ettiğiniz sonucu benimkiyle kıyaslayın (sonuç benimkiyle aynı olacak diye birşey yok; bu verdiğim tanıma uyan farklı farklı arayüzler oluşturmak mümkün):

12

Eğer elde ettiğiniz sonuç benimkine az biraz benziyorsa tebrikler! İşin güzel yanı, burada öğrendiğimiz konumlandırma işlemi tüm UI elemanlarında ortak olan birşey. Yani butonları, panelleri, slider’ları, image’ları vb. hep bu anchor dediğimiz şeyi kullanarak konumlandırıyorsunuz; prosedür hepsinde aynı.

ÖNEMLİ BİLGİ: Buraya kadar kafanız karışmasın diye sizden özellikle sakındığım bir bilgi vardı: bir UI elemanının anchor’larını sadece parent objesinin sınırları içerisinde dolaştırabilirsiniz. Şu ana kadar hep butonlarla işlem yaptık ve butonlarımız da direkt olarak canvas’ın child objeleriydi (bir başka deyişle canvas, butonların parent objesiydi). Bu yüzden anchor’ları canvas’ın sınırları dahilinde istediğimiz gibi dolaştırabiliyorduk. Ama mesela butonun child objesi olan Text‘i ele alalım (her buton varsayılan olarak bir Text child objesi ile oluşturulur). Eğer Hierarchy‘den bir butonun Text isimli child’ını seçecek olursanız göreceksiniz ki bu Text’in anchor’ları sadece butonun içerisinde hareket edebiliyor, butonun dışına çıkamıyor (tıpkı butonun anchor’larının canvas’ın dışına çıkamaması gibi). Buradan anlayacağımız şey şu: bir UI elemanını konumlandırırken anchor’larımızın referans düzlemi parent objenin kendisidir.

Beraber bir örnek daha yapalım. Bu sefer elimizde bir buton olsun ve bu butonun ekranın üst kenarına olan uzaklığı 100 pixel olsun. Butonun genişliği 350 pixel olsun ve bu değer sabit olsun; yani canvas’ın (ekranın) genişliği değişse de butonun genişliği değişmesin. Butonun alt kenarının ekranın üst kenarına uzaklığı ise daima ekranın yüksekliğinin 1/4’ü kadar olsun. Referans resim ve cevap için alttaki resme bakabilirsiniz:

13

NOT: Pivot’un konumuna göre “Pos X“in değeri sizde farklı olabilir.

Butona Basınca Yapılacakların Ayarlanması

Yeni UI sisteminde interaktif buton oluşturmak eski sisteme nazaran biraz değişmiş. Eskiden GUITexture‘lerde OnMouseDown() fonksiyonunu kullanırdık ama artık daha farklı bir yol izliyoruz.

Canvas’ta bir tane buton oluşturun. Bu butona tıklayınca konsola “Merhaba Dünya” yazdırmak istiyoruz diyelim. Bunun için bir scripte ihtiyacımız olacak. “MerhabaScript” adında yeni bir C# script oluşturup içeriğini şöyle düzenleyin:

using UnityEngine;

public class MerhabaScript : MonoBehaviour
{
	public void Merhaba()
	{
		Debug.Log( "Merhaba Dünya" );
	}
}

Bu scripti istediğiniz objeye verin (ben Main Camera‘ya vereceğim). Şimdi buton objesini seçin. Inspector‘da “On Click()” diye bir kısım var. Bu (şu anda boş olan) bir listedir. Butona tıklandığı zaman bu listede yer alan fonksiyonlar otomatik olarak çağrılır. Biz Main Camera’daki MerhabaScript script’inin Merhaba() fonksiyonunu çağırmak istiyoruz. Bunun için oradaki + işaretine tıklayın. Obje olarak Main Camera’yı seçin ve fonksiyon olarak MerhabaScript-Merhaba() yolunu izleyin:

14

Şimdi oyunu çalıştırıp butona tıklayın. Konsola “Merhaba Dünya” yazılması lazım. Gördüğünüz gibi butona tıkladığımız zaman sahnedeki istediğimiz bir objenin istediğimiz bir fonksiyonunu çağırabiliyoruz. Yalnız çağrılabilecek fonksiyonların türleri konusunda bazı kısıtlamalar var. Bunları şöyle sıralayabiliriz:

  • Fonksiyon public olmak zorunda.
  • Fonksiyon 0 ya da 1 parametre alabilir.
  • Fonksiyonun parametresinin türü sadece int, float, bool, string veya Object (mesela Transform veya GameObject) olabilir.

Bizim Merhaba fonksiyonumuz public ve hiç parametre almıyor. MerhabaScript’i açın ve içine şu fonksiyonu ekleyin:

public void Merhaba2( string yazi )
{
    Debug.Log( yazi );
}

Bu fonksiyon public, 1 parametre alıyor ve parametresinin türü String. Yani tüm şartlara uyuyoruz. Şimdi buton objesini tekrar seçin ve “On Click()” listesine bir de “MerhabaScript.Merhaba2()”yi ekleyin:

15

Görüldüğü üzere Merhaba2’nin altında boş bir metin kutusu belirdi. İşte buraya Merhaba2 fonksiyonunun parametre olarak aldığı yazi‘nın değerini girebiliriz. Oraya TEST yazın ve oyunu çalıştırın. Butona tıkladığınızda konsola hem “Merhaba Dünya” hem de “TEST” yazılacaktır.

UI Elemanlarını Konumlandırmakla İlgili Ufak Bir İpucu

Shift tuşu! Bu tuş çok işinize yarayabilir.

Objeyi bir yerden bir yere taşıyorsanız Shift’e basılı tuttuğunuz zaman obje ya yatay eksende ya da dikey eksende hareket eder, diğer eksendeki konumu değişmez.

UI elemanının köşelerinden tutup onu boyutlandırırken Shift’e basılı tutarsanız UI elemanının genişlik/yükseklik oranı bozulmaz, obje her iki eksende de bu oranı bozmayacak şekilde boyutlanır.

Button (Script)

Buton objesini seçtiğiniz zaman Inspector‘unda “Button (Script)” adında bir component‘in yer aldığını farketmişsinizdir. Buradaki değerlerin üzerinden hızlıca geçeceğim.

Interactable: Butonun tıklanabilir olup olmadığını belirlemeye yarar. Bu seçeneği kapatırsanız butonun “On Click()” listesi çalışmaz.

Transition: Butona geçiş (transition) animasyonları vermeye yarar. Peki bu geçişler ne zaman olur? Örneğin butonun üzerine fare imlecini getirdiğinizde “Normal“den “Highlighted“a geçiş yapılır. Butona tıkladığınızda “Highlighted“dan “Pressed“e geçiş yapılır. Eğer buton Interactable değilse daima “Disabled” olarak kalır.

Eğer TransitionColor Tint” ise geçişler sırasında butonun rengi bir nebze değişir. Bu renkleri Inspector‘dan ayarlayabilirsiniz. Buradaki “Fade Duration” değeri renkler arası geçişin kaç saniyede gerçekleşeceğini belirler.

Transition‘ı “Sprite Swap” yaparsanız her transition’da butonun sprite‘sinin değişmesini sağlarsınız. Sprite ne derseniz Texture2D’nin UI sistemindeki versiyonu diyebilirim.

Transition‘ı “Animation” yaparsanız butona Animator component‘i vasıtasıyla istediğiniz kadar detaylı bir animasyon verebilirsiniz. Örneğin butonun üzerine mouse ile gelince butonun boyutu biraz artsın, butona tıklayınca butonun rengi kırmızı olsun istiyoruz diyelim. Bunu sağlamak için önce “Auto Generate Animation” butonuna tıklayın:

16

Controller‘a isim olarak “AnimasyonTest” verin ve asset’i istediğiniz yere kaydedin. Şimdi buton objesi seçiliyken Window-Animation yoluyla Animation penceresini açın. Sol üstteki Normal‘i Highlighted ile değiştirin (Highlighted transition’ı, butonun üzerine mouse imlecini getirdiğimiz zaman gerçekleşir):

17

Highlighted‘ın sol üstünde yer alan kırmızı daire şeklindeki butona bir kere tıklayın. Editörün tepesindeki Play ve Pause butonları kırmızı renge bürünecektir: şu anda kayıt modundayız. Bu haldeyken buton üzerinde yaptığımız değişiklikler animasyona yazılır.

Kayıt modundayken butonun Rect Transform‘undaki Scale X ve Y değerlerini 1.25 yapın. Sonrasında Play tuşuna basarak sistemi test edin. Fare butonun üzerine gelince buton büyüyecek.

Şimdi Animation‘a geri dönün ve Highlighted‘ı Pressed ile değiştirin. Yine kırmızı daireye bir kere tıklayın ve bu sefer butonun Image component‘indeki Color değerini kırmızı yapın:

18

Sistemi tekrar test edin. Butona basınca buton kırmızı renge bürünecek.

Bu bölümde elimden geldiğince butonu anlatmaya çalıştım. Üzerinden geçmediğim kısımları Unity dokümantasyonundan, yazılı ve(ya) video derslerden kendiniz tamamlamaya çalışın. Benzer şekilde, sonraki bölümlerde de ilgili UI elemanlarının sadece temel özelliklerine değineceğim.

Text

Sıradaki UI elemanımız Text. Bunu seçmemin sebebi her butonun halihazırda bir Text ile oluşması. Biz zaten butonu gördüğümüze göre o halde Text’in sırası geldi de geçiyor.

Text dediğimiz eleman ekrana bir yazı yazdırmaya yarar. Butonlar varsayılan olarak “Button” yazısıyla gelirler. Bu yazıyı istediğiniz gibi değiştirmek için butonun child objesi olan Text‘i seçin ve Inspector‘da “Text (Script)” component’i altındaki Text değerini değiştirin. Dikkat edin: Text’in içine birden çok satırdan oluşan bir yazı da girebilirsiniz.

Text (Script)“in sahip olduğu önemli değerler şunlar:

Horizontal Overflow: Değeri Wrap olursa yazının butona sığmayan kısmı bir alt satıra yazılır. Değeri Overflow olursa yazı butonun dışına taşabilir.

Vertical Overflow: Değeri Truncate olursa yazı butonun dışına taşamaz, Overflow olursa taşabilir.

Best Fit: Eğer işaretlenirse yazının boyutu, içinde bulunduğu dikdörtgensel alana tam sığacak şekilde otomatik olarak ayarlanır. Ancak siz yine de bu otomatik boyutlandırmaya bir alt limit (Min Size) ve üst limit (Max Size) belirleyebilirsiniz.

Buradaki diğer özellikler çok bariz olduğu için açıklama zahmetine girmiyorum.

Text ile ilgili güzel bir bilgi daha paylaşmak istiyorum: Text vasıtasıyla oluşturduğunuz yazılara efektler vermeniz mümkün. Şu anda üç efekt var: Shadow (gölge), Outline (dış hat) ve “Position As UV1” (nolduğunu bilmiyorum). Örneğin bir yazıya gölge efekti vermek istiyorsunuz diyelim. Yapmanız gereken o Text objesini seçmek ve Component-UI-Effects-Shadow yolunu izlemek. Artık o yazının bir gölgesi var. “Shadow (Script)” component’indeki ayarlarla oynayarak gölgeyi istediğiniz gibi renklendirebilir ve konumlandırabilirsiniz. Gölge uygulanmış örnek bir Text:

18_2

Panel

Bu UI elemanı benim anladığım kadarıyla ekrana bir kutucuk çizdirmeye yarıyor. Varsayılan olarak bu kutucuk tüm ekranı kaplıyor ancak kutucuğu siz istediğiniz gibi konumlandırabilirsiniz. Daha da bahsedecek bir “özellik” bulamadım.

Arayüze UI Elemanlarının Çizdirilme Sırasını Belirlemek

Bu bilgi kırıntısını bir yere not edin çünkü çok işinize yarayabilir. Arayüz elemanlarının canvas üzerinde çizdirilme sırasını elle belirleyebiliyorsunuz. Örneğin arayüzün arkaplanına bir panel koyacaksınız diyelim. Ama o da ne! Panel butonların üzerini kapatıyor. Biz panelin butonlardan önce çizilmesini, böylece butonların arkasında kalmasını istiyoruz. Bunu yapmanın yolu çok basit: paneli Hierarchy‘de buton objesinin yukarısına taşıyın:

19

Canvas içerisinde yer alan objeler yukarıdan aşağıya doğru çizilir. Biz Panel’i başa alarak önce onun çizilmesini sağladık. Böylece sonradan çizilen Button, panelin üzerinde kalıyor ve sorunumuz çözülmüş oluyor.

Image (ve RawImage)

Image, ekrana bir resim (Sprite) çizdirmeye yarar. Bu objenin en önemli değişkeni tabi ki “Image (Script)” component’i içinde yer alan “Source Image” kısmı. Buraya çizdirmek istediğiniz sprite’yi sürüklemeniz yeterli.

Image objesinin bir de RawImage diye farklı versiyonu mevcut. RawImage ise ekrana bir Sprite değil Texture çizdirmeye yarar. Burada yer alan “UV Rect“, texture’ın tamamını değil de sadece belli bir kısmını ekrana çizdirmeye yarar.

Toggle

Kullanıcı sözleşmelerinin altında, sözleşmeyi onayladığınıza dair bir onay kutucuğu olur. İşte o kutucuk bir toggle‘dır. Toggle dediğimiz onay kutucuğu ya işaretli olur ya da olmaz (bir boolean‘ın değerini değiştirmek için mükemmel tercih).

Yeni bir sahne açın ve içinde GameObject-UI-Toggle yolunu izleyerek bir Toggle oluşturun. Hierarchy‘de Toggle’ın üç child objeye sahip olduğunu göreceksiniz: Background, Checkmark ve Label. Buradaki Background, onay kutucuğunun arkaplanını çizdirmeye yararken Checkmark da kutucuğa konulan tik işaretini çizdirmeye yarar. Label ise Toggle’ın sahip olduğu Text‘i değiştirmeye yarar. Bizi asıl ilgilendiren Toggle objesindeki “Toggle (Script)” component’i.

Bu component’te yer alan önemli değişkenlerden bahsedecek olursak:

Is On: Oyunun başında kutucuğun işaretli olup olmayacağını belirtir.

Toggle Transition: Çok gereksiz bir özellik, bırakın Fade olarak kalsın.

Group: Bazen karşınızda birden çok işaretlenebilir kutucuk olur ama bunlardan aynı anda sadece biri seçili olabilir (örneğin cinsiyeti soran işaret kutucukları). İşte böyle bir durumda, aralarından sadece birinin işaretlenebildiği işaret kutucuklarını gruplandırabiliyoruz. Bu değişkene değer vermeyi birazdan göreceğiz.

On Value Changed(Boolean): Nasıl Button‘da “On Click()” vardıysa bunda da “On Value Changed(Boolean)” var. Onay kutucuğuna işaret koyduğumuz/var olan işareti kaldırdığımız zaman bu listede yer alan fonksiyonlar çağrılır.

Toggle’ı anlatmak için aklıma gelen yöntem şöyle: birlikte tek soruluk bir test uygulaması yapacağız. Soru “Hangi ışıkta geçilir?” olacak ve şıklar da (tahmin edeceğiniz üzere) kırmızı, sarı ve yeşil olacak. Bu Toggle’lardan aynı anda sadece biri işaretlenebilecek. Doğru seçeneği seçtiğimizde (acaba hangisi??) konsola “KAZANDIN!” mesajı yazdırılacak.

O halde boş bir sahne açın ve içinde 1 tane Text, 3 tane de Toggle objesi oluşturun. Text’i en tepeye alın ve Toggle’ları da onun altına istediğiniz gibi dizin. Toggle’ların isimlerini “KirmiziToggle“, “SariToggle” ve “YesilToggle” olarak değiştirin (ki hangi toggle’ın kimi temsil ettiğini rahatça anlayabilelim).

Text‘i seçin ve değerini “Hangi ışıkta geçilir?” olarak değiştirin. Ardından KirmiziToggle‘ın “Label” isimli child objesini seçin ve oradaki Text‘i “Kırmızı” yapın. Eğer biraz daha görsellik katmak istiyorum derseniz de bu sefer KirmiziToggle’ın Background child objesini seçin ve oradaki “Color” değerini kırmızı yapın. Böylece işaret kutucuğu kırmızı renkle boyanacak. Çok havalı! Son olarak Toggle’ın kendisini seçin ve “Is On” değerini false yapın.

Diğer Toggle’lar için de aynı işlemi uygulayın. Bende bu adım sonrasında arayüz şöyle duruyordu:

20

Bu Kırmızı, Sarı ve Yeşil cevaplarından aynı anda maksimum 1 tanesinin seçili olabilmesini istiyoruz. O halde Toggle‘ın “Group” değişkeninden faydalanacağız. Ama öncesinde bir “Toggle Group” oluşturmamız lazım. “Toggle Group” component’ini Component-UI-Toggle Group yolunu izleyerek istediğiniz bir objeye ekleyin. Ben KirmiziToggle objesine ekledim.

Toggle Group‘un özel bir değişkeni var: “Allow Switch Off“. Bu değişkenin değeri true olursa, o grupta aynı anda hiçbir onay kutucuğunun işaretli olmaması mümkün olur. Değişkenin değeri false olursa bu sefer gruptaki işaret kutucuklarından birisi her zaman işaretli olmak zorunda olur. Bizde öyle bir zorunluluk olmadığı için bu değişkeni true yapın:

21

Şimdi KirmiziToggle, SariToggle ve YesilToggle objelerini tek tek seçin ve her birinin Group değişkenine değer olarak “Toggle Group” component’ine sahip objeyi (KirmiziToggle) verin. Oyunu çalıştırdığınızda 3 kutucuk arasından aynı anda maksimum 1 tanesinin işaretlenebildiğini göreceksiniz.

Sıra geldi doğru cevabı bilince ödülümüzü almaya. “KpssScript” adında yeni bir C# script oluşturun. YesilToggle‘ı işaretlediğimiz zaman bu scriptteki bir fonksiyonu çağırmak, çağrılan o fonksiyon vasıtasıyla da konsola “KAZANDIN!” yazdırmak istiyoruz. O halde scriptin içeriğini şöyle düzenleyelim:

using UnityEngine;

public class KpssScript : MonoBehaviour
{
	public void DogruCevap( bool isaretlendiMi )
	{
		if( isaretlendiMi )
			Debug.Log( "KAZANDIN!" );
	}
}

Scripti herhangi bir objeye (Main Camera) verin. Sonrasında YesilToggle‘ı seçip “On Value Changed(Boolean)” listesine Main Camera’daki KpssScript.DogruCevap fonksiyonunu ekleyin. Yalnız burada çok ince bir detay var o da şu ki bu listede iki tane DogruCevap fonksiyonu var:

22

Bu iki DogruCevap arasından üsttekini (“Dynamic bool” altında yer alanı) seçmelisiniz. Üsttekiyle alttakinin ne farkı var derseniz; üsttekinde DogruCevap fonksiyonuna otomatik olarak onay kutucuğunun sahip olduğu değer gönderilirken alttakinde ise DogruCevap fonksiyonuna yollanacak boolean parametresinin değeri elle girilir. Biz, fonksiyona onay kutucuğunun sahip olduğu değerin gitmesini istiyor ve bunun için üstteki DogruCevap’ı seçiyoruz.

Herşeyi düzgün yaptıysanız şu anda oyunu çalıştırıp doğru cevabı bildiğinizde konsola tebrik yazısı yazdırılmalı. Eğer birşey olmuyorsa örnek projeyi kontrol etmenizi öneririm.

Input Field

Bu UI elemanı, adından da anlaşılacağı üzere kullanıcıdan bir String input almaya yarar. Bu input kullanıcının ismi de olabilir, şifresi de olabilir, e-mail adresi de olabilir, o da olabilir bu da olabilir; aklınıza ne gelirse…

Bu kısımda da örnek bir uygulama yapacağız. Ekranımızda iki Input Field yer alacak ve soldakine yazdığımız yazının tersi, sağdakine otomatik olarak yazdırılacak. Yani cümleyi tersten yazdıracağız.

Yeni bir scene oluşturup ekrana iki tane Input Field ekleyin. Bu Input Field’ları alt alta koyun. Üsttekinin arkaplan rengini açık yeşil, alttakinin arkaplan rengini ise açık sarı yapın (hangi Color değerini ellemeniz gerektiğini kendiniz keşfedin). Şimdi birlikte InputField’ın child objelerine bakalım:

Placeholder: Eğer ki input field’ın içi boşsa, input field’a birşeyler karalayana kadar input field’da bu Text görünür.

Text: Input field’a birşeyler karaladığımız anda artık input field’da bu text görünür.

Üstteki input field’ın placeholder’ının yazısını “Birşeyler yazın…” olarak, alttakinin yazısını ise “Yazılan cümlenin tersi…” olarak değiştirin:

23

Gelelim “Input Field (Script)” component’indeki önemli değişkenlere:

Text: Oyunun başında input field’da yazılı olan değeri değiştirmeye yarar. Varsayılan olarak burası boştur.

Character Limit: Girilen input’un maksimum kaç karakter uzunluğunda olabileceğini belirler.

Content Type: Girilen input’un türünü belirler. Ona göre o input field her karakteri kabul etmez. Önemli content type’lar şunlar:

  • Standard: Her türlü karakter kabul edilir.
  • Integer Number: Sadece rakamlar kabul edilir.
  • Decimal Number: Rakamlar ve nokta işareti kabul edilir (küsürlü sayılar girmek için)
  • Password: Her karakter kabul edilir. Input’taki karakterler * işareti ile temsil edilir.
  • Pin: Sadece rakamlar kabul edilir. Input’taki karakterler * işareti ile temsil edilir.

Line Type: Eğer değeri “Single Line” olursa input field tek satırlık String kabul eder, “Multi Line Newline” olursa input field birden çok satırlık String de kabul eder. Yalnız birden çok satırı rahatça göstermek için input field’ın yüksekliğini elle artırmanız gerekebilir.

Caret Blink Rate: Input girerken yanıp sönen o işaretçiğin (tam olarak Türkçe’si ne bilmiyorum) yanıp sönme hızını belirlemeye yarar.

Selection Color: Input Field’dan bir yazı seçtiğimizde, seçili yazının boyanacağı rengi belirler.

On Value Change(String): Input field’a yeni bir karakter girdiğimizde/varolan bir karakteri sildiğimizde bu listedeki fonksiyonlar çağrılır.

End Edit(String): Input field’a gireceklerimizi girip Enter’a bastığımızda veya arayüzdeki boş bir yere tıklayarak işimizi bitirdiğimizde (artık o input field’a odaklanmadığımızda) bu listedeki fonksiyonlar çağrılır.

İsterseniz önce bir “End Edit(String)“i test edelim. “TerstenScript” adında yeni bir C# script oluşturup içeriğini güncelleyin:

using UnityEngine;

public class TerstenScript : MonoBehaviour
{
	public void InputYazdir( string yazi )
	{
		Debug.Log( yazi );
	}
}

Sonrasında bu scripti Main Camera‘ya verin ve üstteki Input Field‘ın “End Edit(String)” listesine TerstenScript.InputYazdir fonksiyonunu ekleyin (“Dynamic string” altında yer alan fonksiyonu seçeceksiniz, en alttakini değil!).

Oyunu çalıştırın. Üstteki kutucuğa birşeyler yazıp Enter’a bastığınızda veya mouse ile başka bir yere tıkladığınızda konsola, input field’daki yazı yazdırılacak.

Gelelim asıl kısma: üstteki input field’a her düzenleme yaptığımızda alttaki input field’ın güncellenmesini istiyoruz. Bunun için alttaki input field’ı bir değişkende tutmalı, üstteki input field’ın değeri değiştikçe alttakinin Text değerini script vasıtasıyla güncellemeliyiz.

TerstenScript“i şu şekilde güncelleyin:

using UnityEngine;
using UnityEngine.UI;

public class TerstenScript : MonoBehaviour
{
	public InputField alttakiInputField;
	 
	public void AlttakiniGuncelle( string usttekiInput )
	{
		string alttakiOutput = "";
		 
		for( int i = usttekiInput.Length - 1; i >= 0; i-- )
		{
			alttakiOutput += usttekiInput[i];
		}
		 
		alttakiInputField.text = alttakiOutput;
	}

	public void InputYazdir( string yazi )
	{
		Debug.Log( yazi );
	}
}

InputField türünde public bir değişkenimiz var: alttakiInputField. Unity’nin yeni UI sistemiyle ilgili kod yazarken scriptimizin başına “using UnityEngine.UI;” komutunu eklemek zorundayız.

Scripte AlttakiniGuncelle adında yeni bir fonksiyon ekledik. Bu fonksiyon bir parametre alıyor, onu ters çevirip alttakiInputField‘ın text‘ine değer olarak veriyor.

Şimdi Main Camera‘ya gelin ve “Tersten Script” component’inin “Alttaki Input Field” değişkenine değer olarak alttaki input field’ı verin. Sonrasında üstteki input field’ı seçin ve “On Value Change(String)” listesine TerstenScript.AlttakiniGuncelle fonksiyonunu ekleyin. Ardından sistemi test edin. İşte örnek bir resim:

24

Slider

Bu eleman ekrana bir slider çizdirmeye yarar elbette ki. Slider’ın ne olduğunu hatırlamıyorsanız sahnede bir Slider oluşturun, hemen anlayacaksınız.

Slider ile ilgili iki örnek uygulama yapacağız. İlkinde ekranda bir slider bir de text olacak ve bu slider’ın değerini değiştirdikçe yazı büyüyüp küçülecek.

O halde hemen yeni bir scene oluşturup içine bir slider bir de text ekleyin. Text’i slider’ın üzerine taşıyın ve değer olarak istediğiniz yazıyı verin:

25

Kodlama yapmaya başlamadan önce “Slider (Script)” component’ini inceleyelim:

Min Value: Slider’ın döndürebileceği minimum değeri belirler.

Max Value: Slider’ın döndürebileceği maksimum değeri belirler.

Direction: Slider’ın yönünü belirler:

  • Left To Right: Slider soldayken minimum, sağdayken maksimum değer döndürülür.
  • Right To Left: Slider soldayken maksimum, sağdayken minimum değer döndürülür.
  • Top To Bottom: Slider tepedeyken minimum, dipteyken maksimum değer döndürülür.
  • Bottom To Top: Slider tepedeyken maksimum, dipteyken minimum değer döndürülür.

Whole Numbers: İşaretlenirse, slider değer olarak sadece [Min Value, Max Value] aralığındaki tamsayıları döndürebilir.

Value: Oyun başladığında slider’ın sahip olacağı değeri belirler.

On Value Changed(Single): Slider’ın değerini değiştirdiğimiz zaman bu listedeki fonksiyonlar çağrılır.

Şimdi “SliderTest” adında yeni bir C# script oluşturun:

using UnityEngine;
using UnityEngine.UI;

public class SliderTest : MonoBehaviour
{
	public Text yazi;

	public void YaziyiBoyutlandir( float boyut )
	{
		Debug.Log( boyut );
		
		yazi.rectTransform.localScale = new Vector3( boyut, boyut, boyut );
	}
}

YaziyiBoyutlandir fonksiyonu bir float parametre alıyor ve yazının “Rect Transform” component’inin “Scale” değerini bu parametreyi kullanarak değiştiriyor (Scale‘i script vasıtasıyla değiştirirken localScale değişkeni kullanılır).

Scripti Main Camera‘ya verin. Yazi‘ya değer olarak Text objesini verin. Sonra slider’ın “On Value Changed(Single)” listesine SliderTest.YaziyiBoyutlandir fonksiyonunu ekleyip oyunu çalıştırın. Yazının slider ile boyutlanması lazım. Eğer olmuyorsa örnek projeyi kontrol edebilirsiniz.

Gelelim ikinci örnek uygulamaya. Bu örnekte bir health bar (sağlık barı) simüle edeceğiz. Ekranda iki de buton olacak: sağlık butonu ve hasar butonu. Sağlık butonu sağlık barını doldururken hasar butonu sağlığın bir kısmını götürecek.

Yeni bir sahne oluşturup içine bir slider, iki de buton ekleyin. Slider‘ın Direction‘ını “Bottom To Top” yapın. İki butonu slider’ın yanına dizin:

26

Bu örnekteki slider’ı biraz kişiselleştirmemiz lazım. Örneğin slider’ın elle değiştirilmesini istemiyoruz. Bu durumda slider’ın ucundaki daireye ihtiyacımız yok. Neyse ki onu direkt olarak silmemiz mümkün ve bu bir sorun da teşkil etmiyor. Slider‘ın “Handle Slide Area” isimli child objesini seçin ve silin. Güle güle daire!

Daireyi silince arkada gri bir arkaplan belirdi. Biz bunu da istemiyoruz. Slider‘ın “Background” isimli child objesini de silin!

Eğer oyunu açıp test ederseniz, slider’ın herhangi bir yerine tıklayınca onun değerini hâlâ değiştirebildiğimizi göreceksiniz. Biz buna kesin bir şekilde engel olmalıyız. Slider’ın değerini sadece kod yardımıyla değiştirebilmeliyiz. Bunu yapmak için Slider objesinin “Interactable” değişkenini false yapın. Artık slider’ın değerini oyun sırasında elle değiştirmek kesinlikle mümkün değil.

Slider (Script)” component’inde bir uyarı mesajı görmüşsünüzdür:

27

Hata mesajı diyor ki slider’a renk değişimi efekti (transition) uygulayabilmek için, bu efektin uygulanacağı bir hedef obje seçmeliyiz. Ama bu slider etkileşime geçilen bir slider olmadığı için biz zaten herhangi bir transition efekti istemiyoruz. Bu uyarıdan kurtulmak için “Transition“ı “None” yapmanız yeterli.

Yapacağımız bir sonraki değişiklik sağlık barının değer aralığını değiştirmek. Benim sağlık barım [0,100] aralığında bir tamsayı değeri alacak. Bunun için slider’ın “Min Value“sini 0, “Max Value“sini 100 yapıyor ve “Whole Numbers” kutucuğunu işaretliyorum. Sonrasında değeri 1 olan “Value“yi 100 yapıyorum. Oyunun başında sağlığımız dolu olacak.

Son olarak sağlık barının rengini yeşil yapalım. Bunun için slider’ın “Fill” isimli child objesinin rengini değiştirmeniz yeterli:

28

Gelelim kod kısmına. “SaglikBari” adında yeni bir C# script oluşturun:

using UnityEngine;
using UnityEngine.UI;

public class SaglikBari : MonoBehaviour
{
	public Slider saglikBari;

	public void HasarVer()
	{
		saglikBari.value -= 10;
		Debug.Log( saglikBari.value );
		
		if( saglikBari.value <= 0 )
			Debug.Log( "Karakter öldü" );
	}
	
	public void Wololo()
	{
		saglikBari.value += 10;
		Debug.Log( saglikBari.value );
	}
}

Bu scriptte “saglikBari” adında public bir değişkenimiz var; değişkenin türü Slider. Bu değişkende sağlık barını depolayacağız.

Scriptin iki fonksiyonu var:

  • HasarVer(): sağlığı 10 azaltıyor ve eğer sağlık 0’a inmişse konsola, öldüğümüze dair bir mesaj yazdırıyor.
  • Wololo(): sağlığı 10 artırıyor.

Yapmamız gereken Hasar butonuna tıklayınca HasarVer() fonksiyonunu, Sağlık butonuna tıklayınca Wololo() fonksiyonunu çağırmak.

Scripti Main Camera‘ya verip “Slider” değişkenine değer olarak sağlık barını verin. Sonra hasar butonunun “On Click()” listesine “SaglikBari.HasarVer” fonksiyonunu, sağlık butonunun “On Click()” listesine de “SaglikBari.Wololo” fonksiyonunu ekleyin. Artık oyunu test edebilirsiniz.

Scrollbar, Scroll Rect ve Mask

Kullanıcı sözleşmelerini bilirsiniz. Sözleşmenin sonuna ulaşmak için yandaki çubuğu milyon pixel aşağı sürüklememiz gerekir. Biz çubuğu aşağı-yukarı kaydırdıkça sözleşmeyi ekrana çizdiren kutucuktaki yazı da aşağı-yukarı kayar. İşte bu örnekteki çubuk bir Scrollbar, sözleşmeyi ekrana çizdiren kutucuk ise Scroll Rect‘tir.

GameObject menüsünde Scroll Rect‘i göremezsiniz. Scroll Rect bir obje değil bir component‘tir. Rect Transform component’ine sahip herhangi bir objeye Scroll Rect de verilebilir.

Scroll Rect ile ilgili yapacağımız örneğin konusu ne tahmin edin: kullanıcı sözleşmesi! Kullanıcı sözleşmesinin altında ise bir buton olacak ve sözleşmeyi okuduysak butona tıklayıp uygulamayı kullanmaya devam edebileceğiz.

Bu örnek biraz uzun olacak o yüzden adım adım gideceğiz. Öncelikle kullanıcı sözleşmesi için sahnede SozlesmeText adında bir Text oluşturun. Text’in içeriğini istediğiniz gibi doldurun ama oldukça uzun bir sözleşme olmasına dikkat edin. Ardından Text’in yüksekliğini (Height), yazıyı içine tam oturtacak şekilde ayarlayın:

29

Şimdi bu uzun sözleşmeyi scroll edebilmek için bir Scroll Rect oluşturalım. Bu Scroll Rect’i ben bir Panel‘in içinde oluşturmayı uygun buldum. Bunun için ScrollPanel adında yeni bir Panel oluşturun ve panele Component-UI-Scroll Rect yolunu izleyerek bir “Scroll Rect” component’i verin.

Panel, varsayılan olarak tüm canvas’ı kaplar; biz bunu epey bi küçültelim. Paneli, genişliği en azından kullanıcı sözleşmesinin genişliği kadar olacak şekilde boyutlandırın. Ardından panelin yüksekliğini, kullanıcı sözleşmesinin sadece bir kısmını içine alabilecek şekilde daraltın. Panelin arkaplan rengini (Color) beyaz yapın ve panel ile kullanıcı sözleşmesinin üst kenarlarını aynı hizaya getirin:

30

Geriye önemli bir tek şey kaldı: panele (Scroll Rect‘e) scroll edeceği UI elemanının kullanıcı sözleşmesi Text‘i olduğunu bildirmek. Bunu yapmak ise sandığınızdan da kolay: SozlesmeText‘i ScrollPanel‘in bir child objesi yapın ve ardından ScrollPanel‘in “Scroll Rect (Script)” component’inde yer alan “Content“e değer olarak SozlesmeText‘i verin:

31

Oyunu çalıştırıp mouse imlecini ScrollPanel üzerinde sürüklerseniz (veya fare imleci panelin üzerindeyken mouse tekerleğini döndürürseniz) kullanıcı sözleşmesinin o yönde hareket ettiğini göreceksiniz.

Oluşturduğumuz sistemin iki eksiği mevcut: kullanıcı sözleşmesinin panelin dışına taşan kısmı hâlâ ekrana çizdiriliyor ve henüz Scroll Rect‘e bir Scrollbar atamadık.

Bu sorunları çözmeden önce dilerseniz “Scroll Rect (Script)“in sahip olduğu değişkenlere bir göz atalım:

Horizontal: Scroll Rect’teki içeriğin yatay eksende (sağ-sol) kaydırılıp (scroll) kaydırılamayacağını belirler.

Vertical: Scroll Rect’teki içeriğin dikey eksende (yukarı-aşağı) kaydırılıp (scroll) kaydırılamayacağını belirler.

Movement Type: Scroll Rect’teki içeriğin (bizde kullanıcı sözleşmesi Text’i) davranış biçimini belirler. Burada üç farklı mod yer almakta:

  • Unrestricted: İçerik Scroll Rect’in içinde kalmak zorunda olmaz. Şu anda kullanıcı sözleşmesini Scroll Rect’in dışında tutmak mümkün değil ama bu seçeneği seçerseniz bu mümkün olur. Neden böyle birşey isteyesiniz orası tartışılır.
  • Elastic: İçerik Scroll Rect’in dışına ancak mouse ile tutulup sürüklenirken çıkarılabilir. Mouse ile sürükleme işlemi sonlandırıldığında içerik otomatik olarak Scroll Rect’in içerisine geri yerleşir.
  • Clamped: İçeriği Scroll Rect’in dışına çıkarmak hiçbir şekilde mümkün olmaz.

Inertia: Eğer bu seçenek işaretliyse, Scroll Rect’in içeriğini (SozlesmeText) tutup bir yöne hızlı bir şekilde fırlatınca içerik aniden durmaz, yavaşlayarak “yumuşak” bir şekilde durur.

Scroll Sensitivity: Fare tekerleğinin hassasiyetini ayarlar. Bence bu değeri en azından 10 yapın zira 1 iken kullanıcı sözleşmesini tekerleği oynatarak hareket ettirmek tam bir işkence.

On Value Changed(Vector2): Scroll Rect’teki içeriği kaydırdıkça (veya scrollbar’ların konumunu değiştirdikçe) bu listedeki fonksiyonlar çağrılır. Buradaki parametrenin türü Vector2‘dir çünkü horizontal scrollbar değerini x, vertical scrollbar değerini ise y içinde tutan en uygun veri türü Vector2‘dir.

Gelelim az önce bahsettiğim sorunları çözmeye. İlk sorunu çözmek için Mask adındaki bir component‘ten faydalanacağız. ScrollPanel‘i seçin ve Component-UI-Mask yolunu izleyin. O da ne: ScrollPanel’in dışında kalan yazı artık ekrana çizilmiyor!

32

Peki bu nasıl oldu? Mask component’i, Scroll Rect‘in dışına taşan alanı gizlemeye yarar. Mask component’i düzgün çalışmak için bir Image component‘ine ihtiyaç duyar. O Image’in sınırları dahilindeki alan Scroll Rect’in çizdireceği alan, Image’in dışında kalan alan ise Scroll Rect’in çizdirmeyeceği alan olarak belirlenir. Şansımıza, Panel objesi zaten bir Image ile geliyor; bu sayede sadece Mask ekleyerek sorunumuzu çözdük. Panelin Image’ı, panel objesinin arkaplanının kendisi. Bu durumda panelin arkaplanının dışına taşan kısımlar Mask sayesinde çizdirilmemiş oluyor.

Mask component’inin bir değişkeni bulunmakta: “Show Mash Graphic“. Bu seçenek Image‘daki sprite‘nin ekrana çizilip çizilmeyeceğini belirler. Eğer bu seçeneği kapatırsanız panelin arkaplanı görünmez olur.

Geldik ikinci sorunu çözmeye; yani sahneye bir Scrollbar ekleyip bunu Scroll Rect‘e bağlamaya.

Öncelikle GameObject-UI-Scrollbar yolunu izleyerek arayüze bir Scrollbar ekleyin. Farketmişsinizdir; “Scrollbar (Script)“in sahip olduğu değerler “Slider (Script)“inkine “oldukça” benziyor. Burada yer alan yeni değişkenler ise şunlar:

Size: Scrollbar’ın tutacağının boyutunu belirler.

Number of Steps: Eğer bu değer 0 ise scrollbar yumuşak bir şekilde hareket eder, değilse “zıplaya zıplaya” hareket eder. Bunu anlamanın en iyi yolu denemek. Bu değişkenin değerini 3 yapıp oyunu çalıştırın ve scrollbar’ı hareket ettirin. Ne demek istediğimi anlayacaksınız.

Şimdi bizim bu scrollbar’da yapmamız gereken değişiklikler neler? İlk yapmamız gereken şey scrollbar’ı yatay değil dikey hale sokmak. Bunun için Direction‘ı “Bottom To Top” olarak değiştirmeniz yeterli.

Ardından Scrollbar‘ı ScrollPanel‘in sağ kenarına getirin ve yüksekliğini ScrollPanel’inkiyle aynı yapın. Son olarak da ScrollPanel’i seçin ve Inspector‘dan “Vertical Scrollbar” değişkenine değer olarak, az önce oluşturduğunuz Scrollbar‘ı verin. Böyle yaparak Scroll Rect‘i dikey eksende (yukarı-aşağı) hareket ettirecek scrollbar’ı belirlemiş oluyoruz.

Oyunu test edin. Eğer scrollbar düzgün çalışmıyorsa örnek projeyi kontrol edin.

Geriye sadece sözleşmeyi onaylamaya yarayan buton kaldı. Yeni bir Button oluşturup bunu ScrollPanel‘in altına yerleştirin. Button’un ismini “OnayButon” olarak değiştirin:

33

Butona tıklayınca yapılacak şeyleri ayarlayalım. Bunun için “SozlesmeScript” adında yeni bir C# script oluşturun:

using UnityEngine;

public class SozlesmeScript : MonoBehaviour
{
	public void OnayButonu()
	{
		Debug.Log( "SÖZLEŞME ONAYLANDI!" );
	}
}

Scripti Main Camera‘ya verip OnayButon objesinin “On Click()” listesine “SozlesmeScript.OnayButonu” fonksiyonunu ekleyin. Artık butona tıklayınca konsola mesaj yazdırılacak.

Biz onay butonuna, ancak ve ancak sözleşmenin dibine ulaşmışsak (yani scrollbar en alt hizadaysa) tıklanabilmesini istiyoruz. Yani buton, oyunun en başında kullanıcının input’larını yoksayacak. Bunu yapmak basit: OnayButon‘daki “Interactable” seçeneğini kapatın. Artık butona tıklayamıyoruz. Şimdi geriye, sözleşmenin sonuna ulaşınca butonu aktif hale getirmek kaldı.

SozlesmeScript scriptini şöyle güncelleyin:

using UnityEngine;
using UnityEngine.UI;

public class SozlesmeScript : MonoBehaviour
{
	public Button onayButonu;

	public void OnayButonu()
	{
		Debug.Log( "SÖZLEŞME ONAYLANDI!" );
	}
	
	public void ButonuAktiflestir( float deger )
	{
		if( deger <= 0.1f )
			onayButonu.interactable = true;
	}
}

Main Camera‘daki “Onay Butonu” değişkenine değer olarak OnayButon‘u verin. Ardından Scrollbar objesini seçip “On Value Changed(Single)” listesine “SozlesmeScript.ButonuAktiflestir” fonksiyonunu ekleyin (listeden fonksiyonu seçerken üsttekini seçmeyi unutmayın!).

Naptık derseniz şöyle yaptık: artık Scrollbar‘ın değeri değiştikçe ButonuAktiflestir fonksiyonu çağrılıyor ve scrollbar’ın değeri (value) fonksiyondaki “deger” parametresine aktarılıyor. Scrollbar’ın “Direction“ı “Bottom To Top” olduğu için, eğer scrollbar tepedeyse “value” 1, dipteyse “value” 0 değerini alır. Bu bilgiyi kullanarak, eğer “deger” değişkeninin değeri 0.1’den küçükse, yani scrollbar epey dipteyse (oyuncu mecburen sözleşmeyi aşağı kaydırdıysa) OnayButon‘un “Interactable” değişkenini true yapıyoruz ve böylece artık butona tıklayabiliyoruz.

Bu örnekle birlikte hemen hemen tüm UI elemanlarını görmüş olduk. Geriye anlatacak birkaç ufak detay kaldı sadece.

Bir UI Elemanına Basılı Tutulduğu Sürece Yapılacak Şeyleri Belirlemek (Event Trigger Sistemi)

Butonu ele alalım. Butona tıkladığımızda istediğimiz bir fonksiyonu çağırabiliyoruz. Ama diyelim ki biz, butona basılı tuttuğumuz sürece bir fonksiyonu çağırmak istiyoruz. Bu durumda “Event Trigger” adında bir component kullanılır. Buton, varsayılan olarak sadece “On Click()” event’ine destek verirken Event Trigger ile daha fazla event desteklemesi sağlanabilir.

Bu konuyla ilgili iki örnek uygulama yapacağız. İkisinde de butonlar üzerinden gideceğiz. İlk örnek ile başlayalım isterseniz…

Yeni bir scene açıp içinde bir tane buton oluşturun. Butona RenkButon ismini verin. Yapmak istediğimiz şey şu: bu butona basılı tuttuğumuz sürece butonun arkaplan rengi değişecek. Butona basılı tuttuğumuz sürece bir iş yaptırmak için Event Trigger‘ı kullanacağız. Butonu seçin ve Component-Event-Event Trigger yolunu izleyin.

Inspector panelinde Event Trigger component‘i belirecek. Bu component şu anda birşey yapmıyor çünkü henüz o UI elemanına uygulanacak özel bir event seçmedik. Mevcut event’lerin listesini görmek için “Add New Event Type” butonuna tıklayın:

34

Burada oldukça fazla sayıda event yer almakta. Ben bunlar arasından bildiklerimi sizlerle paylaşayım:

PointerEnter: Mouse imleci bu UI elemanının üzerine geldiği anda tek seferlik çalıştırılır.

PointerExit: Mouse imleci bu UI elemanının üzerinden çekildiği anda tek seferlik çalıştırılır.

PointerDown: Bu UI elemanına mouse/parmak ile dokunulduğu anda tek seferlik çalıştırılır.

PointerUp: Bu UI elemanına mouse/parmak ile dokunma işlemi sonlandırıldığı anda tek seferlik çalıştırılır.

PointerClick: Button‘daki “On Click()” ile aynı şeyi yapar. Yani bu UI elemanına mouse/parmak ile click yapıldığında (tıklanıp hemen ardından bırakıldığında) tek seferlik çalıştırılır.

Drag: Bu UI elemanına mouse/parmak basılı durumda iken mouse/parmak her hareket ettirildiğinde çalıştırılır. Bu event’i OnMouseDrag() ile karıştırmayın. OnMouseDrag() fonksiyonu, bir objeye basılı tuttuğumuz sürece çalıştırılıyordu ve bu esnada mouse’u/parmağı hareket ettirip ettirmediğimiz önemsizdi. Ancak Drag event’inde yer alan fonksiyonların çağrılması için mouse’un/parmağın hareket etmesi şart.

Burada bahsettiğim event’ler hemen her durum için yeterlidir. Diğer event’leri dilerseniz kendiniz araştırabilirsiniz.

EventScript” adında yeni bir C# script oluşturun:

using UnityEngine;
using UnityEngine.UI;

public class EventScript : MonoBehaviour
{
	public Image arkaplan;
	private bool drag = false;
	private Vector3 renkRGB = Vector3.one;
	
	public void ButonaTiklandi()
	{
		drag = true;
	}
	
	public void ButonBirakildi()
	{
		drag = false;
	}
	
	void Update()
	{
		if( drag )
		{
			renkRGB += new Vector3( 0.1f, 0.2f, 0.3f ) * Time.deltaTime;
			Color arkaplanRenk = new Color();
			arkaplanRenk.r = Mathf.PingPong( renkRGB.x, 1f );
			arkaplanRenk.g = Mathf.PingPong( renkRGB.y, 1f );
			arkaplanRenk.b = Mathf.PingPong( renkRGB.z, 1f );
			arkaplanRenk.a = 1f;
			arkaplan.color = arkaplanRenk;
		}
	}
}

Az önce Drag event’ini açıklarken bahsettim: Drag event’inin çalışması için mouse’un hareket halinde olması lazım. Oysa biz, mouse’u sabit tuttuğumuz sürece de butonun renginin değişmesini istiyoruz. Bizim rengi değiştirirken aradığımız tek koşul butona basılı tutuyor olmak.

Bunun için şöyle bir yol düşündüm: butona dokunulduğu anda ButonaTiklandi() fonksiyonunu çağıracağız ve “drag” adındaki bir değişken true değerini alacak. Butonu bıraktığımızda ise ButonBirakildi() fonksiyonunu çağıracağız ve “drag” değişkeni false değerini alacak. Update() fonksiyonunda ise “drag”ın değerinin true olup olmadığına bakacağız ve eğer true ise “arkaplan” değişkeninde tutulan UI elemanının (butonun) arkaplan rengini değiştireceğiz (Update() fonksiyonu içinde yaptığımız tek şey “arkaplan” objesinin arkaplan rengini değiştirmek; kodun uzun olduğuna bakmayın).

O halde planımızı uygulamaya sokalım. İlk iş olarak Main Camera‘ya “EventScript.js” scriptini verin. Script’teki “Arkaplan” değişkenine değer olarak RenkButon objesini verin. Sonrasında RenkButon objesinin Event Trigger component’ine gelin ve buraya bir PointerDown event’i ekleyin. Event gerçekleşince çağrılacak fonksiyonlar listesine ise kameradaki EventScript.ButonaTiklandi fonksiyonunu ekleyin. Ardından Event Trigger’a bir de PointerUp event’i ekleyin ve bu event’e de EventScript.ButonBirakildi fonksiyonunu ekleyin:

35

Oyunu test edin. Butona basılı tuttuğunuz sürece butonun arkaplan rengi değişmeli. Birşeyler düzgün çalışmıyorsa örnek projeyi kontrol edebilirsiniz.

Geldik ikinci örnek uygulamaya. Bu örnekte de ekranda bir buton olacak ve bu butonu oyun sırasında fare ile tutup sürükleyerek istediğimiz yere taşıyabileceğiz.

Bu sefer yeni bir sahne oluşturmanıza gerek yok. Sadece sahnede yeni bir buton oluşturup onu önceki butondan farklı bir yere taşıyın. Bu butona HareketButon adını verin. Sonra bu butona da Event Trigger component’i ekleyin.

Artık “EventScript” scriptini güncellemeye hazırız:

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class EventScript : MonoBehaviour
{
	public Image arkaplan;
	private bool drag = false;
	private Vector3 renkRGB = Vector3.one;
	
	public void ButonaTiklandi()
	{
		drag = true;
	}
	
	public void ButonBirakildi()
	{
		drag = false;
	}
	
	void Update()
	{
		if( drag )
		{
			renkRGB += new Vector3( 0.1f, 0.2f, 0.3f ) * Time.deltaTime;
			Color arkaplanRenk = new Color();
			arkaplanRenk.r = Mathf.PingPong( renkRGB.x, 1f );
			arkaplanRenk.g = Mathf.PingPong( renkRGB.y, 1f );
			arkaplanRenk.b = Mathf.PingPong( renkRGB.z, 1f );
			arkaplanRenk.a = 1f;
			arkaplan.color = arkaplanRenk;
		}
	}
	
	public void ButonSurukleniyor( BaseEventData data )
	{
		PointerEventData mouseData = (PointerEventData) data;
		mouseData.pointerPress.transform.Translate( mouseData.delta );
	}
}

Tek yaptığımız şey scripte ButonSurukleniyor adında yeni bir fonksiyon eklemek oldu. Bu fonksiyonu, butonun Drag event’inde çağıracağız.

Event fonksiyonlarında eğer ki mouse’un/parmağın konumuna, hareket etme miktarına vb. erişmek istiyorsanız o zaman fonksiyona BaseEventData türünde bir parametre eklemek zorundasınız; parametrenin ismi önemli değil (ben “data” ismini verdim). Sonra script içerisinde bu parametreyi PointerEventData‘ya typecast yapmalısınız (ben bu değişkene “mouseData” ismini verdim). Artık PointerEventData türündeki değişkeni kullanarak mouse/parmak ile ilgili detaylı bilgilere erişebilirsiniz.

PointerEventData‘yı kullanarak erişebileceğimiz önemli bilgiler neler diye soracak olursanız:

button: UI elemanına hangi fare tuşuyla tıklanıldığını depolar. Üç değer alabilir:

  • InputButton.Left: Sol mouse tuşu
  • InputButton.Middle: Orta mouse tuşu
  • InputButton.Right: Sağ mouse tuşu

clickTime: UI elemanına tam olarak ne zaman tıklanıldığını depolar.

delta: Bu event esnasında mouse’un/parmağın ekranda kaç pixel hareket ettiğini depolar.

position: Mouse’un/parmağın ekrandaki mevcut konumunu depolar.

pointerPress: Tıklanılan UI elemanını GameObject türünde depolar.

Peki biz fonksiyonda ne mi yapıyoruz? Önce pointerPress ile tıkladığımız butona (GameObject olarak) erişiyoruz. Sonra bu GameObject‘in Transform component’ine erişiyoruz. Sonra da Translate fonksiyonu ile bu objeyi hareket ettiriyoruz. Peki ne kadar hareket ettiriyoruz? delta kadar; yani mouse’un yatay ve dikey eksende oynadığı pixel sayısı kadar.

NOT: ButonSurukleniyor fonksiyonunun düzgün çalışması için scriptin başına “using UnityEngine.EventSystems;” komutu eklemek zorundaydık çünkü BaseEventData ve PointerEventData class’ları UnityEngine.EventSystems namespace‘inde yer almaktadırlar.

Geriye sadece HareketButon‘daki Event Trigger‘a Drag event‘i ekleyip bu event’te EventScript.ButonSurukleniyor fonksiyonunu çağırmak kaldı:

36

Oyunu test ederseniz butonun fare ile sürüklenebildiğini göreceksiniz. Tebrikler!

Arayüzün Her Çözünürlükte Aynı Görünmesini Sağlamak

Button’u işlerken anchor‘ları kullanarak arayüz elemanlarının arayüzle beraber nasıl boyutlanabileceğini gördük. Ancak bazen özel durumlar olur. Örneğin arayüzde bir resim çizdiriyorsunuz diyelim. Resmin anchor’larını canvas’ın dört bir köşesine yaydınız; resim canvas ile büyüyüp küçülüyor. Ama burada ufak bir sıkıntı var: resmin en/boy oranı (aspect ratio) korunmuyor! Bu, butonlar için bir sıkıntı değil ama bir resim çizdirirken genelde resmin en/boy oranının korunmasını isteriz. Bu gibi durumlarda yeni UI sisteminin bize sağladığı birkaç seçenek mevcut:

Aspect Ratio Fitter

Bu component, atandığı UI elemanının en/boy oranının daima aynı kalmasını sağlar. Bu component’i Component-Layout-Aspect Ratio Fitter yolunu izleyerek istediğiniz UI elemanına verebilirsiniz. Component’in sahip olduğu “Aspect Mode” değişkeni burada önem arz ediyor:

37

Bu seçenekler sırayla şöyle:

None: Component işlevini kaybeder.

Width Controls Height: UI elemanının genişliği değiştikçe; yüksekliği, en/boy oranını koruyacak şekilde otomatik olarak değiştirilir.

Height Controls Width: UI elemanının yüksekliği değiştikçe; genişliği, en/boy oranını koruyacak şekilde otomatik olarak değiştirilir.

Fit In Parent: UI elemanının ya genişliği ya da yüksekliği daima parent objenin kenarlarıyla temas halinde olur (bu esnada en/boy oranı korunur).

Envelope Parent: UI elemanı, parent objesinin tamamını içine alacak şekilde otomatik olarak boyutlandırılır (bu esnada en/boy oranı korunur).

Son iki seçenek benim pek ilgimi çekmedi ama ondan önceki iki seçenek gerçekten kullanışlı duruyor. Bu iki seçeneği kullanarak hazırladığım örnek bir scene’i, örnek projenin içinde bulabilirsiniz.

Bu component’i kullanırken bilmeniz gereken önemli bir nokta daha var: pivot noktasının konumu. Eğer ki UI elemanının hep ekranın en sol üstünde yer almasını istiyorsanız ve Aspect Ratio Fitter component’ini kullanıyorsanız o zaman pivot noktasını UI elemanının sol üst köşesine taşımalısınız. Böylece UI elemanının otomatik olarak boyutlandırılması sağ ve alt kenarlar üzerinden gerçekleşecek, sol üst noktanın konumu değişmeyecek.

Canvas Scaler

Bu component benim gerçekten çok hoşuma gidiyor; kullanması da gayet basit:

Öncelikle Game panelinin sol üstündeki çözünürlük butonu vasıtasıyla çözünürlüğü 1024×768 yapıyoruz:

38

Sonra Canvas objesini seçiyoruz ve “Canvas Scaler (Script)” component’inin “Ui Scale Mode“unu “Scale With Screen Size” yapıyoruz. Karşımıza gelen yeni değişkenlerden referans çözünürlüğü 1024×768 yapıyor, “Screen Match Mode“u ise “Expand” yapıyoruz:

39

Artık arayüzümüzü hazırlamaya hazırız. Arayüzü hazırlarken dikkat etmemiz gereken nokta, UI elemanlarının anchor noktalarını dört farklı noktaya yaymak yerine bir noktada toplamak. Örnek projede bu konuyla ilgili de ufak bir örnek mevcut; incelemenizi öneririm.

NOT: Canvas Scaler‘ın sahip olduğu diğer değişkenleri araştırmak size düşmüş; onların nolduğunu ben de tam bilmiyorum.

3 Boyutlu (3D) Arayüzler Oluşturmak

UI sisteminin en güzel yanlarından birisi budur kesinlikle. Artık 3 boyutlu düzlemde bir pozisyon ve eğime sahip arayüzler oluşturabiliyoruz. Örneğin sitemde paylaştığım Infinite Runner örneğindeki ( https://yasirkula.com/2015/01/15/unity-3d-temple-run-tarzi-infinite-runner-oyun-ornegi/ ) 3D skor yazısını UI sistemi ile oluşturdum.

Peki nasıl üç boyutlu arayüz oluşturuyoruz? Canvas objesini seçiyorsunuz ve “Canvascomponent‘indeki “Render Mode“u “World Space” ile değiştiriyorsunuz. Bu kadar! Ardından canvas’ı Scale aracıyla “oldukça” küçültmek isteyebilirsiniz.

3D arayüz ile ilgili örnek bir uygulama yapmayacağız çünkü bence bu çok basit bir konu, anlatılacak pek birşey yok. Ancak önemli sayılabilecek bir nokta var onu paylaşayım: eğer ki 3D arayüzünüzde yazılar bulanık görünüyorsa Canvas‘ın “Canvas Scaler (Script)” component’indeki “Dynamic Pixels Per Unit” değerini artırmayı deneyin.

3 boyutlu arayüz ile ilgili örnek bir scene‘i örnek projede bulabilirsiniz. Örnekten bir resim:

40

Bu uzun dersin burada sonuna gelmiş bulunmaktayız. Umuyorum ki az biraz faydalı olmuştur. Eğer ki konuya ilginiz varsa o zaman Unity’nin resmî video tutoriallerini izlemenizi şiddetle öneririm.

Sonraki derslerde görüşmek dileğiyle!

yorum
  1. Altay dedi ki:

    Merhaba. Bu sorumun yeri bu makalemi bilemedim ama en uygunu burası gibi duruyor. Rect Tool daki o beyaz ayarlama yaptığımız oklar arkaplandaki renk beyaz olunca görünmez hale geliyor. Onun renk değişimi gibi bir yöntemi var mı? Preferences > Color kısmında aradım ama bulamadım. Bununla ilgili bir yöntem biliyor musunuz?

    Teşekkür ederim.

  2. hocam merhaba,
    unityde herhangi bir butonun pc çözünürlüğünde görünürken mobil görünümde nasıl kaybederim. Bu şekilde telefonda görünmesini istediğim pc de görünmesi istemediğim bir sürü şey var,
    böyle bir yöntem mevcut mu?
    şimdiden çok teşekkür ederim.

    • yasirkula dedi ki:

      Koddan Application.platform’un değerini kontrol edebilirsiniz veya #if !UNITY_EDITOR && (UNITY_ANDROID || UNITY_IOS) preprocessor’u kullanabilirsiniz.

      • hocam,
        webgl için bu durumu nasıl yapabiliriz?
        uygulamayı webgl olarak export ediyorum
        ancak telefon çözünürlüğünde ve bilgisayar çözünürlüğünde farklı buttonlar kullandığım için kullanıcı uygulamayı telefonda açtığında bilgisayarda kullandığım butonların görünmesini istemiyorum.
        Verdiğiniz linkte webgl uzantısı var ama bilgisayar ve telefon olarak ayrıştırmıyor.
        bunu nasıl çözebilirim.
        çok teşekkür ederim hocam

      • yasirkula dedi ki:

        Oyunun WebGL export alınıp alınmadığını öğrenebiliyorsunuz ama WebGL oyunun bilgisayarda mı telefonda mı açıldığını nasıl öğrenebilirsiniz onu maalesef bilmiyorum. Siz çözünürlükten bahsettiğiniz için, belki Screen.width ve Screen.height değerlerini kullanarak doğrudan çözünürlük üzerinden hesaplamalar yapabilirsiniz.

  3. LS dedi ki:

    Merhaba hocam. Geçen yardımlarınız ile projemi baya ilerletmiştim. Sizin nokta atış tavsiyelerinizle hızlı ilerliyorum. Projemde iki parça arasından geçince o parça arasındaki boşluk kadar objemin daralmasını istiyorum. Araştırdığımda deform işlemi yapmam gerekiyor fakat çok yol alamadım. Bu projemi nasıl yapabilirim? Örnek tutorial bu tarz var mı acaba bildiğiniz?

    • yasirkula dedi ki:

      Obje o boşluğa denk geldiğinde, scale x değerini boşluğun boyutu kadar düşürseniz, position’ını da boşluğun ortasına kendini hizalayacak şekilde ayarlasanız olmaz mı? Scale’i elleyince güzel durmadığı için mi deform kullanıyorsunuz?

      • LS dedi ki:

        Hamur tarzı esnek bir parçam olduğundan bunun belirli bölgelerde şeklinin değişmesini istiyorum. Son olarak bir cube gibi parçayı kum tanelerine ayırabilir miyiz? ya da kum gibi objeleri nasıl elde edebiliriz bir bütünden?

      • yasirkula dedi ki:

        Maalesef bunlar şu anda bilgim olmayan konular o yüzden yardımcı olamayacağım.

    • LS dedi ki:

      Teşekkür ederim hocam. Esnetme işlemini Blender’da kemikler ekleyip, o eklenen yerlerden joint ile esnetme işlemi yaparak çözümünü buldum. Böyle bir yol da düşünebilirmişiz. Hızlı geri bildirimleriniz için teşekkür ederim ayrıca.

  4. muhammet aksoy dedi ki:

    hocam merhaba ben mobil oyunum için otobüs durağı yapmayı planlıyorumda nasıl yapabilirim

  5. Erdem dedi ki:

    Hocam, bir konuda takıldım ve çözüm bulamıyorum. Bir nesneyi drag drop ile başka bir nesnenin içine yerleştirebiliyorum ancak bir nesneye tıkladığımda onun üzerinde başka bir nesne oluşturup mouse’u diğer kutunun üzerine taşıdığımda onu kutunun üstüne kadar taşıyabiliyorum ancak drop event’i gerçekleşmiyor. Bunu nasıl çözebilirim? Bunu herkese sordum ama son zamanlarda kimse birbirine yardım etme taraftarı deği. Bana yardım ederseniz çok sevinirim.

  6. Yunus Emre dedi ki:

    hocam butonun üstüne gelince nasıl bilgi kutucuğu çıkarabilirim

  7. Mahmutcan ZAMAN dedi ki:

    Light renderer ve cinemachine paketlerini kurduğumda mobile çıktı aldığımda zorlanıyorum.Düzgün çalışmıyor bazı telefonlarda. Light renderer desteklemiyor mu telefonlar?

    • yasirkula dedi ki:

      Light Probe veya Line Renderer mı demek istiyorsunuz? Her ikisini de tüm cihazların çalıştırmasını beklerdim ben. EDIT: LWRP (URP) diyorsunuz sanırım. Unity 2019.4 kullanmayı deneyin isterseniz çünkü LWRP uzun zaman önce URP’ye dönüştü ve muhakkak epey sorunu da bu zaman aralığında düzeltilmiştir.

      • Mahmutcan dedi ki:

        Hocam projeyi universal render pipeline olarak açtım light renderer yaptım ama bazı telefonlarda ışık yok

      • yasirkula dedi ki:

        URP ile henüz çalışmadığım için büyük ihtimalle benim bilgim dışında bir konu. Ama hâlâ Light Renderer’ın ne olduğunu çözemedim.

      • Mahmutcan dedi ki:

        hocam benim light renderer dediğim urp idi zaten. URP demek ki tüm telefonlarda çalışmıyor.

      • yasirkula dedi ki:

        Unity URP sloganı, her cihazı destekleyen performanslı render pipeline olarak geçiyor. Logcat’ten aldığınız hataları bulup, screenshot’lar eşliğinde Unity forumlarında destek istemenizi öneririm.

  8. Uras dedi ki:

    Bende UI Katagorisi Yok Ne Yapmalıyım?

  9. Emre dedi ki:

    Hocam öncelikle bu güzel bilgiler için çok teşekkür ederim. Tavsiyenize ihtiyacım var. Oyun esnasında bir butonu bir panele sürüklediğimde butonun, panelin child’i olmasını nasıl sağlayabilirim?

    • yasirkula dedi ki:

      Buradaki asıl olay drag & drop sistemi. Ardından drop olduğunda butonun parent’ını SetParent ile değiştiriverirsiniz. “unity ui drag drop” şeklinde arama yaparak ilgili tutorialler bulabilirsiniz.

      • Emre dedi ki:

        Hocam sağolun. SetParent ile butonu sürüklediğimde panelin child’i yapabiliyorum ama sadece panelin içine sürükleyince değil herhangi bir yere sürüklesem dahi panelin childi oluyor.Bu sorunu nasıl düzeltebilirim?

      • yasirkula dedi ki:

        Drag & drop sisteminin hangi objenin üzerine drop yaptığını söylemesi lazım. Sadece panelin üzerine drop yapınca parent yapacaksınız tabii ki.

  10. halil dedi ki:

    Hocam Emeğeniz için çok teşekkür ederim. Benim bir sorunum vardı , Uİ I dan image seçtiğimde , inspectorde İmage(sicript) olarak göremiyorum sadece script olarak gözüküyor . Bunun sebebi nedir bir çözümünüz varmı

    • yasirkula dedi ki:

      Component bende daima Image olarak gözüküyor. Sizde niye böyle olmuş bilemedim. Package Manager’da “Built-in packages” listesinde UI kapalı ise onu Enable etmeyi deneyebilirsiniz.

      • halil dedi ki:

        hocam özür dilerim soruyu yalnış sormuşum , inspectorde image(script) olarak göremiyorum sadece image olarak görüyorum. yani parantez içinde script yok bunun sebebini merak etmiştim

      • yasirkula dedi ki:

        Mesh Filter component’inin ismi de “Mesh ismi (Mesh Filter)” olarak gözüküyor. Neden böyle bilmiyorum, açıkçası pek araştırma ihtiyacı hissetmedim 😀

  11. Serkan Başaran dedi ki:

    Hocam selam

    Event Trigger ile eklediğim tuşlarda sesler biraz gecikmeli çıkıyor bunu ayarlabilmemin bir yolu var m?

    • yasirkula dedi ki:

      Click’te ses çalıyorsanız, parmağı ekrandan çekince ses çalınır. Parmakla dokunduğu gibi ses çalmak için Pointer Down’ı kullanmanız lazım. Android’de maalesef genel olarak seslerin biraz gecikmeli çalınması sorunu var (Event Trigger’dan bağımsız), plugin kullanmadan bu sorun aşılabilir mi bilmiyorum. Yaşadığınız sıkıntı belki de budur.

      • Serkan Başaran dedi ki:

        Hocam çok teşekkür ederim. Böyle faydalı bir site kurup soruları kısa süre içinde cevaplaman, elin dert görmesin.

  12. arjin dedi ki:

    Hocam merhaba,sahneler arası geçişlerde pause butonunu prefab olarak kopyalayıp diğer tüm özellikleri asıl sahnedeki buton gibi yapsam da kopyaladığım sahnelerde butonu tıklanabilen bir obje olarak görmüyor,herhangi bir hata da almıyorum sebebi sizce nedir?

    • yasirkula dedi ki:

      Tıklanabilir UI objelerinin olduğu her sahnede bir EventSystem objesi de olması lazım. Belki sıkıntılı sahnelerde EventSystem yoktur. İlaveten, Canvas’ta Graphic Raycaster component’i olması lazım.

      • arjin dedi ki:

        Dediğiniz gibi sorun eventSystem den kaynaklıymış çok teşekkür ederim haftalardır geçiştirmek zorunda kaldığım bir sorundu 🙂

  13. Ahmet dedi ki:

    Yasir hocam oyunum içinde manuel olarak hazırlanmış bir klavye var. Anchorları harflerin tam olarak köşelerine getirmeye çalışıyorum. Milimetrik olarak tam köşelere denk gelmiyor. Bunun için ne yapılabilir.

    • yasirkula dedi ki:

      Klavyedeki CTRL, Alt veya Shift tuşlarından birine basılı tutarken hâlâ istediğiniz gibi çalışmıyorsa, RectTransform’dan Anchor’ları elle girmek dışında aklıma bir şey gelmiyor.

  14. Kaan dedi ki:

    Merhabalar.Videolar yardımıyla bir puzzle oyunu yaptım. Oyun oluşturmuş olduğum çözünürlükte sorunsuz çalışıyor. Diğer çözünürlüklerde ise resim küçülüyor ekrana oranlanmıyor. Çözünürlük olayını tüm dosyaları canvas içerisinde oluşturarak çözdüm. Bu sefer de oyun sadece tek çözünürlükte düzgün çalışmaya başladı. Sorunun kaynağını buldum fakat çözemiyorum. Şöyle ki puzzle parçaları normalde Z ekseninde “0” da otomatik olarak oluşuyor Fakat canvas içerisinde iken -2600 lerde oluşuyor. Bu yüzden örtüşmüyor. Kod normalde -2600 lük kısmı 0 yapıyor fakat canvasın içine attığım için z ekseni “0” olmuyor. Bunu nasıl çözebilirim. Yardım eder misiniz. Mümkünse Canvas içerisinde çalışabilecek Z eksenini mouse un tıkladığı puzzle parçasında z eksenini “0” yapacak bir kod var mıdır?

    • yasirkula dedi ki:

      Objenin transform.localPosition’ının z’sini 0 yaparak Z koordinatını sıfırlayabilirsiniz. Instantiate kullanıyorsanız, “Instantiate(Object original, Transform parent, bool instantiateInWorldSpace);” fonksiyonunu kullanıp parent’ı objenin parent objesi, instantiateInWorldSpace’i de false yapmanızı öneririm.

      • Kaan dedi ki:

        Hocam
        transform.localPosition’ının z’sini 0 yaparak Z koordinatını sıfırlayabilirsiniz. Dediğinizi yaptım fakat seçtiğimde mouse çok yavaş hareket ediyor. Ama “z” i sıfırlamayı başardım.

      • yasirkula dedi ki:

        Mouse’un yavaşlığından kastınız oyunun takılması ise, localPosition’ın Z’sini değiştirmenin performansa bir etkisi olmaz, sıkıntı başka bir yerdedir.

  15. fatih temiz dedi ki:

    unity 2d android Canvas Scaler’a 1080×1920 çözünürlüğü atadığımızda dinamik olarak çağırdığımız nesneler diğer boyutlara göre değişiyor. bunları bütün cönüklerde sabit görünecek sekilde nasıl ayarlaya biliriz .bir nesneyi cogaltacagız . nesne dinamik .contentfitter ve verticallayoutgroup kullanmamıza ragmen neynelerin sekli bozuluyor .

  16. Hüseyin dedi ki:

    hocam merhaba kolay gelsin

    ben uygulamamı tatamladım test etmek için yeni nesil bir telefonlana attım (samsung S8, Huawei yeni telefonları, LG G7 gibi) uygulamam diklemesine uzuyor.
    Yeni nesil telefonların her yeri ekran oldugunday dolayı oyun diklemesine büyüdügünü düşünüyorum normal telefonların ekran boyutu ( 16.9) yeni nesil telefonların ekranı 16.9 dan büyük.
    uygulamanın her telefonda 16.9 ekran büyüklügünde çalışmasını nasıl saglayabilirim.
    geri kalan bölgeler siyah görüksün istiyorum
    biraz araştırdım manifesto ya

    şöyle birşey yazın diyorlar yazdım ama olmadı yardım edersen çok sevinirim teşekkürler: <meta-data android: name = “android.max_aspect” android: value = “2.1” />

    şu sitetede daha iyi anlatıyor

    https://android-developers.googleblog.com/2017/03/update-your-app-to-take-advantage-of.html?m=1

    kolay gelsin

  17. hepaldim dedi ki:

    Hocam merhabalar Kolay gelsin.Cok degerli ve Emek verilen bilgiler..
    Müsait iseniz benim bir sorum olacaktı.
    Bir Infinite Runner oyunun düşünün,
    Sağ üst köşede bir Ui Button olan “Pause Buttonu bulunmakta” ve sorum burda ortaya cıkmaktadır..
    GamePlay modunda iken bu Buttona basıldığında ekrana basılmış gibi hareket edip önce karakter sağ tarafa yönelip daha sonrasında ise pauseMenu açılmaktadır.. Bunu nasıl Önleyebilirim..
    Bir kaç yerde EventSystem ile yapmam gerektiği söylendi fakat bir türlü çözemedim.
    Şimdiden teşekkürler..

    • yasirkula dedi ki:

      Karakter hareket script’inizde UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()’in değeri true ise karakterinizi hareket ettirmeyin.

  18. Mustafa dedi ki:

    hocam merhaba,
    bir butona tıkladığımızda fonksiyon içerisinde oyunnesnesi.gameObject.SetActive(true); satırıyla görüntülediğimiz bir oyun nesnesini ikinci kez aynı butona tıkladığımızda nasıl görünmez yapabiliriz. destroy() komutuyla yapılması gerek ama nasıl yapabileceğimi çözemedim. Bir de exitPanel oluşturdum. Update fonksiyonunda, esc tuşuna basıldığı zaman exitPanel görüntüleniyor. panelde “oyundan çıkmak için geri tuşuna 2 kez hızlı basın” uyarısı çıkıyor. tekrar geri tuşuna basılırsa exitPanel kapansın istiyorum. 2 kez üstüste basılırsa application.quit() nasıl çalıştırırım acaba? şimdiden çok teşekkürler..

    • yasirkula dedi ki:

      Butona bastıkça objenin görünürlüğünün değişmesini oyunnesnesi.gameObject.SetActive(!oyunnesnesi.gameObject.activeSelf); koduyla yapabilirsiniz. İki kere Esc’ye basmayı algılamak için, Esc’ye basma anını tutan bir float değişkenini olmalı (mesela private float escAni;). Esc’ye basınca if(Time.realtimeSinceStartup-escAni<1.0f) Application.Quit(); kodu ile, 1 saniye içerisinde Esc'ye iki kez basılırsa çıkış yapabilirsiniz. Esc'ye basınca çalışan kodun sonuna escAni=Time.realtimeSinceStartup; da eklediniz mi bir sorun kalmaması lazım.

  19. ali fuat dedi ki:

    slm bu güzel kaynağı hazırladığınız için teşekkürler

    benim sorum ekrandaki bir butonun rengini başka bir butona basarak nasıl değiştiririm ?

    yani o anda game ekranında görülen butonun rengini kod ile değiştirmek istiyorum nasıl yaparım bunu ?

    • yasirkula dedi ki:

      Buton objesini bir “public Button buton;” değişkeninde tutup Inspector’dan değişkene değer olarak verdiniz diyelim. Bu durumda buton.GetComponent<Image>().color = new Color(1,0,0,1); komutu ile butonun rengini değiştirebilirsiniz. Bunu başka bir butona basınca yapmak için, o butonun On Click’ine kaydolabilirsiniz.

  20. osman dedi ki:

    merhaba canvas içindeki nesneler unity de gozukuyor ama mobil veya bilgisayarda gozukmuyor nasıl düzeltirim

  21. Hakan Güler dedi ki:

    örneğin 1920×1080 landspace bir ekran seçip çalıştım Canvas içine buton yerleştirdim sonra farklı çözünürlükte denediğimde butonların yeri kayıyor, kısacası 1024 mobil cihazda da full hd cihazda da buton noktasının aynı olmasını nasıl sağlarım? Teşekkürler.

    • Hakan Güler dedi ki:

      1024×768 seçeneği yok, ben manuel ekliyorum o da saçma bir kare görüntü oluyor nedense, 1280×720 çözünürlükte butonları koyuyorum, 1280 de üstte olan butonlar 1920×1080 çözününürlükte sayfanın neredeyse ortasına kadar iniyor.

    • yasirkula dedi ki:

      Hep yukarıda olmasını istediğiniz butonun RectTransform’unun anchor Y değerlerini 1 yapabilirsiniz. İlaveten, Canvas objenizin Canvas Scaler’ının Scale Mode’u ile oynayarak da istediğiniz gibi bir arayüz elde edebilirsiniz. Benim önerim “Ui Scale Mode”u “Scale With Screen Size”, “Screen Match Mode”u “Match Width Or Height” ve “Match”i de 1 yapmanız yönünde.

  22. servet dedi ki:

    oyunda item info olarak panel ve içinde text kullanmak istiyorum. ama tüm infolar aynı uzunlukta olmayacak bunun için panelin boyutunun içindeki text e göre y ekseninde küçülüp büyümesini nasıl yapabiiirim.

    • yasirkula dedi ki:

      Panele Vertical Layout Group component’i verip Child Controls Size’ın Height’ını işaretleyin. Diğer seçenekleri, birazdan anlatacağım şeyleri de yaptıktan sonra, istediğiniz şey olana kadar değişik kombinasyonlarda açıp kapamayı deneyebilirsiniz ama tahminimce Child Force Expand’ın Height’ını kapatıp Width’ini açmalı ve Child Controls Size’ın Width’ini kapatmalısınız. Ardından panele bir de Content Size Fitter verip Vertical Fit’i Preferred Size yapın. Son olarak, info yazısına da Content Size Fitter verin ve Vertical Fit’i Preferred Size yapın. Yazı ile panel arasına boşluk koymak için panelin Padding değerleri ile oynayabilirsiniz.

  23. tenay karaman dedi ki:

    hocam merhabalar. event trigger sadece UI lar için mi kullanılabilir. sprite için kullanılabilir mi? sprite için kullanmak istediğimizde hangi yolu izlemeliyiz?

    bu vermiş olduğunuz örnekte ki gibi sprite a tıklanıldığı an ilgili script de ki fonksiyon bağlantısını yapıyorum fakat konsoldan çıktı alamıyorum. yani çalışmıyor.

    • yasirkula dedi ki:

      Sprite’ta kullanmak için sahnenizde bir EventSystem objesi olduğundan emin olun (yoksa “UI-Event System” ile oluşturun) ve kameranıza “Physics 2D Raycaster” component’i verin.

      • tenay karaman dedi ki:

        Hocam Allah senden razı olsun.Nihayet çalıştı.

      • Efe Can dedi ki:

        Yasir hocam selamlar,

        Hocam benim size yine bir sorum olacak
        Benim uygulamamda butonlar var fakat bu butonlara basıp bıraktığım zaman ses dosyasını çalıştırıyor. Ben basıp bırakmadan yani butona tıklamadan üstünden geçerken bile ses dosyasını çalıştırmasını istiyorum bunu nasıl sağlayabilirim.

      • yasirkula dedi ki:

        Butona Event Trigger component’i ekleyip Pointer Enter event’inde ses dosyasını çalıştırabilirsiniz.

Cevap Yazın

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.