From 33e2a65eb76a7ef0a15a2843d595cdf865210601 Mon Sep 17 00:00:00 2001 From: landgreen Date: Sun, 19 Jan 2020 07:46:23 -0800 Subject: [PATCH] rail gun balance (uses energy now) --- js/bullets.js | 438 +++++++++++++++++++++++++------------------------- js/index.js | 19 +-- js/level.js | 7 +- js/mobs.js | 10 +- 4 files changed, 230 insertions(+), 244 deletions(-) diff --git a/js/bullets.js b/js/bullets.js index 5b563b4..f3103c4 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -74,7 +74,7 @@ const b = { name: "depleted uranium rounds", //0 description: `your bullets are +13% larger
increased mass and physical damage`, count: 0, - maxCount: 33, + maxCount: 9, effect() { b.modBulletSize += 0.13 } @@ -119,7 +119,7 @@ const b = { { name: "high explosives", //15 description: "the radius of explosions are +20% larger
immune to harm from explosions", - maxCount: 1, + maxCount: 3, count: 0, effect: () => { b.modExplosionRadius += 0.2; @@ -129,7 +129,7 @@ const b = { { name: "auto-loading heuristics", //5 description: "your delay after firing is +12% shorter", - maxCount: 9, + maxCount: 5, count: 0, effect() { b.modFireRate *= 0.88 @@ -147,7 +147,7 @@ const b = { { name: "Lorentzian topology", //7 description: "your bullets last +33% longer", - maxCount: 9, + maxCount: 3, count: 0, effect() { b.isModBulletsLastLonger += 0.33 @@ -258,7 +258,7 @@ const b = { { name: "energy conservation", //18 description: "gain energy proportional to damage done", - maxCount: 9, + maxCount: 3, count: 0, effect() { b.modEnergySiphon += 0.15; @@ -268,7 +268,7 @@ const b = { { name: "entropy exchange", //19 description: "heal proportional to damage done", - maxCount: 9, + maxCount: 3, count: 0, effect() { b.modHealthDrain += 0.015; @@ -890,7 +890,7 @@ const b = { } }, }); - const SPEED = 8 + 3 * Math.random(); + const SPEED = 4 + 8 * Math.random(); const ANGLE = 2 * Math.PI * Math.random() Matter.Body.setVelocity(bullet[bIndex], { x: SPEED * Math.cos(ANGLE), @@ -1202,13 +1202,13 @@ const b = { for (let i = 0; i < b.guns.length; i++) { b.inventory[i] = i; b.guns[i].have = true; - b.guns[i].ammo = b.guns[i].ammoPack * ammoPacks; + b.guns[i].ammo = Math.floor(b.guns[i].ammoPack * ammoPacks); } } else { if (!b.guns[gun].have) b.inventory.push(gun); if (b.activeGun === null) b.activeGun = gun //if no active gun switch to new gun b.guns[gun].have = true; - b.guns[gun].ammo = b.guns[gun].ammoPack * ammoPacks; + b.guns[gun].ammo = Math.floor(b.guns[gun].ammoPack * ammoPacks); } game.makeGunHUD(); }, @@ -1397,208 +1397,7 @@ const b = { } }, { - name: "rail gun", //5 - description: "electro-magnetically launch a dense rod
hold left mouse to charge, release to fire", //and repel enemies - ammo: 0, - ammoPack: 1, - have: false, - isStarterGun: false, - fire() { - const me = bullet.length; - bullet[me] = Bodies.rectangle(0, 0, 0.012 * b.modBulletSize, 0.0025 * b.modBulletSize, { - density: 0.01, //0.001 is normal - //frictionAir: 0.01, //restitution: 0, - // angle: 0, - // friction: 0.5, - frictionAir: 0, - dmg: 0, //damage done in addition to the damage from momentum - classType: "bullet", - collisionFilter: { - category: 0, - mask: cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield - }, - minDmgSpeed: 5, - onDmg() {}, //this.endCycle = 0 //triggers despawn - onEnd() {} - }); - mech.fireCDcycle = Infinity; // cool down - World.add(engine.world, bullet[me]); //add bullet to world - bullet[me].endCycle = Infinity - bullet[me].isCharging = true; - bullet[me].charge = 0; - bullet[me].do = function () { - if (this.isCharging) { - if ((!game.mouseDown && this.charge > 0.6)) { //fire on mouse release - this.isCharging = false - mech.fireCDcycle = mech.cycle + 2; // set fire cool down - Matter.Body.scale(this, 8000, 8000) // show the bullet by scaling it up (don't judge me... I know this is a bad way to do it) - this.endCycle = game.cycle + 140 - this.collisionFilter.category = cat.bullet - Matter.Body.setPosition(this, { - x: mech.pos.x, - y: mech.pos.y - }) - Matter.Body.setAngle(this, mech.angle) - const speed = 90 - Matter.Body.setVelocity(this, { - x: mech.Vx / 2 + speed * this.charge * Math.cos(mech.angle), - y: mech.Vy / 2 + speed * this.charge * Math.sin(mech.angle) - }); - - //knock back - const KNOCK = ((mech.crouch) ? 0.1 : 0.5) * b.modBulletSize * b.modBulletSize * this.charge * this.charge - player.force.x -= KNOCK * Math.cos(mech.angle) - player.force.y -= KNOCK * Math.sin(mech.angle) * 0.35 //reduce knock back in vertical direction to stop super jumps - - //push away blocks when firing - let range = 700 * this.charge - for (let i = 0, len = body.length; i < len; ++i) { - const SUB = Vector.sub(body[i].position, mech.pos) - const DISTANCE = Vector.magnitude(SUB) - - if (DISTANCE < range) { - const DEPTH = Math.min(range - DISTANCE, 300) - const FORCE = Vector.mult(Vector.normalise(SUB), 0.003 * Math.sqrt(DEPTH) * body[i].mass) - body[i].force.x += FORCE.x; - body[i].force.y += FORCE.y - body[i].mass * (game.g * 1.5); //kick up a bit to give them some arc - } - } - for (let i = 0, len = mob.length; i < len; ++i) { - const SUB = Vector.sub(mob[i].position, mech.pos) - const DISTANCE = Vector.magnitude(SUB) - - if (DISTANCE < range) { - const DEPTH = Math.min(range - DISTANCE, 300) - const FORCE = Vector.mult(Vector.normalise(SUB), 0.003 * Math.sqrt(DEPTH) * mob[i].mass) - mob[i].force.x += 1.5 * FORCE.x; - mob[i].force.y += 1.5 * FORCE.y; - } - } - } else { // charging on mouse down - mech.fireCDcycle = Infinity //can't fire until mouse is released - if (mech.crouch) { - this.charge = this.charge * 0.965 + 0.035 // this.charge converges to 1 - } else { - this.charge = this.charge * 0.985 + 0.015 // this.charge converges to 1 - } - //draw laser targeting - let best; - let range = 3000 - const dir = mech.angle - const path = [{ - x: mech.pos.x + 20 * Math.cos(dir), - y: mech.pos.y + 20 * Math.sin(dir) - }, - { - x: mech.pos.x + range * Math.cos(dir), - y: mech.pos.y + range * Math.sin(dir) - } - ]; - const vertexCollision = function (v1, v1End, domain) { - for (let i = 0; i < domain.length; ++i) { - let vertices = domain[i].vertices; - const len = vertices.length - 1; - for (let j = 0; j < len; j++) { - results = game.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]); - if (results.onLine1 && results.onLine2) { - const dx = v1.x - results.x; - const dy = v1.y - results.y; - const dist2 = dx * dx + dy * dy; - if (dist2 < best.dist2) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[j], - v2: vertices[j + 1] - }; - } - } - } - results = game.checkLineIntersection(v1, v1End, vertices[0], vertices[len]); - if (results.onLine1 && results.onLine2) { - const dx = v1.x - results.x; - const dy = v1.y - results.y; - const dist2 = dx * dx + dy * dy; - if (dist2 < best.dist2) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; - - //check for collisions - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - }; - vertexCollision(path[0], path[1], mob); - vertexCollision(path[0], path[1], map); - vertexCollision(path[0], path[1], body); - if (best.dist2 != Infinity) { //if hitting something - path[path.length - 1] = { - x: best.x, - y: best.y - }; - } - - //draw laser beam - ctx.beginPath(); - ctx.moveTo(path[0].x, path[0].y); - ctx.lineTo(path[1].x, path[1].y); - ctx.strokeStyle = `rgba(100,0,180,0.7)`; - ctx.lineWidth = this.charge * 1 - ctx.setLineDash([10, 20]); - ctx.stroke(); - ctx.setLineDash([0, 0]); - - //draw magnetic field - const X = mech.pos.x - const Y = mech.pos.y - const unitVector = Vector.normalise(Vector.sub(game.mouseInGame, mech.pos)) - const unitVectorPerp = Vector.perp(unitVector) - - function magField(mag, arc) { - ctx.moveTo(X, Y); - ctx.bezierCurveTo( - X + unitVector.x * mag, Y + unitVector.y * mag, - X + unitVector.x * mag + unitVectorPerp.x * arc, Y + unitVector.y * mag + unitVectorPerp.y * arc, - X + unitVectorPerp.x * arc, Y + unitVectorPerp.y * arc) - ctx.bezierCurveTo( - X - unitVector.x * mag + unitVectorPerp.x * arc, Y - unitVector.y * mag + unitVectorPerp.y * arc, - X - unitVector.x * mag, Y - unitVector.y * mag, - X, Y) - } - ctx.fillStyle = `rgba(50,0,100,0.05)`; - for (let i = 3; i < 7; i++) { - const MAG = 8 * i * i * this.charge * (0.93 + 0.07 * Math.random()) - const ARC = 6 * i * i * this.charge * (0.93 + 0.07 * Math.random()) - ctx.beginPath(); - magField(MAG, ARC) - magField(MAG, -ARC) - ctx.fill(); - } - } - } else { //normal bullet behavior - this.force.y += this.mass * 0.00015 / this.charge; // low gravity that scales with charge - } - } - } - }, - { - name: "missiles", //6 + name: "missiles", //5 description: "fire missiles that accelerate towards enemies
explodes when near target", ammo: 0, ammoPack: 3, @@ -1694,7 +1493,7 @@ const b = { } } }, { - name: "flak", //7 + name: "flak", //6 description: "fire a cluster of short range projectiles
explodes on contact or after half a second", ammo: 0, ammoPack: 6, @@ -1735,7 +1534,7 @@ const b = { } } }, { - name: "grenades", //8 + name: "grenades", //7 description: "lob a single bouncy projectile
explodes on contact or after one second", ammo: 0, ammoPack: 6, @@ -1762,7 +1561,7 @@ const b = { }; } }, { - name: "vacuum bomb", //9 + name: "vacuum bomb", //8 description: "fire a bomb that sucks before exploding
click left mouse again to detonate", ammo: 0, ammoPack: 2, @@ -1866,7 +1665,7 @@ const b = { } } }, { - name: "mine", //10 + name: "mine", //9 description: "toss a proximity mine that sticks to walls
fires nails at enemies within range", ammo: 0, ammoPack: 3, @@ -1885,7 +1684,7 @@ const b = { } }, { - name: "spores", //11 + name: "spores", //10 description: "fire orbs that discharge spores
spores seek out enemies", ammo: 0, ammoPack: 4, @@ -1930,7 +1729,7 @@ const b = { } }, { - name: "drones", //12 + name: "drones", //11 description: "deploy drones that crash into enemies
collisions reduce drone cycles by 1 second", ammo: 0, ammoPack: 9, @@ -1942,7 +1741,7 @@ const b = { } }, { - name: "foam", //13 + name: "foam", //12 description: "spray bubbly foam that sticks to enemies
does damage over time and slows movement", ammo: 0, ammoPack: 35, @@ -2035,6 +1834,209 @@ const b = { }); } }, + { + name: "rail gun", //13 + description: "electro-magnetically launch a dense rod
holding left mouse uses energy to charge ", + ammo: 0, + ammoPack: 2, + have: false, + isStarterGun: false, + fire() { + const me = bullet.length; + bullet[me] = Bodies.rectangle(0, 0, 0.015 * b.modBulletSize, 0.0015 * b.modBulletSize, { + density: 0.01, //0.001 is normal + //frictionAir: 0.01, //restitution: 0, + // angle: 0, + // friction: 0.5, + frictionAir: 0, + dmg: 0, //damage done in addition to the damage from momentum + classType: "bullet", + collisionFilter: { + category: 0, + mask: cat.map | cat.body | cat.mob | cat.mobBullet | cat.mobShield + }, + minDmgSpeed: 5, + onDmg() {}, //this.endCycle = 0 //triggers despawn + onEnd() {} + }); + mech.fireCDcycle = Infinity; // cool down + World.add(engine.world, bullet[me]); //add bullet to world + bullet[me].endCycle = Infinity + bullet[me].charge = 0; + bullet[me].do = function () { + const FIELD_DRAIN = 0.002 //laser drains energy as well as bullets + + if ((!game.mouseDown && this.charge > 0.6)) { //fire on mouse release + //normal bullet behavior occurs after firing, overwrite this function + this.do = function () { + this.force.y += this.mass * 0.00015 / this.charge; // low gravity that scales with charge + } + + mech.fireCDcycle = mech.cycle + 2; // set fire cool down + Matter.Body.scale(this, 8000, 8000) // show the bullet by scaling it up (don't judge me... I know this is a bad way to do it) + this.endCycle = game.cycle + 140 + this.collisionFilter.category = cat.bullet + Matter.Body.setPosition(this, { + x: mech.pos.x, + y: mech.pos.y + }) + Matter.Body.setAngle(this, mech.angle) + const speed = 90 + Matter.Body.setVelocity(this, { + x: mech.Vx / 2 + speed * this.charge * Math.cos(mech.angle), + y: mech.Vy / 2 + speed * this.charge * Math.sin(mech.angle) + }); + + //knock back + const KNOCK = ((mech.crouch) ? 0.1 : 0.5) * b.modBulletSize * b.modBulletSize * this.charge * this.charge + player.force.x -= KNOCK * Math.cos(mech.angle) + player.force.y -= KNOCK * Math.sin(mech.angle) * 0.35 //reduce knock back in vertical direction to stop super jumps + + //push away blocks when firing + let range = 700 * this.charge + for (let i = 0, len = body.length; i < len; ++i) { + const SUB = Vector.sub(body[i].position, mech.pos) + const DISTANCE = Vector.magnitude(SUB) + + if (DISTANCE < range) { + const DEPTH = Math.min(range - DISTANCE, 300) + const FORCE = Vector.mult(Vector.normalise(SUB), 0.003 * Math.sqrt(DEPTH) * body[i].mass) + body[i].force.x += FORCE.x; + body[i].force.y += FORCE.y - body[i].mass * (game.g * 1.5); //kick up a bit to give them some arc + } + } + for (let i = 0, len = mob.length; i < len; ++i) { + const SUB = Vector.sub(mob[i].position, mech.pos) + const DISTANCE = Vector.magnitude(SUB) + + if (DISTANCE < range) { + const DEPTH = Math.min(range - DISTANCE, 300) + const FORCE = Vector.mult(Vector.normalise(SUB), 0.003 * Math.sqrt(DEPTH) * mob[i].mass) + mob[i].force.x += 1.5 * FORCE.x; + mob[i].force.y += 1.5 * FORCE.y; + } + } + } else if (mech.fieldMeter > 0.005) { // charging on mouse down + mech.fireCDcycle = Infinity //can't fire until mouse is released + const lastCharge = this.charge + let chargeRate = (mech.crouch) ? 0.965 : 0.985 + chargeRate *= Math.pow(b.modFireRate, 0.04) + this.charge = this.charge * chargeRate + (1 - chargeRate) // this.charge converges to 1 + mech.fieldMeter -= (this.charge - lastCharge) * 0.25 //energy drain is proportional to charge gained, but doesn't stop normal mech.fieldRegen + + //draw laser targeting + let best; + let range = 3000 + const dir = mech.angle + const path = [{ + x: mech.pos.x + 20 * Math.cos(dir), + y: mech.pos.y + 20 * Math.sin(dir) + }, + { + x: mech.pos.x + range * Math.cos(dir), + y: mech.pos.y + range * Math.sin(dir) + } + ]; + const vertexCollision = function (v1, v1End, domain) { + for (let i = 0; i < domain.length; ++i) { + let vertices = domain[i].vertices; + const len = vertices.length - 1; + for (let j = 0; j < len; j++) { + results = game.checkLineIntersection(v1, v1End, vertices[j], vertices[j + 1]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2) { + best = { + x: results.x, + y: results.y, + dist2: dist2, + who: domain[i], + v1: vertices[j], + v2: vertices[j + 1] + }; + } + } + } + results = game.checkLineIntersection(v1, v1End, vertices[0], vertices[len]); + if (results.onLine1 && results.onLine2) { + const dx = v1.x - results.x; + const dy = v1.y - results.y; + const dist2 = dx * dx + dy * dy; + if (dist2 < best.dist2) { + best = { + x: results.x, + y: results.y, + dist2: dist2, + who: domain[i], + v1: vertices[0], + v2: vertices[len] + }; + } + } + } + }; + + //check for collisions + best = { + x: null, + y: null, + dist2: Infinity, + who: null, + v1: null, + v2: null + }; + vertexCollision(path[0], path[1], mob); + vertexCollision(path[0], path[1], map); + vertexCollision(path[0], path[1], body); + if (best.dist2 != Infinity) { //if hitting something + path[path.length - 1] = { + x: best.x, + y: best.y + }; + } + + //draw laser beam + ctx.beginPath(); + ctx.moveTo(path[0].x, path[0].y); + ctx.lineTo(path[1].x, path[1].y); + ctx.strokeStyle = `rgba(100,0,180,0.7)`; + ctx.lineWidth = this.charge * 1 + ctx.setLineDash([10, 20]); + ctx.stroke(); + ctx.setLineDash([0, 0]); + + //draw magnetic field + const X = mech.pos.x + const Y = mech.pos.y + const unitVector = Vector.normalise(Vector.sub(game.mouseInGame, mech.pos)) + const unitVectorPerp = Vector.perp(unitVector) + + function magField(mag, arc) { + ctx.moveTo(X, Y); + ctx.bezierCurveTo( + X + unitVector.x * mag, Y + unitVector.y * mag, + X + unitVector.x * mag + unitVectorPerp.x * arc, Y + unitVector.y * mag + unitVectorPerp.y * arc, + X + unitVectorPerp.x * arc, Y + unitVectorPerp.y * arc) + ctx.bezierCurveTo( + X - unitVector.x * mag + unitVectorPerp.x * arc, Y - unitVector.y * mag + unitVectorPerp.y * arc, + X - unitVector.x * mag, Y - unitVector.y * mag, + X, Y) + } + ctx.fillStyle = `rgba(50,0,100,0.05)`; + for (let i = 3; i < 7; i++) { + const MAG = 8 * i * i * this.charge * (0.93 + 0.07 * Math.random()) + const ARC = 6 * i * i * this.charge * (0.93 + 0.07 * Math.random()) + ctx.beginPath(); + magField(MAG, ARC) + magField(MAG, -ARC) + ctx.fill(); + } + } + } + } + }, { name: "laser", //14 description: "emit a beam of collimated coherent light
drains energy instead of ammunition", diff --git a/js/index.js b/js/index.js index e139944..3550423 100644 --- a/js/index.js +++ b/js/index.js @@ -2,20 +2,6 @@ /* TODO: ******************************************* ***************************************************** -show difficulty increase text in custom mode - -chart showing info about each mob type - can use css-grid chart like custom mod - -add setting for random drops instead of choosing - -custom mode - custom mode grey out mods that are bad, like selection based mods - -change nail-bot's movement - maybe have it move in a circle around player? - high friction very high acceleration towards circle location - add mouse constraint in testing mode https://github.com/liabru/matter-js/blob/master/examples/events.js @@ -199,7 +185,7 @@ const build = { }, makeGrid() { let text = - `
+ `
start @@ -256,7 +242,7 @@ const build = { calculateCustomDifficulty() { let difficulty = build.list.length * game.difficultyMode if (game.difficultyMode === 0) difficulty = build.list.length * 1 - 6 - document.getElementById("starting-level").innerHTML = `starting level: ${difficulty}` + document.getElementById("starting-level").innerHTML = `starting level: ${difficulty}` }, startBuildRun() { spawn.setSpawnList(); @@ -291,6 +277,7 @@ document.getElementById("build-button").addEventListener("click", () => { document.getElementById("info").style.display = 'inline' } else { build.list = [] + build.reset() // let text = '

The difficulty increases by one level for each power up you choose.

' build.isShowingBuilds = true el.style.display = "grid" diff --git a/js/level.js b/js/level.js index dba9390..49999be 100644 --- a/js/level.js +++ b/js/level.js @@ -14,12 +14,9 @@ const level = { start() { if (level.levelsCleared === 0) { // game.difficulty = 6; //for testing to simulate possible mobs spawns - // b.giveGuns(10) + // b.giveGuns(13) // mech.setField(3) - // b.giveMod(11); - // b.giveMod(11); - // b.giveMod(10); - // b.giveMod(11); + // b.giveMod(6); level.intro(); //starting level // level.testingMap(); diff --git a/js/mobs.js b/js/mobs.js index c716a63..ffcbcad 100644 --- a/js/mobs.js +++ b/js/mobs.js @@ -1013,7 +1013,8 @@ const mobs = { }, //replace dead mob with a regular body replace(i) { - if (this.leaveBody) { + //large mobs or too many bodies go intangible and fall until removed from game to help performance + if (this.leaveBody && this.mass < 10 && body.length < 50) { const len = body.length; body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, this.vertices); Matter.Body.setVelocity(body[len], this.velocity); @@ -1021,10 +1022,9 @@ const mobs = { body[len].collisionFilter.category = cat.body; body[len].collisionFilter.mask = cat.player | cat.map | cat.body | cat.bullet | cat.mob | cat.mobBullet; - //large mobs or too many bodies go intangible and fall until removed from game to help performance - if (body[len].mass > 10 || 45 + 10 * Math.random() < body.length) { - body[len].collisionFilter.mask = cat.player | cat.bullet | cat.mob | cat.mobBullet; - } + // if (body[len].mass > 10 || 45 + 10 * Math.random() < body.length) { + // body[len].collisionFilter.mask = cat.player | cat.bullet | cat.mob | cat.mobBullet; + // } body[len].classType = "body"; World.add(engine.world, body[len]); //add to world }