1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Kinect+unity 实现体感格斗闯关小游戏

Kinect+unity 实现体感格斗闯关小游戏

时间:2019-10-12 06:02:50

相关推荐

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 MVC4.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技术总结

项目地址

/wyj16340227/Kick996

1 项目概况

1.1 项目简介

1.1.1 游戏介绍

使用kinectuinity 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模型

将基本框架分为ModelViewController三个部分。分别控制数据、视图、控制器。

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.模式应用

对应关系为:

3.优势

能够做到场景与对象完全分离,角色分工明确清晰。不会造成一个对象既要控制场景又要控制角色的情况,避免了很多设计上的冗余。

4.1.2 工厂模式

1.概念描述

对于unity,重复的对象进行大量的DestroryCreate是一笔巨大的开销。因此,类似线程池,将对象存储在仓库中,在不使用时,将其SetActive(false);并放在摄像头的背面。使用时激活并放入场景中。

2.实现逻辑 得到对象 销毁对象

4.1.3 单例模式

1.概念描述

是unity中应用最为广泛的一种模式。顾名思义,即对某个对象,对于某个对象全局中只存在一个实例,其他队想要获得该对象的时候,都要通过它提供的方法GetInsitance来取得。

2.模式应用

全局中有一个单例SceneController

事实上,ModelSceneControllerUIController都应当作为单例。但是在设计中,ModelUIController放在了SceneController,中,因此可以通过在SceneController中添加Get方法来取得它们的实例。

4.1.4 多场景切换

1.概念描述

由于游戏中需要多个场景,不同的场景需要不同的场景元素,因此在游戏设计中需要考虑多场景切换的问题。

有两种较为常用的场景切换方法。

第一种方法就是通过不停的切换摄像机的位置。通过将不同的布景放在各个不会互相干扰(摄像机不能同时拍摄到)的地方,由场景控制器来控制场景的变换。

第二种方法是创建多个场景,并通过方法Application.LoadLevel()来切换场景。这种方法设计起来更加的方便且实用,但是存在数据传递的问题。

2.技术难点

采取第二种场景切换的方法,但是存在技术难点,即:当前场景的数据在切换到下一个场景的时候会销毁。

有两种解决方案。

第一种方案:在场景切换的时候将数据存放在本地文件中,在新场景加载出来后再从本地文件中读取数据。

第二种解决方案为:将数据挂载在一个对象身上,并使用DontDestroyOnLoad()方法使其在场景切换时不被销毁。只需将其放在摄像机看不到的地方即可。

4.1.5 发布者-订阅者模式

1.概念描述

角色消息的交互是必要的。例如,在本游戏中,玩家的位置、状态信息就时刻影响着敌人的动作。如果在update里不断地获取玩家的状态,将是一件开销十分巨大的事情。因此,使用消息的发布-订阅模式。一方作为消息的发布方,一方作为消息的订阅方;只有在发布方状态更改了之后,才会向订阅者发布消息。

2.模式应用

在本游戏中,有两组消息发布-接收者。分别是:

由于场景控制器要时刻控制游戏进度,当消灭的敌人数目达到下一关要求的时候,才会跳转到下一关。因此,需要EnemyFactorySceneController发布信息。

3.实现难点

由于C#语法中不能够继承多个类,因此无法让SceneController同时作为PlayerEnemyFactoryObserver,因此,在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 ManagerKinect控制器, 当加载此脚本时, 将会连接kinect,处理数据流Kinect Gesture ListenerKinect 姿势识别器, 当加载此脚本, 会进行姿势的监控**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 ShoulderRightFrontcase 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 LeanLeft

4.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 REHABILITATIONV. Pterneas, “IMPLEMENTING KINECT GESTURES,” 27 January . [Online]. Available://01/27/implementing-kinect-gestures/. [Accessed ].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,/10.1016/j.procs..12.233.“Tracking Users with Kinect Skeletal Tracking,” [Online]. Available: /enus/library/jj131025.aspx. [Accessed ].

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。