html5体感游戏开发,使用HTML5开发Kinect体感游戏
npm install kinect2
四、實例演示
說什么都不如給我一個例子!
如下圖所示,我們演示如何獲取人體骨骼,并標識脊椎中段及手勢:
1、服務器端
創建web服務器,并將骨骼數據發送到瀏覽器端,代碼如下:
var Kinect2 = require('../../lib/kinect2'),
express = 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){}); //還有哪些數據類型呢?
2、骨骼節點類型
body.joints[11] // joints包括哪些呢?
4、骨骼數據
body [object] {
bodyIndex [number]:索引,允許6人
joints [array]:骨骼節點,包含坐標信息,顏色信息
leftHandState [number]:左手手勢
rightHandState [number]:右手手勢
tracked [boolean]:是否捕獲到
trackingId
}
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.2、接投影儀后,如果渲染面積比較大,會出現白屏,需要關閉瀏覽器硬件加速。
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、結合移動設備,太可以挖掘的東西了……想想都激動不是么!
評論
總結
以上是生活随笔為你收集整理的html5体感游戏开发,使用HTML5开发Kinect体感游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Go Atomic
- 下一篇: 【最优化导论】一维搜索方法