improve grappling hook physics and rendering
This commit is contained in:
parent
4753f879e5
commit
663305bd23
11 changed files with 129 additions and 55 deletions
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -22,6 +22,8 @@ class Ship extends Body {
|
||||||
this.thrust = {
|
this.thrust = {
|
||||||
forward: data[6]
|
forward: data[6]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.debug = data[9];
|
||||||
}
|
}
|
||||||
|
|
||||||
tick() {
|
tick() {
|
||||||
|
|
|
@ -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() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"power": {
|
"power": {
|
||||||
"forward": 0.015,
|
"forward": 0.015,
|
||||||
"back": 0,
|
"back": 0,
|
||||||
"rotation": 0.001
|
"rotation": 0.003
|
||||||
},
|
},
|
||||||
"hull": [
|
"hull": [
|
||||||
[
|
[
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue