Attach wings via physics engine (they're now... odd.)
authorJoe Wreschnig <joe.wreschnig@gmail.com>
Thu, 18 Sep 2014 13:41:40 +0000 (15:41 +0200)
committerJoe Wreschnig <joe.wreschnig@gmail.com>
Thu, 18 Sep 2014 13:41:40 +0000 (15:41 +0200)
New auto-wrapping approach.

src/main.js
src/yuu/core.js

index debe1b5b6343b888f8ebabf4594b946f55241a31..ecff045199e696e668da38e7b431df441ce53f0a 100644 (file)
@@ -12,33 +12,47 @@ yf.ipairs(function (k, v) { Box2D[k] = Box2D[v]; }, {
     DYNAMIC_BODY: 'b2_dynamicBody'
 });
 
-function accessor (T, p) {
-    if (p[0].toLowerCase() === p[0])
-        return { get: T.prototype['get_' + p],
-                 set: T.prototype['set_' + p] };
-    else
-        return { get: T.prototype['Get' + p],
-                 set: T.prototype['Set' + p] };
+function camelizeCase (s) {
+    return s.replace(/_([a-z])/g, function (m) {
+        return m[1].toUpperCase();
+    });
 }
 
+function wrapEmscriptenType (T) {
+    var P = T.prototype;
+    var keys = Object.keys(P);
+    var members = keys.filter(function (k) { return k.startsWith("get_"); });
+    var accessors = keys.filter(function (k) { return k.startsWith("Get"); });
+    members.forEach(function (k) {
+        var name = camelizeCase(k.slice(4));
+        if (!name || name in P) return;
+        Object.defineProperty(P, name, {
+            get: P[k], set: P['s' + k.slice(1)]
+        });
+            
+    });
+    accessors.forEach(function (k) {
+        var name = k.slice(3);
+        name = name[0].toLowerCase() + name.slice(1);
+        if (!name || name in P) return;
+        Object.defineProperty(P, name, {
+            get: P[k], set: P['S' + k.slice(1)]
+        });
+            
+    });
+}
+
+yf.each(wrapEmscriptenType, [
+    Box2D.b2Vec2, Box2D.b2BodyDef, Box2D.b2Body,
+    Box2D.b2JointDef, Box2D.b2RevoluteJointDef,
+    Box2D.b2Joint, Box2D.b2DistanceJoint, Box2D.b2RevoluteJoint,
+]);
+
 yT.defineProperties(Box2D.b2Vec2.prototype, {
-    x: accessor(Box2D.b2Vec2, 'x'),
-    y: accessor(Box2D.b2Vec2, 'y'),
     0: { alias: 'x' },
     1: { alias: 'y' },
 });
 
-yT.defineProperties(Box2D.b2BodyDef.prototype, {
-    type: accessor(Box2D.b2BodyDef, 'type'),
-    position: accessor(Box2D.b2BodyDef, 'position'),
-});
-
-yT.defineProperties(Box2D.b2Body.prototype, {
-    position: accessor(Box2D.b2Body, 'Position'),
-    linearVelocity: accessor(Box2D.b2Body, 'LinearVelocity'),
-    angle: accessor(Box2D.b2Body, 'Angle'),
-});
-
 
 var storage;
 
@@ -46,29 +60,31 @@ var BodyC = yT(yuu.C, {
     SLOTS: ['transform'],
 
     constructor: function (body, size) {
-        this._body = body;
+        this.body = body;
         this._matrix = mat4.create();
     },
 
-    position: { alias: '_body.position' },
-    linearVelocity: { alias: '_body.linearVelocity' },
-    ApplyForce: { proxy: '_body.ApplyForce' },
+    position: { alias: 'body.position' },
+    linearVelocity: { alias: 'body.linearVelocity' },
+    ApplyForce: { proxy: 'body.ApplyForce' },
 
     matrix: { get: function () {
         var mat = this._matrix;
         mat4.identity(mat);
-        mat4.rotateZ(mat, mat, this._body.angle);
-        var pos = this._body.position;
+        var pos = this.body.position;
         mat4.translate(mat, mat, [pos.x, pos.y, 0]);
+        mat4.rotateZ(mat, mat, this.body.angle);
         return mat;
     } }
 });
 
 var PlayerController = yT(yuu.C, {
-    constructor: function (body, left, right) {
+    constructor: function (body, left, right, leftJoint, rightJoint) {
         this.body = body;
         this.left = left;
         this.right = right;
+        this.leftJoint = leftJoint;
+        this.rightJoint = rightJoint;
         this.dleftLeft = this.dleftRight = 
             this.drightLeft = this.drightRight = 0;
         this.up = 0;
@@ -94,8 +110,13 @@ var PlayerController = yT(yuu.C, {
     },
 
     _updateTransforms: function () {
-        this.left.yaw = -this.leftPivot * Math.PI / 2;
-        this.right.yaw = this.rightPivot * Math.PI / 2;
+        var gain = 1.0;
+        var leftTarget = this.leftPivot * Math.PI / 2;
+        var rightTarget = -this.rightPivot * Math.PI / 2;
+        var leftError = this.leftJoint.jointAngle - leftTarget;
+        var rightError = this.rightJoint.jointAngle - rightTarget;
+        this.leftJoint.motorSpeed = -gain * leftError;
+        this.rightJoint.motorSpeed = -gain * rightError;
     },
 
     tick: function () {
@@ -137,7 +158,7 @@ var PlayerController = yT(yuu.C, {
 function bodyFromAABB (world, position, aabb, density) {
     var bd = new Box2D.b2BodyDef();
     var shape = new Box2D.b2PolygonShape();
-    shape.SetAsBox(aabb.w / 2, aabb.h / 2);
+    shape.SetAsBox(aabb.hw, aabb.hh);
     if (density)
         bd.type = Box2D.DYNAMIC_BODY;
     bd.position = new b2Vec2(position[0], position[1]);
@@ -155,6 +176,15 @@ function bodyFromLine (world, p0, p1) {
     return body;
 }
 
+function pinJoint (world, bodyA, bodyB, anchor) {
+    var dfn = new Box2D.b2RevoluteJointDef();
+    dfn.Initialize(bodyA, bodyB, new b2Vec2(anchor));
+    dfn.maxMotorTorque = 10.0;
+    dfn.motorSpeed = 0.0;
+    dfn.enableMotor = true;
+    return Box2D.castObject(world.CreateJoint(dfn), Box2D.b2RevoluteJoint);
+}
+
 var GameScene = yT(yuu.Scene, {
     constructor: function () {
         yuu.Scene.call(this);
@@ -173,20 +203,18 @@ var GameScene = yT(yuu.Scene, {
                 .setSize([0.89, 1.0])
         );
 
-        var leftWing = new yuu.E(left = new yuu.Transform()
-                                 .setPosition([-0.25, 0.15, 0]),
-                                 new yuu.QuadC('@left')
-                                 .setZ(-1)
-                                 .setAnchor("right")
-                                 .setSize([0.45, 0.22])
-                                 .setPosition([0, 0]));
-        var rightWing = new yuu.E(right = new yuu.Transform()
-                                  .setPosition([0.25, 0.15, 0]),
-                                  new yuu.QuadC('@right')
-                                  .setZ(-1)
-                                  .setAnchor('left')
-                                  .setSize([0.45, 0.22])
-                                  .setPosition([0, 0]));
+        var leftWing = new yuu.E(left = new BodyC(
+            bodyFromAABB(world, [-0.50, 5.15], new yuu.AABB(0.45, 0.22), 1.0)),
+            new yuu.QuadC('@left')
+                .setZ(-1)
+                .setSize([0.45, 0.22]));
+        var leftJoint = pinJoint(world, left.body, body.body, [-0.1, 5.15]);
+        var rightWing = new yuu.E(right = new BodyC(
+            bodyFromAABB(world, [0.50, 5.15], new yuu.AABB(0.45, 0.22), 1.0)),
+            new yuu.QuadC('@right')
+                .setZ(-1)
+                .setSize([0.45, 0.22]));
+        var rightJoint = pinJoint(world, right.body, body.body, [0.1, 5.15]);
         this.player.addChildren(leftWing, rightWing);
         this.entity0.addChild(this.player);
 
@@ -199,11 +227,12 @@ var GameScene = yT(yuu.Scene, {
         this.entity0.addChild(ground);
 
         this.player.attach(
-            this.controller = new PlayerController(body, left, right));
+            this.controller = new PlayerController(body, left, right,
+                                                  leftJoint, rightJoint));
         Object.assign(this.commands, this.controller.commands);
 
         this.entity0.attach(new yuu.Ticker(function () {
-            world.Step(1/60, 4, 4);
+            world.Step(1/60, 8, 8);
             return true;
         }, 1));
 
index b526131c6f1ec2d4ea90217c721ca918df1eb5ce..1923d2cdf700086f60fd3997d1251794ed2faf33 100644 (file)
 
         size: { swizzle: "wh" },
 
+        hw: { get: function () { return this.w / 2; } },
+        hh: { get: function () { return this.h / 2; } },
+
         contains: yf.argcd(
             function (p) { return this.contains(p.x, p.y); },
             function (x, y) {