Unity 3D Coroutine’ler

Yayınlandı: 20 Kasım 2018 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde

Hepinize merhabalar,

Bu derste, Unity‘nin popüler ve bir o kadar da güçlü bir özelliği olan coroutine‘lerden bahsedeceğiz. Coroutine’ler vasıtasıyla örneğin bir kodun çalışmasını birkaç saniye geciktirebilir, belli bir işlemin bitmesini bekleyebilir veya işlemi birkaç saniyeye yayabilirsiniz (bir objeyi bir yerden başka bir yere 2 saniyede hareket ettirmek gibi).

Hazırsanız derse başlayalım!

Coroutine’ler de aslında birer fonksiyondurlar ve birkaç ufak fark haricinde, aşina olduğunuz normal fonksiyonlardan bir farkları yoktur:

  1. coroutine’ler IEnumerator döndürmelidir. Bu arayüze erişebilmek için kodunuzun başına using System.Collections; satırını eklemeniz gerekir. Ama belki fark ettiğiniz üzere, yeni oluşturulan script’lere Unity otomatik olarak bu satırı ekler çünkü coroutine’ler Unity’de sıklıkla kullanılmaktadır
  2. coroutine’ler StartCoroutine fonksiyonu ile çağrılmalıdır (aksi taktirde coroutine çalışmayacaktır)
  3. coroutine’in içinde en az bir yield return ifadesi kullanılmalıdır

Örneğin alttaki koda bir göz atalım:

void Start()
{
	Debug.Log( "Start başlangıç" );
	StartCoroutine( CoroutineTest() ); // CoroutineTest coroutine'ini başlat
	Debug.Log( "Start bitiş" );
}

IEnumerator CoroutineTest()
{
	Debug.Log( "İlk frame" );
	yield return null; // 1 frame bekle
	Debug.Log( "İkinci frame" );
}

Tahmin edeceğiniz üzere, bu koddaki coroutine’imiz CoroutineTest fonksiyonu. Bu coroutine içerisine yazdığımız yield return null; satırı, coroutine’in orada 1 frame beklemesini sağlar. Coroutine’ler, onları çağıran fonksiyonlardan bağımsız olarak hareket eder. Yani bizim CoroutineTest fonksiyonunu 1 frame bekletmemiz, Start fonksiyonunu da 1 frame bekletiyor olmamız anlamına gelmez. CoroutineTest 1 frame beklerken, Start normal seyrinde çalışmaya devam eder. Bu yüzden de bu programın çıktısı şöyle olur:

Start başlangıç
İlk frame
Start bitiş
İkinci frame

Şimdi bir de şu coroutine’e göz atalım:

IEnumerator CoroutineTest()
{
	Debug.Log( "Zaman: " + Time.time );
	yield return new WaitForSeconds( 1.5f ); // 1.5 saniye bekle
	Debug.Log( "Zaman: " + Time.time );
}

Gördüğünüz üzere, WaitForSeconds fonksiyonu vasıtasıyla bir coroutine’i belli bir süre boyunca bekletebilirsiniz. Burada dikkat etmeniz gereken nokta, bu sürenin Time.timeScale’e bağlı olmasıdır. Yani eğer timeScale’i 0.5 yaparak oyunu yavaş çekime aldıysanız, bu kod 1.5 saniye değil de 3 saniye bekler. Eğer timeScale’den bağımsız bir şekilde birkaç saniye beklemek isterseniz, WaitForSecondsRealtime fonksiyonunu kullanabilirsiniz.

Aşağıdaki örnekte ise, WWW sınıfını kullanarak internetten nasıl resim indirip bu resmi, script’in atandığı objenin materyaline atayabileceğinizi görüyorsunuz. Ayrıca bir coroutine’in parametre de alabileceğini görmüş oluyorsunuz. Bir WWW objesini yield return yaparsanız, kodunuz o WWW işleminin bitmesini bekler (bu örnekte, resmin internetten inmesini). Koddaki using ibaresinin coroutine’ler ile bir alakası olmadığı için ona çok takılmayın.

void Start()
{
	StartCoroutine( ResimIndir( "http://flags.fmcdn.net/data/flags/w580/tr.png" ) ); // ResimIndir coroutine'ini, girilen parametre ile başlat
}
 
IEnumerator ResimIndir( string url )
{
	using( WWW www = new WWW( url ) ) // WWW bir IDisposable obje olduğu için using kullanıyoruz, yani bunun coroutine'lerle bir alakası yok
	{
		yield return www; // Resmin inmesini bekle
		
		if( !string.IsNullOrEmpty( www.error ) ) // Resmi indirirken bir hata alıp almadığımıza bak
			Debug.LogError( "Bir hata oluştu: " + www.error );
		else
		{
			// Bir hata yok, resmi bu objenin materyaline texture olarak ata
			Texture2D resimTexture = www.texture;
			GetComponent<Renderer>().material.mainTexture = resimTexture;
		}
	}
}

NOT: eğer WWW yerine UnityWebRequest kullanmak isterseniz, işlemin bitmesini beklemek için UnityWebRequest objesinin Send/SendWebRequest fonksiyonunu çağırınca döndürülen objeyi yield return yapabilirsiniz.

Aşağıdaki örnek kod, kodun atandığı objeyi 3 saniyede mevcut konumundan 10,10,10 konumuna taşımaya yarar:

IEnumerator ObjeyiKimildat()
{
	float kimildamaSuresi = 3f; // Objeyi 3 saniyede hareket ettir
	float gecenSure = 0f;

	Vector3 mevcutKonum = transform.position;
	Vector3 hedefKonum = new Vector3( 10, 10, 10 );

	while( gecenSure < kimildamaSuresi ) // Henüz kimildamaSuresi kadar süre geçmediği müddetçe bu kodu çalıştır
	{
		gecenSure += Time.deltaTime; // gecenSure her saniye 1 artar
		transform.position = Vector3.Lerp( mevcutKonum, hedefKonum, gecenSure / kimildamaSuresi ); // Objenin konumunu mevcutKonum ile hedefKonum arasında oynat

		yield return null; // 1 frame bekle (yumuşak hareket için objenin konumunu bir anda değil, frame frame değiştirmeliyiz)
	}

	// kimildamaSuresi kadar süre geçti, objenin hedefKonum'a tam oturduğundan emin ol
	transform.position = hedefKonum;
}

Dilerseniz, yine StartCoroutine ile bir coroutine’in içerisinden başka bir coroutine’i başlatabilir ve bu coroutine’in bitmesini beklemek için, onu yield return yapabilirsiniz (eğer beklemek istemezseniz yield return yapmak zorunda değilsiniz):

IEnumerator CoroutineTest()
{
	Debug.Log( "Test2'yi beklemeden önce" );
	yield return StartCoroutine( CoroutineTest2() ); // CoroutineTest2 coroutine'ini başlat ve bitmesini bekle
	Debug.Log( "Test2'yi bekledikten sonra" );

	Debug.Log( "Test2'yi başlatmadan önce" );
	StartCoroutine( CoroutineTest2() ); // CoroutineTest2 coroutine'ini başlat ama bitmesini bekleme
	Debug.Log( "Test2'yi başlattıktan sonra" );
}

IEnumerator CoroutineTest2()
{
	Debug.Log( "Test2 başlangıç" );
	yield return new WaitForSecondsRealtime( 1 );
	Debug.Log( "Test2 bitiş" );
}

Peki diyelim ki çalışmakta olan bir coroutine’i durdurmak istiyorsanız napacaksınız? Burada ise StopCoroutine ve StopAllCoroutines fonksiyonları devreye giriyor. StopAllCoroutines fonksiyonu, bu objede StartCoroutine ile başlatılan tüm coroutine’leri durdurmaya yararken, StopCoroutine fonksiyonu ise, parametre olarak girilen belli bir coroutine’i durdurmaya yarar. Bunun için, durdurmak istediğiniz coroutine’i bir Coroutine değişkeninde tutmanız lazım. Örneğin:

private Coroutine donmeCoroutine;

void Update()
{
	if( Input.GetKeyDown( KeyCode.E ) ) // E tuşuna basınca
	{
		if( donmeCoroutine == null ) // Çalışmakta olan bir DondurCoroutine yok, bu coroutine'i çalıştır ve değişkene at
			donmeCoroutine = StartCoroutine( DondurCoroutine() );
		else // DondurCoroutine çalışıyor, onu durdur
		{
			StopCoroutine( donmeCoroutine );
			donmeCoroutine = null;
		}
	}
}

IEnumerator DondurCoroutine()
{
	while( true ) // Bu coroutine, durdurulmadığı sürece sürekli çalışmaya devam eder
	{
		transform.Rotate( 0, 90 * Time.deltaTime, 0 ); // Objeyi Y ekseninde döndür
		yield return null;
	}
}

Bu şekilde bu dersin sonuna geldik. Daha sonraki derslerde görüşmek üzere!

yorum
  1. PoinDexter dedi ki:

    hocam merhaba bende unity üzerinden bir oyun tasarlamaya çalışıyorum ancak bir yerde takıldım. Space Shooter tarzı bir oyun yapıyorum ve oyun başlangıcında meteorlar oluşuyor her bir meteor yok etmesi 1 puan değerinde ve 10 ve katı puan olduğu zaman meteorların oluşmasını durdurup düşman uzay gemisi oluşturmak istiyorum. Düşman uzay gemisi yok olduğunda meteorlar gelmeye devam edecek ve bu şekilde devam edecek. Bunun için ne kullanmalıyım yardımcı olur musunuz?

  2. ramazan dedi ki:

    merhaba hocam blogunuz çok güzel burada paylaştığınız şeyler sayesinde kendimi çok iyi geliştirdim size bir kaç soru soracaktım bu coroutineler update fonksiyonu gibi degil anladıgım kadarıyla işi bitince StopCoroutine ile durduruyoruz surekli update fonksiyonu gibi sistemi yormuyor degil mi ? bir de bu while(true) içine en son yazdıgımız yield return null; kodu ne işe yarıyor tam olarak cunki benim izledigim bir yabancı kaynakta hemen hemen su sekilde kullanılmaktaydı

    public void ShopBtn()
    {
    if (!ShopOn)
    {
    MenuCanvas.SetActive(false);
    CameraAnim.Play(“CameraMenuShopAnim”);
    StartCoroutine(“ShopOnClick”);
    }

    }
    IEnumerator ShopOnClick()
    {
    while (true)
    {
    if (Camera.transform.position == ShopPos)
    {
    ShopCanvas.SetActive(true);
    StopCoroutine(“ShopOnClick”);
    }
    yield return null;
    }

    }
    şimdiden zaman ayırdıgınız ve guzel blogunuz için teşekkür ederim!

    • yasirkula dedi ki:

      Coroutine sonsuza kadar çalışan bir loop içeriyorsa, durdurmak için StopCoroutine yapmak ya da objeyi inaktif hale getirmek gerekir evet. Aksi taktirde, coroutine fonksiyonu tamamen çalıştığında coroutine otomatik olarak durur. StartCoroutine’e string parametre vermek yerine, derste gösterdiğim şekilde kullanmanızı öneririm. Ayrıca DOTween’i de öğrenmenizi öneririm çünkü attığınız örnek kod DOTween için biçilmiş kaftan. “yield return null” coroutine’in 1 frame beklemesini sağlar. Yani oyun 60 fps ise, 1/60 saniye beklemeyi (sonraki frame’i beklemeyi) sağlar.

      • ramazan dedi ki:

        Hızlı cevabınız için teşekkür ederim önerilerinizi uygulayacağım iyi günler dilerim.

  3. eyyup dedi ki:

    hocam kolay gelsin bir butona tıklayınca 2 saniye sonra iki fonksiyon çağırsın istiyorum ama bende birtürlü olmuyor
    örnek butona tıklayınca aşağıdaki fonksiyonlar 2 sn sonra çalışsın

    public void tikla() //buton onclicki ne eklediğim script
    {
    StartCoroutine(m_wait);
    mDelete();
    StartCoroutine(Rastgele());
    }

    IEnumerator m_wait()
    {
    Debug.Log( “Zaman: ” + Time.time );
    yield return new WaitForSeconds( 2f ); // 1.5 saniye bekle
    Debug.Log( “Zaman: ” + Time.time );
    }

    AMA OLMUYOR TIK DİYE ÇALIŞIYOR.

  4. Mustafa dedi ki:

    Merhaba unity de yeni oyun yapıyorum 2d ile zıplama yapıyorum zıpladıktan sonra belli bir süre bekleme süresi olmasını ıstiyorum IEnumerator bu kod ile denedım olmadı yardım edermisiniz.
    birde sag sol hareketleri input.GetKey ile yaptım sizce dogrumu

    • yasirkula dedi ki:

      Şöyle yapabilirsiniz: “float sonZiplamaAni;” değişkeni olur ve zıplarken “Time.time-sonZiplamaAni”nın değerinin 1 saniyeden büyük olup olmadığını kontrol edersiniz. Büyükse zıplar ve sonZiplamaAni’nı Time.time’a eşitlersiniz. Sağ-sol hareket için genelde Input.GetAxis(“Horizontal”) kullanılıyor çünkü WASD ve ok tuşlarını (ve sanırım joystick) destekliyor ama bu sizin için önemli değilse GetKey kullanmanızda hiç sakınca görmüyorum.

  5. mushroom dedi ki:

    Çok iyi bir anlatım olmuş. Her şey kafamda oturdu.

  6. cazzsaa dedi ki:

    Hocam Unity personal ‘i kullanmak için github kullanmamız gerekiyormuş diye öğrendim ama github hesabını açtım da unity de nasıl personal ‘ı kullanacağımı bilemedim. Biliyorsanız yardımcı olabilir misiniz?

    • yasirkula dedi ki:

      GitHub hesabı gerekmiyor. Sadece Unity’nin web sitesinden ücretsiz bir şekilde hesap açmanız yeterli. Ardından Unity Hub programına hesabınızla giriş yaparken, lisans olarak ücretsiz Personal lisansı seçebilirsiniz (eğer sorarsa).

  7. sıddık çiçek dedi ki:

    Selamun aleyküm hocam ben şunu anlamadım. yield return, Coroutine ‘de ne göreve sahip?

  8. Uğur Yılmaz dedi ki:

    Merhaba,
    Biraz uzun ama bir konuda sorum olacak şimdiden teşekkürler.
    Oyun level geçmeyi sağlayan yada bölümü tekrarlatan oyun bitti ve yeni level kodlarım var tek script içinde.
    Oyun bitti kısmı farklı bir scripte de tag üzerinden temas oluyorsa çalışıyor ve GamePanel butonunu aktif ediyor.
    OYUN BİTTİ TAG

    if (col.tag == “kucukarrowtag”)
    {
    oyunYoneticisi.GetComponent().OyunBitti();
    }

    Game paneli üzerinde tekrar oyna ve anamenü dön seçenekleri var
    10 ok varsa 9cu ok temas ederse sorun yok bölümü tekrarlıyor, fakat 10uncu ok oyunbittitag çalıştırsa bile bölüm geçmesine sebep oluyor.
    public void OyunBitti() içine ” SceneManager.LoadScene(int.Parse(SceneManager.GetActiveScene().name) + 1);” Eklemem lazım
    Bunu ekleyince GamePanel.SetActive(true); paneli aktif oluyor hemen seçim yatprmadan oyun başlıyor kaldığın yerden bunu butonla manuel yapmak istiyorum bunu nasıl yapabilirim.
    public void OyunBitti()
    Yerine
    IEnumerator OyunBitti() Yapınca
    if (col.tag == “kucukarrowtag”)
    {
    oyunYoneticisi.GetComponent().OyunBitti();
    }
    Kodu tag kodu hata biliyor
    ————————————————————————————–
    IEnumerator yenilevel()
    {
    hedef.GetComponent().enabled = true;
    AnaArrow.GetComponent().enabled = false;
    yield return new WaitForSeconds(2);
    if (kontrol)
    {
    SceneManager.LoadScene(int.Parse(SceneManager.GetActiveScene().name) + 2);
    level_id = int.Parse(SceneManager.GetActiveScene().name) + 0;
    if(PlayerPrefs.GetInt(“levelid”) < level_id)
    PlayerPrefs.SetInt("levelid", level_id);
    }
    }
    public void OyunBitti()
    {
    GamePanel.SetActive(true);
    hedef.GetComponent().enabled = false;
    AnaArrow.GetComponent().enabled = false;
    }

    • yasirkula dedi ki:

      Mesajınızı iki defa okudum ama yaşadığınız sıkıntıyı tam anlayamadım. Oyununuzla ilgili hiçbir şey bilmeyen birine anlatır gibi (örneğin oklar nedir, 9. ok ve 10. okun farkı nedir hiç fikrim yok) anlatır mısınız?

  9. Burak Taha dedi ki:

    normalde internette çok yorum bırakmam ama sanırım tam da aradığım şeyi buldum, c# winform’da timer gibi unity için de bu tarz bir şey arıyordum InvokeRepeating de işime yarıyordu ama parametre giremediğim için buna yöneliyorum, gerçekten çok yararlı ve güzel anlatımın için teşekkür ederim.

  10. islam dedi ki:

    Merhaba. Bu verdiğiniz bilgiler çok ama çok değerli. Bu kadar bilgiyi ücretsiz biçimde insanlara sunduğunuz için ben kendi adıma size teşekkür ediyorum. Mükemmel bir insansın.

  11. Semih dedi ki:

    Burayı okudum okuyunca anlıyorsun ancak uygulamada sorunlar çıkıyor malum. Şunu yapmak istiyorum yardımcı olur musunuz.

    speed adında bir değişken var. Bir butona bastığımızda bu speed değişkeni 5 saniye boyunca 2 katına çıksın, sonrasında tekrar eski haline gelsin istiyorum.

    public void ButtonSpeed()
    {
    StartCoroutine(SpeedPower());
    }

    Öncelikle bir butona basınca çalışması için yukarıdaki gibi yapmak şart mı?

    IEnumerator SpeedPower()
    {
    Burada tıkandım. İstiyorum ki speed = speed*2 olsun 5 saniye boyunca. Bu 5 saniye bittiğinde de tekrar speed eski haline gelsin. Speed için bir değer giremeyiz çünkü o başka yerlerde değişiyor.
    }

    • yasirkula dedi ki:

      Butona basınca çalışması için yukarıdaki gibi yapmak maalesef şart, StartCoroutine’in çağrılması zorunlu. Coroutine’in içerisinde ise speed’i 2’ye katlayıp WaitForSeconds ile 5 saniye bekleyip ardından speed’i 2’ye bölmek işinizi görmüyor mu?

      • Semih dedi ki:

        while gibi bir şeyler olup içine bir şeyler yazmak gerekiyor diye düşünmüştüm. Şimdi siz söyleyince while falan kullanmadan yazdım oldu sanırım. While gibi ifadelerin her zaman olması gerektiğini düşünmüştüm bu şekilde de problem yok sanırım.

        speed = speed*2;
        yield return new WaitForSeconds (5);
        speed = speed/2

      • yasirkula dedi ki:

        Evet bunun bu şekilde olması gerekiyor. while’ı sadece ihtiyacınız olduğunda kullanacaksınız.

  12. Barış dedi ki:

    Gerçekten süper bir yazı. Yabancı kaynaklardan bile iyi.

  13. birisi dedi ki:

    ben bir spawner yazdım.birkaç saniyede bir obje spawnlıyor.bu beklemeyi coroutine ile sağladım ama 1kere bekliyor spawnlıyor daha sonra beklemeyi atlayıp sürekli spawnlıyor.bunun sebebi nedir?

  14. Semih dedi ki:

    Merhabalar, açıklama için teşekkürler güzel bir konu olmuş. Birçok yerde işe yarayacak bir sistem.

    Bir sorum olacak size:

    Ben oyunumda bir güç olsun istiyorum, örneğin topu hızlı gitmesi. Bu gücün 5 veya belirlediğim bir değişkene bağlı saniye kadar çalışmasını daha sonra eski hızına dönmesini istiyorum. Bunu nasıl sağlarım? Bu konuyla benziyor gibi bu şekilde mi çözülür tam emin olamadım. Kodlar dilinden biraz detaylı açıklayacak olursam.

    speed = 300 normalde
    F tuşuna basınca
    speed = 5 saniyeliğine(veya bir süre) 600 olsun, 5 saniye sonunda tekrar 300e(ilk haline) dönsün.

    İlk haline dönsün kısmını 300 olarak elimle girmek istemiyorum açıkçası, çünkü bu değişebilecek bir şey, normal hızı ileride 400 yapabilirim örneğin.

    yapmak istediğim böyle bir şey. Yarımcı olabilirseniz çok memnun olurum.

    Araştırmalarım sonucu net bir bilgiye ulaşamadım. Sürekli belirli bir saniye aralığında ya da belirli bir saniye sonra çalıştırılan fonksiyonlar ya da işlemlerin cevaplarını görüyorum. Bu konuda benim mi bir hatam var acaba? Oyunda istediğim bu işlemi farklı bir şekilde mi yapmalıyım. Yani siz olsanız bu özel kullanılabilir gücü nasıl eklerdiniz.

    • yasirkula dedi ki:

      speedMultiplier diye 2. bir değişken oluşturabilir ve değerini 5 saniyeliğine 1’den 2’ye çekebilirsiniz. Hareket kodunuzda da hız olarak speed*speedMultiplier‘ı kullanabilirsiniz.

      • Semih dedi ki:

        Teşekkürler, evet dediğinizi anladım fakat asıl sorum “5 saniyeliğine” kısmı. Herhangi bir fonksiyonu veya bir değişkeni 5 veya 10 saniye yani belirli bir süreliğine nasıl çalıştırabiliriz. Bu süre bittiğinde eski düzenine dönecek şekilde.

      • Semih dedi ki:

        private float speed;;
        private float speedMultiplier;

        void Speed() //Speed isminde bir fonksiyon
        {
        speed = speed*speedMultiplier; //sanırım böyle bir şey diyorsunuz
        }

        Örneğin bu şekilde “Speed” isminde bir fonksiyon var. Bu fonksiyon 5 saniye çalışsın ve 5 saniye sonunda speed değişkenim tekrar ilk haline dönsün istiyorum

      • yasirkula dedi ki:

        IEnumerator SpeedMultiplierCoroutine()
        {
        speedMultiplier = 2;
        yield return new WaitForSeconds(5);
        speedMultiplier = 1;
        }

        Ardından: rigidbody.AddForce(speed*speedMultiplier);

  15. ali dedi ki:

    üstad bir bölümde çarpışmadan sonra animasyon çıkıyor . 3-4 saniye sonra levelin tekrar başlamasını istiyorum. Bu şekilde bir kod yazdım ama çalışmıyor hatam nerede olablir.

    unity bu hatayı veriyor.
    Assets\scripts\CollisionDetector.cs(16,25): error CS0103: The name ‘yenidenbasla’ does not exist in the current context

    https://hizliresim.com/5JGdUd

  16. Nuri dedi ki:

    Kokay gelsin. Bu WWW olayı kaldırılmış galiba? Bilginiz var mı ?

    • yasirkula dedi ki:

      Kaldırıldı mı bilmiyorum ama kaldırıldıysa da aynı işlevi gören UnityWebRequest’i kullanabilirsiniz: https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.html

      • Samet dedi ki:

        Abi Unityde bir oyun tasarlıyorum ama animasyonu yapamadım karakter düşmana değdiği zaman bir animasyon çalışması gerekiyor bi türlü yapamadım çözüm önerebilirmisin ?

      • yasirkula dedi ki:

        Animation component’i kullanıyorsanız animationComponenti.Play(“AnimasyonIsmi”), Animator component’i kullanıyorsanız animatorComponenti.Play(“AnimasyonIsmi”) veya animatorComponenti.SetTrigger veya animatorComponenti.SetBool kullanmanız lazım. Animasyonunuz Animation component’ine veya Animator component’inin AnimatorController’ına ekli olmalı. Eğer hiç Animation veya Animator kullanmadıysanız, önce YouTube’da bu konuyla alakalı birkaç video izlemenizi öneririm.

  17. Emrullah Ertaş dedi ki:

    Kaçırdığım önemli bir yorum var.

    Acaba yorum geçmişini nerden bakabilirim?

    “Nurullah Ertaş” , “Emrullah Ertaş” , “Yasin Çakıcı”

    bunların yaptıkları yorum önemliydi. nerden bakabilirim yardımcı olabilirmisiniz?

    yan tarafta yorum geçmişi bulunuyor lakin sadece 5 yorum geçmişi

    Not : 2 gün önceki yorum

  18. Arda dedi ki:

    üzgünüm buradan yazıyorum ama bir sorum daha var
    ben karakterime şöyle zıplama verdim
    if (Input.GetKeyDown(KeyCode.Space))
    {
    rb.AddForce(Vector3.up*ziplama);
    anim.speed = 1;
    anim.SetBool(“JUMP”, true);
    }
    ve bu sefer hem addforce sayesinde zıplıyor hemde karakterin animasyonu sayesinde böylece fazla zıplamış gözüküyor bunu nasıl düzeltebilirim

  19. Arda dedi ki:

    merhaba öncelikle ben unity ye yeni başladım ve karakter animasyonlarını yapıyordum
    if (Input.GetKey(KeyCode.W) && (Input.GetKey(KeyCode.V)))
    {
    transform.Translate(transform.forward * 0.3f);
    anim.speed = 1;
    anim.SetBool(“TAKLA”, true);
    }
    if (Input.GetKeyUp(KeyCode.V))
    {
    transform.Translate(transform.forward * 0.3f);
    anim.speed = 1;
    anim.SetBool(“TAKLA”, false);
    }
    ben 2 .if de transformdan önce bekle kullanmak istiyorum oyun hata veriyor bunu yaptığımda
    yani kısaca sorunum şu ben W + V tuşuna bastığımda takla atacak ama basılı tutmam gerekiyor
    alttaki if kısmını eklemezsem bu olayı sürekli tekrar ediyor.

    ben sizin anlattığınız kısımda IEnumerator bunu anlamadım galiba oyuzden yapamadım void update altına yazıyorum kodlarımı şimdiden teşekkürler

    • yasirkula dedi ki:

      Animasyonlar arası geçiş kötü durduğu için biraz beklemek istiyorsunuz diye düşünüyorum. Bence karakterin AnimatorController asset’ini açın (Window-Animator penceresini açıp AnimatorController’a Project panelinden çift tıklayın), ardından TAKLA false olduğunda gerçekleşen geçişe tıklayın ve Inspector’dan Settings’teki ayarları biraz düzenleyin (dokümantasyon: https://docs.unity3d.com/Manual/class-Transition.html). Örneğin Exit Time’ın değerini değiştirmeyi deneyebilirsiniz (0 ile 1 arasında değerler deneyin).

      • Arda dedi ki:

        demek istediğim şu ben tek tıklamada yapmak istiyorum ama ozaman animasyon iptal oluyor yani yaptığım komutta basılı tutmam gerekiyor

      • yasirkula dedi ki:

        Boolean değil de Trigger değişkeniniz olsun ve anim.SetTrigger(“TAKLA”) fonksiyonu ile bunu aktifleştirerek takla animasyonuna geçiş yapın. Takla animasyonundan normal animasyona geri geçişte bir Condition kullanmayın, hata alırsanız Exit Time condition’ı kullanın.

      • Arda dedi ki:

        bu sefer sonsuz döngü oldu yani sürekli takla atıyor sizide yoruyorum kusura bakmayın

      • yasirkula dedi ki:

        SetTrigger sürekli çağrılıyor demek ki. SetTrigger’ın olduğu satıra Debug.Log ekleyerek de bunu tespit edebilirsiniz. SetTrigger’ı sadece karakterin takla atmasını istediğinizde çağırın.

  20. L dedi ki:

    Yasir bey iyi akşamlar .
    Benim oyunumda iki karakter var ikisinin healt ı box collider is triger seçeneği seçili vaziyette . Ben bu iki karakterin birbirlerinin içinden geçmemesini nasıl yaparım . ( Herbirine bir collider daha verdim is triger seçili değil , bu şekilde de savruluyorlar . ) Yardım ricası ile kolay gelsin .

    • yasirkula dedi ki:

      Birbirinin içinden geçemediğini ama temas ettiklerinde bi titreştiklerini anlıyorum, yanlışım varsa düzeltin. Eğer transform.Translate ile hareket ediyorsanız Rigidbody’nin MovePosition’ını kullanmayı deneyebilirsiniz.

      • Levent dedi ki:

        Yasir bey
        Hareket için GetAxis kullanıyorum .Benim istediğim iki karakterde birbirine temas ettiğinde hareket etmemeli .Misal bir duvara yada engele karakter dokunduğu zaman onu nasıl geçemiyorsa oyuncunun başka bir tarafa yönlendirmesiyle gidiyorsa bende o şekilde yapmaya çalışıyorum .
        Teşekkurler.

      • yasirkula dedi ki:

        Eğer MovePosition işe yaramadıysa maalesef bir fikrim yok :/

  21. Levent dedi ki:

    Yasir bey
    Yaptığım bir oyunda (Samsung app ta yayınladım askıya alındı .) canvasta olan joystyic, buttonlar , karakterin yaşam çizgisi farklı boyutlardaki telefon veya tabletlerde şeklinin bozulduğu veya kaybolup görünmediği ile bilgili bildirim aldım . Her boyutta ve çözünürlükte cihaza uygun olarak nasıl yapabilirim .
    Yardım ricası ile kolay gelsin .

  22. oğuz dedi ki:

    Merhaba Yasir hocam ufak bir sorum olacaktı.

    Oyun menüsünde butona basılınca coroutine ile ekranda 1.texti gösteriyorum ve belli bir saniye sonra text objesini destroy ediyorum. Oyuncu aynı butona tekrar basınca 2.text objesini göstermek istiyorum ama burada sıkıntı oluyor.

    Nasıl yapabilirim acaba ? Coroutine’nin içine ikinci bir if bloğu ekleyerek yapmaya çalıştım ama her seferinde direkt 2.text’i ekrana yazdırdı.

    Yardımlarını bekliyorum kolay gelsin hocam.

    • yasirkula dedi ki:

      Bir “bool text1Gozuktu = false;” değişkeniniz olsun. Bunun değeri false ise ilk text’i gösterin ve değişkeni true yapın, değeri true ise de ikinci text’i gösterin.

  23. Levent dedi ki:

    Yasir bey iyi akşamlar ben yuzey objesine collider vermek istiyorum yuzey çok girintili çıkıntılı olduğu için mesh collider vereceğim convex yapıp yüzeyde olan objelerin düşmemesini sağlamak istiyorum fakat mesh girinti ve çıkıntılara uymuyor kare şeklinde çıkıyor convex i kapatınca tam yuzeye colider oturuyor bu seferde objeler üstünden düşüyor. Yardım ricası ile kolay gelsin .

    • Levent dedi ki:

      Yasir bey bir türlü yapamadım .Onun yerini tek tek collider verdim .Uzun sürdü ama oluyor .

    • yasirkula dedi ki:

      Unity’nin dokümantasyonunda yazdığına göre, yüzeyde Rigidbody component’i olmazsa Mesh Collider’daki Convex’in işaretini kaldırabilirmişsiniz ve sistem düzgün çalışırmış. Ama kendim test etmedim. Bu işe yaramazsa da ya bir plugin kullanmalı (“unity concave collider” şeklinde arama yapabilir) ya da tek tek collider vermeye devam etmelisiniz.

  24. Uğur dedi ki:

    Öncelikle bu site için teşekkürler. Ben bilgisayara karşı bir satranç oyunu yapsam, ben bir taş oynayınca bilgisayarda bir taş oynayacak, bu sistemde sıra bana gelene kadar ben bekleyeceğim, sıra bana gelince bilgisayar bekleyecek. Burada bir fonksiyonun işlemi bittikten sonra başka bir fonksiyonun bitmesini beklemesini nasıl sağlayabilirim.

    • yasirkula dedi ki:

      Bir coroutine’de while(birDegisken==true) yield return null; kodu yazarak birDegisken’in değeri false olana kadar o coroutine’i bekletebilirsiniz.

    • Erhan AYGÖREN dedi ki:

      Coroutine fonksiyonu ile halledebilirsin sanırım. Aynı sorunu ben yield return new WaitUntil( () => (değerlendirilecek ifade)) komutu ile çözmüştüm.

  25. Erhan AYGÖREN dedi ki:

    Merhaba Yasir Bey,

    Ben Unity ile basit oyunlar geliştiriyorum. Geliştirmekte olduğum bir uygulama da girilen konutları stackleyip, başlama butonu ile stackdeki komutları teker teker gerçekleştirmek istiyorum. Girilen komutları diziye atıp döngüler ile işliyorum. Komutlar, ileri gitme, sağa ve sola dönme ve geri gitmeden oluşuyor. Sorunum şu; hareket etme işlemini anında gerçekleştiriyor bense her bir adımı 1 saniye gibi bir zamanda gerçekleştirmesini istiyorum uygulamanın daha anlaşılır olması için. Hareket etme işlemini Canvas’a yerleştirdiğim 4×4 lük panellerin position bilgisi ile gerçekleştiriyorum. Sorunumu Coroutine ile çözebilir miyim? Şimdiden teşekkürler saygılarımla iyi çalışmalar.

    Uygulamanın görüntüsü; https://i.hizliresim.com/JZMEjY.jpg

    • yasirkula dedi ki:

      Evet coroutine işinizi görür. Her bir komut arasında bir yield return new WaitForSeconds(1.0f); çalıştırarak 1 saniye bekleyebilirsiniz.

  26. julinan dedi ki:

    –Konuyla alakasız–
    Merhaba ben bir shooter oyunu yapıyorum.Elimde bir spawner var bunun sayesinde bir çok düşman oluşturabiliyorum yaptığım kodlarda eğer düşmanla aramadaki mesafe 1.5 den küçükse benim canımın azalması şeklinde ayarlı ama bu işlem sadece bir düşman için geçerli çevremdeki her düşmanla aramdaki mesafeyi ölçmesini nasıl sağlarım ?

    • yasirkula dedi ki:

      Component’i player’a vermek yerine düşman prefab’ına verebilirsiniz, böylece her düşman kendi mesafesini kendi ölçer. Daha iyisi ise, tüm düşmanları bir List veya array’de tutabilir ve bu listenin içindeki tüm düşmanların player’a mesafesini tek tek ölçebilirsiniz.

      • julinan3 dedi ki:

        Component’i düşman prefab’ına vermeyide denedim çalıştı hepsi izliyor,vuruyor falan ama can barım sıkıntı oluyo bazıları scriptte canımı götürüyo gözüküyor ama bar azalmıyor bazen script sadece son oluşan klonda is görüyor.

      • yasirkula dedi ki:

        Can barı script’iniz nasıl ve ne zaman güncelleniyor bilmediğimden bu konuda pek yardımcı olamayacağım. Player’a hasar verdikçe can barını da güncellemeniz lazım normalde.

  27. Sami dedi ki:

    –Konuyla Alakası Yok–
    Ben Unity de Monodevelop Kullanıyorum Yeni Bir Kod Yazdıkdan Sonra Monodevelop da f5 e Basmadan yada Debug Yapmadan Unity Yeni Yazdığım Kodu Görmüyor Bunu Nasıl Çözebilirim

  28. Levent dedi ki:

    Yasir bey klonlama yaparken (Instantite) for döngüsü kullanarak (int i=0;i<2;i++)start ta yazınca sadece 2 adet kolonluyor azalınca artırmıyor update ye yazınca sınırsız olarak arttırıyor .klonlanan nesne ikiden az olunca tekrardan sadece iki taneyi instante edemedim . Nasıl yapabilirim . Yardım ricasıyla kolay gelsin .

    • yasirkula dedi ki:

      Kodu Start’ta bırakın ve objeye verdiğiniz script’in OnDestroy fonksiyonunda yeni bir obje Instantiate edin. Böylece bir obje yok olunca yeni bir obje oluşacak. Daha da iyisi, yeni bir obje Instantiate etmek yerine var olan objenin yerini değiştirmek suretiyle o objeyi tekrar kullanın; ama bu işlemi OnDestroy’da değil, objeyi nerede Destroy ediyorsanız orada yapmanız lazım.

  29. Emirhan Koçoğlu dedi ki:

    Size bişey sormak istiyorum. Coroutinelerle alakası yok farkındayım.Ben bir bool tanımladım ve eğer bu bool açıksa bir gameobject tanımlamasını istiyorum yani şöyle

    public bool asd
    if(asd){
    public GameObject dsa
    }

    Ama bu kodu
    ****——-if(asd){
    public GameObject dsa
    }———-****
    Setup Veya Updatenşn içine yazdığımda sıkıntı veriyor çözümü varmı
    Bu arada bir strateji oyunu yapmak istiyorum
    Şimdiden teşekkürler.

  30. Levent dedi ki:

    Destroy ettiğim enemy objesi silinince ses kayboluyor .destroyu bu sistemde geciktiremedim . Nasıl yapmalıyım : patSesi.PlayOneShot (PatlamaSesi, 0.1f);

  31. Batuhan Mafratoglu dedi ki:

    Abi ben playerprefs A sahnesinde altin degerini alip B sahnesindeki magza yerini yazdirmak istiyorum bunu nasil yapabilirim bi turlu yapamadim

    • Batuhan Mafratoğlu dedi ki:

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      using UnityEngine.SceneManagement;
      using UnityEngine.UI;
      using System;

      public class Menu : MonoBehaviour {

      public GameObject menucanvas;
      public GameObject settingcanvas;
      public GameObject shopcanvas;
      public GameObject infocanvas;
      public GameObject backbtn;
      public Toggle mutetog;
      public Toggle shoptog;
      public Text infotext;
      int newaltin;
      public static int totalaltin;
      public Text toplamaltintext;
      public Text bincoinstext;

      void Start ()
      {
      newaltin = PlayerPrefs.GetInt(“Altin”);
      totalaltin = Rabbit.altindeger;
      newaltin = Convert.ToInt32(toplamaltintext);

      }

      void Update ()
      {
      totalaltin += newaltin;
      PlayerPrefs.SetInt(“Altin”, totalaltin);
      toplamaltintext.text = totalaltin.ToString();

      }

      public void Playbutton()
      {
      menucanvas.SetActive(false);
      settingcanvas.SetActive(false);
      SceneManager.LoadScene(1);
      }

      public void Settingsbutton()
      {
      menucanvas.SetActive(false);
      settingcanvas.SetActive(true);
      }

      public void Shopbutton()
      {
      menucanvas.SetActive(false);
      shopcanvas.SetActive(true);

      }

      public void Backbutton()
      {
      if (mutetog.isActiveAndEnabled==true)
      {
      menucanvas.SetActive(true);
      settingcanvas.SetActive(false);
      }
      else if (shoptog.isActiveAndEnabled == true)
      {
      menucanvas.SetActive(true);
      shopcanvas.SetActive(false);
      }
      else if (infotext.isActiveAndEnabled == true)
      {
      infotext.gameObject.SetActive(false);
      settingcanvas.SetActive(true);
      backbtn.SetActive(false);
      }

      }

      public void Infobutton()
      {
      settingcanvas.SetActive(false);
      infocanvas.SetActive(true);
      infotext.gameObject.SetActive(true);
      backbtn.SetActive(true);
      }

      public void Exitbutton()
      {
      Application.Quit();
      }

      public void Bincoins()
      {
      if(Rabbit.altinvalue == 2000)
      {
      Debug.Log(“Satın alındı”);
      Rabbit.altinvalue -= 2000;
      }
      else
      {
      Debug.Log(“Para Yeterli Değil”);
      }

      }

      private void OnApplicationQuit()
      {
      PlayerPrefs.SetInt(“Altin”, totalaltin);
      }
      }

      • yasirkula dedi ki:

        A sahnesinde altının değerini kaydetmek için PlayerPrefs.SetInt(“Altin”, altın miktarı) fonksiyonunu kullanıp B sahnesinde bu değere PlayerPrefs.GetInt(“Altin”) şeklinde erişebilirsiniz. Attığınız kod static değişkenlerle vs. karmaşık geldi ben onu tam çözemedim.

  32. Dilaver dedi ki:

    Harika bir ders herkesin işine yaricaktir teşekkürler hocam

Mustafa için bir cevap yazın Cevabı iptal et

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