事件(event)的觸發是PlayMaker交互設計的基礎。
鼠標(mouse)、鍵盤(keyboard)、按鈕(button)觸發
這類觸發邏輯的原理是:
當用戶通過輸入設備(比如鼠標、鍵盤、觸碰屏、手柄等)向游戲發送信息時(比如按鍵被按下、滾輪被撥動等等),觸發指定event并通過該event實現狀態改變。
這類觸發事件的相關動作可以在PlayMaker的Input Actions中找到。
1. 鼠標(mouse)
-
GetMouseButton
單純檢測鼠標按鍵是否被按下,并將結果儲存在一個bool變量中 -
GetMouseButtonDown
在鼠標按鍵被按下時立刻觸發指定event -
GetMouseButtonUp
在鼠標按鍵被松開時立刻觸發指定event
我們可以在PlayMaker中檢測到的鼠標按鈕包括:Left、Middle、Right、None。
注意:MouseButtonDown不等于鼠標單擊。鼠標單擊代表快速執行按鍵的按下和松開兩個操作。如果一定需要檢測“單擊”輸入操作,需要使用多個state來設計一個簡單的邏輯:
-
State 1
檢測按鍵是否被按下 -
State 2
檢測按鍵是否被松開,但添加了一個短暫的計時器(使用wait
動作),在時限內如果按鍵松開,單擊操作成立,觸發LMB down事件 - 如果在短暫的時間間隔內(比如0.1s)按鍵沒有被松開,說明單擊操作不成立,觸發cancel事件
- 因為cancel事件導致
State 2
休眠,所以之后即便再松開按鍵也不再會觸發LMB down事件了
觸發檢測到按鍵松開則跳轉到“單擊”所觸發的目標狀態,同時在State 2
中設定一個計時器,設置一個短暫的時間間隔(比如0.1s),一旦超過時間間隔,立即跳轉到“
2. 鍵盤(keyboard)
-
AnyKey
任何按鍵被按下都會觸發event -
GetKey
單純檢測一個按鍵是否被按下,并將結果儲存在一個bool變量中 -
GetKeyDown
在指定按鍵被按下時立刻觸發指定event -
GetKeyUp
在指定按鍵被松開時立刻觸發指定event
指定按鍵比較麻煩,要從一個很長的列表中選擇,這也算是“可視化”帶來的弊端之一吧。
3. 按鈕(Button)
-
GetButton
單純檢測一個按鈕是否被按下,并將結果儲存在一個bool變量中 -
GetButtonDown
在指定按鈕被按下時立刻觸發指定event -
GetButtonUp
在指定按鈕被松開時立刻觸發指定event
注意,按鈕名稱需要自行輸入,必須嚴格與Input面板中的名稱對應,請注意大小寫規范以及是否空格。
按鈕(Button)的概念在Unity3D中比較特殊。并不一定專指鼠標按鍵、鍵盤或者手柄,而是通過預先的定義可以囊括一系列不同的按鍵,以方便使用。
從菜單Edit
> Project Settings
> Input
可以打開Input面板:
這里指定了18個不同的Axes,可以理解為“軸向值”。Name
是這個軸向的名稱,Positive Button
和Alt Positive Button
中所指定的按鍵被按下時,該軸向的值迅速增長到1,Negative Button
和Alt Negative Button
中所指定的按鍵被按下時,該軸向的值迅速減少為-1,無任何按鍵被按下時,軸向值迅速歸0。
而Button就是指的軸向中所規定的所有按鍵。比如這個叫做Horizontal的軸向,我們可以理解為“橫向輸入按鈕”,當鍵盤left
、right
鍵或a
、d
鍵被按下時,就相當于“橫向輸入按鈕”被按下了。
我們經常會使用到的Button有:
- 使用Horizontal、Vertical來設置運動方向或旋轉方向
- 使用Fire1來控制攻擊行為
- 使用Jump來控制跳躍
- 使用Cancel來取消或者呼出游戲菜單
- …
我們還可以自己增加更多的Axes。
碰撞(collision)觸發
這類觸發邏輯的原理是:
Unity3D的游戲物體可以設置碰撞邊界(Collider),當有其他的帶有collider組件的游戲物體進入/離開/停留這個游戲物體時,可以觸發event并由此引起游戲物體的狀態改變。
Collision Event行為:
- 當
Collision
中所指定的情況發生,且碰撞對象帶有Collide Tag
中所指定的Tag時,觸發Send Event
中指定的事件,并可以將碰撞對象儲存為一個GameObject類型變量,將碰撞力量儲存為一個Vector3類型變量 -
On Collision Enter
、On Collision Stay
、On Collision Exit
三個選項針對其他碰撞體collider進入、停留、離開本碰撞體的狀況 -
On Controller Collider Hit
選項針對Controller類型的碰撞體與本碰撞體碰撞的狀況 -
On Particle Collision
選項針對與粒子物體發生碰撞的狀況
Get Collision Info行為:
- 這個行為可以緊接著Collision Event行為使用,用來儲存更多關于碰撞的信息,比如:碰撞物體、相對速度(vector3)、相對速度(float)、碰撞點坐標(vector3)、碰撞點法線方向(vector3)、物理材質名稱。
在Collider組件上,我們可以勾選Is Trigger
選項來將碰撞體變成一個觸發器(trigger)。觸發器和碰撞體的區別在于,觸發器不會實際阻擋其他碰撞體,相當于一個虛擬的開關。
如果設置成了Trigger,不能使用Collision Event和Get Collision Info行為了,而要使用Trigger Event和Get Trigger Info行為,用法是一樣的。
Trigger Event
Get Trigger Info
通常適合使用碰撞觸發來制作的交互邏輯有:
- 拾取游戲物體:
將道具放置在場景中,設置成trigger類碰撞體,玩家進入碰撞體范圍時觸發相應事件 - 玩家“獲得”物品
- 道具模型消失
- 游戲積分增加
- …
- 啟動機關:
當碰撞發生時機關被觸發,可以是“開門”、“啟動升降機”、“進入下一關”等等 - 傷害、死亡:
當“子彈”物體與對象發生碰撞時,對對象造成傷害或者讓對象死亡 - 特效:
當“子彈”擊中對象時,從“傷口”處發射粒子特效(血、煙霧、碎片等等)
射線(raycast)觸發
這類觸發邏輯的原理是:
從目標點向特定方向發射一條光線(ray),然后獲得這條光線與場景物體的碰撞信息。通常是從某個游戲物體沿著特定軸向(x、y、z)發射,或者是攝影機平面上某一點垂直于攝影機平面向場景發射。
Raycast是即時發生的,不論距離多遠,都會在同一幀返回碰撞結果,所以適用于需要立即得到反饋的情況。
Raycast:
Raycast從一個游戲物體(From Game Object
)或某個點(From Position
)沿著特定坐標空間(Space
)某個方向(Direction
)發射一條長度為Distance
單位長度的探測光線,并將結果儲存在相應的變量中:
-
Hit Event
:如果碰到游戲物體,則觸發相應事件 -
Store Did Hit
:是否碰到游戲物體(bool) -
Store Hit Object
:碰撞對象物體(GameObject) -
Store Hit Point
:碰撞接觸點(Vector3) -
Store Hit Normal
:碰撞法線方向(Vector3) -
Store Hit Distance
:發射點距離碰撞點距離(float) -
Repeat Interval
:射線發射頻率(0代表僅發射1次;1代表每幀發射一次;2代表每兩幀發射一次…) -
Layer Mask
:可以指定僅探測與特定層中的物體之間的碰撞 -
Debug
:可以在視圖中顯示一條直線方便我們判斷raycast是否正確
注意:ray是有長度的,在這個長度范圍以內如果沒有觸碰到物體,那就是“沒有擊中”。這個長度默認為100米,如果場景過大有可能會出現距離不夠而不能正確返回結果的情況。同時特定情況下也可以將這個值縮小以獲得特定效果,比如游戲設定手槍射距為30米的話,就要將ray設成30。
Raycast All:
Raycast All和Raycast用法幾乎完全一樣,但Raycast All會返回Ray碰撞到的所有游戲物體并返回為一個GameObject類型的數組(array)變量Store Hit Objects
Get Raycast Hit Info:
Get Raycast All Info:
這兩個行為用在Raycast行為之后用以獲得更多的碰撞信息。
有一些action同樣基于Raycast原理,但名字中沒有“ray”這個詞,也沒有被歸類在Physics動作組中。
Mouse Pick:
Mouse Pick會由鼠標屏幕二維坐標轉換成攝影機平面二維坐標,再將這一坐標對應的三維空間位置沿著垂直于攝影機平面的方向發射一條長度為Ray Distance
的ray,并返回碰撞結果為相應數據類型的變量值。
Mouse Pick Event:
Mouse Pick Event同樣基于上述原理,是用來查看鼠標是否在特定游戲物體(Game Object
)上,并根據不同的鼠標狀態而觸發不同的事件:
-
Mouse Over
:鼠標劃入游戲物體范圍內 -
Mouse Down
:鼠標在游戲物體范圍內按下左鍵 -
Mouse Up
:鼠標在游戲物體范圍內松開左鍵 -
Mouse Off
:鼠標從游戲物體范圍內劃出
Mouse Pick 2d與Mouse Pick 2d Event這兩個行為與上兩個行為完全一致,只不過專門適用于2D游戲,因為它們返回的位置坐標數據類型是Vector2而不是Vector3
通常適合使用碰撞觸發來制作的交互邏輯有:
- FPS類游戲中的設計判定,使用Raycast來判斷是否擊中目標,比發射子彈后再判斷碰撞要準確得多
- 獲得鼠標指向位置,并通過這個位置來指引角色運動
- 通過鼠標與游戲物體進行互動
數據觸發
關于“數據”和“數據格式”的詳細介紹,可以參看《Unity3D的變量及數據類型》。
數據觸發的基本原理是:
通過監控數據的數值狀態或數值變化,并使用各種數值比較action來觸發不同的事件。
Bool Test檢查一個bool變量的值,然后根據“True/False”可以觸發最多2個不同的event
Int Compare和Float Compare檢查兩個不同的int數值或者float數值,根據“第一個數值等于/小于/大于第二個數值”可以觸發最多3個不同的event
String Compare檢查兩個字符串是否一致,根據“一致/不一致”可以觸發最多2個不同的event
Object Compare檢查兩個Object(也就是組件)是否一致,根據“一致/不一致”可以觸發最多2個不同的event
Object Compare檢查兩個數組是否一致(一致的意思是A數組中每一個數據都等于B數組中對應序號的數據),根據“一致/不一致”可以觸發最多2個不同的event
Enum Compare檢查兩個Enum狀態是否一致,根據“一致/不一致”可以觸發最多2個不同的event
Fsm State Test檢查特定游戲物體上某個FSM是否正處于某個特定State,根據“True/False”可以觸發最多2個不同的event
這些檢查都可以將結果儲存進一個bool變量中(
Store Result
)。
Every Frame
選項如果被勾選,則代表該action會一直不斷執行,也就是實時監控數據是否滿足比較標準。如果不被勾線,則只在剛進入該state時執行一次數值比較。
在這些情況下我們通常使用這種數值觸發來設計交互邏輯:
- 角色離某個NPC的距離小于特定數值的時候,角色吸引NPC的注意,NPC開始追逐角色
- 角色生命值小于等于0的時候,角色死亡
- 當時間間隔超過特定數值的時候,開始執行某種操作
- 當對象處于特定state(比如攻擊僵直)的時候,指令輸入不起作用