GÜNCELLEME (01.09.2018): Kodlar C#’a çevrildi ve OnLevelWasLoaded fonksiyonu, SceneManager fonksiyonları ile değiştirildi.
Hepinize merhaba,
Bu dersimizde, Unity 3D‘de bir objenin sahneler (scene) arası geçiş yapmasını ve ne olursa olsun o objeden aynı anda sadece bir tane olmasını nasıl sağlayacağınızı göreceğiz.
Örneğin oyununuz çok zor bir runner oyunu ve oyuncu ortalama 5-10 saniyede bir ölüp duruyor. Oyuncu ölünce Application.LoadLevel ile bölüme restart atıyorsunuz diyelim. Eğer oyununuzun bir arkaplan müziği varsa her restart atışınızda bu müzik başa saracaktır ve kısa bir süre sonra bu oyuncuyu gıcık edecektir. Onun yerine oyuncu ölüp bölüme restart atılsa bile müziğin kaldığı yerden devam etmesini istiyorsunuz diyelim. İşte burada iki prensip bir arada kullanılmakta:
1- Müzik objesi scene’ler arası geçişte yok olmuyor, böylece müzik kaldığı yerden çalmaya devam ediyor
2- Bölüme restart atınca müzik objesinden elinizde iki tane oluyor: birisi önceki scene’den gelen ve çalmaya devam eden müzik objesi, öteki ise scene’e restart atınca sıfırdan oluşan müzik objesi. Bu sıfırdan oluşan müzik objesinin çalmasını istemiyoruz (singleton prensibi)
Anlayacağınız üzere, singleton prensibi bir objeden aynı anda sadece bir tane olmasını (ve bu objenin de scene’ler arası geçiş yaparken bizimle gelen obje olmasını) sağlar. Saydığım bu iki özelliği de oyununuzda uygulamak çok basit.
SingletonMuzik adında yeni bir C# script oluşturup bunu müzik objenize verin ve ardından scripti şöyle değiştirin:
using UnityEngine; public class SingletonMuzik : MonoBehaviour { private static SingletonMuzik obje = null; void Awake() { if( obje == null ) { obje = this; DontDestroyOnLoad( this ); } else if( this != obje ) { Destroy( gameObject ); } } }
Artık levela restart attığınızda müzik kaldığı yerden çalmaya devam edecek. Harika!
Peki bu birkaç satırlık script nasıl oluyor da bu işi başarıyor? Şöyle ki, elimizde SingletonMuzik türünde static bir değişken var: “obje“. Bu static değişkenin ilk değeri “null“. “obje” değişkenimizin görevi, scene’ler arası geçiş yapan müzik objesindeki SingletonMuzik scriptini depolamak. Static değişkenlerde şöyle bir şey var ki bir static değişkenin ilk değerini alması sadece bir kere gerçekleşir. Yani “obje” değişkeni, script ilk kez çalıştırıldığında null değeri alır ama sonradan levela restart atıp scriptin yeniden çalıştırılmasını sağlasak da “obje”nin değeri tekrar otomatik olarak null’a ayarlanmaz!
Awake fonksiyonu scene açıldığında tek seferlik çalıştırılır, tıpkı Start fonksiyonu gibi. Tek fark, Awake fonksiyonu Start fonksiyonundan daha önce çalıştırılır. Bu fonksiyonda “obje“nin değerinin null olup olmadığına bakıyoruz. Eğer null ise, bunun anlamı henüz bizimle scene’ler arası geçiş yapan bir müzik objesi yok demektir (bir başka deyişle oyunu yeni başlatmışız demektir). Bu durumda obje’ye değer olarak scriptin kendisini (this) veriyoruz ve bu scriptin atandığı müzik objesinin scene’ler arası geçişlerde yok olmamasını sağlıyoruz: “DontDestroyOnLoad(this);“.
Oyuna restart atınca elimizde iki müzik objesi oluyor: bizimle scene’ler arası geçiş yapan obje ve scene açıldığında sıfırdan oluşturulan müzik objesi. Biz sıfırdan oluşturulan müzik objesinin çalmasını istemiyoruz. Neyse ki scriptin Awake fonksiyonundaki “else if” koşulu bunu bizim için yapıyor: müzik objesindeki SingletonMuzik scriptinin (this), “obje” değişkeninde depolanan script ile aynı olup olmadığına bakıyoruz. Hayır, aynı değil çünkü “obje” değişkeninde depolanan SingletonMuzik scripti, bizimle scene’ler arası geçiş yapan müzik objesindeki SingletonMuzik scripti. Bu durumda scene açıldığında yeniden oluşturulan müzik objesini “Destroy( gameObject );” fonksiyonu yardımıyla siliyoruz ve elimizde sadece scene’ler arası geçiş yapan müzik objesi kalmış oluyor.
Tek bir şeye dikkat etmeniz lazım: müzik objesi scene’ler arası geçiş yaptığı için eğer ki menüye geçiş yaparsanız müzik de sizinle beraber menüye gelecek ve burada da çalmaya devam edecektir. Bunu önlemek ve menüye dönünce müzik objesinin yok olmasını sağlamak için “SingletonMuzik“i şuna benzer bir şekilde değiştirebilirsiniz:
using UnityEngine; using UnityEngine.SceneManagement; public class SingletonMuzik : MonoBehaviour { private static SingletonMuzik obje = null; void Awake() { if( obje == null ) { obje = this; DontDestroyOnLoad( this ); SceneManager.sceneLoaded += SahneYuklendi; } else if( this != obje ) { Destroy( gameObject ); } } // Yeni bir sahne yüklenince çağrılır void SahneYuklendi( Scene scene, LoadSceneMode mode ) { if( scene.name == "AnaMenu" ) { obje = null; Destroy( gameObject ); } } }
“SceneManager.sceneLoaded += SahneYuklendi;” kodu vasıtasıyla, yeni bir scene yüklenince “SahneYuklendi” fonksiyonunu çağırıyoruz. Bu fonksiyonda, geçiş yapılan scene’in adının “AnaMenu” olup olmadığına bakıyoruz ve eğer öyleyse müzik objesini yok ediyoruz.
Umarım ders faydalı olur; başka derslerde görüşmek üzere!
Merhaba hocam ben sahnedeki müziği kapatma butonu yapmak istiyorum player prefs olarak nasıl yapabilirim?
Diyelim butona basınca
PlayerPrefs.SetInt("MuzikKapali",1)
fonksiyonunu çalıştırabilir, müzik objenizde dePlayerPrefs.GetInt("MuzikKapali")==1
ise müziği kapatabilirsiniz. Eğer müzik objesi zaten mevcut sahnede var ise, direkt bu müzik objesine erişip AudioSource’unu kapatabilirsiniz. Müzik objesine ulaşmanın birkaç yolunu şurada bulabilirsiniz: https://yasirkula.com/2019/07/27/unity-bir-scriptten-baska-bir-scriptteki-degiskene-ulasmak/Merhaba ben yok edilen bir game objecti geri çağrabiliyormuyum yani Destroy(Elmas); dedim diyelim sonra bunu geri çağırmak istiyorum nası yaparım
Maalesef mümkün değil. En basit alternatif, objeyi Destroy etmek yerine SetActive(false) ile inaktif hale getirip, geri çağırmak istediğinizde SetActive(true) ile tekrar aktif yapmak.
tam yaptım siz ayzdınız sağolun
Hocam selamlar,
Yakın zamanda unity’de yapımına başladığım oyunda bir hata alıyorum. İkinci level’ı direkt olarak çalıştırdığım zaman herhangi bir problem olmadan oynayabiliyorum, karakter hareket ediyor ve yaptığım tüm kodlamalar çalışıyor. Ancak oyunu en baştan başladığım zaman, main screen’den başlıyor level1’e geçiş yapıyorum oynuyorum bölüm bittikten sonra beni bir sahneye geçiş yapıyorum ve ordan tekrar next level dediğimde ikinci seviyeye geçiyor. sahne açılıyor kodladığım tuşlar çalışıyorum. mouse ile kamerayı kontrol edebiliyorum ancak karakter oynamıyor, hareket etmiyor. Bunun çözümü ne olabilir?
Kullandığım karakter Unity’nin fpscontroller’ı.
Oyunu ilk bölümden başlatınca konsolda herhangi bir hata alıyor musunuz? Eğer almıyorsanız sıkıntıyı tahmin edebileceğimi sanmıyorum, karakteri hareket ettiren kodu bulup bu kodun hangi objede olduğunu tespit etmeli ve bu objeye ne oluyor gözlemlemelisiniz.
hocam ben alttaki fonksiyonu kullanarak müzikleri aç kapa yapıyorum oyun açıldıktan sonra sıkıntı yok oyna restart atınca bu sefer sesi aç kapa yapamıyorum sebebi nedir?
public List ses_muzikler;
public void ses_muzikler_duzenle(bool deger){
foreach (AudioSource ses in ses_muzikler) {
ses.enabled=deger;
PlayerPrefs.SetInt(“muzik”, (deger ? 1 : 0));
}
}
Hocam yukardaki scr.pti kullanıyom müzik tekrar etmesi için onu yazmayı unutmuşum bu scriptti kaldırınca herzaman oyunu aç kapa yapıyorum lakin bu scriptti ekleyince ilk seferde yapıyorum restart yapınca olmuyor?
SingletonMuzik’e şu kodu ekleyin:
public static AudioSource[] ses_muzikler = new AudioSource[0];
void Start()
{
ses_muzikler = GetComponentsInChildren();
}
Artık ses_muzikler_duzenle fonksiyonunun içerisinde ses_muzikler değil SingletonMuzik.ses_muzikler’i kullanın.
Abi magazadan bi obje alıp yerlestirip oyunu yeniden açınca o objenin orda olmasını anlat sana zahmet ya
En basitinden PlayerPrefs kullanabileceğiniz gibi, bir xml save dosyası oluşturup bunu Application.persistentDataPath’te de tutabilirsiniz. Tabi ikinci yöntem, ilkinden daha karmaşık ama daha güçlü.