UNITY – OnMouseDown Fonksiyonunu Android’e Uyarlamak

Yayınlandı: 28 Temmuz 2013 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde
Etiketler:, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

GÜNCELLEME (18.06.2017): Yazı Unity’nin son versiyonuna uygun olarak güncellendi ve kodlar C#’a çevrildi.

Tekrar merhaba,

Bu derste Android için yaptığınız Unity oyunlarında bir objeye parmak ile dokunulup dokunulmadığını test etmenin yöntemini göstereceğim, yani bir başka deyişle PC’deki OnMouseDown fonksiyonunu Android’de nasıl multi-touch bir şekilde çalıştıracağınızı göstereceğim. Eğer oyununuz multi-touch gerektirmiyorsa o zaman bu derse ihtiyacınız yok; scriptlerinizde direkt OnMouseDown kullanabilirsiniz. Bu fonksiyon Unity tarafından otomatik olarak çağrılır ancak maalesef multi-touch desteklemez.

Dersin ilham kaynağı için tıklayın: http://wiki.unity3d.com/index.php?title=OnMouseDown

Bu işlemi yapmak için Raycast kullanacağız. Yani kameranın merkezinden başlayan ve ekranda tıkladığımız koordinat yönünde olan sonsuz uzunlukta bir ışın yollayacağız ve eğer bu ışın bir obje ile temas ederse anlayacağız ki parmağımızla dokunduğumuz objeyi bulduk. Ardından (eğer varsa) o objedeki MouseDown fonksiyonunu çağıracağız. Dikkat edin: MouseDown fonksiyonunu çağırıyoruz, OnMouseDown fonksiyonunu değil! Aksi taktirde dokunduğumuz bir objedeki OnMouseDown fonksiyonu hem bizim tarafımızdan hem de Unity tarafından çağrılabileceğinden fonksiyonu istemeden iki kere çalıştırabiliriz.

OnMouseDownMultitouch isminde yeni bir C# scripti oluşturup scripti Main Camera‘ya atın ve içeriğini şöyle düzenleyin (bu script hem PC’de hem de mobil cihazlarda çalışır, tek yapmanız gereken scriptlerinizdeki OnMouseDown fonksiyonlarını MouseDown’a çevirmek):

using UnityEngine;

public class OnMouseDownMultitouch : MonoBehaviour 
{
	void Update()
	{
		Camera camera = Camera.main;
		RaycastHit hit;
		
		if( camera == null )
			return;
		
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL
		// PC için kod (mouse)
		
		if( Input.GetMouseButtonDown( 0 ) )
		{
			if( Physics.Raycast( camera.ScreenPointToRay( Input.mousePosition ), out hit ) )
				hit.transform.gameObject.SendMessage( "MouseDown", SendMessageOptions.DontRequireReceiver );
		}
#else
		// Mobil cihazlar için kod (multi-touch)
	
		// Ekranda basılı olan tüm parmaklara bak
		for( int i = 0; i < Input.touchCount; i++ )
		{
			Touch parmak = Input.GetTouch( i );
			if( parmak.phase == TouchPhase.Began )
			{
				// Eğer bir parmak ekrana daha yeni basılmışsa o noktada bir Raycasting yaparak herhangi bir objeye tıklanıp tıklanmadığına bak
				if( Physics.Raycast( camera.ScreenPointToRay( parmak.position ), out hit ) )
					hit.transform.gameObject.SendMessage( "MouseDown", SendMessageOptions.DontRequireReceiver );
			}
		}
#endif
	}
}

Kodumuzu biraz daha geliştirerek OnMouseDrag ve OnMouseUp fonksiyonlarına da destek verebiliriz (yalnız yukarıda belirttiğim sebepten ötürü bizim durumumuzda MouseDrag ve MouseUp fonksiyonları çağrılacak):

using UnityEngine;
using System.Collections.Generic;

public class OnMouseDownMultitouch : MonoBehaviour 
{
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL
	private GameObject dokunulanObje = null;
#else
	private Dictionary<int, GameObject> dokunulanObjeler = new Dictionary<int, GameObject>();
#endif

	void Update()
	{
		Camera camera = Camera.main;
		RaycastHit hit;
		
		if( camera == null )
			return;

#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBGL
		// PC için kod (mouse)

		if( Input.GetMouseButtonDown( 0 ) )
		{
			if( Physics.Raycast( camera.ScreenPointToRay( Input.mousePosition ), out hit ) )
			{
				dokunulanObje = hit.transform.gameObject;
				dokunulanObje.SendMessage( "MouseDown", SendMessageOptions.DontRequireReceiver );
			}
		}
		else if( Input.GetMouseButton( 0 ) )
		{
			if( dokunulanObje != null && !dokunulanObje.Equals( null ) )
				dokunulanObje.SendMessage( "MouseDrag", SendMessageOptions.DontRequireReceiver );
		}
		else if( Input.GetMouseButtonUp( 0 ) )
		{
			if( dokunulanObje != null && !dokunulanObje.Equals( null ) )
				dokunulanObje.SendMessage( "MouseUp", SendMessageOptions.DontRequireReceiver );
		}
#else
		// Mobil cihazlar için kod (multi-touch)
	
		// Ekranda basılı olan tüm parmaklara bak
		for( int i = 0; i < Input.touchCount; i++ )
		{
			Touch parmak = Input.GetTouch( i );
			if( parmak.phase == TouchPhase.Began )
			{
				// Eğer bir parmak ekrana daha yeni basılmışsa o noktada bir Raycasting yaparak herhangi bir objeye tıklanıp tıklanmadığına bak
				if( Physics.Raycast( camera.ScreenPointToRay( parmak.position ), out hit ) )
				{
					GameObject obje = hit.transform.gameObject;
					dokunulanObjeler[parmak.fingerId] = obje;
					obje.SendMessage( "MouseDown", SendMessageOptions.DontRequireReceiver );
				}
			}
			else if( parmak.phase == TouchPhase.Ended || parmak.phase == TouchPhase.Canceled )
			{
				// Eğer bir parmak ekrandan çekilirse ve bu parmak ekrana ilk dokunduğunda bir objeye tıklamışsa o obje için MouseUp fonksiyonunu çağır
				GameObject obje;
				if( dokunulanObjeler.TryGetValue( parmak.fingerId, out obje ) )
				{
					// Parmağın dokunulduğu obje yok edilmemişse
					if( obje != null && !obje.Equals( null ) )
						obje.SendMessage( "MouseUp", SendMessageOptions.DontRequireReceiver );
				}
			}
			else
			{
				// Eğer bir parmak ekranda basılı durumdaysa ve bu parmak ekrana ilk dokunduğunda bir objeye tıklamışsa o objenin MouseDrag fonksiyonunu çağır
				GameObject obje;
				if( dokunulanObjeler.TryGetValue( parmak.fingerId, out obje ) )
				{
					// Parmağın dokunulduğu obje yok edilmemişse
					if( obje != null && !obje.Equals( null ) )
						obje.SendMessage( "MouseDrag", SendMessageOptions.DontRequireReceiver );
				}
			}
		}
#endif
	}
}

İşte bu kadar!

yorum
  1. murat dedi ki:

    Emeginiz icin tesekkurler bu sayede test ederken derleyip android e atma ihtiyacimiz da kalmiyor sanirim

    • yasirkula dedi ki:

      Demek istediğinizi tam anlamadım. Oyunu test ederken yine Build edip Android’e atmanız en iyisi. Burada anlattığım şeyle bağlantısı yok yani.

      • murat dedi ki:

        Demek istedigim her ufak degisiklik icin tekrar androoite atmaya gerek yok android te debug islemini bilemedigim icin unity icinden debug etmek daha kolay on mouse down calisacagi icin debug edebilirim ayrica android build islemi 15-20 saniye suruyor bundan kurtuluruz diye dusunmustum yeni oldugum icin bilmedigim bir baska yontem varsa o baska tabi

  2. murat dedi ki:

    Yasin bey verdiğiniz bilgiler için teşekkürler en sonunda istediğimi yapabildim. Yukarıdaki koda ek olarak yeni bir script oluşturup onuda sürüklemek istediğim objelere atadıktan sonra sorunum çözüldü kodu altta paylaştım. Tekrar teşekkürler

    using UnityEngine;
    using System.Collections;

    public class Surukle : MonoBehaviour
    {

    private Vector3 screenPoint;
    private Vector3 offset;

    void OnMouseDown ()
    {
    screenPoint = Camera.main.WorldToScreenPoint (gameObject.transform.position);

    offset = gameObject.transform.position – Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));

    }

    void OnMouseDrag ()
    {
    Vector3 curScreenPoint = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);

    Vector3 curPosition = Camera.main.ScreenToWorldPoint (curScreenPoint) + offset;
    transform.position = curPosition;
    }

    }

  3. hakanyıldızhan dedi ki:

    selam konuyla alakalı diil belki ama. dokunmatik ekranda bir bölgeyi yada bir guiTexture ye dokunulduğunda klavyede belirlenmiş birtuşa basılmış gibi davranacak bir script yazmak mümkünmü? bunu daha önceden pc yada web için yapılan oyunların port işleminde kolaylık olucağını düşünüyorum yardımcı olusanız sevinirim.

  4. murat dedi ki:

    Adamın dibisin

    • yasirkula dedi ki:

      Konuyu yorumun hemen ardından güncelledim (daha önceden yapacaktım ama unutmuştum). Şimdi OnMouseUp ve OnMouseDrag daha düzgün çalışıyor.

  5. Emre dedi ki:

    Bir şey sormak istiyorum. Ben bir oyun yaptım ve oyuna fps controller kapsülü ekledim. Bu oyunu android telefonuma attım ama telefonumda fps controlleri hareket ettiremiyorum. Acaba bunun için herhangi bir kod var mıdır?

  6. umut dedi ki:

    hocam burada OnMouseDown dedikya OnmouseDown fonksiyonunumu çağırıyoruz orayı anlamadım yani bi fuction OnMaouseDown fonksiyonu var biz raycast kullanarak o fonksiyonumu çağırdık

    for( var i = 0; i < Input.touchCount; i++ )
    {
    if( Input.touches[i].phase == TouchPhase.Began )
    {
    // Eğer bir parmak ekrana daha yeni basılmışsa o noktada bir Raycasting yaparak herhangi bir objeye tıklanıp tıklanmadığına bak
    if( Physics.Raycast( camera.ScreenPointToRay( Input.touches[i].position ), hit ) )
    hit.transform.gameObject.SendMessage( "OnMouseDown" );
    }
    }

    • yasirkula dedi ki:

      Evet öyle yaptık çünkü Android’de mouse olmadığı için OnMouseDown da normal şartlarda çalıştırılmaz(dı) Unity tarafından. Ama artık OnMouseDown fonksiyonu Android’de de otomatik olarak çalışıyor, bu koda gerek yok yani.

  7. umut dedi ki:

    hocam OnMouseDown çalışıyor 😀 ama parmakla üstüne basdıktan 2-3 saniye sonra çalışıyor normaldede böylemidir ?

    • yasirkula dedi ki:

      Hayır normalde anında çalışması lazım. Bende hiç öyle bir sorun olmamıştı, şimdi kesin birşey söyleyemeyeceğim. Belki yanlışlıkla OnMouseUp ya da OnMouseDrag fonksiyonlarını kullanıyor olabilir misiniz OnMouseDown niyetine? Öyle bir durum yoksa peki oyununuz telefonunuzda kasıyor mu?

  8. umut dedi ki:

    evet normalde her 45 birimde background zemin tavan ve engel oluşturuyor ve bunları oluşturduğu an 1 -2 saniyelik bir kasma oluşuyor

    • yasirkula dedi ki:

      Tam o kasma anında tıklıyorsanız OnMouseDown’ın kasması normal gibi ama oyun akıcıyken bastığınız halde OnMouseDown çalışmıyorsa sorun var. Unity’nin son sürümlerinde OnMouseDown’ı Android’de de otomatik olarak desteklediklerini düşünüyorum; ben öyle bir deneyim yaşamıştım. Eğer buradaki kodu kullanıyorsanız OnMouseDown()’ı çağırmak için kodu hiç kullanmayın ve öyle deneyin oyunu çalıştırmayı.

  9. umut dedi ki:

    hocam sorunu buldum be yazının üstüne OnMOuseDown fonksiyonu kullanmıştım yazı 3 boyutlu ortamda masanın arkasında kalıyormuş masaya tıklıyorum yani onu öne aldım herşey düzeldi 😀 ama dediğim gibi 45 birimde bir kameranın sağ tarafına platform oluşturuyorum o anda kasıyor ne yapabilirim sizce ?

    • yasirkula dedi ki:

      Demek ki kullandığın algoritma kullanışsız. Daha pratik bir kod üretmen lazım, başka yolu yok.

      • umut dedi ki:

        Gereksiz yere fazladan clone oluşturmuyor o sorunu çözmüştüm ama bence sorun oyun ilerledikçe oluşan nesnelerin çokluğu. geçtiğim platform u silsem düzelebilir diye düşünüyorum ?

        for( var g : GameObject in GameObject.FindGameObjectsWithTag( “Engel” ) )
        {
        Destroy( g );
        }

        bu kodla tüm engel tagına sahip nesneleri silebiliyordum peki ben geçtiğim engelleri silmek istesem nasıl bir şey yapabilirim geçtiğim ve geçmediğim tüm engellerin ismi enemy(clone) diye oluşuyor bunları nasıl ayırt edebilirim ?

      • yasirkula dedi ki:

        Eğer karakter x koordinatında sağa doğru hareket ediyorsa şuna benzer kod yazabilirsin:

        for( var g : GameObject in GameObject.FindGameObjectsWithTag( “Engel” ) )
        {
        if( g.transform.position.x < transform.position.x )
        Destroy( g );
        }

        Bu kod objenin solundaki engelleri siler.

        Bir başka yol ise oluşturulan objeleri bir Queue'nin içinde tutmaktır. Queue veri yapısını internetten araştırabilirsin. Unity'de hiç Queue kullanmadığımdan nasıl kullanılacağını bilmiyorum.

  10. umut dedi ki:

    birde atıyorum 5 platform yaptım bunların içinden rasgele birini seçip bunu prefab a atmak istiyorum rastgele bir seçim için rand fonksiyonu var ama bu C için unity için böyle bir şey bulamadım siz biliyormusunuz

  11. umut dedi ki:

    for( var g : GameObject in GameObject.FindGameObjectsWithTag( “Engel” ) )
    {
    if( g.transform.position.x < transform.position.x )
    Destroy( g );
    }

    kodu denedim ama çalışmıyor bende bundan ilham alarak şöyle bir kod yazdım

    reel1 = GameObject.Find("enemy1");
    if(reel1.transform.position.x<transform.position.x){
    Destroy(reel1);
    }

    bunuda function Update() in içine attım ilk başta 2 engeli doğru bir şekilde siliyor ama sonrasında kameranın sağındakileride siliyor çözemedim tam sizce sorun nerede ?

  12. yasirkula dedi ki:

    reel1 = GameObject.Find(“enemy1”); komutunu görünce Unity bulduğu ilk “enemy1” isimli objeyi döndürür. Bu obje kameranın solunda da olabilir sağında da.

    Madem “g.transform.position.x < transform.position.x" çalışmıyor o zaman "g.transform.position.z transform.position.x” gibi başka kombinasyonlar deneyin.

  13. mehmeterozkan dedi ki:

    Kolay gelsin. Bir oyun yapıyorum da skor kaydedıyorum ama uygulamayı telefonda kapatıp actıgım da yuksekskor degerı ,skor degeri ne olursa olursa onu alıp yuksekskora kaydedıyor. kodları atacam hocam bir de oncollisionenter fonksıyonum var ve bir kup ve bir kurem var kure sonsuz tane oluşturuyorum ve kupe deydıgı an oyun sonlansın ıstıyorum fakat bazen dokunmadan oyun sonlanıyor kodlar atıyorum hocam yardımlarınızı beklıyorum.

    ol.js

    function OnCollisionEnter2D (colli : Collision2D){

    if (skor.yuksekskor < skor.score){
    skor.yuksekskor=skor.score;
    PlayerPrefs.SetInt("yuksekscore",skor.yuksekskor);
    PlayerPrefs.Save();

    skor.score=0;
    }
    else {
    skor.score=0;
    Application.LoadLevel("bitti");
    }
    }

    • yasirkula dedi ki:

      Yüksekskor kayıt kodunda sıkıntı yok. Küp belki bazen küreye değil de başka bir objeye çarpıyordur ve oyun o yüzden bitiyordur. Ya da küreler gerçek-zamanlı oluşturuluyorsa belki bir küre tam küpün üzerinde oluşturuluyordur.

  14. Burak dedi ki:

    Merhaba. paylaşım için teşekkürler. Benim bir sorum olacaktı bu kodlar çoklu tıklamaya izin veriyormu. Örneğin ben ekrana 2 buton koydum ve birine elim basılıyken ateş ederken aynı anda öbürüne basınca sola veya sağa hareket etmesini istiyorum.

    • yasirkula dedi ki:

      Bu kod OnMouseDown’ı birden çok obje için destekler ama OnMouseDrag ve OnMouseUp’ı sadece tek obje için destekler. Ekrandaki bir GUITexture’a dokunulup dokunulmadığını anlamak için şu kodu kullanabilirsiniz: if( guiTexture.HitTest( Input.touches[i].position ) )

  15. gökhan dedi ki:

    oyunumda her şey sol mouse tuşuyla çalışıyor bu kodla androidde çalışır mı

  16. halis dedi ki:

    merhaba hocam dokunmatik ekranda oyundan geri çıkmak için nasıl bir kod kullanabilirim yardımcı olabilirmisiniz ben baktımda yaptıklarım işe yaramadı şimdiden teşekürler.

  17. halis dedi ki:

    Allah razı olsun hocam bir sorum daha olacak unity de yaptığım bir oyunu farklı boyuttaki ekranlar için nasıl ayarlayabilirim.tablette yada telefonlarda butonların kaymaması için.buton koydum ekrana game ekranından portrait ve 480×800 boyutunu seçip apk sını aldım ama telefonda çalıştırdığımda butonların yerleri hepten kaymıştı farklı yerlerde duruyorlar nasıl halledebilirim.

  18. megmud dedi ki:

    hocam mousedown’lar androidde çalışıyor ama acaba düşük sürümlerindemi çalışmıyor

  19. Samir dedi ki:

    Hocam benim yaptigim oyunda ilk dokunusda top saga ikinci dokunusta sola gitmesi lazim ancak bunu yapamadim boyle bisey munkunmu munkunse hangi kodla?

    • yasirkula dedi ki:

      Bir boolean ile olur. Boolean true ise top sağa gider ve boolean’ın değeri false yapılır. Boolean false ise top sola gider ve boolean’ın değeri true yapılır.

  20. savas dedi ki:

    OnMouseDown direkt olarak çalışıyor Android’de. Ancak parmağı kaldırdığımda olacak şeyleri belirleyemiyorum. Bir butonum var. Buna basınca silahımın ucundan ateş eder gibi partikül efekt çıkıyor. Ama parmağımı çekince de partikül efekt devam ediyor. Ben butona basmadığımda değerin false a dönmesini istiyorum. Ama bir türlü bulamadım nasıl yapacağımı

  21. bahadır dedi ki:

    Hocam saygılar . Android oyunumda ekranda ateş eden bir top var.4 farklı buton yardımı ile top saga sola aşağı yukarı hareket ediyor.Butona basılı tuttuğumda hareket edip çektiğimde durmasını istiyorum.Ne yaptıysam olmadı Update içine yazıyorum,ya ben daha basmadan hareket ediyor yada kare kare hareket ediyor sürekli basmak gerekiyor yani.Nasıl bir yöntem kullanabilirim acaba C# kullanıyorum.

  22. umut dedi ki:

    2D oyundada çalışır mı bu işlem

    • yasirkula dedi ki:

      Artık Android kendiliğinden OnMouseDown destekliyor ancak multi-touch bir şekilde değil. Multi-touch istiyorsanız OnMouseDown fonksiyonlarınızın ismini MouseDown gibi başka bir şeye değiştirmeli ve yazdığım kodda da OnMouseDown’ları MouseDown’a çevirmelisiniz.

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