1. 程式人生 > >Unity中的Input.Touch,移動端的觸控操作

Unity中的Input.Touch,移動端的觸控操作

這篇博文將簡單的記錄,如何用unity處理在移動裝置上的觸控操作。
iOS和Android裝置能夠支援多點觸控。在unity中你可以通過Input.touches屬性集合訪問在最近一幀中觸控在螢幕上的每一根手指的狀態資料。簡單的觸控響應實現起很簡單,不過一些複雜的觸控響應或觸控手勢什麼的,還是使用一些第三方的外掛吧,當然你也可以自己封裝。不管什麼情況,瞭解決unity原生api還是非常必要的。    

相關的api
    1、Toch類:用來記錄一個手指觸控在螢幕上的狀態與位置的各種相關資料。這其它中只有兩個屬性是你要注意的,就是Touch.fingerId和Touch.tapCount。
               

Touch.fingerId: 一個Touch的標識。Input.touches陣列中的同一個索引在兩幀之前,指向的可不一定是同一個Touch。用來標識某個具體的touch一定要用fingerId,在分析手勢時、或處理多點觸控時,fingerId是非常重要的。
               Touch.tapCount: 點選的總人數,這個屬性可以用來模擬“雙擊”的效果。
               這裡先普及一個概念吧,一個touch的生命週期是:當一個手指接觸到觸屏時,產生一個Touch,並分配它一個fingerId,到這個手指離開觸屏這個touch就有了。在它整個生命週期裡,它的figerId是不會變的。死掉的touch所使用過fingerId當也會被之後的touch多次使用。ps:其實也不是手指一離開,這個touch就立馬死掉。還有一種特殊的情況就是:在手指敲開的地方,在一個很短的時間內,一個手指又回到這個地方的話,這個touch沒不會死掉,這個也是Touch.tapCount屬於的由來吧。這個touch生命週期,是我自己理解的,實際情況是不是這樣就不知道了,料想也不會差的太多。

    2、TouchPhase列舉:它列表描述了手指觸控的幾種狀態。對應Touch類中的phase屬性。這是狀態分別是:Began、Move、Stationary、Ended、Canceled。
3、Input.touches:一個Touch陣列,代表當前幀,所有手指在螢幕上的觸碰狀態與相關資料。(只讀)
4、Input.touchCount: 觸控數量,相當於Input.touches.Length。(只讀)
5、Input.multiTouchEnabled:設定與指示當前系統(注意不是指裝置哦!)是否啟用多點觸控。不過這個屬性有點怪,我在電腦上測試給它賦false不會報錯但完全是沒有用的,它的值一值是true. 不過在我的安卓手機上測試是正常的!Ture表示支援多點觸控(一般是5點);False表示單點觸控。
    6、
Input.GetTouch(int index)
:安索引值獲取一個Touch物件。

下面一個測試Demo
1、簡述:
         這個Demo主要是讓你的觸控視覺化的顯示在你的手機(或平板)螢幕上;
         並實時記錄和顯示了手指在螢幕上的狀態和相關資料。

2、相關截圖:

3、指令碼就一個

/*
 * author: AnYuanLzh
 * date:   2014/01/18
 * */
using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class MyTouch : MonoBehaviour
{
	/// <summary>
	/// 定義的一個手指類
	/// </summary>
	class MyFinger
	{
		public int id = -1;
		public Touch touch;

		static private List<MyFinger> fingers = new List<MyFinger>();
		/// <summary>
		/// 手指容器
		/// </summary>
		static public List<MyFinger> Fingers
		{
			get
			{
				if(fingers.Count==0)
				{
					for(int i=0; i<5; i++)
					{
						MyFinger mf = new MyFinger();
						mf.id = -1;
						fingers.Add(mf);
					}
				}
				return fingers;
			}
		}

	}

	// 小圈圈:用來實時顯示手指觸控的位置
	GameObject[] marks = new GameObject[5];
	public GameObject markPerfab = null;

	// 粒子效果:來所顯示手指手動的大概路徑
	ParticleSystem[] particles = new ParticleSystem[5];
	public ParticleSystem particlePerfab = null;


	// Use this for initialization
	void Start ()
	{
		// init marks and particles
		for(int i=0; i<MyFinger.Fingers.Count; i++)
		{
			GameObject mark = Instantiate(markPerfab, Vector3.zero, Quaternion.identity) as GameObject;
			mark.transform.parent = this.transform;
			mark.SetActive(false);
			marks[i] = mark;

			ParticleSystem particle = Instantiate(particlePerfab, Vector3.zero, Quaternion.identity) as ParticleSystem;
			particle.transform.parent = this.transform;
			particle.Pause();
			particles[i] = particle;
		}
	}
	
	// Update is called once per frame
	void Update ()
	{
		Touch[] touches = Input.touches;

		// 遍歷所有的已經記錄的手指
		// --掦除已經不存在的手指
		foreach(MyFinger mf in MyFinger.Fingers)
		{
			if(mf.id == -1)
			{
				continue;
			}
			bool stillExit = false;
			foreach(Touch t in touches)
			{
				if(mf.id == t.fingerId)
				{
					stillExit = true;
					break;
				}
			}
			// 掦除
			if(stillExit == false)
			{
				mf.id = -1;
			}
		}
		// 遍歷當前的touches
		// --並檢查它們在是否已經記錄在AllFinger中
		// --是的話更新對應手指的狀態,不是的放放加進去
		foreach(Touch t in touches)
		{
			bool stillExit = false;
			// 存在--更新對應的手指
			foreach(MyFinger mf in MyFinger.Fingers)
			{
				if(t.fingerId == mf.id)
				{
					stillExit = true;
					mf.touch = t;
					break;
				}
			}
			// 不存在--新增新記錄
			if(!stillExit)
			{
				foreach(MyFinger mf in MyFinger.Fingers)
				{
					if(mf.id == -1)
					{
						mf.id = t.fingerId;
						mf.touch = t;
						break;
					}
				}
			}
		}

		// 記錄完手指資訊後,就是響應相應和狀態記錄了
		for(int i=0; i< MyFinger.Fingers.Count; i++)
		{
			MyFinger mf = MyFinger.Fingers[i];
			if(mf.id != -1)
			{
				if(mf.touch.phase == TouchPhase.Began)
				{
					marks[i].SetActive(true);
					marks[i].transform.position = GetWorldPos(mf.touch.position);

					particles[i].transform.position = GetWorldPos(mf.touch.position);
				}
				else if(mf.touch.phase == TouchPhase.Moved)
				{
					marks[i].transform.position = GetWorldPos(mf.touch.position);

					if(!particles[i].isPlaying)
					{
						particles[i].loop = true;
						particles[i].Play();
					}
					particles[i].transform.position = GetWorldPos(mf.touch.position);
				}
				else if(mf.touch.phase == TouchPhase.Ended)
				{
					marks[i].SetActive(false);
					marks[i].transform.position = GetWorldPos(mf.touch.position);

					particles[i].loop = false;
					particles[i].Play();
					particles[i].transform.position = GetWorldPos(mf.touch.position);
				}
				else if(mf.touch.phase == TouchPhase.Stationary)
				{
					if(particles[i].isPlaying)
					{
						particles[i].Pause();
					}
					particles[i].transform.position = GetWorldPos(mf.touch.position);
				}
			}
			else
			{
				;
			}
		}

		// exit
		if(Input.GetKeyDown(KeyCode.Home) || Input.GetKeyDown(KeyCode.Escape))
		{
			Application.Quit();
		}

//		// test
//		if(Input.GetMouseButtonDown(0))
//		{
//			GameObject mark = Instantiate(markPerfab, Vector3.zero, Quaternion.identity) as GameObject;
//			mark.transform.parent = this.transform;
//			mark.transform.position = GetWorldPos(Input.mousePosition);
//
//			ParticleSystem particle = Instantiate(particlePerfab, Vector3.zero, Quaternion.identity) as ParticleSystem;
//			particle.transform.parent = this.transform;
//			particle.transform.position = GetWorldPos(Input.mousePosition);
//			particle.loop = false;
//			particle.Play();
//		}
	}

	/// <summary>
	/// 顯示相關高度資料
	/// </summary>
	void OnGUI()
	{
		GUILayout.Label("支援的手指的數量:" + MyFinger.Fingers.Count);
		GUILayout.BeginHorizontal(GUILayout.Width(Screen.width));
		for(int i=0; i< MyFinger.Fingers.Count; i++)
		{
			GUILayout.BeginVertical();
			MyFinger mf = MyFinger.Fingers[i];
			GUILayout.Label("手指" + i.ToString());
			if(mf.id != -1)
			{
				GUILayout.Label("Id: " + mf.id);
				GUILayout.Label("狀態: " + mf.touch.phase.ToString());
			}
			else
			{
				GUILayout.Label("沒有發現!");
			}
			GUILayout.EndVertical();
		}
		GUILayout.EndHorizontal();
	}

	public Vector3 GetWorldPos(Vector2 screenPos)
	{
		return Camera.main.ScreenToWorldPoint(new Vector3(screenPos.x, screenPos.y, Camera.main.nearClipPlane + 10));
	}


}

4、相關下載(點下面的連結)
           專案檔案 和 釋出好的apk,下載點這裡(不需要下載積分)
   注:這個apk對Android系統的要求是Android4.0及以上版本。