HTML5开发Kinect体感游戏的实例应用

网友投稿 320 2023-04-02


HTML5开发Kinect体感游戏的实例应用

HTML5开发Kinect体感游戏的实例应用

一、简介

我们要做的是怎样一款游戏?

在前不久成都TGC2016展会上,我们开发了一款《火影忍者手游》的体感游戏,主要模拟手游章节《九尾袭来 》,用户化身四代,与九尾进行对决,吸引了大量玩家参与。 表面上看,这款游戏与其它体感体验无异,实际上,它一直运行于浏览器Chrome下,也就是说,我们只需要掌握前端相应技术,就可以开发基于Kinect的网页体感游戏。

二、实现原理

实现思路是什么?

使用H5开发基于Kinect的体感游戏,其实工作原理很简单,由Kinect采集到玩家及环境数据,比如人体骨骼,使用某种方式,使浏览器可以访问这些数据。

1、采集数据

Kinect有三个镜头,中间镜头类似普通摄像头,获取彩色图像。左右两边镜头则是通过红外线获取深度数据。我们使用微软提供的SDK去读取以下类型数据:

色彩数据:彩色图像;

深度数据:颜色尝试信息;

人体骨骼数据:基于以上数据经计算,获取到人体骨骼数据。

2、使浏览器可访问到Kinect数据

我尝试和了解过的框架,基本上是以socket让浏览器进程与服务器进行通信 ,进行数据传输:

Kinect-HTML5 用C#搭建服务端,色彩数据、尝试数据、骨骼数据均有提供;

ZigFu 支持H5、U3D、Flash进行开发,API较为完整,貌似收费;

Depthjs  以浏览器插件形式提供数据访问;

Node-Kinect2 以Nodejs搭建服务器端,提供数据比较完整,实例较多。

Kinect: 捕获玩家数据,比如深度图像、彩色图像等;

Node-Kinect2: 从Kinect获取相应数据,并进行二次加工;

浏览器: 监听node应用指定接口,获取玩家数据并完成游戏开发。

三、准备工作

先得买个Kinect啊

1、系统要求:

这是硬性要求,我曾在不符合要求的环境下浪费太多时间。

USB3.0

支持DX11的显卡

win8及以上系统

支持Web Sockets的浏览器

当然Kinect v2传感器是少不了的

2、环境搭建流程:

连接上Kinect v2

安装 KinectSDK-v2.0

安装 Nodejs

安装 Node-Kinect2

npm install kinect2

四、实例演示

说什么都不如给我一个例子!

1、服务器端

创建web服务器,并将骨骼数据发送到浏览器端,代码如下:

var Kinect2 = require('../../lib/kinect2'),

exprehttp://ss = require('express'),

app = express(),

server = require('http').createServer(app),

io = require('socket.io').listen(server);

var kinect = new Kinect2();

// 打开kinect

if(kinect.open()) {

// 监听8000端口

server.listen(8000);

// 指定请求指向根目录

app.get('/', function(req, res) {

res.sendFile(__dirname + '/public/index.html');

});

// 将骨骼数据发送给浏览器端

kinect.on('bodyFrame', function(bodyFrame){

io.sockets.emit('bodyFrame', bodyFrame);

});

// 开始读取骨骼数据

kinect.openBodyReader();

}

2、浏览器端

浏览器端获取骨骼数据,并用canvas描绘出来,关键代码如下:

var socket = io.connect('/');

var ctx = canvas.getContext('2d');

socket.on('bodyFrame', function(bodyFrame){

ctx.clearRect(0, 0, canvas.width, canvas.height);

var index = 0;

// 遍历所有骨骼数据

bodyFrame.bodies.forEach(function(body){

if(body.tracked) {

for(var jointType in body.joints) {

var joint = body.joints[jointType];

ctx.fillStyle = colors[index];

// 如果骨骼节点为脊椎中点

if(jointType == 1) {

ctx.fillStyle = colors[2];

}

ctx.fillRect(joint.depthX * 512, joint.depthY * 424, 10, 10);

}

// 识别左右手手势

updateHandState(body.leftHandState, body.joints[7]);

updateHandState(body.rightHandState, body.joints[11]);

index++;

}

});

});

很简单的几行代码,我们便完成了玩家骨骼捕获,有一定 javascript基础的同学应该很容易能看明白,但不明白的是我们能获取哪些数据?如何获取?骨骼节点名称分别是什么?而node-kienct2并没有文档告诉我们这些。

五、开发文档

Node-Kinect2并没有提供文档,我将我测试总结的文档整理如下:

1、服务器端能提供的数据类型;

kinect.on('bodyFrame', function(bodyFrame){}); //还有哪些数据类型呢?

bodyFrame

骨骼数据

infraredFrame

红外数据

longExposureInfraredFrame

类似infraredFrame,貌似精度更高,优化后的数据

rawDepthFrame

未经处理的景深数据

depthFrame

景深数据

colorFrame

彩色图像

multiSourceFrame

所有数据

audio

音频数据,未测试

2、骨骼节点类型

body.joints[11] // joints包括哪些呢?

节点类型

JointType

节点名称

0

spineBase

脊椎基部

1

spineMid 

脊椎中部

2

neck

颈部

3

head

头部

4

shoulderLeft

左肩

5

elbowLeft

左肘

6

wristLeft

左腕

7

handLeft

左手掌

8

shoulderRight

右肩

9

elbowRight

右肘

10

wristRight

右腕

11

handRight

右手掌

12

hipLeft

左屁

13

kneeLeft

左膝

14

ankleLeft

左踝

15

footLeft

左脚

16

hipRight

右屁

17

kneeRight

右膝

18

ankleRight

右踝

19

footRight

右脚

20

spineShoulder

颈下脊椎

21

handTipLeft

左手指(食中无小)

22

thumbLeft

左拇指

23

handTipRight

右手指

24

thumbRight

右拇指

3、手势,据测识别并不是太准确,在精度要求不高的情况下使用

0

unknown

不能识别

1

notTracked

未能检测到

2

open

手掌

3

closed

握拳

4

lasso

剪刀手,并合并中食指

4、骨骼数据

body [object] {

bodyIndex [number]:索引,允许6人

joints [array]:骨骼节点,包含坐标信息,颜色信息

leftHandState [number]:左手手势

rightHandState [number]:右手手势

tracked [boolean]:是否捕获到

trackingId

}

5、kinect对象

on

监听数据

open

打开Kinect

close

关闭

openBodyReader

读取骨骼数据

open**Reader

类似如上方法,读取其它类型数据

六、实战总结

火影体感游戏经验总结

接下来,我总结一下TGC2016《火影忍者手游》的体感游戏开发中碰到的一些问题。

1、讲解之前,我们首先需要了解下游戏流程。

2、服务器端

游戏需要玩家骨骼数据(移动、手势),彩色图像数据(某一手势下触发拍照),所以我们需要向客户端发送这两部分数据。值得注意的是,彩色图像数据体积过大,需要进行压缩。

var emitColorFrame = false;

io.sockets.on('connection', function (socket){

socket.on('startColorFrame', function(data){

emitColorFrame = true;

});

});

kinect.on('multiSourceFrame', function(frame){

// 发送玩家骨骼数据

io.sockets.emit('bodyFrame', frame.body);

// 玩家拍照

if(emitColorFrame) {

var compression = 1;

var origWidth = 1920;

var origHeight = 1080;

var origLength = 4 * origWidth * origHeight;

var compressedWidth = origWidth / compression;

var compressedHeight = origHeight / compression;

var resizedLength = 4 * compressedWidth * compressedHeight;

var resizedBuffer = new Buffer(resizedLength);

// ...

// 照片数据过大,需要压缩提高传输性能

zlib.deflate(resizedBuffer, function(err, result){

if(!err) {

var buffer = result.toString('base64');

io.sockets.emit('colorFrame', buffer);

}

});

emitColorFrame = false;

}

});

kinect.openMultiSourceReader({

frameTypes: Kinect2.FrameType.body | Kinect2.FrameType.color

});

3、客户端

客户端业务逻辑较复杂,我们提取关键步骤进行讲解。

3.1、用户拍照时,由于处理的数据比较大,为防止页面出现卡顿,我们需要使用web worker

(function(){

importScripts('pako.inflate.min.js');

var imageData;

function init() {

addEventListener('message', function (event) {

switch (event.data.message) {

case "setImageData":

imageData = event.data.imageData;

break;

case "processImageData":

processImageData(event.data.imageBuffer);

break;

}

});

}

function processImageData(compressedData) {

var imageBuffer = pako.inflate(atob(compressedData));

var pixelArray = imageData.data;

var newPixelData = new Uint8Array(imageBuffer);

var imageDataSize = imageData.data.length;

for (var i = 0; i < imageDataSize; i++) {

imageData.data[i] = newPixelData[i];

}

for(var x = 0; x < 1920; x++) {

for(var y = 0; y < 1080; y++) {

var idx = (x + y * 1920) * 4;

var r = imageData.data[idx + 0];

var g = imageData.data[idx + 1];

var b = imageData.data[idx + 2];

}

}

self.postMessage({ "message": "imageReady", "imageData": imageData });

}

init();

})();

3.3、现场光线较暗,其它玩家干扰,在追踪玩家运动轨迹的过程中,可能会出现抖动的情况,我们需要去除干扰数据。(当突然出现很大位移时,需要将数据移除)

var tracks = this.tracks;

var len = tracks.length;

// 数据过滤

if(tracks[len-1] !== window.undefined) {

if(Math.abs(n - tracks[len-1]) > 0.2) {

return;

}

}

this.tracks.push(n);

3.4、当玩家站立,只是左右少量晃动时,我们认为玩家是站立状态。

// 保留5个数据

if(this.tracks.length > 5) {

this.tracks.shift();

} else {

return;

}

// 位移总量

var dis = 0;

for(var i = 1; i < this.tracks.length; i++) {

dis += this.tracks[i] - this.tracks[i-1];

}

if(Math.abs(dis) < 0.01) {

this.stand();

} else {

if(this.tracks[4] > this.tracks[3]) {

this.turnRight();

} else {

this.turnLeft();

}

this.run();

}

七、展望

1、使用HTML5开发Kinect体感游戏,降低了技术门槛,前端工程师可以轻松的开发体感游戏;

2、大量的框架可以应用,比如用jquery、CreateJS、Three.js(三种不同渲染方式);

3、无限想象空间,试想下体感游戏结合webAR,结合webAudio、结合移动设备,太可以挖掘的东西了……想想都激动不是么!

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:前端常见跨域解决方案(全)
下一篇:接口测试用例参数组合(接口测试用例包含哪些内容)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~