目錄
- FingerGestures包結構
- FingerGestures例子列表
- 設置場景
- 教程:識別一個輕敲手勢
- 教程:手勢識別器
- 教程:輕擊手勢識別器
- 教程:拖拽手勢識別器
- 教程:滑動手勢識別器
- 教程:長按手勢識別器
- 教程:縮放手勢識別器
- 教程:旋轉手勢識別器
- 教程:自定義手勢識別器
- 教程:識別手勢事件
- 建議:使用.net代理事件
fingerGestures包結構
路徑,相對Assets/Plugin/… | 描述 |
---|
FingerGestures/ | 插件的根目錄 |
FingerGestures/Prefabs | 可以直接拖放到場景中的預設資源(prefabs) |
FingerGestures/Scripts |
核心腳本和組件 |
FingerGestures/Scripts/Gesture Recognizers | 每個手勢識別 的腳本 |
FingerGestures/Scripts/Finger Event Detectors | 每個觸摸事件檢測器的腳本 |
FingerGestures/Scripts/Components | 手勢識別和觸摸事件所需要添加的額外組件 |
FingerGestures/Toolbox | FingerGestures 自帶的工具箱腳本 |
FingerGestures/Samples.unitypackage | 所有例子的子包 |
FingerGestures/PlayMaker Actions.unitypackage | FingerGestures對PlayMaker擴展的插件 |
Editor/FingerGestures | FingerGestures對編輯器的擴展 |
FingerGestures例子列表
Finger Event(鼠標或手指事件)
FingerEventsPart1: 展示如何通過不同的檢測器( FingerEventDetectors )去檢測鼠標或者手指的上(down)、下(up),按下不移動(stationary,懸停(hover) 事件。
FingerEventsPart2: 展示如何識別不同鼠標或者手指動作(FingerMotionDetector)。
Gestures(手勢)
BasicGestures: 識別單擊(react to tap),雙擊(double tap),拖動(drag),長按(long——press),滑動(swipe)等基礎手勢。
PinchAndTwist: 兩個或多個手指同時在觸摸屏上擠壓(pinch)或扭轉(twist)時,觸發手勢的事件。(PS:通常都是用來縮放或旋轉)
PointCloudGestures: 示範如何識別一個點雲(point cloud)手勢。(PS:通常是指用用戶畫的圖案作為識別)
Toolbox(工具箱)
Camera(放入攝像機的腳本):
Toolbox-DragView: 展示使用 TBDragView
腳本,實現拖動視角。
Toolbox-Orbit: 展示使用 TBOrbit
腳本,實現圍繞目標旋轉視角。
Toolbox-Pan: 展示使用 TBPan
腳本,實現以自身為軸旋轉視角。
Toolbox-PinchZoom: 展示使用 TBPinchZoom
腳本,實現變焦。
Object-Based(放入普通場景對象的腳本):
Toolbox-Drag: 展示使用 TBDrag
腳本,實現簡單的物體拖動
Toolbox-Hover: 展示使用 TBHoverChangeMaterial
和 TBHoverChangeScale
腳本,實現當鼠標或者手指懸停在物體上時候的響應。(PS:類似鼠標放到圖標上,圖標發亮的效果)
Toolbox-PinchToScale 展示使用 TBPinchToScale
腳本,實現縮放物體
Toolbox-TwistToRotate: 展示使用 TBTwistToRotate
腳本,實現旋轉物體
設置場景
需要在場景中實例化一個FingerGesture組件才可使用。 FingerGesture在項目中的作用是管理用戶輸入和識別手勢和鼠標或手指事件。
有兩種添加方式,一是直接把Plugins\FingerGestures\Prefabs下的 FingerGestures
prefab文件拖入場景中。二是可以創建一個空物件,然後把 FingerGestures
組件添加進去。

使用 Make Persistent
標誌可以讓使FingerGestures 單例在跨場景後一直有效,所以只要保證它在第一個場景設置就足夠。
教程:識別一個輕敲手勢
該章節會學習到如何識別一個簡單的單擊動作,然後到特殊物件的單擊動作識別,最後到識別一個三個手指的雙擊動作。
初始化
第一步,如上章節設置;
第二步,創建一個GameObject 命名為 Gestures
;
第三步,給 Gestures
添加一個 TapRecognizer
組件,並保持默認設置,你可以在項目面板搜索到它或者直接打開Component > FingerGestures > Gestures > Tap menu item。

TapRecognizer 是其中一種手勢識別器,它用於監控用戶輸入而且當一個有效的單擊動作被識別時候工作。
第四步,創建一個新的C# script 叫做 TapTutorial
並添加到第二步創建的 Gestures
中。
輕敲屏幕
第一步,點擊TapGestures組件上的 Copy Event To Clipboard
按鈕,它會把TapGesture所需要的時間信號代碼copy到黏貼板。
第二步,粘貼到 TapTutorial
腳本裡,如下:
public class TapTutorial : MonoBehaviour
{
void OnTap( TapGesture gesture )
{
/* your code here */
}
}
OnTap
函數匹配定義在TapRecognizer 組件內的訊息名屬性,當識別器要識別一個輕敲手勢,它會使用unity3d的 SendMessage API
先向Gestures物件內所有的腳本廣播 OnTap
訊息,只要TapTutorial綁定在該物件上,它的 OnTap
函數就會被調用到。
出於性能考慮,通常使用.net標準的事件模型代替unity3d的SendMessage API。
第三步,修改 OnTop
函數:
void OnTap( TapGesture gesture )
{
Debug.Log( "Tap gesture detected at " + gesture.Position +
". It was sent by " + gesture.Recognizer.name );
}
gesture
參數包含著手勢事件數據,在上面的代碼,我們主要輸出了位置和 TapRecognizer
內工作的事件。你還可以在 gesture
參數內獲得更多屬性,例如通過 gesture.Fingers
獲得鼠標或手指相關的手勢列表,還有可以通過 gesture.Selection
獲得當前是哪個場景被輕敲 。
第四步,可以測試,通過敲不同位置,可以看到debug訊息輸出。
教程:手勢識別器
在FingerGesture裡,用戶的手勢都由 GestureRecognizers
組件來處理,它是順序處理被識別匹配的用戶動作的。
找到GestureRecognizers
每種手勢都有自己的腳本,存放腳本的路徑在 Plugins\FingerGestures\Scripts\Gesture Recognizers
。
你也可以從 Component > FingerGestures > Gestures menu
裡面找到。

基本使用
要識別一個特殊手勢,你需要:
1、添加對應的 GestureRecognizer
組件到場景中的目標物件。
2、配置它的屬性。
3、監聽它的手勢事件和對應響應。
作為手勢事件通知的一部分, GestureRecognizer
傳遞一個包含相關訊息(位置,手指觸屏點列表,選擇的場景物件,相關的GestureRecognizer等)的事件參數。
一個手勢識別器有以下監聽事件的方式:
1、使用標準的.net 委託事件模型,每一個手勢識別器都暴露一個.net事件接口。
2、使用unity的 SendMessage()
函數 :
手勢事件將會被廣播到遊戲對像裡所有的組件。
手勢事件也可以指向當前相關的場景對象,這時候需要把手勢識別器配置到 `Raycaster `組件中才能檢測場景對象。
這取決於你的選擇。.net的事件模型較為高效,unity的 SendMessage()
較為方便。
屬性
由同一基類派生出來的各種手勢識別器共用一個通用配置和一些函數。例如,我們可以看到 TapRecognizer
和 SwipeRecognizer
組件的配置放置在同一個對像裡。
設置:
你可以看到,兩個組件共用了一部分配置: fingers setup
, reset mode
, event notification settings
, references to additional components
...
同樣,每個手勢識別器都有自己獨特的配置,例如滑動識別器要設置距離閥值、速度、和偏差。而多點觸控可以設置最大持續時間等。
事件訊息廣播:
此處使用 SendMessage()
函數去通知其他系統。你可以使用 Message Name
屬性去指定響應的函數名。
通常, Message Target
會設置你加入的手勢識別器組件。但你也可以設置別的對象。
組件:
你可以收到手動指定添加組件。例如:添加一個 ScreenRaycaster
組件讓手勢識別器獲知場景內對像碰撞。並把消息發送到相應的監聽器。它允許識別器轉發消息到正在有關聯的場景對象。
教程:輕擊手勢識別器

屬性
Required Taps
:連續輕擊的次數。
Max Delay Between Taps
:兩次輕擊間最大的時間間隔。(秒)
Movement Tolerance
:連續輕敲時候,和第一次輕擊的位置相隔的偏差大小。
Max Duration
:最大可以識別的手指數。
事件
void OnTap( TapGesture gesture )
{
// 輕擊的數量
int taps = gesture.Taps;
}
教程:拖拽手勢識別器

屬性
Movement Tolerance
:最小的拖動距離才觸發識別器。
Apply Same Direction Constraint
:只能用於多點拖拽,打開後,如果所有點不是向同一個方向拖拽,識別器將不會識別。
事件
void OnDrag( DragGesture gesture )
{
// 當前識別器階段 (Started/Updated/Ended)
ContinuousGesturePhase phase = gesture.Phase;
// 最後一幀的拖拽/移動數據
Vector2 deltaMove = gesture.DeltaMove;
//完整的拖拽數據
Vector2 totalMove = gesture.TotalMove;
}
教程:滑動手勢識別器

屬性
Min Distance
: 必須滑動的最小距離。
Max Distance
:允許滑動的最大距離。
Min Velocity
:滑動時候最小速度。
Max Deviation
:允許的最大角度偏差。(度)
事件
void OnSwipe( SwipeGesture gesture )
{
// 完整的滑動數據
Vector2 move = gesture.Move;
// 滑動的速度
float velocity = gesture.Velocity;
// 大概的滑動方向
FingerGestures.SwipeDirection direction = gesture.Direction;
}
教程:長按手勢識別器

教程:縮放手勢識別器

屬性
Minimum DOT
:允許的小向量點積。
Minimum Distance
:兩個手指第一次觸屏時候允許的最短路徑。
事件
void OnPinch( PinchGesture gesture )
{
// 識別器當前狀態(Started/Updated/Ended)
ContinuousGesturePhase phase = gesture.Phase;
// 當前兩個手指的距離
float gap = gesture.Gap;
// 當前與上一幀的變動值
float delta = gesture.Delta;
}
教程:旋轉手勢識別器

屬性
Minimum DOT
:允許的小向量點積。
Minimum Rotation
:必須的最小自旋角度。
事件
void OnTwist( TwistGesture gesture )
{
// 識別器當前狀態 (Started/Updated/Ended)
ContinuousGesturePhase phase = gesture.Phase;
// 最近一次角度變化(度)
float delta = gesture.DeltaRotation;
// 總的角度變化(度)
float total = gesture.TotalRotation;
}
桌面仿真
在桌面環境,你可以通過 left-CTRL
鍵加上鼠標轉輪去調節角度。也可以在 Mouse Input Provider
配置別的按鍵。
教程:自定義手勢識別器
自從FingerGestures 3.0之後,可以通過 PointCloudRecognizer
識別自定義手勢。利用基於$P recognizer 是手勢匹配算法實現。現在只支持單手指操作的識別,將來會支持多點自定義手勢。
點雲識別器會對比用戶輸入和已經設置好的手勢模板,然後會返回最近接近的匹配結果,會返回匹配得分和差距值。
點雲識別器是規模和方向固定不變的,這就意味著它可以識別畫得比較大或者小的,也或者是反方向的(李若:從左到右變成從右到左)。
點雲識別器模板
一個模板包括要識別的手勢的數據。是通過一個編輯器編輯的。
創建一個模板需要以下步驟:
1:在你的項目編碼,右擊-> create ->PonitCloud Gesture Template
一個新的模板就好添加到項目裡面,可以自己重命名。
2:選擇模板然後在 Inspecrot 面板內點擊 Edit。
3:然後開始畫圖案。

使用點雲識別器
第一步:
1:保證場景對像已經設置好了finger gesture的屬性。
2:創建一個新的 Gestures
對象。
3:添加一個 PointCloudRecognizer
組件。
以下屬性需要特別注意。
Max Match Distance
:控制識別的精確的程度。數值越低,越精確。
Sampling Distance
: 連貫動作取樣時候,兩點間隔的最小距離。越小越精確,但是取樣會更多。
Gesture Templates List
:我們指定的模板列表。
第二步:
添加剛剛創建的模板拖放到手勢模板列表中。

第三步:
1、創建一個c#文件,此處命名為 PointCloudTutorial.cs
。
2、在 PointCloudRecognizer
下面創建一個手勢對象。
3、編輯c#文件:
public class PointCloudTutorial : MonoBehaviour
{
void OnCustomGesture( PointCloudGesture gesture )
{
Debug.Log( "Recognized custom gesture: " + gesture.RecognizedTemplate.name +
", match score: " + gesture.MatchScore +
", match distance: " + gesture.MatchDistance );
}
}
手勢事件保護下面幾個重要屬性:
gesture.RecognizedTemplate
: 被認為是最佳匹配的手勢模板。
gesture.MatchScore
:一個百分比的值,表示匹配的程度。
gesture.MatchDistance
:一個測量絕對值,表示匹配程度。
你還可以使用其他手勢的屬性。 例如位置和選擇對像等屬性。
用代碼創建模板
你可以使用api字自己的編輯器擴展中在運行時候創建手勢模板。
void Awake()
{
PointCloudGestureTemplate triangle = ScriptableObject.CreateInstance<PointCloudGestureTemplate>();
triangle.name = "Triangle Gesture Template";
triangle.BeginPoints();
triangle.AddPoint( 0, 1, 1 );
triangle.AddPoint( 0, 2, 2 );
triangle.AddPoint( 0, 3, 1 );
triangle.AddPoint( 0, 1, 1 );
triangle.EndPoints();
PointCloudGestureTemplate square = ScriptableObject.CreateInstance<PointCloudGestureTemplate>();
square.name = "Square Gesture Template";
square.BeginPoints();
square.AddPoint( 0, 2, 1 );
square.AddPoint( 0, 2, 3 );
square.AddPoint( 0, 4, 3 );
square.AddPoint( 0, 4, 1 );
square.AddPoint( 0, 2, 1 );
square.EndPoints();
PointCloudRegognizer recognizer = gameObject.AddComponent<PointCloudRegognizer>();
recognizer.AddTemplate( triangle );
recognizer.AddTemplate( square );
}
第一個參數 AddPoint
是一個筆畫的順序,該api暫時只支持單線筆畫的手勢。
當 EndPoints()
調用時候,手勢模板會被格式化,所有的點都會重新繪製成0到1範圍的數。
教程:識別手指事件
FingerGestures 可以識別向上,向下,懸停,移動,長按等單點輸入手勢。各種 FingerEventDetector
組件用於識別對應的手指事件,與 GestureRecognizers
類似,都是通過廣播訊息去觸發。
- FingerEventDetector
所有的手指事件識別器都派生與一個基礎抽像類。通常,每個 FingerEventDetector
實例監控著所有手指事件信號。也可以配置 Finger Index Filter
屬性,讓其只跟蹤特定的手指事件。
和手勢識別器一樣,手指事件識別器傳遞一個事件數據對象,改該對像派生於 FingerEvent
類,包含以下屬性:
屬性 | 類型 | 描述 |
---|
Name | string | 消息的名字 |
Detector | FingerEventDetector | 該次事件中的手指事件識別器 |
Finger | FingerGestures.Finger | 該次事件中的手指類 |
Position | Vector2 | 事件所發生的位置 |
Selection | GameObject |
被選中遊戲對像 (依賴`ScreenRaycaster `組件) |
Hit/td> | RaycastHit | 光線投射碰撞,由`ScreenRaycaster`提供,在正常顯示上非常有用 |
FingerUpDetector
void OnFingerUp( FingerUpEvent e )
{
//手指已經持續的時間
float elapsedTime = e.TimeHeldDown;
}
FingerHoverDetector
void OnFingerHover( FingerHoverEvent e )
{
// 檢查狀態,是進入還是離開.
if( e.Phase == FingerHoverPhase.Enter )
{
Debug.Log( e.Finger + " entered object: " + e.Selection );
}
else if( e.Phase == FingerHoverPhase.Exit )
{
Debug.Log( e.Finger + " exited object: " + e.Selection );
}
}
FingerMotionDetector
該識別器能夠識別兩種事件。
1、OnFingerMove :當手指位置距離上一幀位置有發生變化。
2、OnFingerStationary :當手指與上一幀位置一樣。
void OnFingerMove( FingerMotionEvent e )
{
float elapsed = e.ElapsedTime;
if( e.Phase == FingerMotionPhase.Started )
Debug.Log( e.Finger + " started moving at " + e.Position);
else if( e.Phase == FingerMotionPhase.Updated )
Debug.Log( e.Finger + " moving at " + e.Position );
else if( e.Phase == FingerMotionPhase.Ended )
Debug.Log( e.Finger + " stopped moving at " + e.Position );
}
void OnFingerStationary( FingerMotionEvent e )
{
float elapsed = e.ElapsedTime;
if( e.Phase == FingerMotionPhase.Started )
Debug.Log( e.Finger + " started stationary state at " + e.Position );
else if( e.Phase == FingerMotionPhase.Updated )
Debug.Log( e.Finger + " is still stationary at " + e.Position );
else if( e.Phase == FingerMotionPhase.Ended )
Debug.Log( e.Finger + " stopped being stationary at " + e.Position );
}
建議:使用.net代理事件
當使用unity的 SendMessage()
函數廣播事件消息非常方便,但是效率低而且不夠.NET代理事件靈活。
* Gesture Events
每個手勢識別器都暴露一個公共的 OnGesture
.NET事件,可以匹配手勢事件和手指事件。用法跟用 SendMessage()
一樣。
[RequireComponent( typeof( TapGesture ) )]
public class TapTutorial : MonoBehaviour
{
void Start()
{
// 在對像裡面尋找輕擊事件識別器
TapRecognizer tap = GetComponent<TapRecognizer>();
// 訂閱它的.NET事件
tap.OnGesture += MyTapEventHandler;
}
void MyTapEventHandler( TapGesture gesture )
{
Debug.Log( "Tap detected at " + gesture.Position );
}
}
有時候你需要停止監聽事件。你可以用以下辦法:
tap.OnGesture -= MyTapEventHandler;
注意停止監聽事件時候相關對象的生命週期,有可能會導致內存洩露,這是.NET代理事件的陷阱。
另外一種方法是, FingerGestures
單例暴露一個全局的 OnGestureEvent
鉤子,可以監聽到任何手勢事件。
void Start()
{
FingerGestures.OnGestureEvent += FingerGestures_OnGestureEvent;
}
void FingerGestures_OnGestureEvent( Gesture gesture )
{
Debug.Log( gesture.Recognizer.name + " fired its gesture event" );
if( gesture is TapGesture )
Debug.Log( "Tapped: " + ((TapGesture)gesture).Taps );
}
--EOF