本篇文章不介紹Unity、TUIO、雷達是什么以及有什么作用。剛接觸TUIO的親們,建議直接硬剛。至於剛接觸Unity的親,這邊建議親直接放棄治療呢
下面開始正兒八經的教程
需要准備的東西
- Unity(版本我用的2018.2,建議不要太新也不要太老)
- Visual Studio(用不到,但是要有。。。當然其他編輯器也可以,記事本尤佳)
- 一個雷達(當然,調試的時候也可以沒有)
- 一個插件TouchScripts
這個插件在Unity的Asset Store上是免費的,可以直接搜索下載,我就不提供了
就是這個東東,建議Store上下載最新的,從他的介紹里面可以看到他是支持tuio的
- 一個工具
這是一個TUIO的模擬工具,我們可以模擬雷達的消息,界面長這個樣子的,
這個是Java寫的,運行需要先配置java環境
開始工作
- 導入TouchScripts
我們下載下來之后全部導入
注意,這里要點Go Ahead,不要點No Thanks。人家又沒讓你捐款,你點什么No Thanks!!!
導完了之后會有一個彈出框,把我們需要的都安排一下…
接下來是瀏覽欣賞別人的demo時間…
看一下這個牛逼的插件能實現的功能以及基本的使用方法。當然,這是以后的事了,冷靜,冷靜,我們是要用來接tuio的
2. 啟用TUIO
在導入插件的彈框里,我們已經將Enable TUIO給安排上了,說明已經支持TUIO了,接下來是使用
我們直接使用它里面的一個demo來做介紹,比如說就這個
打開之后他是一個類似球球大作戰的小游戲,真好玩。。。。
接下來找到這么一個腳本
這個腳本處理tuio的輸入,需要把它添加到場景中,但是當你拖到一個gameobject中發現拖不上去,打開腳本發現他被sealed關鍵字修飾了,簡單粗暴的方法當然是直接刪掉
好了,現在可以拖了
然后,就沒有然后了,直接看效果
最后,給點小建議
1、不建議使用Drag,上面使用的模擬器當然不會有什么問題,問題是部分雷達可能會出現掉幀的情況,這就導致在拖動過程中物體隨時可能會掉。這個你無法避免,只能避免使用Drag這種交互
2、注意產生事件的時間,我們經常用OnButtonDown對應TouchScripts里面的Press事件來檢測用戶的點擊,這種對鼠標用戶當然沒有問題,問題是雷達在安裝的時候不可能像鼠標那樣映射的那么准確,以及雷達掃射面與互動面的距離、用戶點擊姿勢不規范等等問題容易導致看起來是點中了一個button,然而實際上並沒有,別人就會說你這軟件點不動,有問題啊。然而你在測試的時候一點一個准,沒問題。然后兩人就開始撕逼了。。。。
所以在此先建議盡量把觸發區域弄大一點。。。大一點。。。一點。。。點。
3、關於地面互動
地面互動的話建議就不要用事件了。因為人一走進互動區域就一直是Pressed狀態,即便踩到一個button,button的Press,Tap事件都不會被觸發,因為他的上一個狀態還沒有被釋放。而且你不能期望體驗者把腳抬高來釋放。所以死穴。我的建議是回歸原始,使用射線。具體方法是隔一定時間遍歷所以Pressed狀態的“指針”(即按下的鼠標以及雷達掃描到的物體,找不到一個合適的詞來表達,就用插件提供的“Pointer”吧,然后在指針的位置向世界發送一條射線,看碰撞物。
最后附上我之前寫地面互動的一個腳本

1 using UnityEngine; 2 using System.Collections; 3 using TouchScript; 4 using System.Collections.Generic; 5 6 /// <summary> 7 /// 這是一個土得掉渣的步步生花 8 /// </summary> 9 public class FlowerSpawner : MonoBehaviour 10 { 11 12 /// <summary> 13 /// 花的預制體 14 /// </summary> 15 public GameObject FlowerPerfab; 16 17 /// <summary> 18 /// 軟件掃描的頻率 19 /// </summary> 20 public float Rate = 30; 21 private float time; 22 /// <summary> 23 /// 用來發射射線的攝像機 24 /// </summary> 25 public Camera EventCamera; 26 public void Start() 27 { 28 time = 1f / Rate; 29 StartCoroutine(Spawner()); 30 } 31 32 private IEnumerator Spawner() 33 { 34 while (true) 35 { 36 ///時間間隔小於Time.deltaTime沒有意義 37 if(time < Time.deltaTime) 38 time = Time.deltaTime; 39 40 Check(); 41 yield return new WaitForSeconds(time); 42 } 43 } 44 45 private void Check() 46 { 47 ///遍歷所有按下狀態的指針 48 IList<TouchScript.Pointers.Pointer> PressedPointers = TouchManager.Instance.PressedPointers; 49 foreach(TouchScript.Pointers.Pointer pointer in PressedPointers) 50 { 51 ///向每個指針發送射線 52 ToRay(pointer.Position); 53 } 54 } 55 56 /// <summary> 57 /// 根據點擊屏幕的位置發送射線 58 /// </summary> 59 /// <param name="position"></param> 60 private void ToRay(Vector2 position) 61 { 62 Ray ray = EventCamera.ScreenPointToRay(position); 63 RaycastHit hit; 64 if (Physics.Raycast(ray, out hit)) 65 { 66 ///不要重復生成 67 /// 68 ///這里可以做一下比較,看一下點中(踩中)的是什么,看你的邏輯 69 //hit.collider.tag == "" 70 71 } 72 else 73 { 74 Vector3 spawnerPos = EventCamera.ScreenToWorldPoint(new Vector3(position.x, position.y, 50)); 75 GameObject go = Instantiate(FlowerPerfab);//這里為了方便演示直接實例化了,建議用池子 76 go.transform.position = spawnerPos; 77 } 78 } 79 }