improve grappling hook physics and rendering

This commit is contained in:
Asraelite 2016-03-27 02:22:49 +01:00
parent 4753f879e5
commit 663305bd23
11 changed files with 129 additions and 55 deletions

View file

@ -4,14 +4,17 @@ class Effect {
this[i] = data[i]; this[i] = data[i];
} }
this.pos.x;
this.pos.y;
this.particles = new Set(); this.particles = new Set();
this.pallet = game.renderer.pallet; this.pallet = game.renderer.pallet;
if (this.type == 'explosion') { if (this.type == 'explosion') {
this.createExplosion(); this.createExplosion();
} else if (this.type == 'rope') {
this.createRope();
this.pos = {
x: 0,
y: 0
};
} else { } else {
} }
@ -44,10 +47,29 @@ class Effect {
p.tick(); p.tick();
}); });
if (this.particles.size == 0) { if (this.particles.size == 0 && !this.keepAlive) {
game.renderer.effects.delete(this); game.renderer.effects.delete(this);
} }
rope: if (this.type == 'rope') {
let bd = game.world.bodies;
if (!bd[this.bodyA.id] || !bd[this.bodyB.id]) {
this.keepAlive = false;
break rope;
}
let p1 = this.posA;
let p2 = this.posB;
let posA = this.bodyA.b2body.GetWorldPoint(new b2Vec2(p1.x, p1.y));
let posB = this.bodyB.b2body.GetWorldPoint(new b2Vec2(p2.x, p2.y));
let context = this.pallet.context;
context.beginPath();
context.moveTo(posA.x * SCALE, posA.y * SCALE);
context.lineTo(posB.x * SCALE, posB.y * SCALE);
context.strokeStyle = '#555';
context.stroke();
}
this.pallet.restore(); this.pallet.restore();
} }
@ -59,4 +81,12 @@ class Effect {
let b = 'sizzle'; let b = 'sizzle';
this.generateParticles(0, 0, 1, num, colors, [1, 2], b, 50, 3); this.generateParticles(0, 0, 1, num, colors, [1, 2], b, 50, 3);
} }
createRope() {
this.bodyA = game.world.bodies[this.bodyA];
this.bodyB = game.world.bodies[this.bodyB];
if (!this.bodyA || !this.bodyB) return;
this.keepAlive = true;
}
} }

View file

@ -25,6 +25,10 @@ Renderer.prototype.renderShip = (pallet, ship) => {
pallet.image(img, 0, 0, 0); pallet.image(img, 0, 0, 0);
pallet.image(ship.thrust.forward ? thr8 : thr0, 0, 0, 0); pallet.image(ship.thrust.forward ? thr8 : thr0, 0, 0, 0);
if (ship.debug) {
pallet.square('#f00', ship.debug.x * SCALE, ship.debug.y * SCALE, 2);
}
pallet.restore(); pallet.restore();
//pallet.text(ship.name, x + vx | 0, y + vy | 0, '#fff', 'FreePixel', 16, 'center', 'bottom'); //pallet.text(ship.name, x + vx | 0, y + vy | 0, '#fff', 'FreePixel', 16, 'center', 'bottom');

View file

@ -28,7 +28,7 @@ class Physics {
bodyDef.angularVelocity = 0; bodyDef.angularVelocity = 0;
bodyDef.bullet = body.type == 'missile'; bodyDef.bullet = body.type == 'missile';
bodyDef.linearDamping = body.bodyType == 'asteroid' ? 0.003 : 0.01; bodyDef.linearDamping = body.bodyType == 'asteroid' ? 0.003 : 0.01;
bodyDef.angularDamping = body.bodyType == 'asteroid' ? 0.003 : 0.01; bodyDef.angularDamping = body.bodyType == 'asteroid' ? 0.003 : 0.04;
bodyDef.type = body.bodyType == 'structure' ? bodyDef.type = body.bodyType == 'structure' ?
b2Body.b2_staticBody : b2Body.b2_dynamicBody; b2Body.b2_staticBody : b2Body.b2_dynamicBody;
bodyDef.allowSleep = false; bodyDef.allowSleep = false;
@ -76,6 +76,7 @@ class Physics {
var r = 0.1; var r = 0.1;
var body = game.world.bodies[i]; var body = game.world.bodies[i];
var pos = body.getPos(); var pos = body.getPos();
if (Math.abs(body.r - pos.r) > 0.3) pos.r = body.r;
var x = (body.x * r + pos.x) / (r + 1); var x = (body.x * r + pos.x) / (r + 1);
var y = (body.y * r + pos.y) / (r + 1); var y = (body.y * r + pos.y) / (r + 1);
var r = (body.r * r + pos.r) / (r + 1); var r = (body.r * r + pos.r) / (r + 1);

View file

@ -22,6 +22,8 @@ class Ship extends Body {
this.thrust = { this.thrust = {
forward: data[6] forward: data[6]
} }
this.debug = data[9];
} }
tick() { tick() {

View file

@ -36,6 +36,14 @@ class Body {
this.b2body.ApplyTorque(f); this.b2body.ApplyTorque(f);
} }
setRotation(r) {
this.b2body.SetAngleRadians(r);
}
setVelocity(x, y) {
this.b2body.SetLinearVelocity(new b2Vec2(x, y));
}
contact() { contact() {
} }

View file

@ -12,8 +12,8 @@ class Grapple extends Projectile {
this.xvel = pos.xvel; this.xvel = pos.xvel;
this.yvel = pos.yvel; this.yvel = pos.yvel;
this.r = pos.r; this.r = pos.r;
this.xvel += Math.cos(this.r) * 0.4; this.xvel += Math.cos(this.r) * 0.25;
this.yvel += Math.sin(this.r) * 0.4; this.yvel += Math.sin(this.r) * 0.25;
this.welded = false; this.welded = false;
@ -22,8 +22,8 @@ class Grapple extends Projectile {
this.type = 'grapple'; this.type = 'grapple';
this.frame = [ this.frame = [
[[0, -8], [5, -12], [4, 0], [0, 0]], [[0, -8], [5, -12], [2, 0], [0, 0]],
[[0, 0], [4, 0], [5, 12], [0, 8]] [[0, 0], [2, 0], [5, 12], [0, 8]]
]; ];
} }
@ -39,24 +39,25 @@ class Grapple extends Projectile {
connect() { connect() {
let p1 = { x: 0, y: 0.5 }; let p1 = { x: 0, y: 0.5 };
let p2 = { x: 4, y: 0 }; let p2 = { x: 0.0625, y: 0 };
this.rope = new Rope(this.player.ship, this, p1, p2); this.rope = new Rope(this.player.ship, this, p1, p2);
this.rope.initLength = 6;
this.world.addCopula(this.rope); this.world.addCopula(this.rope);
this.rope.length = 5;
} }
contact(body, contact) { contact(body, contact) {
if (this.welded || body == this.source) if (this.welded || body == this.source)
return; return;
this.welded = true; let normal = this.world.physics.contactData(contact).worldNormal;
let normal = this.world.physics.contactData(contact).normal;
let angle = Math.atan2(normal.y, normal.x); let angle = Math.atan2(normal.y, normal.x);
this.b2body.SetAngleRadians(angle); this.setRotation(angle + Math.PI);
this.world.weld(this, body); this.b2body.SetAngularVelocity(0);
this.setVelocity(0, 0);
this.world.weld(this, body, { x: 0.15625, y: 0 });
this.welded = true;
} }
tickType() { tickType() {
} }
packTypeDelta() { packTypeDelta() {

View file

@ -89,7 +89,7 @@ class Ship extends Body {
packTypeDelta() { packTypeDelta() {
let t = this.thrust; let t = this.thrust;
return [t.forward, t.left, t.right]; return [t.forward, t.left, t.right, this.debug || false];
} }
packFull() { packFull() {

View file

@ -9,11 +9,23 @@ class Rope extends Copula {
} }
get length() { get length() {
return this.b2joint.GetMaxLength(); //return this.b2joint.GetMaxLength();
return 8;
} }
set length(len) { set length(len) {
this.b2joint.SetMaxLength(len); //this.b2joint.SetMaxLength(len);
}
packFull() {
return {
type: 'rope',
length: this.length,
bodyA: this.bodyA.id,
bodyB: this.bodyB.id,
posA: this.pointA,
posB: this.pointB
};
} }
} }

View file

@ -82,7 +82,7 @@ class World {
addCopula(copula) { addCopula(copula) {
this.copulae.add(copula); this.copulae.add(copula);
this.physics.createCopula(copula); this.physics.createCopula(copula);
this.room.broadcast('create', copula.packFull()); this.room.broadcast('effect', copula.packFull());
} }
applyDelta(body, data) { applyDelta(body, data) {
@ -138,8 +138,8 @@ class World {
this.room.broadcast('destroy', copula.id); this.room.broadcast('destroy', copula.id);
} }
weld(bodyA, bodyB) { weld(bodyA, bodyB, point) {
this.physics.weld(bodyA, bodyB); this.physics.weld(bodyA, bodyB, point);
} }
start() { start() {

View file

@ -21,20 +21,14 @@ class Physics {
this.world = new Box2D.b2World(new b2Vec2(0, 0), false); this.world = new Box2D.b2World(new b2Vec2(0, 0), false);
this.toRemove = []; this.toRemove = [];
this.toWeld = []; this.toWeld = [];
this.contacts = [];
this.idk = false;
let onContact = contact => { let onContact = contact => {
let bodya = contact.GetFixtureA().GetBody().GetUserData(); let bodya = contact.GetFixtureA().GetBody().GetUserData();
let bodyb = contact.GetFixtureB().GetBody().GetUserData(); let bodyb = contact.GetFixtureB().GetBody().GetUserData();
if (bodya) { this.contacts.push([bodya, bodyb, contact]);
bodya.applyDelta();
bodya.contact(bodyb. contact);
}
if (bodyb) {
bodyb.applyDelta();
bodyb.contact(bodya, contact);
}
} }
let listener = new Box2D.b2ContactListener(); let listener = new Box2D.b2ContactListener();
@ -58,7 +52,7 @@ class Physics {
bodyDef.angularVelocity = body.rvel || 0; bodyDef.angularVelocity = body.rvel || 0;
bodyDef.bullet = body.type == 'missile'; bodyDef.bullet = body.type == 'missile';
bodyDef.linearDamping = body.type == 'asteroid' ? 0.003 : 0.01; bodyDef.linearDamping = body.type == 'asteroid' ? 0.003 : 0.01;
bodyDef.angularDamping = body.type == 'asteroid' ? 0.003 : 0.01; bodyDef.angularDamping = body.type == 'asteroid' ? 0.003 : 0.04;
bodyDef.type = body.type == 'structure' ? bodyDef.type = body.type == 'structure' ?
Box2D.b2BodyType.b2_staticBody : Box2D.b2BodyType.b2_dynamicBody; Box2D.b2BodyType.b2_staticBody : Box2D.b2BodyType.b2_dynamicBody;
if (body.player || true) bodyDef.allowSleep = false; if (body.player || true) bodyDef.allowSleep = false;
@ -83,14 +77,18 @@ class Physics {
// TODO: Make this shorter somehow. // TODO: Make this shorter somehow.
createCopula(copula) { createCopula(copula) {
let s = SCALE;
if (copula.type == 'rope') { if (copula.type == 'rope') {
let b1 = copula.bodyA.b2body; let b1 = copula.bodyA.b2body;
let b2 = copula.bodyB.b2body; let b2 = copula.bodyB.b2body;
let p1 = copula.pointA; let p1 = new b2Vec2(copula.pointA.x, copula.pointA.y);
let p2 = copula.pointB; let p2 = new b2Vec2(copula.pointB.x, copula.pointB.y);
// See top of file. // See top of file.
let start = b1.GetWorldPoint(new b2Vec2(p1.x, p1.y), {}); let start = b1.GetWorldPoint(p1, {});
let end = b2.GetWorldPoint(new b2Vec2(p2.x, p2.y), {}); let end = b2.GetWorldPoint(p2, {});
copula.bodyA.debug = p1;
//copula.bodyB.debug = end;
let dx = start.x - end.x let dx = start.x - end.x
let dy = start.y - end.y; let dy = start.y - end.y;
let len = Math.sqrt(dx * dx + dy * dy); let len = Math.sqrt(dx * dx + dy * dy);
@ -98,10 +96,10 @@ class Physics {
let ropeDef = new Box2D.b2RopeJointDef(); let ropeDef = new Box2D.b2RopeJointDef();
ropeDef.bodyA = b1; ropeDef.bodyA = b1;
ropeDef.bodyB = b2; ropeDef.bodyB = b2;
ropeDef.maxLength = len; ropeDef.maxLength = copula.initLength || len;
ropeDef.collideConnected = true; ropeDef.collideConnected = true;
ropeDef.worldAnchorA = new b2Vec2(start); ropeDef.localAnchorA = p1;
ropeDef.worldAnchorB = new b2Vec2(end); ropeDef.localAnchorB = p2;
let b2joint = this.world.CreateJoint(ropeDef); let b2joint = this.world.CreateJoint(ropeDef);
copula.b2joint = b2joint; copula.b2joint = b2joint;
@ -109,17 +107,28 @@ class Physics {
} }
weld(bodyA, bodyB) { weld(bodyA, bodyB, point) {
this.toWeld.push([bodyA, bodyB]); let b1 = bodyA.b2body;
let b2 = bodyB.b2body;
let jointDef = new Box2D.b2WeldJointDef();
let anchor = b1.GetWorldPoint(new b2Vec2(point.x, point.y), {});
jointDef.bodyA = b1;
jointDef.bodyB = b2;
jointDef.collideConnected = true;
jointDef.localAnchorA = b1.GetLocalPoint(anchor, {});
jointDef.localAnchorB = b2.GetLocalPoint(anchor, {});
jointDef.localAnchorA = new b2Vec2(jointDef.localAnchorA.x, jointDef.localAnchorA.y);
jointDef.localAnchorB = new b2Vec2(jointDef.localAnchorB.x, jointDef.localAnchorB.y);
jointDef.referenceAngle = b2.GetAngleRadians() - b1.GetAngleRadians();
this.world.CreateJoint(jointDef);
} }
contactData(contact) { contactData(contact) {
let worldManifold = new Box2D.b2WorldManifold(); let worldManifold = new Box2D.b2WorldManifold();
contact.GetWorldManifold(worldManifold); contact.GetWorldManifold(worldManifold);
let localManifold = new Box2D.b2WorldManifold(); let localManifold = contact.GetManifold();
contact.GetManifold(localManifold);
let worldNormal = worldManifold.normal; let worldNormal = worldManifold.normal;
let normal = localManifold.normal; let normal = localManifold.localNormal;
return { return {
normal: normal, normal: normal,
@ -167,18 +176,25 @@ class Physics {
this.world.DestroyBody(this.toRemove[i].b2body); this.world.DestroyBody(this.toRemove[i].b2body);
} }
for (var i = 0; i < this.toWeld.length; i++) { this.toRemove = [];
let b1 = this.toWeld[i][0].b2body;
let b2 = this.toWeld[i][1].b2body; for (var i = 0; i < this.contacts.length; i++) {
let jointDef = new Box2D.b2WeldJointDef(); let contact = this.contacts[i][2];
jointDef.bodyA = b1; let bodya = this.contacts[i][0];
jointDef.bodyB = b2; let bodyb = this.contacts[i][1];
//jointDef.referenceAngle = b1.GetAngleRadians() - b2.GetAngleRadians();
this.world.CreateJoint(jointDef); if (bodya) {
bodya.applyDelta();
bodya.contact(bodyb, contact);
}
if (bodyb) {
bodyb.applyDelta();
bodyb.contact(bodya, contact);
}
} }
this.toRemove = []; this.contacts = [];
this.toWeld = [];
} }
} }

View file

@ -5,7 +5,7 @@
"power": { "power": {
"forward": 0.015, "forward": 0.015,
"back": 0, "back": 0,
"rotation": 0.001 "rotation": 0.003
}, },
"hull": [ "hull": [
[ [