UNITY Fonksiyonlarının (Update gibi) Görevleri ve Çalıştırılma Öncelikleri

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

Hepinize merhaba,

Bu derste Unity‘nin Start, Update gibi MonoBehaviour fonksiyonlarının kısaca ne zaman çalıştırıldıklarını ve birbirlerine göre çalıştırılma önceliklerini göreceğiz. Yani önce hangi fonksiyon, sonra hangi fonksiyon çalıştırılır onu göreceğiz. Bu sıralamayı bilmek bazen çok işinize yarayabilir. Dersin İngilizce kaynağı için tıklayın: http://docs.unity3d.com/Documentation/Manual/ExecutionOrder.html

Artık derse başlayalım…

NOT: Ders boyunca frame (oyun karesi) terimini göreceksiniz. Bu terimi şöyle açıklayabilirim: Siz oyununuzu oynarken bilgisayar donanımınızın gücüne göre oyununuz akıcı ya da yavaş çalışır. İşte bu hız olayı frame ile ilgilidir. Bir saniyede gördüğünüz frame sayısı ne kadar çoksa oyun o kadar akıcıdır. Her bir frame’de objelerinizin scriptlerindeki Update, OnGUI gibi devamlı görev yapan fonksiyonlar çalıştırılır. Objeler hareket ettirilir, fizik simülasyonları gerçekleşir vb.

Yeni Bir Scene Yüklendiğinde

Bu fonksiyonlar yeni bir scene yüklendiği anda, sahnedeki her obje için tek seferlik çalıştırılır.

  • Awake: Bu fonksiyon daima Start fonksiyonundan önce çalıştırılır, ayrıca bir prefab Instantiate edildiği anda da çalıştırılır. (Eğer GameObject aktif (active) değilse bu fonksiyon obje aktif olana kadar ya da bu objedeki bir scriptte yer alan bir fonksiyon dışarıdan çağrılana kadar çalıştırılmaz.)
  • OnEnable: (sadece eğer obje active ise çalıştırılır) Bu fonksiyon script enabled yapıldığı anda çalıştırılır. Bu durum ise objeye oyun sırasında yeni bir component eklenmesiyle, scene’in yüklenmesiyle ya da GameObject’in Instantiate edilmesiyle gerçekleşir.

Update Metodu İlk Kez Çalıştırılmadan Hemen Önce

  • Start: Start metodu, Update fonksiyonu henüz hiç çalıştırılmamışken tek seferlik gerçekleşir (eğer script enabled ise). Yani Update’ten önce çalıştırılır.

İki Frame Arasında

  • OnApplicationPause: Mevcut frame’de yapılacak işlemler bittikten sonra (frame’in sonunda) eğer pause durumu gerçekleşmişse bu fonksiyon çalıştırılır.

Update Sıralaması

Genelde aşağıdaki fonksiyonlardan Update’i kullanmanız tavsiye edilir ama duruma göre diğerlerini de kullanmak isteyebilirsiniz.

  • FixedUpdate: Genelde Update’ten daha sık çalıştırılır. Eğer oyun kasıyorsa bir frame’de birden çok kez çalıştırılabilir ya da oyun çok akıcıysa bazı karelerde hiç çalıştırılmayabilir de. Fizik olayları ve hesaplamaları FixedUpdate’ten hemen sonra gerçekleşir. Bu fonksiyonun içinde Time.deltaTime kullanmanıza lüzum yok çünkü Update’in aksine bu fonksiyon hep sabit bir süre aralıkla çalıştırılır.
  • Update: Her frame’de tek bir kez çalıştırılır. En sık kullanılan Update çeşididir.
  • LateUpdate: Sahnedeki objelerdeki Update metodlarının çalıştırılması bittikten sonra LateUpdate çalıştırılır ve yine her frame’de sadece bir kez çalışır. En meşhur kullanım alanlarından biri kameranın gerçek zamanlı konumlandırılmasıdır. Karakter Update metodunda hareket ettikten sonra kamera LateUpdate fonksiyonunda karakterin yeni konumunu baz alarak uygun şekilde konumlandırılabilir.

Render (Görüntü) Alma

  • OnGUI: Bir frame’de birkaç kez çalıştırılır. Önce GUI elemanları ekrana dizilir (layout) ve çizdirilir (repaint), ardından her Input eventi için tekrar çalıştırılır.
  • OnDrawGizmos: Oyunu test ederken görsel anlamda kılavuz olması için Scene panelinde gizmo çizmeye yarar.

Coroutine

Tüm Update fonksiyonları bittikten sonra çalıştırılırlar. Coroutine fonksiyonların özelliği çalıştırılmasının yarıdayken bir süreliğine duraklatılabilmesidir. Bu süre belli bir miktar (mesela 5 saniye) olabileceği gibi belirsiz bir miktar da olabilir (mesela internetten oyununuz için global yüksekskor verilerini çekiyorsunuz diyelim. Bu işlem bitene kadar coroutine vasıtasıyla çalıştırdığınız fonksiyonu duraklatabilirsiniz.).

  • yield: Coroutine’i bir frame bekletir. Yani kodun devamını bir sonraki frame’deki Update fonksiyonu çalıştıktan sonra işleme sokar.
  • yield WaitForSeconds(2): Belli bir saniye geçtikten sonra kodun çalıştırılmasına devam edilir.
  • yield WaitForFixedUpdate(): Tüm scriptlerdeki FixedUpdate fonksiyonlarının çalıştırılmasının bitmesini bekler.
  • yield WWW: Bir WWW verinin internetten indirilmesi tamamlandıktan sonra kodu çalıştırmaya devam eder.
  • yield StartCoroutine( BirCoroutineFonksiyon ): İçine girilen coroutine fonksiyonu çalıştırır ve onun bitmesini bekler. Ardından mevcut kodu çalıştırmaya kaldığı yerden devam eder.

Obje Yok Olduğunda

  • OnDestroy: Obje yok olmadan önceki son frame’inde, tüm Update() fonksiyonları çalıştırıldıktan sonra gerçekleşir. Objenin yok olmasının sebebi Destroy metodunun kullanımı olabileceği gibi başka bir sahneye (scene) geçiş de olabilir.

Oyundan Çıkarken

  • OnApplicationQuit: Oyundan çıkılmadan hemen önce gerçekleşir. Web player’da oyuncu web sayfasını kapatmak istediği anda çalıştırılır.
  • OnDisable: Script disabled yapıldığında ya da GameObject inactive yapıldığında çalıştırılır.

Özetleyecek olursak, işte scriptlerin çalıştırılma sıralaması:

  • Tüm scriptlerdeki Awake fonksiyonları
  • Tüm Start fonksiyonları
  • Tüm FixedUpdate fonksiyonları
  • Fizik hesaplamaları
  • OnEnter/Exit/Stay Trigger fonksiyonları
  • OnEnter/Exit/Stay Collision fonksiyonları
  • Eğer Rigidbody’de interpolate özelliği açıksa bunun için gerekli hesaplamalar yapılır
  • OnMouseDown/Up vb. olaylar gerçekleşir
  • Tüm Update fonksiyonları
  • Animasyon işleri gerçekleştirilir
  • Tüm LateUpdate fonksiyonları
  • Render (görüntü) alma işlemi
yorum
  1. Anıl dedi ki:

    iyi günler hocam, update fonksiyonu içerisinde dönen bir sayım var onu bool değerle kontrol ediyorum. sorum şu;
    control penceresinde sürekli 1 yazıyor ben butona basınca sıralama 1-2-3 mü olur anlık yoksa 1-3-2 mi olur şimdiden teşekkür ederim.
    akibet = true;
    private void Update()
    {
    if(akibet == true)
    {
    aa = 1;
    Debug.Log(aa);
    }
    else
    {
    aa = 2;
    Debug.Log(aa);
    }
    }
    public void tusabas()
    {
    akibet = false;
    aa = 3;
    Debug.Log(aa);
    }

    • yasirkula dedi ki:

      akibet’i false yapsanız bile Update anında çalışmayacağı için, bir sonraki Update çağrılana kadar aa’nın değeri 3 kalır. Yani 1-3-2.

  2. ewoshadow dedi ki:

    Merhaba Hocam, bende Update metodunu kullanmaktan sürekli kaçıyorum. Bu konuda biraz hassas davranıyorum sanırım ama 10 saniyede bir kez güncellenecek bir verinin her frame’de kontrol edilmesi gereksiz bir güç kullanımı gibi geliyor. (Tabi her değer için değil) Bu yüzden ya 1 saniyede bir ya da 0.1 saniyede bir Invoke veya InvokeRepeating kullanarak kendi update metodlarımı kendim yazıyorum. Hatta Time mekaniği için bile böyle yapıyorum. Umarım kaş yapıyorum derken göz çıkarmıyorumdur 🙂

    • yasirkula dedi ki:

      Siz nasıl rahat ediyorsanız 🙂 Çok fazla objede Update yoksa ve Update’in içinde her frame karmaşık if koşulları çalışmıyorsa, bence Update de kullanabilirsiniz mevcut düzende de devam edebilirsiniz. Mevcut düzeniniz yine de daha performanslı geliyor kulağıma.

      • ewoshadow dedi ki:

        Cevabınız için teşekkür ederim. İnsan bazen doğru yaptığını düşünüyor ancak bunu teyit etmek istiyor. Bilen birinin yorumunu duymak çok iyi geliyor.

  3. LS dedi ki:

    Merhaba hocam. Slider ile bir küpün hızını ayarlayıp, döndürüyorum. Bunu Update fonksiyonu ile yapıyordum. Daha sonra Update fonksiyonunu zorunda kalmadıkça kullanmayın dediklerini öğrendim. Şimdi Update metoduna if(speed>1) {} böyle kod bloğu ekledim.Sistem 1 üstünde sadece çalışıyor.(Kafamdaki soru update’te olması beni etkiler mi hala? şart koydum ya..) Şimdi soruma gelecek olursak Update metodunda yaptığım bu işlem optimizasyon olarak bana fayda sağlar mı? Update metodundan uzak sürekli döndürme işlemini nasıl yapabilirim? Teşekkürler şimdiden. Kodlarım normalde böyleydi:

    void update()
    {
    transform.Rotate(0, speed * Time.deltaTime, 0);
    }

    public void AdjustSpeed(float newSpeed)
    {
    speed = newSpeed;
    transform.Rotate(0, speed * Time.deltaTime, 0);
    }

    • yasirkula dedi ki:

      Sadece birkaç objenin Update’i olması hiç önemli değil. Binlerce hatta belki on binlerce olunca anca o zaman Update kullanmanın olumsuz etkisini görebilirsiniz (tabi burada varsayıyorum ki, Update’te çalıştıracağınız kodu hangi yöntemi kullanırsanız kullanın her frame’de çalıştıracaksınız). Update’ten uzak bir şekilde aynı işi yapmanın bir yolu, while(true) içeren (sürekli çalışan) bir coroutine kullanmak. Başka bir yolu ise, Update’i olan objeleri bir List‘te tutup her frame bu List’teki objelerin, eskiden Update’te yer alan kodunu çalıştırmak.

      • LS dedi ki:

        Teşekkür ederim hocam. Update konusunda çok aydınlandım. Korkarak kod yazıyordum bu bölümde. 🙂

  4. gizem dedi ki:

    merhaba öncelikle unity üzerinden AR ile çalışıyorum da objeleri destroy etme de sıkıntılar çekiyorum, yardımcı olabilir misiniz?

  5. JEEMSilver dedi ki:

    Selamlar Yasir Bey;

    Oyundaki objelerimi sabit ivmeli bir hıza sahip olmaları için transfrom.translate ile hareket ettiriyorum. Bunları fixedupdate içerisinde time.deltatime çarpımı ile çalıştırıyorum. Fakat sanırım Unity kendi sitesinde Fixedupdate içerisinde time.fixedDeltaTime kullanmayı öneriyor. Biraz kafam karıştı doğrusu, yoksa time.deltaTime ı kullancaksam sadece update fonkiyonu mu kullanmalıyım yardımcı olabilir misiniz?

    Teşekkürler

    • yasirkula dedi ki:

      FixedUpdate’te Time.deltaTime’ı çağırdığınızda otomatik olarak Time.fixedDeltaTime döndürülür (kaynak). O yüzden her yerde Time.deltaTime kullanabilirsiniz.

  6. dreamON dedi ki:

    Awake fonksiyonu oyun başladığında eğer obje aktif değilse çalışmıyor ve obje sonradan aktif edilirse çalışıyor diye anladım. Bu bir kere mi oluyor yoksa oyun çalıştıktan sonra obje her aktif, pasif edildiğinde tekrardan çalışıyor mu acaba?

  7. Ogün dedi ki:

    Merhabalar,

    Benim de özel bir sorum var mümkün ise cevaplarsanız çok sevinirim…

    Bir projeye sahibim,

    Unity üzerinden mysql ile iletişim sağlıyorum.
    Oyuncular kayıt olup oyuna giriş yapabiliyor.
    Ama, burada ufak bir sorunum var.
    Kullanıcıların skor bilgilerini update ederken sorun yaşıyorum.

    Şöyle anlatayım.

    Şimdi projemde bir Timer var bu Timer atıyorum 100.000 saniyeden geriye doğru sayıyor. ( 99.999-99.998 ….. vesaire )

    Bu Timer çalışırken kullanıcının Skor’u her 1 saniyede 1 puan artıyor. ( her kullanıcının kendine özel dakikası ve skor’ u var.. )
    Fakat oyuncu oyundan ayrıldığı zaman ne Timer çalışmakta nede Skor bilgisi ( sürekli olarak ) güncellenmekte…

    Yani ben oyuncu oyunda olsa da olmasa da mutlaka her geçen saniye hem Timer’ın çalışmasını hem de Oyuncunun puanlarının artmasını istiyorum. Sizce bu sorunu nasıl çözebilirim.

    Şimdiden teşekkürler.

  8. Barış dedi ki:

    Zaman sayacım var ama sayacı sadece belirdi zamanda (butona tıklayınca) çalıştırıyorum. Benim amacım Update i hep az kullanmak olduğu için hani mesela sadece buntonabasildi == 1; olduğu zaman (diyelimki öyle bir kod olsa) değil butona basinca hiç update e bulaşmadan -= Time.deltaTime; ı sürekli çalıştırabilir miyim?

  9. Onur dedi ki:

    Merhabalar, müsadenizle bir şey danışmak istiyorum.Belki size çok basit bir soru gibi gelecek ama 2 gündür takıldım çözüm bulamıyorum.Yardımcı olursanız çok sevinirim.

    kendi oluşturduğum bir void içine yazdığım koşullar gerçekleşmiyor.Sanırım counter int değerini bir şekilde kontrol ettirmem gerekiyor.
    Update içine yazarsam counter 1 olduktan sonra sürekli çalışıp sınırsız spawn ediyor.

    Mesela

    void spawner()
    {
    if (counter ==1)
    {

    Invoke(“circlespawn”, 1.5f);
    }

    void circlespawn()
    {

    Instantiate(circlePrefab, new Vector3(0, 4, 0), Quaternion.identity);
    }

    • yasirkula dedi ki:

      counter’ı 1 artıran kod neredeyse, o kodun içerisinde counter 1 arttıktan sonra değerini kontrol edip gerekirse circlespawn fonksiyonunu çağırabilirsiniz.

      • Onur dedi ki:

        Bu kadar çabuk geri dönüş yaptığınız için teşekkür ederim.Acemi olduğum için belki sorunu tam anlatamadım kusura bakmayın lütfen.

        counter’ı arttıran kod başka bir script içinden çağrılıyor ve counter +1 olarak artıyor bunu hierarchy panelinde görebiliyorum ancak spawn kodlarını yazdığım scripte algılatamıyorum sanırım.

        counter değeri değişip 1 olduğu halde void spawner devreye girmiyor.

        public class spawncounter : MonoBehaviour
        {

        public static spawncounter instance;
        public int counter;

        void spawner()
        {
        if (counter ==1)
        {
        Invoke(“circlespawn”, 1.5f);
        }

      • yasirkula dedi ki:

        Sadece Update, FixedUpdate ve OnCollisionEnter gibi belli başlı Unity fonksiyonları otomatik olarak çağrılırlar. Kendi yazdığınız spawner gibi fonksiyonlar, siz elle çağırmadığınız sürece çalışmazlar. Benim önerim, counter’ı property’e çevirip set fonksiyonunda eğer değeri 1 ise circlespawn’ı çağırmanız. Property dersim için: https://yasirkula.com/2015/09/16/unity-3d-propertyleri-taniyalim-c/

  10. Altay dedi ki:

    iki tane farklı script dosyasında awake tanımladığımızı düşünelim. Bunların birine a script dosyası digeride b script dosyası olsun. a daki awake b deki awake den önce çalışması gerekiyor. Fakat debug ta bakıldıgında ilk b deki awake çalışıyor sonraa daki çalışıgı için hata alıyorum. Bu awakeleri bir çalışma önceliği tanıtmam mümkün mü?

    • yasirkula dedi ki:

      Edit-Project Settings-Script Execution Order’a iki script’i de atıp, A’nın B’nin yukarısında olmasını sağlayabilirsiniz. Sonra Apply’a tıklamayı unutmayın.

      • Altay dedi ki:

        Çok çok teşekkür ederim. İşe yaradı. Bu kadar hızlı dönüş yapacağınızı düşünmemiştim. Çok kaliteli bir siteniz var sizi tebrik ederim.

      • yasirkula dedi ki:

        Teşekkür ederim ^^

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.