diff --git a/public/js/wingbase/input.js b/public/js/wingbase/input.js index 068a167..3e867fc 100644 --- a/public/js/wingbase/input.js +++ b/public/js/wingbase/input.js @@ -4,7 +4,17 @@ class Input { x: 0, y: 0, held: {}, - pressed: {} + pressed: {}, + + get wx() { + let x = this.x + game.world.center.x; + return (x - game.renderer.canvas.width / 2) / SCALE; + }, + + get wy() { + let y = this.y + game.world.center.y; + return (y - game.renderer.canvas.height / 2) / SCALE; + } }; this.keys = { @@ -12,11 +22,15 @@ class Input { pressed: {} }; + this.mouse + document.addEventListener('mousemove', this.mouseMove.bind(this)); document.addEventListener('mousedown', this.mouseDown.bind(this)); document.addEventListener('mouseup', this.mouseUp.bind(this)); document.addEventListener('keydown', this.keyDown.bind(this)); document.addEventListener('keyup', this.keyUp.bind(this)); + + document.addEventListener('contextmenu', e => e.preventDefault()); } mouseMove() { diff --git a/public/js/wingbase/player.js b/public/js/wingbase/player.js index 814e081..f964c15 100644 --- a/public/js/wingbase/player.js +++ b/public/js/wingbase/player.js @@ -12,6 +12,10 @@ class Player { let inputs = [87, 65, 68]; inputs = inputs.map(k => game.input.keys.held[k] || false); inputs[3] = game.input.keys.pressed[32] || false; + inputs[4] = game.input.mouse.wx; + inputs[5] = game.input.mouse.wy; + inputs[6] = game.input.mouse.held[3]; + inputs[7] = game.input.mouse.pressed[1]; let delta = this.lastInputs == inputs ? false : inputs; this.lastInputs = inputs; return delta; diff --git a/public/js/wingbase/render/body.js b/public/js/wingbase/render/body.js index 84e7213..5b16aaa 100644 --- a/public/js/wingbase/render/body.js +++ b/public/js/wingbase/render/body.js @@ -8,18 +8,20 @@ Renderer.prototype.renderBody = (pallet, body) => { pallet.view(x + vx, y + vy, false, pos.r); var context = pallet.context; - var points = body.frame[0]; - context.beginPath(); - context.moveTo(points[0][0], points[0][1]); - for (var i = 1; i < points.length; i++) { - context.lineTo(points[i][0], points[i][1]); + var polys = body.frame; + for (var points of polys) { + context.beginPath(); + context.moveTo(points[0][0], points[0][1]); + for (var i = 1; i < points.length; i++) { + context.lineTo(points[i][0], points[i][1]); + } + context.closePath(); + context.lineWidth = 0.5; + context.strokeStyle = '#fff'; + context.fillStyle = '#200'; + context.fill(); + context.stroke(); } - context.closePath(); - context.lineWidth = 0.5; - context.strokeStyle = '#fff'; - context.fillStyle = '#200'; - context.fill(); - context.stroke(); pallet.restore(); }; diff --git a/public/js/wingbase/world/body.js b/public/js/wingbase/world/body.js index bf189f2..7185965 100644 --- a/public/js/wingbase/world/body.js +++ b/public/js/wingbase/world/body.js @@ -54,4 +54,8 @@ class Body { updateType() { } + + tick() { + + } } diff --git a/public/js/wingbase/world/world.js b/public/js/wingbase/world/world.js index 86a7bd2..bec6465 100644 --- a/public/js/wingbase/world/world.js +++ b/public/js/wingbase/world/world.js @@ -14,21 +14,9 @@ class World { } } + // Deprecated getCenter() { - if (!this.playerShip) return { x: 0, y: 0 }; - - var x = this.playerShip.getPos().x * SCALE; - var y = this.playerShip.getPos().y * SCALE; - var comx = this.playerShip.com.x * SCALE; - var comy = this.playerShip.com.y * SCALE; - var r = this.playerShip.getPos().r; - var d = Math.sqrt(comx * comx + comy * comy); - var a = Math.atan2(comy, comx); - - x += Math.cos(a + r) * d; - y += Math.sin(a + r) * d; - - return { x: x, y: y }; + return this.center; }; add(data) { @@ -37,6 +25,7 @@ class World { if (data.type == 'ship') body = new Ship(data); if (data.type == 'structure') body = new Structure(data); if (data.type == 'missile') body = new Missile(data); + if (!body) body = new Body(data); this.bodies[body.id] = body; this.physics.createBody(body); @@ -80,4 +69,21 @@ class World { this.bodies[i].tick(); } }; + + get center() { + if (!this.playerShip) return { x: 0, y: 0 }; + + let x = this.playerShip.getPos().x * SCALE; + let y = this.playerShip.getPos().y * SCALE; + let comx = this.playerShip.com.x * SCALE; + let comy = this.playerShip.com.y * SCALE; + let r = this.playerShip.getPos().r; + let d = Math.sqrt(comx * comx + comy * comy); + let a = Math.atan2(comy, comx); + + x += Math.cos(a + r) * d; + y += Math.sin(a + r) * d; + + return { x: x, y: y }; + } } diff --git a/server/game/room/world/body/body.js b/server/game/room/world/body/body.js index 8a6d5ec..a57f3bf 100644 --- a/server/game/room/world/body/body.js +++ b/server/game/room/world/body/body.js @@ -65,9 +65,15 @@ class Body { } packTypeDelta() { + return []; } packFull() { + return { + type: 'body', + id: this.id, + delta: this.packDelta() + } } get com() { diff --git a/server/game/room/world/body/projectile/grapple.js b/server/game/room/world/body/projectile/grapple.js index c026a4c..2f38ea0 100644 --- a/server/game/room/world/body/projectile/grapple.js +++ b/server/game/room/world/body/projectile/grapple.js @@ -1,7 +1,7 @@ 'use strict'; const Projectile = require('./projectile.js'); -const Rope = require('../copula/rope.js'); +const Rope = require('../../copula/rope.js'); class Grapple extends Projectile { constructor(world, pos, source) { @@ -12,12 +12,13 @@ class Grapple extends Projectile { this.xvel = pos.xvel; this.yvel = pos.yvel; this.r = pos.r; - this.xvel += Math.cos(this.r) * 0.2; - this.yvel += Math.sin(this.r) * 0.2; + this.xvel += Math.cos(this.r) * 0.4; + this.yvel += Math.sin(this.r) * 0.4; + + this.welded = false; this.source = source; this.player = source.player; - this.rope = new Rope(this, this); this.type = 'grapple'; this.frame = [ @@ -26,29 +27,36 @@ class Grapple extends Projectile { ]; } - contact(body) { - this.detonate(); - } - - detonate() { - this.world.explosion(this.center, 10); - this.world.room.broadcast('effect', { - type: 'explosion', - size: 10, - pos: this.center - }); + release() { + this.source.grapple = false; this.world.removeBody(this); } - tickType() { - let power = 0.004; - let x = Math.cos(this.b2body.GetAngleRadians()) * power; - let y = Math.sin(this.b2body.GetAngleRadians()) * power; - this.applyForce(x, y); + retract() { + if (this.rope.length > 0.05) + this.rope.length = this.rope.length - 0.1; + } + + connect() { + let p1 = { x: 0, y: 0.5 }; + let p2 = { x: 4, y: 0 }; + this.rope = new Rope(this.player.ship, this, p1, p2); + this.world.addCopula(this.rope); + this.rope.length = 5; + } + + contact(body, contact) { + if (this.welded || body == this.source) + return; + this.welded = true; + let normal = this.world.physics.contactData(contact).normal; + let angle = Math.atan2(normal.y, normal.x); + this.b2body.SetAngleRadians(angle); + this.world.weld(this, body); + } + + tickType() { - if(this.fuel-- <= 0) { - this.detonate(); - } } packTypeDelta() { @@ -57,7 +65,7 @@ class Grapple extends Projectile { packFull() { return { - type: 'missile', + type: 'grapple', id: this.id, source: this.source.id, frame: this.frame, @@ -66,4 +74,4 @@ class Grapple extends Projectile { } } -module.exports = Missile; +module.exports = Grapple; diff --git a/server/game/room/world/body/projectile/projectile.js b/server/game/room/world/body/projectile/projectile.js index 09e63c3..2d6d5ad 100644 --- a/server/game/room/world/body/projectile/projectile.js +++ b/server/game/room/world/body/projectile/projectile.js @@ -6,6 +6,10 @@ class Projectile extends Body { constructor(world) { super(world); } + + connect() { + + } } module.exports = Projectile; diff --git a/server/game/room/world/body/ship.js b/server/game/room/world/body/ship.js index 8447264..1782810 100644 --- a/server/game/room/world/body/ship.js +++ b/server/game/room/world/body/ship.js @@ -23,6 +23,7 @@ class Ship extends Body { this.player = player; this.type = 'ship'; this.inputs = {}; + this.grapple = false; this.thrust = { forward: 0, @@ -36,7 +37,11 @@ class Ship extends Body { forward: data[0], left: data[1], right: data[2], - missile: data[3] + missile: data[3], + mx: data[4], + my: data[5], + grapple: data[6], + release: data[7] }; this.thrust.forward = this.inputs.forward; @@ -44,12 +49,26 @@ class Ship extends Body { this.thrust.right = this.inputs.right; if (this.inputs.missile) this.launchMissile(); + if (this.inputs.grapple) { + if (this.grapple) { + this.grapple.retract(); + } else { + this.launchGrapple(this.inputs.mx, this.inputs.my); + } + } + if (this.inputs.release && this.grapple) { + this.grapple.release(); + } } launchMissile() { this.world.spawner.spawnMissile(this); } + launchGrapple(x, y) { + this.grapple = this.world.spawner.spawnGrapple(this, x, y); + } + tickType() { if (this.thrust.forward) { let power = this.power.forward; diff --git a/server/game/room/world/copula/copula.js b/server/game/room/world/copula/copula.js index a69b642..7befee6 100644 --- a/server/game/room/world/copula/copula.js +++ b/server/game/room/world/copula/copula.js @@ -7,6 +7,10 @@ class Copula { this.pointA = p1 || b1.com; this.pointB = p2 || b2.com; } + + packFull() { + return {}; + } } module.exports = Copula; diff --git a/server/game/room/world/copula/rope.js b/server/game/room/world/copula/rope.js index 82804e4..79a3ca6 100644 --- a/server/game/room/world/copula/rope.js +++ b/server/game/room/world/copula/rope.js @@ -3,19 +3,17 @@ const Copula = require('./copula.js'); class Rope extends Copula { - constructor(b1, b2) { - super(b1, b2); + constructor(b1, b2, p1, p2) { + super(b1, b2, p1, p2); this.type = 'rope'; - this._length = 0; } get length() { - return this._length; + return this.b2joint.GetMaxLength(); } set length(len) { - this.length = len; - this.b2joint.SetLength(len); + this.b2joint.SetMaxLength(len); } } diff --git a/server/game/room/world/index.js b/server/game/room/world/index.js index d4c25af..c473dca 100644 --- a/server/game/room/world/index.js +++ b/server/game/room/world/index.js @@ -14,7 +14,7 @@ class World { this.copulae = new Set(); this.structures = new Set(); this.asteroids = new Set(); - this.missiles = new Set(); + this.projectiles = new Set(); this.ships = new Map(); this.players = new Set(); this.room = room; @@ -67,9 +67,10 @@ class World { this.addBody(asteroid); } - addMissile(missile) { - this.missiles.add(missile); - this.addBody(missile); + addProjectile(projectile) { + this.projectiles.add(projectile); + this.addBody(projectile); + projectile.connect(); } addBody(body) { @@ -128,7 +129,7 @@ class World { this.ships.delete(body); this.structures.delete(body); this.asteroids.delete(body); - this.missiles.delete(body); + this.projectiles.delete(body); this.room.broadcast('destroy', body.id); } @@ -137,6 +138,10 @@ class World { this.room.broadcast('destroy', copula.id); } + weld(bodyA, bodyB) { + this.physics.weld(bodyA, bodyB); + } + start() { this.interval = setInterval(_ => this.tick(this), 1000 / 60); } @@ -158,7 +163,7 @@ class World { tickBodies(self.ships, 1); tickBodies(self.asteroids, 4); - tickBodies(self.missiles, 1); + tickBodies(self.projectiles, 1); if (Date.now() - this.tpsStart > 5000) { this.tps = this.tpsCount / 5 | 0; diff --git a/server/game/room/world/physics.js b/server/game/room/world/physics.js index c5c5aad..76b13b3 100644 --- a/server/game/room/world/physics.js +++ b/server/game/room/world/physics.js @@ -20,6 +20,7 @@ class Physics { constructor() { this.world = new Box2D.b2World(new b2Vec2(0, 0), false); this.toRemove = []; + this.toWeld = []; let onContact = contact => { let bodya = contact.GetFixtureA().GetBody().GetUserData(); @@ -27,12 +28,12 @@ class Physics { if (bodya) { bodya.applyDelta(); - bodya.contact(bodyb); + bodya.contact(bodyb. contact); } if (bodyb) { bodyb.applyDelta(); - bodyb.contact(bodya); + bodyb.contact(bodya, contact); } } @@ -88,9 +89,8 @@ class Physics { let p1 = copula.pointA; let p2 = copula.pointB; // See top of file. - let start = b1.GetWorldPoint(b1.GetLocalCenter(), {}); + let start = b1.GetWorldPoint(new b2Vec2(p1.x, p1.y), {}); let end = b2.GetWorldPoint(new b2Vec2(p2.x, p2.y), {}); - console.log(start, end); let dx = start.x - end.x let dy = start.y - end.y; let len = Math.sqrt(dx * dx + dy * dy); @@ -109,6 +109,24 @@ class Physics { } + weld(bodyA, bodyB) { + this.toWeld.push([bodyA, bodyB]); + } + + contactData(contact) { + let worldManifold = new Box2D.b2WorldManifold(); + contact.GetWorldManifold(worldManifold); + let localManifold = new Box2D.b2WorldManifold(); + contact.GetManifold(localManifold); + let worldNormal = worldManifold.normal; + let normal = localManifold.normal; + + return { + normal: normal, + worldNormal: worldNormal + }; + } + raycast(start, end) { let p1 = new b2Vec2(start.x, start.y); let p2 = new b2Vec2(end.x, end.y); @@ -149,7 +167,18 @@ class Physics { this.world.DestroyBody(this.toRemove[i].b2body); } + for (var i = 0; i < this.toWeld.length; i++) { + let b1 = this.toWeld[i][0].b2body; + let b2 = this.toWeld[i][1].b2body; + let jointDef = new Box2D.b2WeldJointDef(); + jointDef.bodyA = b1; + jointDef.bodyB = b2; + //jointDef.referenceAngle = b1.GetAngleRadians() - b2.GetAngleRadians(); + this.world.CreateJoint(jointDef); + } + this.toRemove = []; + this.toWeld = []; } } diff --git a/server/game/room/world/spawner.js b/server/game/room/world/spawner.js index 2f6f78a..731db72 100644 --- a/server/game/room/world/spawner.js +++ b/server/game/room/world/spawner.js @@ -1,6 +1,7 @@ 'use strict'; const Asteroid = require('./body/asteroid.js'); +const Grapple = require('./body/projectile/grapple.js'); const Missile = require('./body/projectile/missile.js'); class Spawner { @@ -29,7 +30,26 @@ class Spawner { yvel: ship.vel.y }; let missile = new Missile(this.world, pos, ship); - this.world.addMissile(missile); + this.world.addProjectile(missile); + return missile; + } + + spawnGrapple(ship, x, y) { + let sx = ship.center.x; + let sy = ship.center.y; + let dx = x - sx; + let dy = y - sy; + let a = Math.atan2(dy, dx); + let pos = { + x: sx + Math.cos(a) * 1, + y: sy + Math.sin(a) * 1, + r: a, + xvel: ship.vel.x, + yvel: ship.vel.y + }; + let grapple = new Grapple(this.world, pos, ship); + this.world.addProjectile(grapple); + return grapple; } }