2013年7月31日水曜日

LeapMotion と box2dweb でブラウザアプリ

先日うちの会社にもやってきました。LeapMotion

leapjs (http://js.leapmotion.com/) を読み込むことでブラウザJSでも使えます。
サンプルもいくつか出てます。↓
http://js.leapmotion.com/examples

ということで、js物理演算ライブラリのbox2dWeb に reap motion を繋いでみます。
指二本で動かします。


デモはこちら (対応してないブラウザだったらごめんなさい)

ソースコードはこちら

ということで要点だけ

参考サイト

box2dwebとleapのjsファイルを読み込む

<script type="text/javascript" src="js/libs/Box2dWeb-2.1.a.3.min.js"></script>
<script type="text/javascript" src="js/libs/leapjs/leap.js"></script>

box2dwebの初期化

var world = new this.b2World(
 new this.b2Vec2(0, 20)    //gravity
 ,true                 //allow sleep
);
this.world = world;
 
 //setup debug draw
var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
var debugDraw = new b2DebugDraw();
debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
debugDraw.SetDrawScale(30.0);
debugDraw.SetFillAlpha(0.5);
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
 
var self = this;
window.setInterval(function(){
 self._update();
}, 1000 / 60);

適当に円をつくる

setInterval(function(){
 self.createCircle();
}, 500);

LeapApp.prototype.createCircle = function(data){
 var fixDef = new this.b2FixtureDef;
 fixDef.density = 1.0;
 fixDef.friction = 0.5;
 fixDef.restitution = 0.2;

 var bodyDef = new this.b2BodyDef;
 bodyDef.type = this.b2Body.b2_dynamicBody;
 fixDef.shape = new this.b2CircleShape(
  Math.random() + 0.1 //radius
 );

 bodyDef.position.x = Math.random() * 20;
 bodyDef.position.y = Math.random() * 5;

 var body = this.world.CreateBody(bodyDef);
 body.CreateFixture(fixDef);
 var ImpulseVec = new this.b2Vec2(10-(Math.random() * 20), - (Math.random() * 10));
 var point = body.GetPosition();
 body.ApplyImpulse(ImpulseVec, point);

 this.circleList.push(body);
};

leapのイベントを拾う

leap.jsをよみこむと Leapがいるのでそいつにコールバックを登録します。

Leap.loop({enableGestures: false}, function(frame){
 self._leapLoop(frame);
});

二本指検出

ここにはいってくる「frame」オブジェクトの解説は
KRAY -JavaScriptでLeapMotionアプリを作る方法-
が分かりやすい。KRAYさんありがとう!

LeapApp.prototype._leapLoop = function(frame){
 // pointable filter 
    var pointables = frame.pointables;
    var pointablesCount = pointables.length;
    if(pointablesCount < 2){
     this.world.DestroyBody(this.fingerLine);
     this.rightFinger.SetActive(false);
     this.leftFinger.SetActive(false);
     return;
 }

    var leftPoint, rightPoint;
    if(pointables[0].tipPosition[0] < pointables[1].tipPosition[0]){
     leftPoint = pointables[0].tipPosition;
     rightPoint = pointables[1].tipPosition;
    }else{
     rightPoint = pointables[0].tipPosition;
     leftPoint = pointables[1].tipPosition;
    }

     this._reloadLine(leftPoint, rightPoint); // ↓
};

leapから取り出した指位置情報をbox2dwebに表示する

LeapApp.prototype._reloadLine = function(leftPoint, rightPoint){
 var rate = 10;
 var baseX = 100;
 var baseY = 250;

 // left
 var leftX = leftPoint[0];
 var leftY = leftPoint[1];
 var leftFinger = this.leftFinger;
 var leftPos = leftFinger.GetPosition();
 leftPos.x = (leftX+baseX) / rate;
 leftPos.y = (30-(leftY - baseY)) / rate;
 leftFinger.SetPosition(leftPos);
 leftFinger.SetActive(true);

 // right
 var rightX = rightPoint[0];
 var rightY = rightPoint[1];
 var rightFinger = this.rightFinger;
 var rightPos = rightFinger.GetPosition();
 rightPos.x = (rightX+baseX) / rate;
 rightPos.y = (30-(rightY - baseY)) /rate;
 rightFinger.SetPosition(rightPos);
 rightFinger.SetActive(true);

 // line
 var lenX = rightPos.x-leftPos.x;
 var lenY = rightPos.y-leftPos.y;
 var lineLen = Math.sqrt(Math.pow(lenX, 2) + Math.pow(lenY, 2));
 var rad = Math.atan2(lenY, lenX);

 var fingerLine = this.fingerLine;
 var linePos = fingerLine.GetPosition();
 this.world.DestroyBody(fingerLine);

 var fixDef = new this.b2FixtureDef;
 var bodyDef = new this.b2BodyDef;
 var shape = new this.b2PolygonShape;
 fixDef.shape = shape;
 shape.SetAsBox(lenX/2, 0.2);
 var fingerLine = this.world.CreateBody(bodyDef);
 fingerLine.SetPosition(linePos);
 fingerLine.CreateFixture(fixDef);
 this.fingerLine = fingerLine;

 var linePos = fingerLine.GetPosition();
 linePos.x = leftPos.x + lenX/2;
 linePos.y = leftPos.y + lenY/2;
 fingerLine.SetPositionAndAngle(linePos, rad);
};

以上です。

まとめ

良いと思います。
今回はbox2dWebの実装がちょっと長くなってしまいましたが、LeapMotion のところだけで見ると
leap.jsを読み込んで Leap.loop(op, func); でコールバックを登録するだけで指情報が取得できます。
デバイスが必要になるので一般のwebサイトで使用する機会はあまりないかもしれませんが、キャンペーンページみたいなものでちょっと変わったことしたい、ってときには使えるんじゃないでしょうか。

ネイティブアプリのSDKにもjavascriptを選択できるようです。
LEAP Developer -documentation-
やっぱりこーなるとiphoneアプリとつなげたいですね。
appleさん頑張ってー、使えるようにしてー。
もうleap を買収しちゃえ

jsの開発環境はクロムが最強な気がします。何よりも手軽。
こないだ書いた cocos2dx javascript Bindings みたいなのも出てるし
クロムで開発してそのままネイティブへ移行
的なフローが早く確立しますように。

そんなLeapMotionに興味のある(なくてもOK)デザイナー募集中!

現在スバコラボではデザイナーを【爆裂】で【激求】しています。
お気軽にご応募ください
ご応募はこちらから

0 件のコメント:

コメントを投稿