您的位置:首页 > 移动开发 > Unity3D

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");

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: