Kinect with Unity3D游戏开发的一点思路总结(体感赛车游戏)
2014-11-15 10:28
656 查看
Unity3D是一个非常成熟的3D引擎;Kinect可以理解为一个输入设备(像鼠标键盘一样)所以这里技术上的关键点是:将输入信号与3D图形控制结合起来
设计上的关键点是:构造正常人会在2—3平方米的面积内通常可以做的事情(比如让普通人在这个范围内挥动手臂切水果、罚点球、垫排球等等)
这些是笔者这几天接触Kinect with Unity3D以来的最大感受吧。(为什么使用Unity3D呢;因为它含有丰富的例程和已开发资源,所以初期适宜用来移植合适的游戏到Kinect上)
对于第二点,我想也是每一个Kinect人都在探索和寻找创意的;
而第一点,笔者刚玩这俩东西,稍稍分享一些思路。在Unity3D当中,笔者主要是利用了KinectPointController.cs这个官方提供的脚本。
这个脚本实现了识别全身各个关键部位,那么理论上我们只要将这些量通过某种转化关系之后,用来控制Unity3D已有的各个元素,就完成了任务。笔者因此进行了这方面的尝试,得益于Unity3D非常丰富的Sample,笔者选取官方的Car Tutorial进行改造。我们要做的就是根据识别部位的结果,将动作映射到汽车控制的指令,而后进行不断的测试和优化用户体验,即可。
笔者将KinectPointController.cs所挂的PointMan这个包挂在Car上,这样他们就可以一起移动,而后笔者目前只用到左右手、头和脚这几点,因此在unity中不显示PointMan的其他几点mesh。
在unity中通过KinectPointController.cs识别PointMan各点相对Car中心的坐标值,而后进行分析,笔者选取了若干个姿势,包括转方向盘,前倾踩油门和后倾踩刹车及挂倒档,通过试验正确识别后,下面剩下的就是模拟键盘鼠标控制Car的结果了。
在Car tutorial这个示例中,车子的油门和方向盘主要通过Car.js这个脚本中的throttle和steer来进行控制,而KinectPointController.cs是C#脚本,这就涉及C#对js中变量值的操作。Unity支持这样的操作。
笔者先将Car.js移到"Pro Standard Assets”目录下,然后修改上面两个变量为全局变量,而后直接可以在C#中调用Car.js的全局变量。为什么这样做可以参考官方文档:
http://docs.unity3d.com/Documentation/ScriptReference/index.Script_compilation_28Advanced29.html
因此再辅以对Unity3D图形界面下的若干设置和操作,就完成了目前的体感赛车demo,而剩下的就是根据用户体验对操控方式进行优化。
最后附上目前使用的修改后的KinectPointController.cs脚本,其中含有笔者目前对Car.js脚本中变量的操作方式
/*
* KinectModelController.cs - Moves every 'bone' given to match
* the position of the corresponding bone given by
* the kinect. Useful for viewing the point tracking
* in 3D.
*
* Developed by Peter Kinney -- 6/30/2011
*
* ____________________________________________
*
* Modified By Chen Zhehuai@Dian -- 11/2/2012
*/
using UnityEngine;
using System;
using System.Collections;
public class KinectPointController : MonoBehaviour
{
//Assignments for a bitmask to control which bones to look at and which to ignore
public enum BoneMask
{
None = 0x0,
Hip_Center = 0x1,
Spine = 0x2,
Shoulder_Center = 0x4,
Head = 0x8,
Shoulder_Left = 0x10,
Elbow_Left = 0x20,
Wrist_Left = 0x40,
Hand_Left = 0x80,
Shoulder_Right = 0x100,
Elbow_Right = 0x200,
Wrist_Right = 0x400,
Hand_Right = 0x800,
Hip_Left = 0x1000,
Knee_Left = 0x2000,
Ankle_Left = 0x4000,
Foot_Left = 0x8000,
Hip_Right = 0x10000,
Knee_Right = 0x20000,
Ankle_Right = 0x40000,
Foot_Right = 0x80000,
All = 0xFFFFF,
Torso = 0x10000F, //the leading bit is used to force the ordering in the editor
Left_Arm = 0x1000F0,
Right_Arm = 0x100F00,
Left_Leg = 0x10F000,
Right_Leg = 0x1F0000,
R_Arm_Chest = Right_Arm | Spine,
No_Feet = All & ~(Foot_Left | Foot_Right)
}
public SkeletonWrapper sw;
public GameObject Hip_Center;
public GameObject Spine;
public GameObject Shoulder_Center;
public GameObject Head;
public GameObject Shoulder_Left;
public GameObject Elbow_Left;
public GameObject Wrist_Left;
public GameObject Hand_Left;
public GameObject Shoulder_Right;
public GameObject Elbow_Right;
public GameObject Wrist_Right;
public GameObject Hand_Right;
public GameObject Hip_Left;
public GameObject Knee_Left;
public GameObject Ankle_Left;
public GameObject Foot_Left;
public GameObject Hip_Right;
public GameObject Knee_Right;
public GameObject Ankle_Right;
public GameObject Foot_Right;
private GameObject[] _bones; //internal handle for the bones of the model
//private Vector4[] _bonePos; //internal handle for the bone positions from the kinect
public int player;
public BoneMask Mask = BoneMask.All;
// Use this for initialization
void Start () {
//store bones in a list for easier access
_bones = new GameObject[(int)Kinect.NuiSkeletonPositionIndex.Count] {Hip_Center, Spine, Shoulder_Center, Head,
Shoulder_Left, Elbow_Left, Wrist_Left, Hand_Left,
Shoulder_Right, Elbow_Right, Wrist_Right, Hand_Right,
Hip_Left, Knee_Left, Ankle_Left, Foot_Left,
Hip_Right, Knee_Right, Ankle_Right, Foot_Right};
//_bonePos = new Vector4[(int)BoneIndex.Num_Bones];
}
// Update is called once per frame
void Update () {
Vector3 leftHand = new Vector3(0,0,0);
Vector3 rightHand = new Vector3(0,0,0);
Vector3 HipCenter = new Vector3(0,0,0);
Vector3 HeadCenter = new Vector3(0,0,0);
Vector3 FootLeft = new Vector3(0,0,0);
Vector3 FootRight = new Vector3(0,0,0);
//update all of the bones positions
if (sw.pollSkeleton())
{
Debug.Log("Has Track\n");
for( int ii = 0; ii < (int)Kinect.NuiSkeletonPositionIndex.Count; ii++)
{
//_bonePos[ii] = sw.getBonePos(ii);
if( ((uint)Mask & (uint)(1 << ii) ) > 0 ){
_bones[ii].transform.localPosition = sw.bonePos[player,ii];
}
//hip center
if(ii == 0)
{
HipCenter = _bones[ii].transform.localPosition;
// Debug.Log("Hip: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//head center
if(ii == 3)
{
HeadCenter = _bones[ii].transform.localPosition;
// Debug.Log("Head: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//foot left
if(ii == 15)
{
FootLeft = _bones[ii].transform.localPosition;
// Debug.Log("LeftFoot: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
if(ii == 19)
{
FootRight = _bones[ii].transform.localPosition;
// Debug.Log("RightFoot: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//Right hand
if(ii == 11)
{
rightHand = _bones[ii].transform.localPosition;
// Debug.Log("RightHand: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//left hand
if(ii == 7)
{
leftHand = _bones[ii].transform.localPosition;
// Debug.Log("LeftHand: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
}
//Event.KeyboardEvent("w");
//Car.throttle = 0.5f;
//Car.throttle = 0;
//Car.steer = 0;
//left hand y+z >2 ;right hand y+z <2 右转
if ((leftHand.y + leftHand.z > 2) && (rightHand.y + leftHand.z < 2))
{
//右转
Car.steer = 1f;
//Car.throttle = 0.5f;
Debug.Log("Right Turn\n");
}
if ((leftHand.y + leftHand.z < 2) && (rightHand.y + leftHand.z > 2))
{
//左转
Car.steer = -1f;
//Car.throttle = 0.5f;
Debug.Log("Left Turn\n");
}
/* 倒车-》后倾;油门-》前倾 */
if ((HeadCenter.x > HipCenter.x + 0.06))
{
Debug.Log("UPUP\n");
Car.throttle = Car.throttle + 0.015f;
if (Car.throttle > 1)
Car.throttle = 1;
}
if ((HeadCenter.x < HipCenter.x) && (FootRight.x < HipCenter.x))
{
Debug.Log("DOWNdown\n");
Car.throttle = Car.throttle - 0.015f;
if (Car.throttle < -1)
Car.throttle = -1;
}
Debug.Log("CS-thro " + Car.throttle);
Debug.Log("CS-stee " + Car.steer);
}
else
{
Car.throttle = 0f;
Debug.Log("Not Track--Down\n");
}
}
}
设计上的关键点是:构造正常人会在2—3平方米的面积内通常可以做的事情(比如让普通人在这个范围内挥动手臂切水果、罚点球、垫排球等等)
这些是笔者这几天接触Kinect with Unity3D以来的最大感受吧。(为什么使用Unity3D呢;因为它含有丰富的例程和已开发资源,所以初期适宜用来移植合适的游戏到Kinect上)
对于第二点,我想也是每一个Kinect人都在探索和寻找创意的;
而第一点,笔者刚玩这俩东西,稍稍分享一些思路。在Unity3D当中,笔者主要是利用了KinectPointController.cs这个官方提供的脚本。
这个脚本实现了识别全身各个关键部位,那么理论上我们只要将这些量通过某种转化关系之后,用来控制Unity3D已有的各个元素,就完成了任务。笔者因此进行了这方面的尝试,得益于Unity3D非常丰富的Sample,笔者选取官方的Car Tutorial进行改造。我们要做的就是根据识别部位的结果,将动作映射到汽车控制的指令,而后进行不断的测试和优化用户体验,即可。
笔者将KinectPointController.cs所挂的PointMan这个包挂在Car上,这样他们就可以一起移动,而后笔者目前只用到左右手、头和脚这几点,因此在unity中不显示PointMan的其他几点mesh。
在unity中通过KinectPointController.cs识别PointMan各点相对Car中心的坐标值,而后进行分析,笔者选取了若干个姿势,包括转方向盘,前倾踩油门和后倾踩刹车及挂倒档,通过试验正确识别后,下面剩下的就是模拟键盘鼠标控制Car的结果了。
在Car tutorial这个示例中,车子的油门和方向盘主要通过Car.js这个脚本中的throttle和steer来进行控制,而KinectPointController.cs是C#脚本,这就涉及C#对js中变量值的操作。Unity支持这样的操作。
笔者先将Car.js移到"Pro Standard Assets”目录下,然后修改上面两个变量为全局变量,而后直接可以在C#中调用Car.js的全局变量。为什么这样做可以参考官方文档:
http://docs.unity3d.com/Documentation/ScriptReference/index.Script_compilation_28Advanced29.html
因此再辅以对Unity3D图形界面下的若干设置和操作,就完成了目前的体感赛车demo,而剩下的就是根据用户体验对操控方式进行优化。
最后附上目前使用的修改后的KinectPointController.cs脚本,其中含有笔者目前对Car.js脚本中变量的操作方式
/*
* KinectModelController.cs - Moves every 'bone' given to match
* the position of the corresponding bone given by
* the kinect. Useful for viewing the point tracking
* in 3D.
*
* Developed by Peter Kinney -- 6/30/2011
*
* ____________________________________________
*
* Modified By Chen Zhehuai@Dian -- 11/2/2012
*/
using UnityEngine;
using System;
using System.Collections;
public class KinectPointController : MonoBehaviour
{
//Assignments for a bitmask to control which bones to look at and which to ignore
public enum BoneMask
{
None = 0x0,
Hip_Center = 0x1,
Spine = 0x2,
Shoulder_Center = 0x4,
Head = 0x8,
Shoulder_Left = 0x10,
Elbow_Left = 0x20,
Wrist_Left = 0x40,
Hand_Left = 0x80,
Shoulder_Right = 0x100,
Elbow_Right = 0x200,
Wrist_Right = 0x400,
Hand_Right = 0x800,
Hip_Left = 0x1000,
Knee_Left = 0x2000,
Ankle_Left = 0x4000,
Foot_Left = 0x8000,
Hip_Right = 0x10000,
Knee_Right = 0x20000,
Ankle_Right = 0x40000,
Foot_Right = 0x80000,
All = 0xFFFFF,
Torso = 0x10000F, //the leading bit is used to force the ordering in the editor
Left_Arm = 0x1000F0,
Right_Arm = 0x100F00,
Left_Leg = 0x10F000,
Right_Leg = 0x1F0000,
R_Arm_Chest = Right_Arm | Spine,
No_Feet = All & ~(Foot_Left | Foot_Right)
}
public SkeletonWrapper sw;
public GameObject Hip_Center;
public GameObject Spine;
public GameObject Shoulder_Center;
public GameObject Head;
public GameObject Shoulder_Left;
public GameObject Elbow_Left;
public GameObject Wrist_Left;
public GameObject Hand_Left;
public GameObject Shoulder_Right;
public GameObject Elbow_Right;
public GameObject Wrist_Right;
public GameObject Hand_Right;
public GameObject Hip_Left;
public GameObject Knee_Left;
public GameObject Ankle_Left;
public GameObject Foot_Left;
public GameObject Hip_Right;
public GameObject Knee_Right;
public GameObject Ankle_Right;
public GameObject Foot_Right;
private GameObject[] _bones; //internal handle for the bones of the model
//private Vector4[] _bonePos; //internal handle for the bone positions from the kinect
public int player;
public BoneMask Mask = BoneMask.All;
// Use this for initialization
void Start () {
//store bones in a list for easier access
_bones = new GameObject[(int)Kinect.NuiSkeletonPositionIndex.Count] {Hip_Center, Spine, Shoulder_Center, Head,
Shoulder_Left, Elbow_Left, Wrist_Left, Hand_Left,
Shoulder_Right, Elbow_Right, Wrist_Right, Hand_Right,
Hip_Left, Knee_Left, Ankle_Left, Foot_Left,
Hip_Right, Knee_Right, Ankle_Right, Foot_Right};
//_bonePos = new Vector4[(int)BoneIndex.Num_Bones];
}
// Update is called once per frame
void Update () {
Vector3 leftHand = new Vector3(0,0,0);
Vector3 rightHand = new Vector3(0,0,0);
Vector3 HipCenter = new Vector3(0,0,0);
Vector3 HeadCenter = new Vector3(0,0,0);
Vector3 FootLeft = new Vector3(0,0,0);
Vector3 FootRight = new Vector3(0,0,0);
//update all of the bones positions
if (sw.pollSkeleton())
{
Debug.Log("Has Track\n");
for( int ii = 0; ii < (int)Kinect.NuiSkeletonPositionIndex.Count; ii++)
{
//_bonePos[ii] = sw.getBonePos(ii);
if( ((uint)Mask & (uint)(1 << ii) ) > 0 ){
_bones[ii].transform.localPosition = sw.bonePos[player,ii];
}
//hip center
if(ii == 0)
{
HipCenter = _bones[ii].transform.localPosition;
// Debug.Log("Hip: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//head center
if(ii == 3)
{
HeadCenter = _bones[ii].transform.localPosition;
// Debug.Log("Head: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//foot left
if(ii == 15)
{
FootLeft = _bones[ii].transform.localPosition;
// Debug.Log("LeftFoot: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
if(ii == 19)
{
FootRight = _bones[ii].transform.localPosition;
// Debug.Log("RightFoot: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//Right hand
if(ii == 11)
{
rightHand = _bones[ii].transform.localPosition;
// Debug.Log("RightHand: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
//left hand
if(ii == 7)
{
leftHand = _bones[ii].transform.localPosition;
// Debug.Log("LeftHand: x " + _bones[ii].transform.localPosition.x.ToString() + " y " +
// _bones[ii].transform.localPosition.y.ToString() + " z " +_bones[ii].transform.localPosition.z.ToString());
}
}
//Event.KeyboardEvent("w");
//Car.throttle = 0.5f;
//Car.throttle = 0;
//Car.steer = 0;
//left hand y+z >2 ;right hand y+z <2 右转
if ((leftHand.y + leftHand.z > 2) && (rightHand.y + leftHand.z < 2))
{
//右转
Car.steer = 1f;
//Car.throttle = 0.5f;
Debug.Log("Right Turn\n");
}
if ((leftHand.y + leftHand.z < 2) && (rightHand.y + leftHand.z > 2))
{
//左转
Car.steer = -1f;
//Car.throttle = 0.5f;
Debug.Log("Left Turn\n");
}
/* 倒车-》后倾;油门-》前倾 */
if ((HeadCenter.x > HipCenter.x + 0.06))
{
Debug.Log("UPUP\n");
Car.throttle = Car.throttle + 0.015f;
if (Car.throttle > 1)
Car.throttle = 1;
}
if ((HeadCenter.x < HipCenter.x) && (FootRight.x < HipCenter.x))
{
Debug.Log("DOWNdown\n");
Car.throttle = Car.throttle - 0.015f;
if (Car.throttle < -1)
Car.throttle = -1;
}
Debug.Log("CS-thro " + Car.throttle);
Debug.Log("CS-stee " + Car.steer);
}
else
{
Car.throttle = 0f;
Debug.Log("Not Track--Down\n");
}
}
}
相关文章推荐
- Kinect with Unity3D游戏开发的一点思路总结(体感赛车游戏)
- 赛车游戏开发总结
- 赛车游戏开发总结PHYSX OGRE
- 赛车游戏开发总结
- 开发飞机游戏总结
- OGRE+Physx赛车游戏开发
- android围棋游戏开发第四周总结
- [原创]我对类似QQ游戏数据采集和发送程序的一点思路
- 创享 共赢 戴尔2010在线游戏开发与CPU及GPU研讨会归来【总结】【图】
- 11月21日 iPhone 游戏开发技术聚会 总结
- 一点总结,手机应用开发前景
- 魅族M8游戏框架开发的思路及方法,同样适用于WinCE设备的游戏开发。
- vc++中利用ado和listcontrol控件进行数据库应用开发的一点总结
- 游戏开发总结
- 关于网站开发文件编码的一点总结[转]
- 关于java开发邮件接收程序的一点总结
- 开发手机游戏的一点心得(一)
- 开发手机游戏的一点心得(二)
- 关于DNN Module开发学习以来的一点总结
- 本周ASP.NET开发中的一点总结