Kinect+unity 实现体感格斗闯关小游戏
文章目錄
- 項目地址
- 1 項目概況
- 1.1 項目簡介
- 1.2 項目目的
- 1.3 主要技術
- 2 設計
- 2.1 基本概念
- 2.2 框架
- 2.3 算法
- 2.4 模型
- 2.5 調查問卷
- 3 實現
- 3.1 技術難點
- 3.2 解決方案
- 4 技術支持
- 4.1 游戲設計技術
- 4.1.1 MVC
- 4.1.2 工廠模式
- 4.1.3 單例模式
- 4.1.4 多場景切換
- 4.1.5 發布者-訂閱者模式
- 4.2 Kinect體感技術
- 4.2.1 與Unity結合
- 4.2.2 識別姿勢
- 監聽器介紹
- 接口介紹
- 實現監聽
- Kinect檢測源碼分析
- 4.2.3 連續姿勢和離散姿勢
- 離散動作識別
- 連續動作識別
- 5. 參考文獻
這是我曾經做過的一個用Kinect 和 Unity 實現的一個Unity體感游戲
效果圖如下
下面是項目的實現報告, 如果想看Kinect技術可以直接跳到 4.2 Kinect技術總結
項目地址
https://github.com/wyj16340227/Kick996
1 項目概況
1.1 項目簡介
- 1.1.1 游戲介紹
使用kinect與uinity 3D引擎實現人機交互的AR闖關游戲:Kick996。
通過kinect獲取玩家行為信息(包括動作、語音),通過算法轉化為輸入信息,控制角色動作完成交互。
- 1.1.2游戲規則
玩家具有跳躍、攻擊、移動等動作,每一關有不同的敵人,通過攻擊動作消滅敵人,完成闖關。
1.2 項目目的
kinect是目前應用最廣泛的VR外設之一,我們小組計劃初步學習kinect,結合學過的Unity 3D知識,進行人機交互,實現一個具體的小游戲。通過這個學習過程了解目前Kinect應用的范圍,瓶頸以及日后的應用空間,體會VR技術對于現實生活的影響。
1.3 主要技術
- 1.3.1 kinect行為捕捉
通過kinect for windows固件完成用戶行為信息讀取,通過篩選數據獲得交互信息,舍棄多余信息。并通過接口傳輸信息。
- 1.3.2 unity 3D游戲設計
主要使用技術:剛體碰撞、狀態機、工廠模式、MVC模型、消息發布模式。
- 1.3.3 語音識別
通過Speech Platform API完成識別,并通過算法進行篩選(正則表達式匹配),篩選出正確語音,完成輸入。
2 設計
2.1 基本概念
2.2 框架
- MVC模型
將基本框架分為Model、View、Controller三個部分。分別控制數據、視圖、控制器。
Model單獨存儲數據結構,View記錄視圖中存在的對象及參數,Controller顯示視圖。
2.3 算法
- 工廠模式
考慮到對象的銷毀及產生需要占用大量資源,因此考慮使用對象工廠,通過控制生存狀態,減少對象生產及銷毀所造成的運算資源開銷。
狀態為死亡的對象存放在視圖以外。
- 消息發布模式
玩家將狀態通報所有訂閱對象,對象根據自己的狀態選擇將要執行的動作。
2.4 模型
- 場景模型
使用Unity3D-Terrian組件進行場景構建。
- 角色模型
角色模型選擇在unity asset store上購買。
2.5 調查問卷
經過針對性的問卷調查(對象多為在校學生),約有73%的人(大三居多)認為學習壓力比較繁重,其中有77%曾經過選擇并有意向繼續選擇小游戲紓解壓力。
通過對這些同學進行問詢,普遍認為狂扁小朋友是一款有趣、能夠紓解壓力的游戲。
由于產品尚未制作完成,因此無法進行體驗調查。
3 實現
3.1 技術難點
- 3.1.1 實時性不強
kinect行為捕捉較為緩慢,很容易產生滯后感,當玩家動作過快,容易識別錯誤或無法識別動作,造成信息不準確及信息丟失的問題。很嚴重的影響游戲體驗。
- 3.1.2 游戲設計趣味性有待增強
由于游戲操作較為簡單,因此需要優美的場景及豐富的劇情來增強可玩性。對于unity3D引擎來說,挑戰巨大。
- 3.1.3 語音識別
語音識別滯后性非常強,原則上來說,無法單獨通過語音控制玩家動作。
3.2 解決方案
- 3.2.1 語音識別
- 通過語音與動作相結合,減少滯后性帶來的不便。
- 通過組合技來延長動作時間,為語音識別提供更多的識別時間,減少滯后性。
- 3.2.2 游戲性增強
- 豐富劇情。向其中加入豐富的幽默的字幕解說,來吸引玩家的注意力,其本質是通過解壓游戲+看趣味故事來放松。
- 壓縮場景。過長的故事線只會讓玩家愈發覺得游戲無聊,因此采取快速游戲的策略,在玩家的游戲熱情尚未結束的時候結束游戲。避免越玩越無聊的情況的出現。
4 技術支持
4.1 游戲設計技術
4.1.1 MVC
- 1.概念描述
即Model-View-Controller三個部分。分別控制場景,顯示以及數據。
- 2.模式應用
對應關系為:
| Model | Model |
| UIController | View |
| Controller | Controller |
- 3.優勢
能夠做到場景與對象完全分離,角色分工明確清晰。不會造成一個對象既要控制場景又要控制角色的情況,避免了很多設計上的冗余。
4.1.2 工廠模式
- 1.概念描述
對于unity,重復的對象進行大量的Destrory及Create是一筆巨大的開銷。因此,類似線程池,將對象存儲在倉庫中,在不使用時,將其SetActive(false);并放在攝像頭的背面。使用時激活并放入場景中。
- 2.實現邏輯
- 得到對象
- 銷毀對象
4.1.3 單例模式
- 1.概念描述
是unity中應用最為廣泛的一種模式。顧名思義,即對某個對象,對于某個對象全局中只存在一個實例,其他隊想要獲得該對象的時候,都要通過它提供的方法GetInsitance來取得。
- 2.模式應用
全局中有一個單例SceneController。
事實上,Model SceneController UIController都應當作為單例。但是在設計中,Model及UIController放在了SceneController,中,因此可以通過在SceneController中添加Get方法來取得它們的實例。
4.1.4 多場景切換
- 1.概念描述
由于游戲中需要多個場景,不同的場景需要不同的場景元素,因此在游戲設計中需要考慮多場景切換的問題。
有兩種較為常用的場景切換方法。
第一種方法就是通過不停的切換攝像機的位置。通過將不同的布景放在各個不會互相干擾(攝像機不能同時拍攝到)的地方,由場景控制器來控制場景的變換。
第二種方法是創建多個場景,并通過方法Application.LoadLevel()來切換場景。這種方法設計起來更加的方便且實用,但是存在數據傳遞的問題。
- 2.技術難點
采取第二種場景切換的方法,但是存在技術難點,即:當前場景的數據在切換到下一個場景的時候會銷毀。
有兩種解決方案。
第一種方案:在場景切換的時候將數據存放在本地文件中,在新場景加載出來后再從本地文件中讀取數據。
第二種解決方案為:將數據掛載在一個對象身上,并使用DontDestroyOnLoad()方法使其在場景切換時不被銷毀。只需將其放在攝像機看不到的地方即可。
4.1.5 發布者-訂閱者模式
- 1.概念描述
角色消息的交互是必要的。例如,在本游戲中,玩家的位置、狀態信息就時刻影響著敵人的動作。如果在update里不斷地獲取玩家的狀態,將是一件開銷十分巨大的事情。因此,使用消息的發布-訂閱模式。一方作為消息的發布方,一方作為消息的訂閱方;只有在發布方狀態更改了之后,才會向訂閱者發布消息。
- 2.模式應用
在本游戲中,有兩組消息發布-接收者。分別是:
| player | enemy SceneController | 狀態信息(位置、生命、魔法etc) |
| enemyFactory | SceneController | 敵人信息 |
由于場景控制器要時刻控制游戲進度,當消滅的敵人數目達到下一關要求的時候,才會跳轉到下一關。因此,需要EnemyFactory 向 SceneController發布信息。
- 3.實現難點
由于C#語法中不能夠繼承多個類,因此無法讓SceneController同時作為Player及EnemyFactory的Observer,因此,在Suject中加入兩個函數,實現分類訂閱。
//Player use it notify its observerpublic abstract void NotifyPlayer(PlayerState playerState);//EnemyFactory use it notify its observerpublic abstract void NotifyEnemy(int enemyNum, int bossNum);4.2 Kinect體感技術
4.2.1 與Unity結合
使用 Kinect-package中間件,版本為2.13, 支持Kinect2.
這個包中間有很多Demo, 可以幫助快速上手項目, 其中重點Demo為:KinectGesturesDemo1 其中包括關于手勢的檢測。
其中腳本
- Kinect Manager Kinect控制器, 當加載此腳本時, 將會連接kinect,處理數據流
- Kinect Gesture Listener Kinect 姿勢識別器, 當加載此腳本, 會進行姿勢的監控
- **CubeGestureListener.cs ** 這個是自己寫的腳本, 用于處理Listener的消息
4.2.2 識別姿勢
監聽器介紹
Kinect 自帶的識別器, 也就是 Kinect Gesture Listener
能被流暢的識別以下手勢:
◎RaiseRightHand / RaiseLeftHand – 左手或右手舉起過肩并保持至少一秒
◎Psi –雙手舉起過肩并保持至少一秒
◎Stop – 雙手下垂.
◎Wave –左手或右手舉起來回擺動
◎SwipeLeft – 右手向左揮.
◎SwipeRight – 左手向右揮.
◎SwipeUp / SwipeDown – 左手或者右手向上/下揮
◎ Click – 左手或右手在適當的位置停留至少2.5秒.
◎RightHandCursor / LeftHandCursor – 假手勢,用來使光標隨著手移動
◎ZoomOut – 手肘向下,左右手掌合在一起(求佛的手勢),然后慢慢分開.
◎ZoomIn – 手肘向下,兩手掌相聚至少0.7米,然后慢慢合在一起
◎Wheel –想象一下你雙手握著方向盤,然后左右轉動。
◎Jump –在1.5秒內髖關節中心至少上升10厘米
◎Squat -在1.5秒內髖關節中心至少下降10厘米
◎Push – 在1.5秒內將左手或右手向外推
◎Pull -在1.5秒內將左手或右手向里拉
接口介紹
在CubeGestureListener里需要這一些函數 進行姿勢處理:
UserDetected()用于啟動手勢檢測;
UserLost()用于清理變量或者占用的資源。你并不需要移除UserDetected()中添加的手勢。這些將會在調用UserLost()前自動清除。
GestureInProgress()在一個手勢開始但是還沒有被結束或者取消時調用。
GestureCompleted()在一個手勢結束時調用。你可以在這里添加自己的代碼來處理手勢
GestureCancelled()手勢被取消時調用
實現監聽
在此腳本中我們首先需要開啟檢測的手勢: 我們需要用到的手勢分別是:
離散動作: 右手向左揮、右手向左揮、左手或者右手向上揮,,T字型
連續動作: 前傾,后傾,左傾,右傾等動作
public void UserDetected(long userId, int userIndex){// the gestures are allowed for the primary user onlyKinectManager manager = KinectManager.Instance;if(!manager || (userIndex != playerIndex))return;// detect these user specific gesturesmanager.DetectGesture(userId, KinectGestures.Gestures.SwipeLeft);manager.DetectGesture(userId, KinectGestures.Gestures.SwipeRight);manager.DetectGesture(userId, KinectGestures.Gestures.SwipeUp);manager.DetectGesture(userId, KinectGestures.Gestures.Tpose);manager.DetectGesture(userId, KinectGestures.Gestures.LeanLeft);manager.DetectGesture(userId, KinectGestures.Gestures.LeanRight);manager.DetectGesture(userId, KinectGestures.Gestures.LeanForward);manager.DetectGesture(userId, KinectGestures.Gestures.LeanBack);}這樣我們監聽器就只會監聽這些動作, 而其他動作檢測到也不會觸發。
Kinect檢測源碼分析
官方的監聽器是這樣檢測左傾的, 因為Kinect會把人判斷為26個骨頭節點, 左傾就是左肩膀的節點距離地面的高度要小于右肩膀節點的高度。
// check for ShoulderRightFront case Gestures.ShoulderRightFront: switch(gestureData.state) {case 0: // 左肩膀的節點距離地面的高度要小于右肩膀節點的高度。if(jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[rightHipIndex] &&(jointsPos[leftShoulderIndex].z - jointsPos[rightHipIndex].z) < 0f &&(jointsPos[leftShoulderIndex].z - jointsPos[rightShoulderIndex].z) > -0.15f){SetGestureJoint(ref gestureData, timestamp, leftShoulderIndex, jointsPos[leftShoulderIndex]);gestureData.progress = 0.5f;}break;case 1: // gesture phase 2 = completeif((timestamp - gestureData.timestamp) < 1.5f){bool isInPose = jointsTracked[leftShoulderIndex] && jointsTracked[rightShoulderIndex] && jointsTracked[rightHipIndex] &&(jointsPos[leftShoulderIndex].z - jointsPos[rightShoulderIndex].z) < -0.2f;if(isInPose){Vector3 jointPos = jointsPos[gestureData.joint];CheckPoseComplete(ref gestureData, timestamp, jointPos, isInPose, 0f);}}else{// cancel the gestureSetGestureCancelled(ref gestureData);}break; } break;// check for LeanLeft4.2.3 連續姿勢和離散姿勢
其中離散動作 例如攻擊,在這個函數里進行處理 GestureCompleted, 因為這些動作需要在完成時調用。而連續動作,例如前傾后傾, 則在GestureInProgress 進行處理, 因為在動作完成過程中,動作會發生變化,
離散動作識別
public bool GestureCompleted (long userId, int userIndex, KinectGestures.Gestures gesture, KinectInterop.JointType joint, Vector3 screenPos){// the gestures are allowed for the primary user onlyif(userIndex != playerIndex)return false;sGestureText = gesture + " detected";Debug.Log( sGestureText);if (gesture == KinectGestures.Gestures.SwipeLeft)swipeLeft = true;if(gesture == KinectGestures.Gestures.SwipeRight)swipeRight = true;if(gesture == KinectGestures.Gestures.SwipeUp)swipeUp = true;if (gesture == KinectGestures.Gestures.Tpose){Tpose = true;}return true;}首先我們設置4個bool變量swipeLeft、swipeRight、swipeUp、Tpose, 判斷檢測的姿勢, 如果是對應姿勢則會令這些變量為true, 但是因為是離散動作, 這樣會導致當判斷成功一次后, bool變量會一直變為true, 所以寫一個接口, 當bool變量為為true時, 令它為false, 但是返回為true。 類似于 檢測到一個動作后,變量還原
例如判斷是否是 SwipeUp(向上滑)接口如下, 只要其他部分調用此接口,就能知道是否進行SwipeUp操作
連續動作識別
連續動作識別則不需要重新寫一個接口, 因為狀態會一直變化。 不過會有傾斜程度的參(screenPos.z ),為了游戲體驗,當沒有傾斜太大的時候,將傾斜小的認為是直立, 這樣更加便于操控, 不然結果就是只要稍微左移就會一直操縱任務左移, 而直到右移才會一直往右邊, 我們需要一個中立的狀態才好。 然后其他部分只要讀取這四個變量就知道用戶是否左傾,右傾了。
public void GestureInProgress(long userId, int userIndex, KinectGestures.Gestures gesture, float progress, KinectInterop.JointType joint, Vector3 screenPos){// the gestures are allowed for the primary user onlyif (userIndex != playerIndex)return;if((gesture == KinectGestures.Gestures.Wheel || gesture == KinectGestures.Gestures.LeanLeft || gesture == KinectGestures.Gestures.LeanRight || gesture == KinectGestures.Gestures.LeanForward ||gesture == KinectGestures.Gestures.LeanBack) && progress > 0.01f){if(gestureInfo != null){if (gesture == KinectGestures.Gestures.LeanLeft && screenPos.z > detectSense){sGestureText = "左轉";LeanLeft = true;} else{LeanLeft = false;}if (gesture == KinectGestures.Gestures.LeanRight && screenPos.z > detectSense){sGestureText = "右轉";LeanRight = true;}else{LeanRight = false;}if (gesture == KinectGestures.Gestures.LeanForward && screenPos.z > detectSense){sGestureText = "前進";LeanForward = true;}else{LeanForward = false;}if (gesture == KinectGestures.Gestures.LeanBack && screenPos.z > detectSense + 10){sGestureText = "停止/后退";LeanBack = true;}else{LeanBack = false;}progressDisplayed = true;progressGestureTime = Time.realtimeSinceStartup;}}}和游戲操控結合, 實現同步
人物移動
void Update(){float v = Input.GetAxisRaw("Vertical");float h = Input.GetAxisRaw("Horizontal");if (slideChangeWithGestures && gestureListener){if (gestureListener.LeanLeft){h = -1; //水平移動大小 負數為左邊}if (gestureListener.LeanRight){h = 1;}if (gestureListener.LeanForward){v = 1; //水平移動大小 負數為下邊}if (gestureListener.LeanBack){v = -1;}}}按鍵操控
if (slideChangeWithGestures && gestureListener) {//檢測動作 映射陳實體按鍵if (gestureListener.IsSwipeUp()){return KeyCode.J; //攻擊1}if (gestureListener.IsSwipeLeft()){return KeyCode.K; //攻擊2}if (gestureListener.IsTpose()){return KeyCode.R; // 人物旋轉180度}if (gestureListener.IsSwipeRight()){return KeyCode.Q; //向前瞬移}else{return KeyCode.None;} }5. 參考文獻
- Lamiaa A. Elrefaei, Bshaer Azan1, Sameera Hakami JCAVE: A 3D INTERACTIVE GAME TO ASSIST HOME PHYSIOTHERAPY REHABILITATION
- V. Pterneas, “IMPLEMENTING KINECT GESTURES,” 27 January 2014. [Online]. Available:https://pterneas.com/2014/01/27/implementing-kinect-gestures/. [Accessed 2017].
- M. Pedraza-Hueso, S. Martín-Calzón, F. J. Díaz-Pernas and M. Martínez-Zarzuela, “Rehabilitation
Using Kinect-based Games and Virtual Reality,” Procedia Computer Science, vol. 75, pp. 161-168,2015https://doi.org/10.1016/j.procs.2015.12.233. - “Tracking Users with Kinect Skeletal Tracking,” [Online]. Available: https://msdn.microsoft.com/enus/library/jj131025.aspx. [Accessed 2017].
總結
以上是生活随笔為你收集整理的Kinect+unity 实现体感格斗闯关小游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kinect切水果
- 下一篇: AXI5 new feature: su