"use strict";
+var b2Vec2 = yf.argcd(
+ function (a) {
+ return b2Vec2.call(this, a[0] || a.x || 0.0, a[1] || a.y || 0.0);
+ },
+ Box2D.b2Vec2
+);
+
+
+yf.ipairs(function (k, v) { Box2D[k] = Box2D[v]; }, {
+ DYNAMIC_BODY: 'b2_dynamicBody'
+});
+
+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, {
+ 0: { alias: 'x' },
+ 1: { alias: 'y' },
+});
+
+
var storage;
-var PlayerController = new yT(yuu.C, {
- constructor: function (body, left, right) {
+var BodyC = yT(yuu.C, {
+ SLOTS: ['transform'],
+
+ constructor: function (body, size) {
+ this.body = body;
+ this._matrix = mat4.create();
+ },
+
+ position: { alias: 'body.position' },
+ angle: { alias: 'body.angle' },
+ linearVelocity: { alias: 'body.linearVelocity' },
+ ApplyForce: { proxy: 'body.ApplyForce' },
+
+ matrix: { get: function () {
+ var mat = this._matrix;
+ mat4.identity(mat);
+ 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, 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;
- this.leftPivot = 0;
- this.rightPivot = 0;
- this.x = this.lastX = body.x;
- this.y = this.lastY = body.y;
+ this.free = 0;
this.commands = {
dleftLeft: yuu.propcmd(this, 'dleftLeft'),
dleftRight: yuu.propcmd(this, 'dleftRight'),
drightLeft: yuu.propcmd(this, 'drightLeft'),
drightRight: yuu.propcmd(this, 'drightRight'),
up: yuu.propcmd(this, 'up'),
+ free: yuu.propcmd(this, 'free'),
};
},
_updatePivots: function () {
- var PIVOT_SPEED = 0.03;
- var leftSpeed = (this.dleftRight - this.dleftLeft) * PIVOT_SPEED;
- var rightSpeed = (this.drightLeft - this.drightRight) * PIVOT_SPEED;
- this.leftPivot = yf.clamp(this.leftPivot + leftSpeed, 0, 1);
- this.rightPivot = yf.clamp(this.rightPivot + rightSpeed, 0, 1);
+ var PIVOT_SPEED = 2;
+ this.leftJoint.motorSpeed =
+ (this.dleftRight - this.dleftLeft) * PIVOT_SPEED;
+ this.rightJoint.motorSpeed =
+ (this.drightRight - this.drightLeft) * PIVOT_SPEED;
},
_updateTransforms: function () {
- this.left.yaw = -this.leftPivot * Math.PI / 2;
- this.right.yaw = this.rightPivot * Math.PI / 2;
- this.body.x = this.x;
- this.body.y = this.y;
},
tick: function () {
this._updatePivots();
- var dt = 0.016;
- var GRAVITY = 1;
- var DRAG_MAX = 1;
- var LIFT_MAX = 1;
-
-
- var left = (1 - this.leftPivot) * Math.PI / 2;
- var right = (1 - this.rightPivot) * Math.PI / 2;
-
- var vx = (this.x - this.lastX) / dt;
- var vy = (this.y - this.lastY) / dt;
-
- var rotor = 1 * this.up;
-
- var cleft = Math.cos(left);
- var cright = Math.cos(right);
- var sleft = Math.sin(left);
- var sright = Math.sin(right);
-
- var dvyleft = sleft * rotor;
- var dvyright = sright * rotor;
- var dvxleft = cleft * rotor;
- var dvxright = cright * rotor;
-
- var dvx = (dvxleft - dvxright);
- var dvy = (dvyleft + dvyright) - GRAVITY;
-
- var leftarea = DRAG_MAX * Math.abs(sleft);
- var rightarea = DRAG_MAX * Math.abs(sright);
- var dragy = vy * vy * (leftarea + rightarea);
-
- leftarea = DRAG_MAX * Math.abs(cleft);
- rightarea = DRAG_MAX * Math.abs(cright);
- var dragx = vx * vx * (leftarea + rightarea);
-
- leftarea = LIFT_MAX * Math.abs(cleft);
- rightarea = LIFT_MAX * Math.abs(cright);
- var liftx = vy * vy * (rightarea - leftarea);
-
- leftarea = LIFT_MAX * Math.abs(sleft);
- rightarea = LIFT_MAX * Math.abs(sright);
- var lifty = vx * vx * (rightarea - leftarea);
-
- if (vy > 0) {
- dragy = -dragy;
- liftx = -liftx;
- }
- if (vx > 0) {
- dragx = -dragx;
- lifty = -lifty;
- }
-
- var ax = dvx + liftx + dragx;
- var ay = dvy + lifty + dragy;
-
- var origX = this.x;
- var origY = this.y;
- this.x += (this.x - this.lastX) + ax * dt * dt;
- this.y += (this.y - this.lastY) + ay * dt * dt;
- this.y = Math.max(0, this.y);
- this.lastX = origX;
- this.lastY = origY;
+ var THRUST = 3.5;
+/* var DRAG_FREE = 0.01;
+ var DRAG_OPEN = 0.5;
+ var DRAG_LOCK = 1;
+ var CORRECTION = 1;*/
+
+ var leftAngle = this.leftJoint.GetJointAngle();
+ var rightAngle = this.rightJoint.GetJointAngle();
+ var thrust = +!this.free * +this.up * THRUST;
+ var leftThrust = new b2Vec2(
+ Math.sin(leftAngle) * thrust, Math.cos(leftAngle) * thrust);
+ var rightThrust = new b2Vec2(
+ Math.sin(rightAngle) * thrust, Math.cos(rightAngle) * thrust);
+ this.body.body.ApplyForceToCenter(leftThrust);
+ this.body.body.ApplyForceToCenter(rightThrust);
+
+ /*
+ var v = this.body.linearVelocity;
+ var drag = this.up ? DRAG_OPEN : this.free ? DRAG_FREE : DRAG_LOCK;
+ ax += drag * Math.max(cleft, cright) * v.x * v.x * -Math.sign(v.x);
+ ay += drag * (sleft + sright) * v.y * v.y * -Math.sign(v.y);
+
+ if (!this.up || this.free)
+ ax += CORRECTION * (cleft - cright) * v.y * v.y * Math.sign(v.y);
+ */
+
this._updateTransforms();
},
TAPS: ['tick'],
});
+function bodyFromAABB (world, position, aabb, density, center) {
+ var dfn = new Box2D.b2BodyDef();
+ var shape = new Box2D.b2PolygonShape();
+ if (center)
+ shape.SetAsBox(aabb.hw, aabb.hh, new b2Vec2(center), 0);
+ else
+ shape.SetAsBox(aabb.hw, aabb.hh);
+ if (density !== undefined)
+ dfn.type = Box2D.DYNAMIC_BODY;
+ dfn.position = new b2Vec2(position[0], position[1]);
+ var body = world.CreateBody(dfn);
+ body.CreateFixture(shape, density || 0.0001);
+ return body;
+}
+
+function bodyFromLine (world, p0, p1) {
+ var dfn = new Box2D.b2BodyDef();
+ var shape = new Box2D.b2EdgeShape();
+ shape.Set(new b2Vec2(p0), new b2Vec2(p1));
+ var body = world.CreateBody(dfn);
+ body.CreateFixture(shape, 0);
+ return body;
+}
+
+function pinJoint (world, bodyA, bodyB, anchor) {
+ var dfn = new Box2D.b2RevoluteJointDef();
+ dfn.Initialize(bodyA, bodyB, new b2Vec2(anchor));
+ dfn.maxMotorTorque = 100.0;
+ dfn.motorSpeed = 0.1;
+ dfn.enableMotor = true;
+ return Box2D.castObject(world.CreateJoint(dfn), Box2D.b2RevoluteJoint);
+}
+
var GameScene = yT(yuu.Scene, {
constructor: function () {
yuu.Scene.call(this);
- this.layer0.resize(-1.3333333333/2, -0.2, 1.3333333333, 1);
+ var zoom = 10;
+ this.layer0.resize(
+ zoom * -1.3333333333/2, zoom * -0.2, zoom * 1.3333333333, zoom * 1);
+
+ var world = new Box2D.b2World(new b2Vec2(0, -5));
var body, left, right;
- this.player = new yuu.E(body = new yuu.Transform()
- .setScale([0.081, 0.091, 1]),
- new yuu.QuadC('@player')
- .setAnchor('bottom')
- .setPosition([0, 0]));
- var leftWing = new yuu.E(left = new yuu.Transform()
- .setPosition([-0.3, 0.65, 0])
- .setScale([0.45, 0.22, 1]),
- new yuu.QuadC('@left')
- .setZ(-1)
- .setAnchor("right")
- .setPosition([0, 0]));
- var rightWing = new yuu.E(right = new yuu.Transform()
- .setPosition([0.3, 0.65, 0])
- .setScale([0.45, 0.22, 1]),
- new yuu.QuadC('@right')
- .setZ(-1)
- .setAnchor('left')
- .setPosition([0, 0]));
+ this.player = new yuu.E(
+ body = new BodyC(bodyFromAABB(
+ world, [0, 5], new yuu.AABB(0.89, 1.0), 1.0)),
+ new yuu.QuadC('@player')
+ .setSize([0.89, 1.0])
+ );
+
+ var leftWing = new yuu.E(
+ left = new BodyC(bodyFromAABB(
+ world, [-0.275, 5.15], new yuu.AABB(0.45, 0.22), 0,
+ [-0.45/2, 0.0])),
+ new yuu.QuadC('@left')
+ .setAnchorAtPosition("right")
+ .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), 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);
- var ground = new yuu.E(new yuu.Transform()
- .setPosition([0, -10, 1])
- .setScale([100, 20, 1]),
- new yuu.QuadC()
- .setColor([0, 0.5, 0, 1]));
+ var ground = new yuu.E(
+ new BodyC(bodyFromLine(world, [-100, 0], [100, 0])),
+ new yuu.QuadC()
+ .setAnchorAtPosition('top')
+ .setSize([100, 1])
+ .setColor([0, 0.5, 0, 1]));
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, 8, 8);
+ return true;
+ }, 1));
+
this.ready = yuu.ready([
new yuu.Material('@player'),
new yuu.Material('@left'),
w: '+dleftRight',
o: '+drightLeft',
p: '+drightRight',
+ z: '+free',
+ x: '+up',
}
});