diff --git a/public/js/starbugs/main.js b/public/js/starbugs/main.js index 8c1b369..2a0bf56 100644 --- a/public/js/starbugs/main.js +++ b/public/js/starbugs/main.js @@ -18,11 +18,13 @@ class Game { this.connected = false; this.state = 'connecting'; + this.pingMode = 'fast'; this.input = new Input(); this.net = new Net(); this.world = new World(); this.renderer = new Renderer(); + this.player = new Player(); } tick() { @@ -30,9 +32,10 @@ class Game { var ship = this.world ? this.world.playerShip : false; - if(ship) { - ship.move = [87, 65, 68].map(k => this.input.keys.held[k] || false); - ship.updateMove(); + if(this.player.ship) { + let delta = this.player.packDelta(); + if (delta) + game.net.sendUpdate(delta); } this.input.clear(); diff --git a/public/js/starbugs/net.js b/public/js/starbugs/net.js index 0619a2b..95b580e 100644 --- a/public/js/starbugs/net.js +++ b/public/js/starbugs/net.js @@ -23,15 +23,14 @@ class Net { this.socket.on('world', function(data) { game.world.clear(); - game.world.playerShipId = data.playerShipId; game.world.bounds = data.bounds; for (var i in data.bodies) { game.world.add(data.bodies[i]); } + game.world.setPlayerShip(data.playerShipId); }); this.socket.on('create', function(data) { - console.log(data.id); game.world.add(data); }); @@ -40,12 +39,8 @@ class Net { }); }; - update(move) { - this.socket.emit('move', { - forward: move[0], - left: move[1], - right: move[2] - }); + sendUpdate(inputs) { + this.socket.emit('inputs', inputs); } send(msg, data) { diff --git a/public/js/starbugs/player.js b/public/js/starbugs/player.js new file mode 100644 index 0000000..814e081 --- /dev/null +++ b/public/js/starbugs/player.js @@ -0,0 +1,19 @@ +class Player { + constructor(name, team, ship) { + this.name = name; + this.team = team; + this.ship = ship; + + this.lastInputs = []; + } + + packDelta() { + // W, A, D, Space + let inputs = [87, 65, 68]; + inputs = inputs.map(k => game.input.keys.held[k] || false); + inputs[3] = game.input.keys.pressed[32] || false; + let delta = this.lastInputs == inputs ? false : inputs; + this.lastInputs = inputs; + return delta; + } +} diff --git a/public/js/starbugs/render/body.js b/public/js/starbugs/render/body.js new file mode 100644 index 0000000..84e7213 --- /dev/null +++ b/public/js/starbugs/render/body.js @@ -0,0 +1,25 @@ +Renderer.prototype.renderBody = (pallet, body) => { + var pos = body.getPos(); + var x = pos.x * SCALE; + var y = pos.y * SCALE; + var vx = -game.world.getCenter().x; + var vy = -game.world.getCenter().y; + + 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]); + } + context.closePath(); + context.lineWidth = 0.5; + context.strokeStyle = '#fff'; + context.fillStyle = '#200'; + context.fill(); + context.stroke(); + + pallet.restore(); +}; diff --git a/public/js/starbugs/render/render.js b/public/js/starbugs/render/render.js index e5ff49c..cbcfdcf 100644 --- a/public/js/starbugs/render/render.js +++ b/public/js/starbugs/render/render.js @@ -66,6 +66,7 @@ class Renderer { } else if (body.bodyType == 'asteroid') { this.renderAsteroid(pallet, body); } else { + this.renderBody(pallet, body); // Render structures, projectiles etc.. } } diff --git a/public/js/starbugs/world/missile.js b/public/js/starbugs/world/missile.js new file mode 100644 index 0000000..914057d --- /dev/null +++ b/public/js/starbugs/world/missile.js @@ -0,0 +1,14 @@ +class Missile extends Body { + constructor(data) { + super(data); + this.bodyType = 'missile'; + } + + updateType() { + + } + + tick() { + + } +} diff --git a/public/js/starbugs/world/physics.js b/public/js/starbugs/world/physics.js index 6ea5c55..e92263f 100644 --- a/public/js/starbugs/world/physics.js +++ b/public/js/starbugs/world/physics.js @@ -19,12 +19,14 @@ class Physics { let bodyDef = new b2BodyDef(); bodyDef.userData = body; bodyDef.position = new b2Vec2(body.x || 0, body.y || 0); + bodyDef.angle = body.r || 0; bodyDef.fixedRotation = false; bodyDef.active = true; bodyDef.linearVelocity = new b2Vec2(0, 0); bodyDef.angularVelocity = 0; - bodyDef.linearDamping = body.bodyType == 'ship' ? 0.01 : 0.003; - bodyDef.angularDamping = body.bodyType == 'ship' ? 0.01 : 0.003; + bodyDef.bullet = body.type == 'missile'; + bodyDef.linearDamping = body.bodyType == 'asteroid' ? 0.003 : 0.01; + bodyDef.angularDamping = body.bodyType == 'asteroid' ? 0.003 : 0.01; bodyDef.type = body.bodyType == 'structure' ? b2Body.b2_staticBody : b2Body.b2_dynamicBody; bodyDef.allowSleep = false; diff --git a/public/js/starbugs/world/player.js b/public/js/starbugs/world/player.js deleted file mode 100644 index b4e2214..0000000 --- a/public/js/starbugs/world/player.js +++ /dev/null @@ -1,7 +0,0 @@ -class Player { - constructor(name, team, ship) { - this.name = name; - this.team = team; - this.ship = ship; - } -} diff --git a/public/js/starbugs/world/ship.js b/public/js/starbugs/world/ship.js index 0f4f6ca..aad32bf 100644 --- a/public/js/starbugs/world/ship.js +++ b/public/js/starbugs/world/ship.js @@ -5,7 +5,6 @@ class Ship extends Body { this.team = data.team; this.name = data.name; this.hull = '01'; - this.move = []; this.thrust = {}; this.power = data.power; this.mounts = data.mounts; @@ -19,13 +18,6 @@ class Ship extends Body { this.bodyType = 'ship'; } - updateMove() { - if (JSON.stringify(this.move) != JSON.stringify(this.lastMove) || true) { - game.net.update(this.move); - this.lastMove = Array.apply(0, this.move); // Bloody Javascript. - } - } - updateType(data) { this.thrust = { forward: data[6] @@ -33,18 +25,18 @@ class Ship extends Body { } tick() { - if (this.move[0]) { + if (this.thrust.forward) { var power = this.power.forward; var x = Math.cos(this.getPos().r) * power; var y = Math.sin(this.getPos().r) * power; this.applyForce(x, y); } - if (this.move[1]) { + if (this.thrust.left) { this.applyTorque(-this.power.rotation); } - if (this.move[2]) { + if (this.thrust.right) { this.applyTorque(this.power.rotation); } } diff --git a/public/js/starbugs/world/world.js b/public/js/starbugs/world/world.js index 3066e81..7bebc08 100644 --- a/public/js/starbugs/world/world.js +++ b/public/js/starbugs/world/world.js @@ -4,7 +4,6 @@ class World { constructor() { this.bodies = {}; this.playerShip = false; - this.playerShipId = false; this.physics = new Physics(); this.bounds = { @@ -37,6 +36,7 @@ class World { if (data.type == 'asteroid') body = new Asteroid(data); 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(data.type == 'ship') console.log(body); @@ -59,8 +59,6 @@ class World { }; update(data) { - this.playerShip = this.bodies[this.playerShipId]; - for (var id in data) { if (!this.bodies[id]) { game.net.send('requestBodyData', id); @@ -74,6 +72,11 @@ class World { } }; + setPlayerShip(id) { + this.playerShip = this.bodies[id]; + game.player.ship = this.playerShip; + } + tick() { this.physics.step(); diff --git a/server/game/net/connection.js b/server/game/net/connection.js index a639c6b..a702726 100644 --- a/server/game/net/connection.js +++ b/server/game/net/connection.js @@ -22,8 +22,8 @@ class Connection { this.player.name = data.name.slice(0, 20) || 'Fish'; }); - socket.on('move', data => { - this.player.move(data); + socket.on('inputs', data => { + this.player.updateInputs(data); }); this.server.assignRoom(this.player); diff --git a/server/game/player.js b/server/game/player.js index 2fbab38..f1954e0 100644 --- a/server/game/player.js +++ b/server/game/player.js @@ -18,12 +18,8 @@ class Player { this.room.remove(this); } - move(data) { - this.ship.move({ - forward: data.forward || 0, - left: data.left || 0, - right: data.right || 0 - }); + updateInputs(data) { + this.ship.updateInputs(data); this.lastAction = Date.now(); } diff --git a/server/game/room/world/asteroid.js b/server/game/room/world/asteroid.js index a724f0b..4ab542a 100644 --- a/server/game/room/world/asteroid.js +++ b/server/game/room/world/asteroid.js @@ -8,9 +8,10 @@ class Asteroid extends Body { this.x = pos.x; this.y = pos.y; - this.type = 'asteroid'; this.size = size; + + this.type = 'asteroid'; this.frame = this.randomFrame(); } diff --git a/server/game/room/world/body.js b/server/game/room/world/body.js index cd7f0e6..2e12490 100644 --- a/server/game/room/world/body.js +++ b/server/game/room/world/body.js @@ -37,6 +37,11 @@ class Body { if(pos.x > bounds.right) this.applyForce(-0.03, 0); if(pos.y < bounds.top) this.applyForce(0, 0.03); if(pos.y > bounds.bottom) this.applyForce(-0, -0.03); + + this.tickType(); + } + + tickType() { } packDelta() { @@ -50,11 +55,24 @@ class Body { } packTypeDelta() { - throw new Error('Attempt to pack raw body.'); } packFull() { - throw new Error('Attempt to pack raw body.'); + } + + get center() { + return { + x: this.b2body.GetWorldCenter().x, + y: this.b2body.GetWorldCenter().y + }; + } + + get pos() { + return { + x: this.b2body.GetPosition().x, + y: this.b2body.GetPosition().y, + r: this.b2body.GetAngleRadians() + }; } } diff --git a/server/game/room/world/index.js b/server/game/room/world/index.js index dc98331..b947989 100644 --- a/server/game/room/world/index.js +++ b/server/game/room/world/index.js @@ -1,15 +1,17 @@ 'use strict'; -const Asteroid = require('./asteroid.js'); const Physics = require('./physics.js'); const Ship = require('./ship.js'); +const Spawner = require('./spawner.js'); class World { constructor(room) { this.physics = new Physics(); + this.spawner = new Spawner(this); this.bodies = new Set(); this.structures = new Set(); this.asteroids = new Set(); + this.missiles = new Set(); this.ships = new Map(); this.players = new Set(); this.room = room; @@ -48,6 +50,11 @@ class World { this.addBody(asteroid); } + addMissile(missile) { + this.missiles.add(missile); + this.addBody(missile); + } + addBody(body) { this.bodies.add(body); this.physics.createBody(body); @@ -64,8 +71,7 @@ class World { x: Math.random() * 2000 - 200, y: Math.random() * 500 - 250 }; - let asteroid = new Asteroid(this, pos, Math.random() * 50 + 10); - this.addAsteroid(asteroid); + this.spawner.spawnAsteroid(pos.x, pos.y,Math.random() * 50 + 10); } } @@ -76,11 +82,12 @@ class World { } removeBody(body) { - this.physics.toRemove.push(body); + this.physics.remove(body); this.bodies.delete(body); this.ships.delete(body); this.structures.delete(body); this.asteroids.delete(body); + this.missiles.delete(body); this.room.broadcast('destroy', body.id); } @@ -95,23 +102,23 @@ class World { tick(self) { self.physics.step(); - self.ships.forEach(body => { - body.applyDelta(), - body.tick(); - }); - - if (this.tickCount % 1 == 0) { - self.asteroids.forEach(body => { - body.applyDelta(), + let tickBodies = (set, interval) => { + set.forEach(body => { + if (this.tickCount % interval == 0) + body.applyDelta(); body.tick(); }); + }; - if (Date.now() - this.tpsStart > 5000) { - this.tps = this.tpsCount / 5 | 0; - this.tpsCount = 0; - this.tpsStart = Date.now(); - //console.log('TPS: ' + this.tps); - } + tickBodies(self.ships, 1); + tickBodies(self.asteroids, 4); + tickBodies(self.missiles, 1); + + if (Date.now() - this.tpsStart > 5000) { + this.tps = this.tpsCount / 5 | 0; + this.tpsCount = 0; + this.tpsStart = Date.now(); + //console.log('TPS: ' + this.tps); } this.tpsCount++; diff --git a/server/game/room/world/missile.js b/server/game/room/world/missile.js index 4f3fb37..be57bec 100644 --- a/server/game/room/world/missile.js +++ b/server/game/room/world/missile.js @@ -1,15 +1,21 @@ 'use strict'; -const Body = require('./bodies.js'); +const Body = require('./body.js'); class Missile extends Body { - constructor(world, source) { + constructor(world, pos, source) { super(world); + this.x = pos.x * 32; + this.y = pos.y * 32; + this.r = pos.r; + this.source = source; this.player = source.player; + this.fuel = 100; - this.frame = [[[0, 0], [0, 10], [3, 10], [3, 0]]]; + this.type = 'missile'; + this.frame = [[[0, 0], [10, 0], [10, 3], [0, 3]]]; } detonate() { @@ -17,6 +23,16 @@ class Missile extends Body { this.world.removeBody(this); } + tickType() { + let power = 0.005; + let x = Math.cos(this.b2body.GetAngleRadians()) * power; + let y = Math.sin(this.b2body.GetAngleRadians()) * power; + this.applyForce(x, y); + + if(this.fuel-- <= 0) + this.detonate(); + } + packTypeDelta() { return []; } @@ -26,11 +42,10 @@ class Missile extends Body { type: 'missile', id: this.id, source: this.source.id, - team: this.player.team, frame: this.frame, delta: this.packDelta() }; } } -module.exports = Projectile; +module.exports = Missile; diff --git a/server/game/room/world/physics.js b/server/game/room/world/physics.js index ff72c11..1db2004 100644 --- a/server/game/room/world/physics.js +++ b/server/game/room/world/physics.js @@ -37,12 +37,14 @@ class Physics { let bodyDef = new Box2D.b2BodyDef(); bodyDef.userData = body; bodyDef.position = new b2Vec2(body.x / s || 0, body.y / s || 0); + bodyDef.angle = body.r || 0; bodyDef.fixedRotation = false; bodyDef.active = true; bodyDef.linearVelocity = new b2Vec2(body.xvel / s || 0, body.yvel / s || 0); bodyDef.angularVelocity = body.rvel || 0; - bodyDef.linearDamping = body.type == 'ship' ? 0.01 : 0.003; - bodyDef.angularDamping = body.type == 'ship' ? 0.01 : 0.003; + bodyDef.bullet = body.type == 'missile'; + bodyDef.linearDamping = body.type == 'asteroid' ? 0.003 : 0.01; + bodyDef.angularDamping = body.type == 'asteroid' ? 0.003 : 0.01; bodyDef.type = body.type == 'structure' ? Box2D.b2BodyType.b2_staticBody : Box2D.b2BodyType.b2_dynamicBody; if (body.player || true) bodyDef.allowSleep = false; @@ -64,6 +66,10 @@ class Physics { //if (body.type == 'ship') console.log(b2body.GetLocalCenter()); } + remove(body) { + this.toRemove.push(body); + } + step() { this.world.Step(1, 5, 1 / 60); for (var i = 0; i < this.toRemove.length; i++) { diff --git a/server/game/room/world/ship.js b/server/game/room/world/ship.js index 132cab0..dd8fcbe 100644 --- a/server/game/room/world/ship.js +++ b/server/game/room/world/ship.js @@ -19,6 +19,7 @@ class Ship extends Body { this.size = traits.size; this.player = player; this.type = 'ship'; + this.inputs = {}; this.thrust = { forward: 0, @@ -27,35 +28,40 @@ class Ship extends Body { } } - move(data) { - let b = this.b2body; + updateInputs(data) { + this.inputs = { + forward: data[0], + left: data[1], + right: data[2], + missile: data[3] + }; - //console.log(b.GetLocalCenter()); + this.thrust.forward = this.inputs.forward; + this.thrust.left = this.inputs.left; + this.thrust.right = this.inputs.right; - for(var i in b) { - //if(typeof b[i] == 'function') console.log(i); - } + if (this.inputs.missile) this.launchMissile(); + } - if (data.forward) { + launchMissile() { + this.world.spawner.spawnMissile(this); + } + + tickType() { + if (this.thrust.forward) { let power = this.power.forward; let x = Math.cos(this.b2body.GetAngleRadians()) * power; let y = Math.sin(this.b2body.GetAngleRadians()) * power; this.applyForce(x, y); } - if (data.left) { + if (this.thrust.left) { this.applyTorque(-this.power.rotation); } - if (data.right) { + if (this.thrust.right) { this.applyTorque(this.power.rotation); } - - this.thrust = { - forward: data.forward, - left: data.left, - right: data.right - }; } packTypeDelta() { diff --git a/server/game/room/world/spawner.js b/server/game/room/world/spawner.js new file mode 100644 index 0000000..1408781 --- /dev/null +++ b/server/game/room/world/spawner.js @@ -0,0 +1,34 @@ +'use strict'; + +const Asteroid = require('./asteroid.js'); +const Missile = require('./missile.js'); + +class Spawner { + constructor(world) { + this.world = world; + } + + spawnAsteroid(x, y, size) { + let pos = { + x: x, + y: y + }; + let asteroid = new Asteroid(this.world, pos, size); + this.world.addAsteroid(asteroid); + } + + spawnMissile(ship) { + let r = ship.pos.r; + let ox = Math.cos(r) * 0.7; + let oy = Math.sin(r) * 0.7; + let pos = { + x: ship.center.x + ox, + y: ship.center.y + oy, + r: r + }; + let missile = new Missile(this.world, pos, ship); + this.world.addMissile(missile); + } +} + +module.exports = Spawner;