Unity’de Bir Objenin Sahneler Arası Geçişlerde Yok Olmasını Önlemek + Singleton Prensibi

Yayınlandı: 03 Ağustos 2014 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde
Etiketler:, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

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östereceğim.

Ö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 Javascript oluşturup bunu müzik objenize verin ve ardından scripti şöyle değiştirin:

private static var obje : SingletonMuzik = null;

function 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“in içine şunun gibi bir kod ekleyebilirsiniz:

function OnLevelWasLoaded( level : int )
{
	if( Application.loadedLevelName == "AnaMenu" )
	{
		obje = null;
		Destroy( gameObject );
	}
}

OnLevelWasLoaded fonksiyonu, levela restart atınca veya başka bir levela geçiş yapınca çalıştırılır. 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!

yorum
  1. Kadir dedi ki:

    Merhabalar lütfen ama lütfen çokk acill yardımınıza ihtiyacım var lütfenn yardım edin.

    İlk olarak 3d bir oyunda bir arabanın dümdüz sonsuza dek ilerlemesini nasıl sağlarım ?

    Oyundaki düşmanların arabaya 10 defa vırduklarında arabanın durmasını sağlamak ve oyunun bitmesini sağlamak

    Karakterin gittiği mesafe kadar metre sayacı eklemek . Ör / 10 metre gidebildi 10 metre sonra oldu kaç metre olduğunu hesaplıyacak bir sayaç. Flaypy bırd gibi.

    • yasirkula dedi ki:

      1- Update fonksiyonunda “transform.Translate( Vector3.forward * 10 * Time.deltaTime );” ile araba sonsuza kadar ileri hareket eder (saniyede 10 birim hızıyla).

      2- Düşman bize vurunca “vurmaSayisi” isimli “int” türündeki değişkeni 1 artırın.

      3- “mesafe” adında “float” türünde bir değişkenin değerini Update fonksiyonunda “10 * Time.deltaTime” kadar artırın.

      • kadir dedi ki:

        allah sizden razı olsun . arabanın sonusuza dek düz gitmesi olayını ve sayac işini de halledicem inşallah şimdi de. 2 anlattığınızı anlamadım. nasıl bir kod yazmam gerek ?

      • yasirkula dedi ki:

        “var vurmaSayisi : int = 0;” diye bir değişken tanımlayın. Düşman bize vurunca bunu 1 artırın. Ardından eğer vurmaSayisi’nın değeri 10 olmuşsa arabayı durdurup oyunu bitirin.

  2. furkan dedi ki:

    Yasir Bey,
    Minecraft klon dersleri veya herhangi bir oyun klonlama dersleri yapmayi dusunuyor musunuz?

  3. MarufEmir dedi ki:

    Hocam,
    Uzun Süredir Bir Araba Yarışı Oyunu Yapmaya Çalışıyorum.Model, Network vs. Kodladım.Ancak, Kullanıcının Kullanacağı Arabayı Yapamadım.Yani Araba Fiziği.Ne Yapsamda Bir Türlü Olmadı 😦 Rica Etsem Bana Yardım Edermisin ?

    • yasirkula dedi ki:

      Araba fiziği zor iş ve benim bu konuda tecrübem yok. İnternetten video izleyebilir ya da Asset Store’da ücretli/ücretsiz hazır araba scripti arayabilirsiniz.

    • isimsiz dedi ki:

      şuan bende bir araba yarışı üzerinde çalışıyorum. Size yardım edebilirim. o konuda yazdığım kodlardan verebilirim.(oyunumun kodlarından) olmadı projeleride birleştiririz senin oyunu beğenirsem

  4. kadir dedi ki:

    süleyman bey Vector3.forward * 10 * Time.deltaTime ); scriptini aynen bu şekilde yazıyorum .ancak araba yan gidiyor. başka modellere atıpta denedim hepsi yan gidiyor çeviriyorum cismi yine yan gidiyor yardım 😦

  5. lal13 dedi ki:

    Yenibirşeyleryapıyormusunuz?

  6. yasirkula dedi ki:

    Hayır şu anda yapmıyorum.

  7. gefe dedi ki:

    hocam bunun aynısını menu muziği içinde yapabilirmiyiz

  8. efe dedi ki:

    müziği nasıl ekleyeceğim

  9. feyzi dedi ki:

    hocam bu dersinize geldim ama o bannerreklam.cs’yi buna nasıl uyduracağımı bir türlü anlamadım

  10. feyzi dedi ki:

    haa tamam şimdi yaptımda bu jsyi nereye atacağım hocam

  11. feyzi dedi ki:

    o gameobject muziği atacağım audio source ve bu jsyi dogrumu hocam

  12. arslan dedi ki:

    merhabalar. oyunda anlattığınız şekilde müziği ekledim oyun için sürekli kullanacağım müziği. sahneler arası geçişlerde müzik çalıyor. bunun için çok teşekkür ederim. bir sorum olacak. oyunda silah sesi ölme sesi gibi diğer sesler ile oyunun arka alanında sürekli çalacak olan müzik çakışıyor. sesler bozuluyor. hatta çok kötü sesler çıkıyor. bunu nasıl halledebilirim? şimdiden teşekkürler.

    • yasirkula dedi ki:

      Bu sorun bana Android’de oluyor ama PC’de olmuyor. Android’de aynı anda çalabilecek ses dosyası sayısı sınırlı olabilir.

  13. Özgür dedi ki:

    public void Audio () {
    if (GetComponent().isPlaying){
    GetComponent().Pause ();

    }
    else
    GetComponent().Play();
    }

    Bu kodla butona basıldıgında sesi durduyorum fakat sahneyi tekrar yukledıgımde buton calısmıyor ?

  14. Sefa DOĞAN dedi ki:

    İyi günler ben splash ekranı yapıyorum veya play buyonu işte amaç başka sayfaya geçmek dokunuyorum ve sayfa değişiyor fakat sahnemdeki ışık yok oluyo gibi görünmüyo oyun oynanırken nedeni ne acaba ?

  15. Deniz dedi ki:

    Merhaba. bu kodu Music nesneme koydum koydum music nesnemin ses seviyesini slider ile kontrol ediyorum fakat oyunu baslattıgımda slider calısıyor restart yapinca sahne tekrar yuklenınce slider calısmıyor null reference object diye hata veriyor.

    • yasirkula dedi ki:

      static obje değişkenini public yapmalı ve slider ile “SingletonMuzik.obje.GetComponent( AudioSource ).volume”un değerini değiştirmelisiniz.

  16. Deniz dedi ki:

    tesekkur ederim sagol yaptım 🙂

  17. Batuhan dedi ki:

    Merabalar playstoreda jm tuning race oyunum var aracı modifiye edip sürüyoruz.Aracın modifiye parçaları çok olduğu için birden fazla araç eklediğimde yükleme oldukça yavaşlıyor.Acaba aynı mantıkla araçları sahneler arası taşıyabilirmiyim taşınamazsa bir fikriniz var mı ?

    • yasirkula dedi ki:

      Eğer bir objenin Start fonksiyonunda DontDestroyOnLoad(gameObject); kodunu çalıştırırsanız o obje sahneler arası geçişlerde yok olmaz.

  18. atlokblog dedi ki:

    Hocam ben bu kodu ilk sceneime ekledim, müzik diğer scenelere geçtiğinde devam ediyor, öncellikle teşekkür ederim detaylı açıklama için.

    Fakat, Setting sceneime de müziği durdur buttonu eklemek istiyorum, başka bir scenedeki buttondan ilk scene eklediğim müziği nasıl durdurabilirim? Rica etsem bir fikir verebilir misiniz? Hatta belki biraz daha zor olacak ama aynı buttona bastığımda tekrar müziğin çalmasını istiyorum.

    • yasirkula dedi ki:

      obje değişkenini private’tan public’e çevirin ve butona basınca şu kodu çalıştırın:

      var as : AudioSource = SingletonMuzik.obje.GetComponent(AudioSource);
      if( as.isPlaying )
      as.Pause();
      else
      as.Play();

      • atlokblog dedi ki:

        Hocam işin içine Javascript girince yapamıyorum. İlk olarak SingletonMuzik javascriptin içini göstereyim, burada altı çizili kırmızı, yani hatalı olduğunu iddia ettiği yerler olsa da çalıştırıyor: http://i.hizliresim.com/v8PqA4.png Dediğim gibi kesinti olmadan sceneler arasında geçiş yapıyor, belki de javascriptte altı çizili olması bir şey ifade etmiyordur neyse.

        Yukarıda paylaştığınız kodu da şu şekilde koydum: http://i.hizliresim.com/zlMb6D.png

        Onu buttona atamak istedim ama sanırım mantığı c#’taki gibi işlemiyor ve hata verdi yapamadım: http://i.hizliresim.com/o8Vonm.png

      • yasirkula dedi ki:

        Kodun altının çizili olmasının sebebi şu pluginin kurulu olmaması olabilir: https://www.visualstudio.com/features/unitytools-vs

        Yalnız bunun aldığınız hatayla bir ilgisi yok. Aldığınız hatanın sebebini anlayamadım ben. Ya çok ufak bir detay gözümden kaçıyor ya da hata kodda değil başka bir yerde. Belki Unity’e restart atınca ya da kodu tekrar yazınca düzelir.

  19. atlokblog dedi ki:

    Yok hocam var as : AudioSource = SingletonMuzik.obje.GetComponent(AudioSource);
    var as ile AudioSource arasındaki : beğendiremiyorum visual studio’a.

    • yasirkula dedi ki:

      Javascript’te syntax öyle işte, ReklamScript’te de benzer bir kullanım var. Bunun sıkıntı çıkarmaması lazımdı. Kodu kopyala-yapıştır yerine elinizle yazmayı deneyin bir de.

      • atlokblog dedi ki:

        Elimle yazınca da olmadı maalesef, çözüm bulursam yazarım hocam buraya da, zaman ayırdığınız için teşekkürler.

  20. atlokblog dedi ki:

    Hocam enteresan bir şekilde as ‘yi obje1 diye değiştirince o hatayı vermemeye başladı ama şimdi başka bir hata veriyor, ben izninizle yaptığım her işlemi sırasıyla anlatmak istiyorum, aklımda kalmaması için.

    1. İlk sceneimin adı “title”. “title”da sağ tık Audio Source> Audio Source diyip, yeni bir audio objesi yarattım. İsmi otomatik olarak Audio Source diye atandı. Bunun içine ilk olarak müziğimi attım, hemen ardından da sizin paylaştığınız Javascript kodunu koydum.

    2. Ardından Setting adındaki sceneime geçip Canvas’ın içinde sağ tıklayıp UI>Button diyerek yeni bir button oluşturdum. Ardından, SoundOnOff adında bir javascript oluşturup içine bu kodu yazdım:

    var obje1 : AudioSource = SingletonMuzik.obje.GetComponent(AudioSource);

    function asd()
    {
    if( obje1.isPlaying ){
    obje1.Pause();
    }

    else{
    obje1.Play();

    }
    }

    Bu kodu buttona atadım (Javascript olduğundan emin de değilim doğru atadığımdan), eğer unityi setting sayfasından çalıştırırsam şu hatayı alıyorum: http://i.hizliresim.com/4qjZb0.png

    Eğer Unity’i title sceneinden (ilk scene) çalıştırırsam da; setting sceneine geçtiğimde şu hataları alıyorum: http://i.hizliresim.com/MgVPj6.png

  21. GamePlanet dedi ki:

    Merhaba,Acil Yardıma İhtiyacım var.
    Yeni bir screen açtım ve bir buton ekledim.
    her şey çok süperdi ama amacım
    butona basılınca diğer screene geçmesiydi
    olmadı.
    ACİL YARDIM!!!

    • yasirkula dedi ki:

      Butona bir Javascript verip içine şu fonksiyonu atın:

      public function BolumDegistir()
      {
      Application.LoadLevel(“DigerBolumunAdi”);
      }

      Ardından butonun OnClick event’ine Inspector’dan değer olarak BolumDegistir fonksiyonunu verin. Ayrıca bkz: https://yasirkula.com/2015/01/21/unity-ui-arayuz-sistemi/

      • GamePlanet dedi ki:

        Çok saolun hocam.Bişey daha sorabilirmiyim?
        Benim bir parkur oyunum var ve bu oyuna power up
        kitleri (hız artırıcı,zıplama artırıcı felan) eklemek istiyorum
        nasıl yapabilirim.

        İlginizden Dolayı Çok Teşekür ederim

      • yasirkula dedi ki:

        Normal skor objelerini nasıl spawn ediyorsanız benzer şekilde powerup’ları da spawn etseniz istediğiniz gibi olmuyor mu? Tam olarak nasıl bir sistem arıyorsunuz?

      • GamePlanet dedi ki:

        Mesela iksirler gibi player bu itemi alınca mesela daha iyi zıplıyor veya daha iyi koşuyor.
        böyle bir obje yapıp map in belli bölümlerine koyacağım koyacağım.Böyle bir obje yapmak için
        hangi kodlara ihtiyacım var.

        Tekrardan Teşekürker.

      • yasirkula dedi ki:

        Daha iyi zıplamayı ele alalım. İki değişken kullanabilirsiniz: “dahaIyiKos” adında bir boolean ve “kosuPowerupBitmeAni” adında bir float. Power-up’a dokununca (OnTriggerEnter) “kosuPowerupBitmeAni=Time.time+10;” ve “dahaIyiKos=true;” yapın. Update fonksiyonunda ise şuna benzer bir kod:

        if( dahaIyiKos && Time.time >= kosuPowerupBitmeAni )
        dahaIyiKos=false;”

        Artık hareket kodunuzda “if( dahaIyiKos )” koşulu true döndürüyorsa karakteri daha hızlı hareket ettirebilirsiniz.

  22. Kimex dedi ki:

    Bu Singleton scriptleri içindeki bir funksiyonu bir butona atayınca ve butonun olduğu sahneyi değiştirip tekrar geri geldiğimizde buton çalışmıyor çünkü scriptin atandığı obje kısmında missing yazıyor .Bunu nasıl çözebiliriz ?

    • yasirkula dedi ki:

      Evet, sahneye geri dönünce butonla scriptin atandığı obje arasındaki referansın kopması normal. Bu bağlantıyı scriptin atandığı objenin Start fonksiyonunda elle tekrar sağlamaya çalışabilirsiniz.

  23. assassinfurkan dedi ki:

    Yaptığımda oyunda ses açıp kapatma ekledim ancak 1. bölümden 2.ye geçtiğinde 2.bölümde müziği kapatamıyorum bunu nasıl düzeltebilirim

    • yasirkula dedi ki:

      Sesi nasıl açıp kapıyorsunuz?

      • assassinfurkan dedi ki:

        Canvas ile buton koydum onclick e audio source yi ekledim fonksiyonlardan play pause ile durdurup oynatiyorum

      • yasirkula dedi ki:

        O canvas’ı bir prefab yapıp her sahneye koyun ve de her sahne için o sahnedeki audio source’u canvas’a değer olarak verin. Audio source’unuz, sahneler arası yok olmayan bir singleton ise o zaman bu singleton script’e müziği açıp kapatmaya yarayan public static fonksiyonlar yazıp o fonksiyonları çağırın.

  24. murat dedi ki:

    Merhaba ben sahneler arası geçişi bir tuşa bağlamak istiyorum mesela F tuşuna basınca 2. sahneye geçsin nasıl yapacağım k

    • yasirkula dedi ki:

      Bir scriptin Update fonksiyonunda şuna benzer bir kod yazabilirsiniz:

      if( Input.GetKeyDown( KeyCode.F ) )
      UnityEngine.SceneManagement.SceneManager.LoadScene( 1 );

  25. Mehmet Eray dedi ki:

    Hocam merhaba. Ben bi oyun yaptım, android cihazda oynarken başka bi uygulamadan bildirim gelince oyundaki sesler bidaha çalmıyo. Aynı şekilde home veya çoklu pencere tuşuna basıp tekrar oyuna dönünce sesler yine çalmıyo. Seslerin tekrar çalması için oyunun kapatıp tekrar açmam gerekiyor. Bunu nasıl çözebilirim?

    • yasirkula dedi ki:

      Dediğiniz senaryolar gerçekleşse bile bende böyle bir sıkıntı olmamıştı. Unity’nin bir bug’ı olabilir ya da sadece kullandığınız cihazda rastlanan bir hata olabilir; bir çözüm yolu bilmiyorum.

  26. Tunahan dedi ki:

    Merhabalar Hocam. PlayerPrefs sistemi ile market sistemi yapmaya çalışıyorum. Bu markette karakteri de değiştirmem gerekiyor. Para düşme olayını hallettim fakat karakteri değiştiremiyorum. Bununla ilgili yardımcı olabilir misiniz veya Türkçe bir kaynak bulabilir miyim? Örneğin https://www.youtube.com/watch?v=YBsGhYuTavA&t=87s Teşekkür ederim. İyi Çalışmalar

    • yasirkula dedi ki:

      Bu konuda daha önceden araştırma yapmadım ama “unity character selection tutorial” yazınca bir takım dersler çıkıyor, belki onlar işinize yarar. Paranın düşmesi ama karakterin değişmemesi derken karakteri satın alabiliyorsunuz ama o karakterle oyuna başlayamıyorsunuz gibi birşey mi?

Bir Cevap Yazın

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

WordPress.com Logosu

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

Twitter resmi

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

Facebook fotoğrafı

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

Google+ fotoğrafı

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

Connecting to %s