From 3e1fa6e8515d0c164255220922d242716fa42e8d Mon Sep 17 00:00:00 2001 From: landgreen Date: Mon, 4 May 2020 17:43:09 -0700 Subject: [PATCH] working on gun: neutron bomb --- js/bullets.js | 125 +++++++++++++++++++++++++++++++++++++++++++++++--- js/level.js | 10 ++-- js/mobs.js | 10 ---- js/player.js | 4 +- js/spawn.js | 63 +++++++++++++++---------- todo.txt | 16 ++++--- 6 files changed, 175 insertions(+), 53 deletions(-) diff --git a/js/bullets.js b/js/bullets.js index fe03f00..87068b9 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -540,7 +540,7 @@ const b = { b.isModSlowFPS = true; }, remove() { - b.isModSlowFPS = true; + b.isModSlowFPS = false; } }, { @@ -1130,7 +1130,7 @@ const b = { }, { name: "MIRV", - description: "launch 3 small missiles instead of 1
2x increase in delay after firing", + description: "launch 3 small missiles instead of 1
1.5x increase in delay after firing", maxCount: 1, count: 0, allowed() { @@ -2992,7 +2992,7 @@ const b = { fire() { if (b.isMod3Missiles) { if (mech.crouch) { - mech.fireCDcycle = mech.cycle + 80 * b.modFireRate; // cool down + mech.fireCDcycle = mech.cycle + 60 * b.modFireRate; // cool down const direction = { x: Math.cos(mech.angle), y: Math.sin(mech.angle) @@ -3008,7 +3008,7 @@ const b = { bullet[bullet.length - 1].force.y += push.y * (i - 1); } } else { - mech.fireCDcycle = mech.cycle + 60 * b.modFireRate; // cool down + mech.fireCDcycle = mech.cycle + 45 * b.modFireRate; // cool down const direction = { x: Math.cos(mech.angle), y: Math.sin(mech.angle) @@ -3025,7 +3025,7 @@ const b = { } } } else { - mech.fireCDcycle = mech.cycle + Math.floor(mech.crouch ? 50 : 30) * b.modFireRate; // cool down + mech.fireCDcycle = mech.cycle + Math.floor(mech.crouch ? 45 : 30) * b.modFireRate; // cool down b.missile({ x: mech.pos.x + 40 * Math.cos(mech.angle), y: mech.pos.y + 40 * Math.sin(mech.angle) - 3 @@ -3094,7 +3094,7 @@ const b = { fire() { const me = bullet.length; const dir = mech.angle; // + Math.random() * 0.05; - bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 20, b.fireAttributes(dir, true)); + bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 20, b.fireAttributes(dir, false)); Matter.Body.setDensity(bullet[me], 0.0005); bullet[me].explodeRad = 275; bullet[me].onEnd = function () { @@ -3125,7 +3125,7 @@ const b = { } else { b.fireProps(mech.crouch ? 40 : 30, mech.crouch ? 43 : 32, dir, me); //cd , speed bullet[me].endCycle = game.cycle + Math.floor(mech.crouch ? 120 : 80); - bullet[me].restitution = 0.2; + bullet[me].restitution = 0.4; bullet[me].explodeRad = 275; bullet[me].do = function () { //extra gravity for harder arcs @@ -3258,6 +3258,117 @@ const b = { } } }, + { + name: "neutron bomb", + description: "fire a bomb that emits neutron radiation
detonation occurs after any collision", + ammo: 0, + ammoPack: 4, + have: false, + isStarterGun: false, + isEasyToAim: true, + fire() { + const me = bullet.length; + const dir = mech.angle; + bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 10, 6, b.fireAttributes(dir, false)); + b.fireProps(mech.crouch ? 30 : 20, mech.crouch ? 28 : 14, dir, me); //cd , speed + Matter.Body.setDensity(bullet[me], 0.000001); + bullet[me].endCycle = Infinity; + bullet[me].frictionAir = 0; + bullet[me].friction = 0.5; + bullet[me].restitution = 0; + bullet[me].minDmgSpeed = 0; + bullet[me].damageRadius = 100; + bullet[me].maxDamageRadius = 600 + bullet[me].onDmg = function () {}; + + bullet[me].do = function () { + this.force.y += this.mass * 0.001; + if (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length || Matter.Query.collides(this, mob).length) { + //have the bullet stick to mobs and blocks? + //stun mobs in range + // for (let i = 0, len = mob.length; i < len; i++) { + // const dx = this.position.x - mob[i].position.x; + // const dy = this.position.y - mob[i].position.y; + // if (dx * dx + dy * dy < this.maxDamageRadius * this.maxDamageRadius) { + // mobs.statusStun(mob[i], 60) + // } + // } + + //push away blocks when firing + for (let i = 0, len = body.length; i < len; ++i) { + const SUB = Vector.sub(body[i].position, this.position) + const DISTANCE = Vector.magnitude(SUB) + if (DISTANCE < this.maxDamageRadius) { + const FORCE = Vector.mult(Vector.normalise(SUB), 0.01 * body[i].mass) + body[i].force.x += FORCE.x; + body[i].force.y += FORCE.y - body[i].mass * (game.g * 2); //kick up a bit to give them some arc + } + } + //stun mobs, but don't push away + for (let i = 0, len = mob.length; i < len; ++i) { + if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.maxDamageRadius) { + mobs.statusStun(mob[i], 60) + } + } + + //use a constraint? + Matter.Sleeping.set(this, true) //freeze in place + this.collisionFilter.mask = 0; + Matter.Body.setVelocity(this, { + x: 0, + y: 0 + }); + const SCALE = 0.01 + Matter.Body.scale(this, SCALE, SCALE); + this.do = this.radiationMode; + } + }; + bullet[me].radiationMode = function () { + // if (this.endCycle - 360 < game.cycle) { + // this.damageRadius = this.damageRadius * 0.992 + // } else { + // this.damageRadius = this.damageRadius * 0.98 + 0.02 * this.maxDamageRadius + // this.damageRadius = Math.max(0, this.damageRadius + 2 * (Math.random() - 0.5)) + // } + if (!mech.isBodiesAsleep) { + this.damageRadius = this.damageRadius * 0.9 + 0.1 * this.maxDamageRadius //smooth radius towards max + this.maxDamageRadius = this.maxDamageRadius * 0.999 - 0.7 //slowly shrink max radius + } + if (this.damageRadius < 15) { + this.endCycle = 0; + } else { + //aoe damage to player + if (Vector.magnitude(Vector.sub(player.position, this.position)) < this.damageRadius) { + const DRAIN = 0.003 + if (mech.energy > DRAIN) { + mech.energy -= DRAIN + } else { + mech.energy = 0; + mech.damage(0.001) + } + } + //aoe damage to mobs + for (let i = 0, len = mob.length; i < len; i++) { + if (Vector.magnitude(Vector.sub(mob[i].position, this.position)) < this.damageRadius) { + if (mob[i].shield) { + mob[i].damage(5 * b.dmgScale * 0.02); + } else { + mob[i].damage(b.dmgScale * 0.02); + } + + mob[i].locatePlayer(); + } + } + ctx.beginPath(); + ctx.arc(this.position.x, this.position.y, this.damageRadius, 0, 2 * Math.PI); + ctx.globalCompositeOperation = "lighter" + ctx.fillStyle = `rgba(0,100,120,${0.3+0.05*Math.random()})`; + ctx.fill(); + ctx.globalCompositeOperation = "source-over" + } + } + } + }, { name: "mine", description: "toss a proximity mine that sticks to walls
fires nails at mobs within range", diff --git a/js/level.js b/js/level.js index 8253a01..b3e1a4f 100644 --- a/js/level.js +++ b/js/level.js @@ -21,7 +21,7 @@ const level = { // b.giveMod("renormalization"); // b.giveMod("impact shear"); // b.giveMod("clock gating"); - // b.giveGuns("mine") + b.giveGuns("neutron bomb") // mech.setField("pilot wave") // mech.setField("perfect diamagnetism") @@ -102,7 +102,7 @@ const level = { //****************************************************************************************************************** testing() { - // level.difficultyIncrease(19); + level.difficultyIncrease(9); spawn.setSpawnList(); spawn.setSpawnList(); level.defaultZoom = 1500 @@ -156,9 +156,9 @@ const level = { spawn.boost(1500, 0, 900); // spawn.bomberBoss(2900, -500) - // spawn.suckerBoss(1200, -500) - spawn.hopper(1200, -500) - spawn.laser(1200, -500) + // spawn.shooterBoss(1200, -500) + // spawn.spawns(1200, -500) + spawn.hopper(1600, -500) // spawn.shield(mob[mob.length - 1], 1200, -500, 1); // spawn.nodeBoss(1200, -500, "spiker") diff --git a/js/mobs.js b/js/mobs.js index 4054ff3..0d9aa61 100644 --- a/js/mobs.js +++ b/js/mobs.js @@ -699,16 +699,6 @@ const mobs = { this.force.y -= 2 * forceMag * Math.sin(angle); // - 0.0007 * this.mass; //antigravity } }, - hop() { - //accelerate towards the player after a delay - if (this.cd < game.cycle && this.seePlayer.recall && this.speed < 1) { - this.cd = game.cycle + this.delay; - const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass; - const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x); - this.force.x += forceMag * Math.cos(angle); - this.force.y += forceMag * Math.sin(angle) - 0.04 * this.mass; //antigravity - } - }, hoverOverPlayer() { if (this.seePlayer.recall) { // vertical positioning diff --git a/js/player.js b/js/player.js index 08c9df1..01cfdc6 100644 --- a/js/player.js +++ b/js/player.js @@ -624,8 +624,8 @@ const mech = { if (b.isModSlowFPS) { // slow game game.fpsCap = 30 //new fps game.fpsInterval = 1000 / game.fpsCap; - mech.defaultFPSCycle = mech.cycle + 30 //how long to wait to return to normal fps - if (dmg > 0.1) mech.defaultFPSCycle += 30 + //how long to wait to return to normal fps + mech.defaultFPSCycle = mech.cycle + 20 + Math.min(90, Math.floor(200 * dmg)) } else { if (dmg > 0.05) { // freeze game for high damage hits game.fpsCap = 4 //40 - Math.min(25, 100 * dmg) diff --git a/js/spawn.js b/js/spawn.js index e54645a..4b661ac 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -307,7 +307,7 @@ const spawn = { // }; // }, chaser(x, y, radius = 35 + Math.ceil(Math.random() * 40)) { - mobs.spawn(x, y, 8, radius, "#2c9790"); + mobs.spawn(x, y, 8, radius, "rgb(255,150,100)"); //"#2c9790" let me = mob[mob.length - 1]; // Matter.Body.setDensity(me, 0.0007); //extra dense //normal is 0.001 //makes effective life much lower me.friction = 0; @@ -390,27 +390,36 @@ const spawn = { mobs.spawn(x, y, 5, radius, "rgb(0,200,180)"); let me = mob[mob.length - 1]; me.accelMag = 0.04; - me.g = 0.0015; //required if using 'gravity' - me.frictionAir = 0.018; + me.g = 0.0017; //required if using 'gravity' + me.frictionAir = 0.01; me.restitution = 0; - me.delay = 110; - me.randomHopFrequency = 50 + Math.floor(Math.random() * 1000); + me.delay = 120 * game.CDScale; + me.randomHopFrequency = 200 + Math.floor(Math.random() * 150); me.randomHopCD = game.cycle + me.randomHopFrequency; spawn.shield(me, x, y); me.do = function () { this.gravity(); this.seePlayerCheck(); this.checkStatus(); - this.hop(); - //randomly hob if not aware of player - if (this.randomHopCD < game.cycle && this.speed < 1 && !this.seePlayer.recall) { - this.randomHopCD = game.cycle + this.randomHopFrequency; - //slowly change randomHopFrequency after each hop - this.randomHopFrequency = Math.max(100, this.randomHopFrequency + (0.5 - Math.random()) * 200); - const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.1 + Math.random() * 0.3); - const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI; - this.force.x += forceMag * Math.cos(angle); - this.force.y += forceMag * Math.sin(angle) - 0.04 * this.mass; //antigravity + if (this.seePlayer.recall) { + if (this.cd < game.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) { + this.cd = game.cycle + this.delay; + const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass; + const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x); + this.force.x += forceMag * Math.cos(angle); + this.force.y += forceMag * Math.sin(angle) - (Math.random() * 0.07 + 0.02) * this.mass; //antigravity + } + } else { + //randomly hob if not aware of player + if (this.randomHopCD < game.cycle && (Matter.Query.collides(this, map).length || Matter.Query.collides(this, body).length)) { + this.randomHopCD = game.cycle + this.randomHopFrequency; + //slowly change randomHopFrequency after each hop + this.randomHopFrequency = Math.max(100, this.randomHopFrequency + (0.5 - Math.random()) * 200); + const forceMag = (this.accelMag + this.accelMag * Math.random()) * this.mass * (0.1 + Math.random() * 0.3); + const angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI; + this.force.x += forceMag * Math.cos(angle); + this.force.y += forceMag * Math.sin(angle) - 0.05 * this.mass; //antigravity + } } }; }, @@ -631,7 +640,7 @@ const spawn = { } } }, - spiderBoss(x, y, radius = 50 + Math.ceil(Math.random() * 10)) { + spiderBoss(x, y, radius = 60 + Math.ceil(Math.random() * 10)) { let targets = [] //track who is in the node boss, for shields mobs.spawn(x, y, 6, radius, "#b386e8"); let me = mob[mob.length - 1]; @@ -640,8 +649,8 @@ const spawn = { me.frictionAir = 0.0065; me.lookTorque = 0.0000008; //controls spin while looking for player me.g = 0.00025; //required if using 'gravity' - me.seePlayerFreq = Math.round((40 + 25 * Math.random()) * game.lookFreqScale); - const springStiffness = 0.00006; + me.seePlayerFreq = Math.round((30 + 20 * Math.random()) * game.lookFreqScale); + const springStiffness = 0.000065; const springDampening = 0.0006; me.springTarget = { @@ -691,7 +700,11 @@ const spawn = { spawn.allowShields = false; //don't want shields on individual boss mobs for (let i = 0; i < nodes; ++i) { - spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius); + spawn.stabber(x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius, 12); + // const who = mob[mob.length - 1] + // who.frictionAir = 0.06 + // who.accelMag = 0.005 * game.accelScale + targets.push(mob[mob.length - 1].id) //track who is in the node boss, for shields } //spawn shield for entire boss @@ -1012,7 +1025,7 @@ const spawn = { ctx.lineTo(best.x, best.y); } }, - stabber(x, y, radius = 25 + Math.ceil(Math.random() * 12)) { + stabber(x, y, radius = 25 + Math.ceil(Math.random() * 12), spikeMax = 9) { if (radius > 80) radius = 65; mobs.spawn(x, y, 6, radius, "rgb(220,50,205)"); //can't have sides above 6 or collision events don't work (probably because of a convex problem) let me = mob[mob.length - 1]; @@ -1068,11 +1081,15 @@ const spawn = { } else { if (this.isSpikeGrowing) { this.spikeLength += 1 - if (this.spikeLength > 9) { + if (this.spikeLength > spikeMax) { this.isSpikeGrowing = false; } } else { - this.spikeLength -= 0.1 + + //reduce rotation + Matter.Body.setAngularVelocity(this, this.angularVelocity * 0.8) + + this.spikeLength -= 0.2 if (this.spikeLength < 1) { this.spikeLength = 1 this.isSpikeReset = true @@ -1441,7 +1458,7 @@ const spawn = { this.attraction(); }; }, - exploder(x, y, radius = 25 + Math.ceil(Math.random() * 50)) { + exploder(x, y, radius = 40 + Math.ceil(Math.random() * 50)) { mobs.spawn(x, y, 4, radius, "rgb(255,0,0)"); let me = mob[mob.length - 1]; me.onHit = function () { diff --git a/todo.txt b/todo.txt index bdc5fb4..99492e0 100644 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,5 @@ ************** TODO - n-gon ************** -n-gon outreach ideas - blips - errant signal on youtube - reddit - r/IndieGaming - hacker news - show hacker news post - frozen mobs take +33% damage a lasting AoE damage gun @@ -65,6 +60,10 @@ lore - a robot (the player) gains self awareness the next level is the final level when you die with Quantum Immortality there is a chance of lore text +scrap drops that can be used to buy things in a shop + scrap could be yellow + shop could appear every 4 levels + boss mob - let it die multiple times and come back to life on death event spawns a new version of self, but with a decrementing counter @@ -155,4 +154,9 @@ game mechanics map zones water low friction ground - bouncy ground \ No newline at end of file + bouncy ground + +n-gon outreach ideas + blips - errant signal on youtube + reddit - r/IndieGaming + hacker news - show hacker news post \ No newline at end of file