diff --git a/index.html b/index.html deleted file mode 100644 index 70da1f1..0000000 --- a/index.html +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - - - - - - - - - - - - n-gon - - - - - - - -
-
-
-
-
-
-
- - - - - - - - - - - - - - - -
-
- info -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
FIREleft mouse
FIELDright mouse / spacebar
MOVEWASD / arrows
GUNSQ / E / mouse wheel
ZOOM+ / -
PAUSEP
-
- - - - - Github - - - -

Written by Ross Landgreen

-
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Q - E - W - S - D - A - - - - - - - - - - - - - - guns - move - fire - field - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/js/bullets.js b/js/bullets.js deleted file mode 100644 index 02db190..0000000 --- a/js/bullets.js +++ /dev/null @@ -1,1301 +0,0 @@ -let bullet = []; - -const b = { - dmgScale: null, //scales all gun damage from momentum, but not raw .dmg //this is reset in game.reset - gravity: 0.0006, //most other bodies have gravity = 0.001 - //variables use for gun mod upgrades - mod: null, - modFireRate: null, - modExplosionRadius: null, - modBulletSize: null, - modEnergySiphon: null, - modHealthDrain: null, - modNoAmmo: null, - modBulletsLastLonger: null, - modIsImmortal: null, - setModDefaults() { - b.modFireRate = 1; - b.modExplosionRadius = 1; - b.modBulletSize = 1; - b.modEnergySiphon = 0; - b.modHealthDrain = 0; - b.modNoAmmo = 0; - b.modBulletsLastLonger = 1; - b.modIsImmortal = false; - }, - modText() { - if (b.mod !== null) game.makeTextLog(`${b.mods[b.mod].name}

${b.mods[b.mod].description}

`, 1200); - game.updateModHUD() - }, - mods: [{ - name: "Auto-Loading Heuristics", - description: "your rate of fire is 15% faster", - effect: () => { - b.mod = 0 - b.modText(); - b.setModDefaults(); //good for guns with extra ammo: needles, M80, rapid fire, flak, super balls - b.modFireRate = 0.85 - //ADD: maybe add in something that changes game play - } - }, - { - name: "Anti-Matter Cores", - description: "The radius of your explosions is doubled", - effect: () => { - b.mod = 1 - b.modText(); - b.setModDefaults(); //at 1.4 gives a flat 40% increase, and increased range, balanced by limited guns and self damage - //testing at 1.3: grenade(+0.3), missiles, flak, M80 - b.modExplosionRadius = 2; //good for guns with explosions: - } - }, - { - name: "Depleted Uranium Rounds", - description: "your bullets are larger and do more physical damage", - effect: () => { - b.mod = 2 - b.modText(); - b.setModDefaults(); //good for guns that do mostly projectile damage: - //testing done at 1.15: one shot(+0.38), rapid fire(+0.25), spray, wave beam(+0.4 adds range and dmg), needles(+0.1) - //testing at 1.08: spray(point blank)(+0.25), one shot(+0.16), wave beam(point blank)(+0.14) - b.modBulletSize = 1.07; - //ADD: maybe add in something that changes game play - } - }, - { - name: "Energy Siphon", - description: "regenerate energy proportional to your damage done", - effect: () => { - b.mod = 3 - b.modText(); - b.setModDefaults(); //good with laser, and all fields - b.modEnergySiphon = 0.25; - } - }, - { - name: "Entropy Transfer", - description: "heal proportional to your damage done", - effect: () => { - b.mod = 4 - b.modText(); - b.setModDefaults(); //good with guns that overkill: one shot, grenade - b.modHealthDrain = 0.01; - } - }, - { - name: "Desublimated Ammunition", - description: "use 50% less ammo when crouching", - effect: () => { - b.mod = 5 - b.modText(); - b.setModDefaults(); //good with guns that have less ammo: one shot, grenades, missiles, super balls, spray - b.modNoAmmo = 1 - } - }, - { - name: "Decay Resistant Topology", - description: "your bullets last 40% longer", - effect: () => { - b.mod = 6 - b.modText(); - b.setModDefaults(); //good with: drones, super balls, spore, missiles, wave beam(range), rapid fire(range), flak(range) - b.modBulletsLastLonger = 1.40 - } - }, - { - name: "Quantum Immortality", - description: "after you die continue in an alternate reality with randomized abilities
", - effect: () => { - b.mod = 7 - b.modText(); - b.setModDefaults(); //good with: drones, super balls, spore, missiles, wave beam(range), rapid fire(range), flak(range) - b.modIsImmortal = true; - } - }, - - // () => { - // b.mod = 8; - // game.makeTextLog("Relativistic Velocity
(left click)

Your bullets are effected extra by your own velocity

", 1200); - // b.setModDefaults(); //good with: one shot, rapid fire, spray, super balls - // }, - ], - activeGun: null, //current gun in use by player - inventoryGun: 0, - inventory: [0], //list of what guns player has // 0 starts with basic gun - giveGuns(gun = "all", ammoPacks = 2) { - if (gun === "all") { - b.activeGun = 0; - for (let i = 0; i < b.guns.length; i++) { - b.guns[i].have = true; - b.guns[i].ammo = b.guns[i].ammoPack * ammoPacks; - b.inventory[i] = i; - } - } else { - if (!b.guns[gun].have) b.inventory.push(gun); - b.activeGun = gun; - b.guns[gun].have = true; - b.guns[gun].ammo = b.guns[gun].ammoPack * ammoPacks; - } - game.makeGunHUD(); - }, - fire() { - if (game.mouseDown && mech.fireCDcycle < mech.cycle && (!(keys[32] || game.mouseDownRight) || mech.fieldFire) && b.inventory.length) { - if (b.guns[b.activeGun].ammo > 0) { - b.guns[b.activeGun].fire(); - if (b.modNoAmmo && mech.crouch) { - if (b.modNoAmmo % 2) { - b.guns[b.activeGun].ammo--; - game.updateGunHUD(); - } - b.modNoAmmo++ //makes the no ammo toggle off and on - } else { - b.guns[b.activeGun].ammo--; - game.updateGunHUD(); - } - } else { - mech.fireCDcycle = mech.cycle + 30; //cooldown - // game.makeTextLog("
NO AMMO
E / Q", 200); - game.makeTextLog("
NO AMMO

Q, E, and mouse wheel change weapons

", 200); - } - if (mech.isHolding) { - mech.drop(); - } - } - }, - draw() { - ctx.beginPath(); - let i = bullet.length; - while (i--) { - //draw - let vertices = bullet[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1; j < vertices.length; j += 1) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - //remove bullet if at end cycle for that bullet - if (bullet[i].endCycle < game.cycle) { - bullet[i].onEnd(i); //some bullets do stuff on end - if (bullet[i]) { - Matter.World.remove(engine.world, bullet[i]); - bullet.splice(i, 1); - } else { - break; //if bullet[i] doesn't exist don't complete the for loop, because the game probably reset - } - } - } - ctx.fillStyle = "#000"; - ctx.fill(); - //do things - for (let i = 0, len = bullet.length; i < len; i++) { - bullet[i].do(); - } - }, - fireProps(cd, speed, dir, me) { - mech.fireCDcycle = mech.cycle + Math.floor(cd * b.modFireRate); // cool down - Matter.Body.setVelocity(bullet[me], { - x: mech.Vx / 2 + speed * Math.cos(dir), - y: mech.Vy / 2 + speed * Math.sin(dir) - }); - World.add(engine.world, bullet[me]); //add bullet to world - }, - fireAttributes(dir, rotate = true) { - if (rotate) { - return { - // density: 0.0015, //frictionAir: 0.01, //restitution: 0, - angle: dir, - friction: 0.5, - frictionAir: 0, - dmg: 0, //damage done in addition to the damage from momentum - classType: "bullet", - collisionFilter: { - category: 0x000100, - mask: 0x010011 //mask: 0x000101, //for self collision - }, - minDmgSpeed: 10, - onDmg() {}, //this.endCycle = 0 //triggers despawn - onEnd() {} - }; - } else { - return { - // density: 0.0015, //frictionAir: 0.01, //restitution: 0, - inertia: Infinity, //prevents rotation - angle: dir, - friction: 0.5, - frictionAir: 0, - dmg: 0, //damage done in addition to the damage from momentum - classType: "bullet", - collisionFilter: { - category: 0x000100, - mask: 0x010011 //mask: 0x000101, //for self collision - }, - minDmgSpeed: 10, - onDmg() {}, //this.endCycle = 0 //triggers despawn - onEnd() {} - }; - } - }, - muzzleFlash(radius = 10) { - ctx.fillStyle = "#fb0"; - ctx.beginPath(); - ctx.arc(mech.pos.x + 35 * Math.cos(mech.angle), mech.pos.y + 35 * Math.sin(mech.angle), radius, 0, 2 * Math.PI); - ctx.fill(); - }, - drawOneBullet(vertices) { - ctx.beginPath(); - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1; j < vertices.length; j += 1) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = "#000"; - ctx.fill(); - }, - removeConsBB(me) { - for (let i = 0, len = consBB.length; i < len; ++i) { - if (consBB[i].bodyA === me) { - consBB[i].bodyA = consBB[i].bodyB; - consBB.splice(i, 1); - // b.removeConsBB(me); - break; - } else if (consBB[i].bodyB === me) { - consBB[i].bodyB = consBB[i].bodyA; - consBB.splice(i, 1); - // b.removeConsBB(me); - break; - } - } - }, - explode(me) { - // typically explode is used for some bullets with .onEnd - const radius = bullet[me].explodeRad * b.modExplosionRadius - //add dmg to draw queue - game.drawList.push({ - x: bullet[me].position.x, - y: bullet[me].position.y, - radius: radius, - color: "rgba(255,0,0,0.4)", - time: game.drawTime - }); - let dist, sub, knock; - const dmg = b.dmgScale * radius * 0.01; - - const alertRange = 100 + radius * 2; //alert range - //add alert to draw queue - game.drawList.push({ - x: bullet[me].position.x, - y: bullet[me].position.y, - radius: alertRange, - color: "rgba(100,20,0,0.03)", - time: game.drawTime - }); - - //player damage and knock back - sub = Matter.Vector.sub(bullet[me].position, player.position); - dist = Matter.Vector.magnitude(sub); - if (dist < radius) { - mech.damage(radius * 0.00035); - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), -Math.sqrt(dmg) * player.mass / 30); - player.force.x += knock.x; - player.force.y += knock.y; - mech.drop(); - } else if (dist < alertRange) { - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), -Math.sqrt(dmg) * player.mass / 55); - player.force.x += knock.x; - player.force.y += knock.y; - mech.drop(); - } - - - //body knock backs - for (let i = 0, len = body.length; i < len; ++i) { - sub = Matter.Vector.sub(bullet[me].position, body[i].position); - dist = Matter.Vector.magnitude(sub); - if (dist < radius) { - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg) * body[i].mass) / 18); - body[i].force.x += knock.x; - body[i].force.y += knock.y; - } else if (dist < alertRange) { - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg) * body[i].mass) / 40); - body[i].force.x += knock.x; - body[i].force.y += knock.y; - } - } - - //power up knock backs - for (let i = 0, len = powerUp.length; i < len; ++i) { - sub = Matter.Vector.sub(bullet[me].position, powerUp[i].position); - dist = Matter.Vector.magnitude(sub); - if (dist < radius) { - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg) * powerUp[i].mass) / 26); - powerUp[i].force.x += knock.x; - powerUp[i].force.y += knock.y; - } else if (dist < alertRange) { - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg) * powerUp[i].mass) / 40); - powerUp[i].force.x += knock.x; - powerUp[i].force.y += knock.y; - } - } - - // bullet knock backs (not working: no effect for drones, crash for superballs) - // for (let i = 0, len = bullet.length; i < len; ++i) { - // if (me !== i) { - // sub = Matter.Vector.sub(bullet[me].position, bullet[i].position); - // dist = Matter.Vector.magnitude(sub); - // if (dist < radius) { - // knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg) * bullet[i].mass) / 10); - // bullet[i].force.x += knock.x; - // bullet[i].force.y += knock.y; - // console.log(sub, dist, knock) - // } else if (dist < alertRange) { - // knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg) * bullet[i].mass) / 20); - // bullet[i].force.x += knock.x; - // bullet[i].force.y += knock.y; - // } - // } - // } - - //destroy all bullets in range - // for (let i = 0, len = bullet.length; i < len; ++i) { - // if (me != i) { - // sub = Matter.Vector.sub(bullet[me].position, bullet[i].position); - // dist = Matter.Vector.magnitude(sub); - // if (dist < radius) { - // bullet[i].endCycle = mech.cycle; - // } - // } - // } - - //mob damage and knock back with no alert - // for (let i = 0, len = mob.length; i < len; ++i) { - // if (mob[i].alive) { - // let vertices = mob[i].vertices; - // for (let j = 0, len = vertices.length; j < len; j++) { - // sub = Matter.Vector.sub(bullet[me].position, vertices[j]); - // dist = Matter.Vector.magnitude(sub); - // if (dist < radius) { - // mob[i].damage(dmg); - // mob[i].locatePlayer(); - // knock = Matter.Vector.mult(Matter.Vector.normalise(sub), -Math.sqrt(dmg) * mob[i].mass / 18); - // mob[i].force.x += knock.x; - // mob[i].force.y += knock.y; - // break; - // } - // } - // } - // } - - //mob damage and knock back with alert - let damageScale = 1; // reduce dmg for each new target to limit total AOE damage - for (let i = 0, len = mob.length; i < len; ++i) { - if (mob[i].alive) { - sub = Matter.Vector.sub(bullet[me].position, mob[i].position); - dist = Matter.Vector.magnitude(sub); - if (dist < radius) { - mob[i].damage(dmg * damageScale); - mob[i].locatePlayer(); - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) / 18); - mob[i].force.x += knock.x; - mob[i].force.y += knock.y; - damageScale *= 0.8 //reduced damage for each additional explosion target - } else if (!mob[i].seePlayer.recall && dist < alertRange) { - mob[i].locatePlayer(); - knock = Matter.Vector.mult(Matter.Vector.normalise(sub), (-Math.sqrt(dmg * damageScale) * mob[i].mass) / 35); - mob[i].force.x += knock.x; - mob[i].force.y += knock.y; - } - } - } - - // Matter.Vector.magnitudeSquared(Matter.Vector.sub(bullet[me].position, mob[i].position)) - }, - guns: [{ - name: "laser", - description: "fire a beam of coherent light
reflects off walls at 75% intensity
uses energy instead of ammunition", - ammo: 0, - // ammoPack: 350, - ammoPack: Infinity, - have: false, - fire() { - // mech.fireCDcycle = mech.cycle + 1 - //laser drains energy as well as bullets - const FIELD_DRAIN = 0.003 - if (mech.fieldMeter < FIELD_DRAIN) { - mech.fireCDcycle = mech.cycle + 100; // cool down if out of energy - } else { - mech.fieldMeter -= mech.fieldRegen + FIELD_DRAIN - let best; - const color = "#f00"; - const range = 3000; - const path = [{ - x: mech.pos.x + 20 * Math.cos(mech.angle), - y: mech.pos.y + 20 * Math.sin(mech.angle) - }, - { - x: mech.pos.x + range * Math.cos(mech.angle), - y: mech.pos.y + range * Math.sin(mech.angle) - } - ]; - 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 && (!domain[i].mob || domain[i].alive)) { - 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 && (!domain[i].mob || domain[i].alive)) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - }; - const checkforCollisions = function () { - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - }; - vertexCollision(path[path.length - 2], path[path.length - 1], mob); - vertexCollision(path[path.length - 2], path[path.length - 1], map); - vertexCollision(path[path.length - 2], path[path.length - 1], body); - }; - const laserHitMob = function (dmg) { - if (best.who.alive) { - dmg *= b.dmgScale * 0.06; - best.who.damage(dmg); - best.who.locatePlayer(); - //draw mob damage circle - ctx.fillStyle = color; - ctx.beginPath(); - ctx.arc(path[path.length - 1].x, path[path.length - 1].y, Math.sqrt(dmg) * 100, 0, 2 * Math.PI); - ctx.fill(); - } - }; - - const reflection = function () { - // https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector - const n = Matter.Vector.perp(Matter.Vector.normalise(Matter.Vector.sub(best.v1, best.v2))); - const d = Matter.Vector.sub(path[path.length - 1], path[path.length - 2]); - const nn = Matter.Vector.mult(n, 2 * Matter.Vector.dot(d, n)); - const r = Matter.Vector.normalise(Matter.Vector.sub(d, nn)); - path[path.length] = Matter.Vector.add(Matter.Vector.mult(r, range), path[path.length - 1]); - }; - //beam before reflection - checkforCollisions(); - if (best.dist2 != Infinity) { - //if hitting something - path[path.length - 1] = { - x: best.x, - y: best.y - }; - laserHitMob(1); - - //1st reflection beam - reflection(); - //ugly bug fix: this stops the reflection on a bug where the beam gets trapped inside a body - let who = best.who; - checkforCollisions(); - if (best.dist2 != Infinity) { - //if hitting something - path[path.length - 1] = { - x: best.x, - y: best.y - }; - laserHitMob(0.75); - - //2nd reflection beam - //ugly bug fix: this stops the reflection on a bug where the beam gets trapped inside a body - if (who !== best.who) { - reflection(); - checkforCollisions(); - if (best.dist2 != Infinity) { - //if hitting something - path[path.length - 1] = { - x: best.x, - y: best.y - }; - laserHitMob(0.5); - } - } - } - } - ctx.fillStyle = color; - ctx.strokeStyle = color; - ctx.lineWidth = 2; - ctx.lineDashOffset = 300 * Math.random() - // ctx.setLineDash([200 * Math.random(), 250 * Math.random()]); - - ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); - for (let i = 1, len = path.length; i < len; ++i) { - ctx.beginPath(); - ctx.moveTo(path[i - 1].x, path[i - 1].y); - ctx.lineTo(path[i].x, path[i].y); - ctx.stroke(); - ctx.globalAlpha *= 0.5; //reflections are less intense - // ctx.globalAlpha -= 0.1; //reflections are less intense - } - ctx.setLineDash([0, 0]); - ctx.globalAlpha = 1; - } - } - // }, { - // name: "entropic beam", - // description: "steal entropy to heal
reflects off walls at 75% intensity
uses energy instead of ammunition", - // ammo: 0, - // // ammoPack: 350, - // ammoPack: Infinity, - // have: false, - // fire() { - // // mech.fireCDcycle = mech.cycle + 1 - // //laser drains energy as well as bullets - // const FIELD_DRAIN = 0.0001 //should be 0.001 - // if (mech.fieldMeter < FIELD_DRAIN) { - // mech.fireCDcycle = mech.cycle + 100; // cool down if out of energy - // } else { - // mech.fieldMeter -= mech.fieldRegen + FIELD_DRAIN - // let best; - // const color = "#a0a"; - // const range = 600; - // const path = [{ - // x: mech.pos.x + 20 * Math.cos(mech.angle), - // y: mech.pos.y + 20 * Math.sin(mech.angle) - // }, - // { - // x: mech.pos.x + range * Math.cos(mech.angle), - // y: mech.pos.y + range * Math.sin(mech.angle) - // } - // ]; - // 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 && (!domain[i].mob || domain[i].alive)) { - // 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 && (!domain[i].mob || domain[i].alive)) { - // best = { - // x: results.x, - // y: results.y, - // dist2: dist2, - // who: domain[i], - // v1: vertices[0], - // v2: vertices[len] - // }; - // } - // } - // } - // }; - // const checkforCollisions = function () { - // best = { - // x: null, - // y: null, - // dist2: Infinity, - // who: null, - // v1: null, - // v2: null - // }; - // vertexCollision(path[path.length - 2], path[path.length - 1], mob); - // vertexCollision(path[path.length - 2], path[path.length - 1], map); - // vertexCollision(path[path.length - 2], path[path.length - 1], body); - // }; - // const laserHitMob = function (dmg) { - // if (best.who.alive) { - // dmg *= b.dmgScale * 0.02; - // mech.addHealth(0.002) - // best.who.damage(dmg); - // best.who.locatePlayer(); - // //draw mob damage circle - // ctx.fillStyle = color; - // ctx.beginPath(); - // ctx.arc(path[path.length - 1].x, path[path.length - 1].y, Math.sqrt(dmg) * 100, 0, 2 * Math.PI); - // ctx.fill(); - // } - // }; - // checkforCollisions(); - // if (best.dist2 != Infinity) { - // //if hitting something - // path[path.length - 1] = { - // x: best.x, - // y: best.y - // }; - // laserHitMob(1); - // } - // ctx.fillStyle = color; - // ctx.strokeStyle = color; - // ctx.lineWidth = 4; - // for (let i = 1, len = path.length; i < len; ++i) { - // d = { - // x: path[i].x - path[i - 1].x, - // y: path[i].y - path[i - 1].y - // } - // const a = mech.cycle * 5 - // p1 = { - // x: d.x / 2 * Math.cos(a) - d.y / 2 * Math.sin(a), - // y: d.x / 2 * Math.sin(a) + d.y / 2 * Math.cos(a), - // } - // const wave = 300 / Math.sqrt(d.x * d.x + d.y * d.y) - // ctx.beginPath(); - // ctx.moveTo(path[i - 1].x, path[i - 1].y); - // ctx.bezierCurveTo(path[i - 1].x + p1.x * wave, path[i - 1].y + p1.y * wave, path[i].x + p1.x * wave, path[i].y + p1.y * wave, path[i].x, path[i].y); - // ctx.stroke(); - // } - // } - // } - }, { - name: "one shot", - description: "fire a huge bullet with high recoil
effective at long distances", - ammo: 0, - ammoPack: 5, - have: false, - fire() { - b.muzzleFlash(45); - // mobs.alert(800); - const me = bullet.length; - const dir = mech.angle; - bullet[me] = Bodies.rectangle(mech.pos.x + 50 * Math.cos(mech.angle), mech.pos.y + 50 * Math.sin(mech.angle), 70 * b.modBulletSize, 30 * b.modBulletSize, b.fireAttributes(dir)); - b.fireProps(mech.crouch ? 55 : 40, 50, dir, me); //cd , speed - bullet[me].endCycle = game.cycle + Math.floor(180 * b.modBulletsLastLonger); - bullet[me].do = function () { - this.force.y += this.mass * 0.0005; - }; - - //knock back - const KNOCK = ((mech.crouch) ? 0.025 : 0.25) * b.modBulletSize * b.modBulletSize - player.force.x -= KNOCK * Math.cos(dir) - player.force.y -= KNOCK * Math.sin(dir) * 0.5 //reduce knock back in vertical direction to stop super jumps - } - }, - { - name: "rapid fire", - description: "fire a stream of bullets", - ammo: 0, - ammoPack: 100, - have: false, - fire() { - const me = bullet.length; - b.muzzleFlash(15); - // if (Math.random() > 0.2) mobs.alert(500); - const dir = mech.angle + (Math.random() - 0.5) * ((mech.crouch) ? 0.07 : 0.16); - bullet[me] = Bodies.rectangle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 17 * b.modBulletSize, 5 * b.modBulletSize, b.fireAttributes(dir)); - b.fireProps(mech.crouch ? 11 : 5, mech.crouch ? 44 : 36, dir, me); //cd , speed - bullet[me].endCycle = game.cycle + Math.floor(65 * b.modBulletsLastLonger); - bullet[me].frictionAir = 0.01; - bullet[me].do = function () { - this.force.y += this.mass * 0.0005; - }; - } - }, - { - name: "wave beam", - description: "fire a stream of oscillating particles
propagates through solids
effective at close range", - ammo: 0, - ammoPack: 100, - have: false, - fire() { - const me = bullet.length; - const DIR = mech.angle - const SCALE = (mech.crouch ? 0.963 : 0.95) - const wiggleMag = ((mech.flipLegs === 1) ? 1 : -1) * ((mech.crouch) ? 0.004 : 0.005) - bullet[me] = Bodies.circle(mech.pos.x + 25 * Math.cos(DIR), mech.pos.y + 25 * Math.sin(DIR), 10 * b.modBulletSize, { - angle: DIR, - cycle: -0.43, //adjust this number until the bullets line up with the cross hairs - endCycle: game.cycle + Math.floor((mech.crouch ? 155 : 120) * b.modBulletsLastLonger), - inertia: Infinity, - frictionAir: 0, - minDmgSpeed: 0, - dmg: 0.13, //damage done in addition to the damage from momentum - classType: "bullet", - collisionFilter: { - category: 0x000100, - mask: 0x000010 - }, - onDmg() {}, - onEnd() {}, - do() { - if (!mech.isBodiesAsleep) { - this.cycle++ - const THRUST = wiggleMag * Math.cos(this.cycle * 0.3) - this.force = Matter.Vector.mult(Matter.Vector.normalise(this.direction), this.mass * THRUST) //wiggle - - if (this.cycle > 0 && !(Math.floor(this.cycle) % 6)) Matter.Body.scale(this, SCALE, SCALE); //shrink - } - } - }); - World.add(engine.world, bullet[me]); //add bullet to world - mech.fireCDcycle = mech.cycle + Math.floor((mech.crouch ? 8 : 4) * b.modFireRate); // cool down - const SPEED = mech.crouch ? 5.2 : 4.5; - Matter.Body.setVelocity(bullet[me], { - x: SPEED * Math.cos(DIR), - y: SPEED * Math.sin(DIR) - }); - bullet[me].direction = Matter.Vector.perp(bullet[me].velocity) - // if (mech.angle + Math.PI / 2 > 0) { - // bullet[me].direction = Matter.Vector.perp(bullet[me].velocity, true) - // } else { - // bullet[me].direction = Matter.Vector.perp(bullet[me].velocity) - // } - - World.add(engine.world, bullet[me]); //add bullet to world - } - }, - { - name: "super balls", - description: "fire 3 very bouncy balls", - ammo: 0, - ammoPack: 10, - have: false, - fire() { - b.muzzleFlash(20); - // mobs.alert(450); - const SPREAD = mech.crouch ? 0.04 : 0.14 - let dir = mech.angle - SPREAD; - for (let i = 0; i < 3; i++) { - const me = bullet.length; - bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 7 * b.modBulletSize, b.fireAttributes(dir, false)); - b.fireProps(mech.crouch ? 40 : 20, mech.crouch ? 34 : 26, dir, me); //cd , speed - Matter.Body.setDensity(bullet[me], 0.0001); - bullet[me].endCycle = game.cycle + Math.floor(360 * b.modBulletsLastLonger); - bullet[me].dmg = 0.5; - bullet[me].minDmgSpeed = 0; - bullet[me].restitution = 0.96; - bullet[me].friction = 0; - bullet[me].do = function () { - this.force.y += this.mass * 0.001; - }; - dir += SPREAD; - } - } - }, - { - name: "spray", - description: "fire a burst of bullets with high recoil
more effective at close range", - ammo: 0, - ammoPack: 8, - have: false, - fire() { - b.muzzleFlash(35); - // mobs.alert(650); - const side = 11 * b.modBulletSize - for (let i = 0; i < 9; i++) { - const me = bullet.length; - const dir = mech.angle + (Math.random() - 0.5) * (mech.crouch ? 0.2 : 0.6) - bullet[me] = Bodies.rectangle(mech.pos.x + 35 * Math.cos(mech.angle) + 15 * (Math.random() - 0.5), mech.pos.y + 35 * Math.sin(mech.angle) + 15 * (Math.random() - 0.5), side, side, b.fireAttributes(dir)); - b.fireProps(mech.crouch ? 60 : 30, 36 + Math.random() * 11, dir, me); //cd , speed - bullet[me].endCycle = game.cycle + Math.floor(60 * b.modBulletsLastLonger); - bullet[me].frictionAir = 0.02; - bullet[me].do = function () { - this.force.y += this.mass * 0.001; - }; - } - - //knock back - const KNOCK = ((mech.crouch) ? 0.015 : 0.15) * b.modBulletSize * b.modBulletSize - player.force.x -= KNOCK * Math.cos(mech.angle) - player.force.y -= KNOCK * Math.sin(mech.angle) * 0.5 //reduce knock back in vertical direction to stop super jumps - } - }, - { - name: "needles", - description: "fire a narrow projectile
effective at long distances", - ammo: 0, - ammoPack: 17, - have: false, - fire() { - const me = bullet.length; - const dir = mech.angle; - if (mech.crouch) { - bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(mech.angle), mech.pos.y + 40 * Math.sin(mech.angle), 40 * b.modBulletSize, 3 * b.modBulletSize, b.fireAttributes(dir)); - } else { - bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(mech.angle), mech.pos.y + 40 * Math.sin(mech.angle), 31 * b.modBulletSize, 2 * b.modBulletSize, b.fireAttributes(dir)); - } - b.fireProps(mech.crouch ? 40 : 20, mech.crouch ? 45 : 37, dir, me); //cd , speed - bullet[me].endCycle = game.cycle + Math.floor(180 * b.modBulletsLastLonger); - bullet[me].dmg = mech.crouch ? 1.4 : 1; - b.drawOneBullet(bullet[me].vertices); - bullet[me].do = function () { - //low gravity - this.force.y += this.mass * 0.0002; - }; - } - }, - { - name: "missiles", - description: "fire a missile that accelerates towards nearby targets
explodes when near target", - ammo: 0, - ammoPack: 8, - have: false, - fireCycle: 0, - ammoLoaded: 0, - fire() { - const thrust = 0.0003; - let dir = mech.angle + (0.5 - Math.random()) * (mech.crouch ? 0 : 0.2); - const me = bullet.length; - bullet[me] = Bodies.rectangle(mech.pos.x + 40 * Math.cos(mech.angle), mech.pos.y + 40 * Math.sin(mech.angle) - 3, 30 * b.modBulletSize, 4 * b.modBulletSize, b.fireAttributes(dir)); - b.fireProps(mech.crouch ? 70 : 30, -3 * (0.5 - Math.random()) + (mech.crouch ? 25 : -8), dir, me); //cd , speed - - b.drawOneBullet(bullet[me].vertices); - // Matter.Body.setDensity(bullet[me], 0.01) //doesn't help with reducing explosion knock backs - bullet[me].force.y += 0.00045; //a small push down at first to make it seem like the missile is briefly falling - bullet[me].frictionAir = 0 - bullet[me].endCycle = game.cycle + Math.floor((265 + Math.random() * 20) * b.modBulletsLastLonger); - bullet[me].explodeRad = 150 + 40 * Math.random(); - bullet[me].lookFrequency = Math.floor(8 + Math.random() * 7); - bullet[me].onEnd = b.explode; //makes bullet do explosive damage at end - bullet[me].onDmg = function () { - this.endCycle = 0; //bullet ends cycle after doing damage // also triggers explosion - }; - bullet[me].lockedOn = null; - bullet[me].do = function () { - if (!mech.isBodiesAsleep) { - if (!(mech.cycle % this.lookFrequency)) { - this.closestTarget = null; - this.lockedOn = null; - let closeDist = Infinity; - - //look for targets - for (let i = 0, len = mob.length; i < len; ++i) { - if ( - mob[i].alive && - mob[i].dropPowerUp && - Matter.Query.ray(map, this.position, mob[i].position).length === 0 && - Matter.Query.ray(body, this.position, mob[i].position).length === 0 - ) { - const dist = Matter.Vector.magnitude(Matter.Vector.sub(this.position, mob[i].position)); - if (dist < closeDist) { - this.closestTarget = mob[i].position; - closeDist = dist; - this.lockedOn = mob[i]; - } - } - } - //explode when bullet is close enough to target - if (this.closestTarget && closeDist < this.explodeRad * 0.7) { - this.endCycle = 0; //bullet ends cycle after doing damage //this also triggers explosion - } - - if (this.lockedOn) { - this.frictionAir = 0.04; //extra friction - - //draw locked on targeting - ctx.beginPath(); - const vertices = this.lockedOn.vertices; - ctx.moveTo(this.position.x, this.position.y); - const mod = Math.floor((game.cycle / 3) % vertices.length); - ctx.lineTo(vertices[mod].x, vertices[mod].y); - ctx.strokeStyle = "rgba(0,0,155,0.35)"; //"#2f6"; - ctx.lineWidth = 1; - ctx.stroke(); - } - } - - //rotate missile towards the target - if (this.closestTarget) { - const face = { - x: Math.cos(this.angle), - y: Math.sin(this.angle) - }; - const target = Matter.Vector.normalise(Matter.Vector.sub(this.position, this.closestTarget)); - if (Matter.Vector.dot(target, face) > -0.98) { - if (Matter.Vector.cross(target, face) > 0) { - Matter.Body.rotate(this, 0.08); - } else { - Matter.Body.rotate(this, -0.08); - } - } - } - //accelerate in direction bullet is facing - const dir = this.angle; // + (Math.random() - 0.5); - this.force.x += Math.cos(dir) * thrust; - this.force.y += Math.sin(dir) * thrust; - - //draw rocket - ctx.beginPath(); - ctx.arc(this.position.x - Math.cos(this.angle) * 27 + (Math.random() - 0.5) * 4, this.position.y - Math.sin(this.angle) * 27 + (Math.random() - 0.5) * 4, 11, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(255,155,0,0.5)"; - ctx.fill(); - } else { - //draw rocket with time stop - ctx.beginPath(); - ctx.arc(this.position.x - Math.cos(this.angle) * 27, this.position.y - Math.sin(this.angle) * 27, 11, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(255,155,0,0.5)"; - ctx.fill(); - } - } - } - }, - { - name: "flak", - description: "fire a cluster of explosive projectiles
explode on contact or after half a second", - ammo: 0, - ammoPack: 18, - have: false, - fire() { - b.muzzleFlash(30); - const totalBullets = 5 - const angleStep = (mech.crouch ? 0.06 : 0.15) / totalBullets - const SPEED = mech.crouch ? 27 : 20 - const CD = mech.crouch ? 50 : 20 - const END = Math.floor((mech.crouch ? 27 : 18) * b.modBulletsLastLonger); - let dir = mech.angle - angleStep * totalBullets / 2; - const side1 = 17 * b.modBulletSize - const side2 = 4 * b.modBulletSize - - for (let i = 0; i < totalBullets; i++) { //5 -> 7 - dir += angleStep - const me = bullet.length; - bullet[me] = Bodies.rectangle(mech.pos.x + 50 * Math.cos(mech.angle), mech.pos.y + 50 * Math.sin(mech.angle), side1, side2, b.fireAttributes(dir)); - b.fireProps(CD, SPEED + 25 * Math.random() - i, dir, me); //cd , speed - - //Matter.Body.setDensity(bullet[me], 0.00001); - bullet[me].endCycle = i + game.cycle + END - bullet[me].restitution = 0; - bullet[me].friction = 1; - bullet[me].explodeRad = 75 + (Math.random() - 0.5) * 50; - bullet[me].onEnd = b.explode; - bullet[me].onDmg = function () { - this.endCycle = 0; //bullet ends cycle after hitting a mob and triggers explosion - }; - bullet[me].do = function () { - this.force.y += this.mass * 0.0004; - // if (this.speed < 10) { //if slow explode - // for (let i = 0, len = bullet.length; i < len; i++) { - // bullet[i].endCycle = 0 //all other bullets explode - // } - // } - } - } - } - }, - { - name: "M80", - description: "rapidly fire small bouncy bombs
explodes on contact or after 2 seconds", - ammo: 0, - ammoPack: 45, - have: false, - 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), 10 * b.modBulletSize, b.fireAttributes(dir, false)); - b.fireProps(mech.crouch ? 15 : 8, mech.crouch ? 32 : 24, dir, me); //cd , speed - b.drawOneBullet(bullet[me].vertices); - Matter.Body.setDensity(bullet[me], 0.000001); - bullet[me].totalCycles = 120; - bullet[me].endCycle = game.cycle + Math.floor(120 * b.modBulletsLastLonger); - bullet[me].restitution = 0.6; - bullet[me].explodeRad = 130; - bullet[me].onEnd = b.explode; //makes bullet do explosive damage before despawn - bullet[me].minDmgSpeed = 1; - bullet[me].dmg = 0.25; - bullet[me].onDmg = function () { - this.endCycle = 0; //bullet ends cycle after doing damage //this triggers explosion - }; - bullet[me].do = function () { - //extra gravity for harder arcs - this.force.y += this.mass * 0.0025; - }; - } - }, - { - name: "grenades", - description: "fire a huge sticky bomb
explodes on contact or after 2 seconds", - ammo: 0, - ammoPack: 5, - have: false, - fire() { - const me = bullet.length; - const dir = mech.angle; - bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 22 * b.modBulletSize, b.fireAttributes(dir, false)); - bullet[me].radius = 22; //used from drawing timer - b.fireProps(mech.crouch ? 60 : 40, mech.crouch ? 38 : 30, dir, me); //cd , speed - - b.drawOneBullet(bullet[me].vertices); - Matter.Body.setDensity(bullet[me], 0.000001); - bullet[me].endCycle = game.cycle + Math.floor(140 * b.modBulletsLastLonger); - bullet[me].endCycleLength = Math.floor(140 * b.modBulletsLastLonger); - // bullet[me].restitution = 0.3; - // bullet[me].frictionAir = 0.01; - // bullet[me].friction = 0.15; - bullet[me].inertia = Infinity; //prevents rotation - bullet[me].restitution = 0; - bullet[me].friction = 1; - - bullet[me].explodeRad = 380 + Math.floor(Math.random() * 60); - bullet[me].onEnd = b.explode; //makes bullet do explosive damage before despawn - bullet[me].minDmgSpeed = 1; - bullet[me].onDmg = function () { - this.endCycle = 0; //bullet ends cycle after doing damage //this triggers explosion - }; - bullet[me].do = function () { - //extra gravity for harder arcs - this.force.y += this.mass * 0.0022; - //draw timer - if (!(game.cycle % 10)) { - if (this.isFlashOn) { - this.isFlashOn = false; - } else { - this.isFlashOn = true; - } - } - if (this.isFlashOn) { - ctx.fillStyle = "#000"; - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.radius, 0, 2 * Math.PI); - ctx.fill(); - //draw clock on timer - ctx.fillStyle = "#f12"; - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.radius * (1 - (this.endCycle - game.cycle) / this.endCycleLength), 0, 2 * Math.PI); - ctx.fill(); - } - }; - } - }, - { - name: "spores", - description: "release an orb that discharges spores after 2 seconds
spores seek out targets
spores can pass through blocks", - ammo: 0, - ammoPack: 5, - have: false, - 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), 20, 4.5, b.fireAttributes(dir, false)); - b.fireProps(mech.crouch ? 75 : 55, mech.crouch ? 25 : 14, dir, me); //cd , speed - b.drawOneBullet(bullet[me].vertices); - Matter.Body.setDensity(bullet[me], 0.000001); - bullet[me].endCycle = game.cycle + 100; - bullet[me].frictionAir = 0; - bullet[me].friction = 0.5; - bullet[me].restitution = 0.3; - bullet[me].minDmgSpeed = 0; - bullet[me].onDmg = function () {}; - bullet[me].do = function () { - if (!mech.isBodiesAsleep) { - const SCALE = 1.017 - Matter.Body.scale(this, SCALE, SCALE); - this.frictionAir += 0.00023; - } - - this.force.y += this.mass * 0.00045; - - //draw green glow - ctx.fillStyle = "rgba(0,200,125,0.16)"; - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, 26, 0, 2 * Math.PI); - ctx.fill(); - }; - - //spawn bullets on end - bullet[me].onEnd = function () { - const NUM = 9; - for (let i = 0; i < NUM; i++) { - const bIndex = bullet.length; - const RADIUS = (4 + 2 * Math.random()) * b.modBulletSize; - bullet[bIndex] = Bodies.circle(this.position.x, this.position.y, RADIUS, { - // density: 0.0015, //frictionAir: 0.01, - inertia: Infinity, - restitution: 0.9, - angle: dir, - friction: 0, - frictionAir: 0.01, - dmg: 1.65, //damage done in addition to the damage from momentum - classType: "bullet", - collisionFilter: { - category: 0x000100, - mask: 0x000011 //no collide with body - }, - endCycle: game.cycle + Math.floor((300 + Math.floor(Math.random() * 240)) * b.modBulletsLastLonger), - minDmgSpeed: 0, - onDmg() { - this.endCycle = 0; //bullet ends cycle after doing damage - }, - onEnd() {}, - lookFrequency: 67 + Math.floor(47 * Math.random()), - do() { - this.force.y += this.mass * 0.00025; //gravity - - //find mob targets - if (!(game.cycle % this.lookFrequency)) { - this.closestTarget = null; - this.lockedOn = null; - let closeDist = Infinity; - for (let i = 0, len = mob.length; i < len; ++i) { - if (Matter.Query.ray(map, this.position, mob[i].position).length === 0) { - // Matter.Query.ray(body, this.position, mob[i].position).length === 0 - const targetVector = Matter.Vector.sub(this.position, mob[i].position) - const dist = Matter.Vector.magnitude(targetVector); - if (dist < closeDist) { - this.closestTarget = mob[i].position; - closeDist = dist; - this.lockedOn = Matter.Vector.normalise(targetVector); - if (0.3 > Math.random()) break //doesn't always target the closest mob - } - } - } - } - //accelerate towards mobs - const THRUST = this.mass * 0.0008 - if (this.lockedOn) { - this.force.x -= THRUST * this.lockedOn.x - this.force.y -= THRUST * this.lockedOn.y - } - }, - }); - const SPEED = 9; - const ANGLE = 2 * Math.PI * Math.random() - Matter.Body.setVelocity(bullet[bIndex], { - x: SPEED * Math.cos(ANGLE), - y: SPEED * Math.sin(ANGLE) - }); - World.add(engine.world, bullet[bIndex]); //add bullet to world - } - } - - } - }, - { - name: "drones", - description: "release drones that seek out targets
if no targets, drones move to mouse
", - ammo: 0, - ammoPack: 20, - have: false, - fire() { - const THRUST = 0.0015 - const dir = mech.angle + (Math.random() - 0.5) * 0.7; - const me = bullet.length; - const RADIUS = (4 + 4 * Math.random()) * b.modBulletSize - bullet[me] = Bodies.circle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), RADIUS, { - angle: dir, - inertia: Infinity, - friction: 0, - frictionAir: 0.0005, - restitution: 1, - dmg: 0.14, //damage done in addition to the damage from momentum - lookFrequency: 79 + Math.floor(37 * Math.random()), - endCycle: game.cycle + Math.floor((780 + 360 * Math.random()) * b.modBulletsLastLonger), - classType: "bullet", - collisionFilter: { - category: 0x000100, - mask: 0x010111 //self collide - }, - minDmgSpeed: 0, - lockedOn: null, - isFollowMouse: true, - onDmg() { - this.lockedOn = null - }, - onEnd() {}, - do() { - this.force.y += this.mass * 0.0002; - //find mob targets - if (!(game.cycle % this.lookFrequency)) { - this.lockedOn = null; - let closeDist = Infinity; - for (let i = 0, len = mob.length; i < len; ++i) { - if ( - Matter.Query.ray(map, this.position, mob[i].position).length === 0 && - Matter.Query.ray(body, this.position, mob[i].position).length === 0 - ) { - const TARGET_VECTOR = Matter.Vector.sub(this.position, mob[i].position) - const DIST = Matter.Vector.magnitude(TARGET_VECTOR); - if (DIST < closeDist) { - closeDist = DIST; - this.lockedOn = mob[i] - } - } - } - if (!this.lockedOn) { - //grab a power up if it is (ammo) or (a heal when player is low) - let closeDist = Infinity; - for (let i = 0, len = powerUp.length; i < len; ++i) { - if ( - (powerUp[i].name === "ammo" || powerUp[i].name === "gun" || (powerUp[i].name === "heal" && mech.health < 0.8)) && - Matter.Query.ray(map, this.position, powerUp[i].position).length === 0 && - Matter.Query.ray(body, this.position, powerUp[i].position).length === 0 - ) { - const TARGET_VECTOR = Matter.Vector.sub(this.position, powerUp[i].position) - const DIST = Matter.Vector.magnitude(TARGET_VECTOR); - if (DIST < closeDist) { - if (DIST < 50) { //eat the power up if close enough - powerUp[i].effect(); - Matter.World.remove(engine.world, powerUp[i]); - powerUp.splice(i, 1); - break; - } - closeDist = DIST; - this.lockedOn = powerUp[i] - } - } - } - } - } - if (this.lockedOn) { //accelerate towards mobs - this.force = Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(this.position, this.lockedOn.position)), -this.mass * THRUST) - } else { //accelerate towards mouse - this.force = Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(this.position, game.mouseInGame)), -this.mass * THRUST) - } - // speed cap instead of friction to give more agility - if (this.speed > 6) { - Matter.Body.setVelocity(this, { - x: this.velocity.x * 0.97, - y: this.velocity.y * 0.97 - }); - } - } - }) - b.fireProps(mech.crouch ? 22 : 15, mech.crouch ? 26 : 1, dir, me); //cd , speed - b.drawOneBullet(bullet[me].vertices); - } - }, - ] -}; \ No newline at end of file diff --git a/js/engine.js b/js/engine.js deleted file mode 100644 index 1fc9121..0000000 --- a/js/engine.js +++ /dev/null @@ -1,174 +0,0 @@ -//matter.js *********************************************************** -// module aliases -const Engine = Matter.Engine, - World = Matter.World, - Events = Matter.Events, - Composites = Matter.Composites, - Composite = Matter.Composite, - Constraint = Matter.Constraint, - Vertices = Matter.Vertices, - Query = Matter.Query, - Body = Matter.Body, - Bodies = Matter.Bodies; - -// create an engine -const engine = Engine.create(); -engine.world.gravity.scale = 0; //turn off gravity (it's added back in later) -// engine.velocityIterations = 100 -// engine.positionIterations = 100 -// engine.enableSleeping = true - -// matter events ********************************************************* -//************************************************************************ -//************************************************************************ -//************************************************************************ - -function playerOnGroundCheck(event) { - //runs on collisions events - function enter() { - mech.numTouching++; - if (!mech.onGround) mech.enterLand(); - } - const pairs = event.pairs; - for (let i = 0, j = pairs.length; i != j; ++i) { - let pair = pairs[i]; - if (pair.bodyA === jumpSensor) { - mech.standingOn = pair.bodyB; //keeping track to correctly provide recoil on jump - enter(); - } else if (pair.bodyB === jumpSensor) { - mech.standingOn = pair.bodyA; //keeping track to correctly provide recoil on jump - enter(); - } - } - mech.numTouching = 0; -} - -function playerOffGroundCheck(event) { - //runs on collisions events - function enter() { - if (mech.onGround && mech.numTouching === 0) mech.enterAir(); - } - const pairs = event.pairs; - for (let i = 0, j = pairs.length; i != j; ++i) { - if (pairs[i].bodyA === jumpSensor) { - enter(); - } else if (pairs[i].bodyB === jumpSensor) { - enter(); - } - } -} - -function playerHeadCheck(event) { - //runs on collisions events - if (mech.crouch) { - mech.isHeadClear = true; - const pairs = event.pairs; - for (let i = 0, j = pairs.length; i != j; ++i) { - if (pairs[i].bodyA === headSensor) { - mech.isHeadClear = false; - } else if (pairs[i].bodyB === headSensor) { - mech.isHeadClear = false; - } - } - } -} - -function mobCollisionChecks(event) { - const pairs = event.pairs; - for (let i = 0, j = pairs.length; i != j; i++) { - for (let k = 0; k < mob.length; k++) { - if (mob[k].alive && mech.alive) { - if (pairs[i].bodyA === mob[k]) { - collide(pairs[i].bodyB); - break; - } else if (pairs[i].bodyB === mob[k]) { - collide(pairs[i].bodyA); - break; - } - - function collide(obj) { - //player and mob collision - if (obj === playerBody || obj === playerHead) { - if (mech.damageImmune < mech.cycle) { - //player is immune to mob collision damage for 30 cycles - mech.damageImmune = mech.cycle + 30; - mob[k].foundPlayer(); - let dmg = Math.min(Math.max(0.025 * Math.sqrt(mob[k].mass), 0.05), 0.3) * game.dmgScale; //player damage is capped at 0.3*dmgScale of 1.0 - mech.damage(dmg); - if (mob[k].onHit) mob[k].onHit(k); - game.drawList.push({ - //add dmg to draw queue - x: pairs[i].activeContacts[0].vertex.x, - y: pairs[i].activeContacts[0].vertex.y, - radius: dmg * 500, - color: game.mobDmgColor, - time: game.drawTime - }); - } - //extra kick between player and mob - //this section would be better with forces but they don't work... - let angle = Math.atan2(player.position.y - mob[k].position.y, player.position.x - mob[k].position.x); - Matter.Body.setVelocity(player, { - x: player.velocity.x + 8 * Math.cos(angle), - y: player.velocity.y + 8 * Math.sin(angle) - }); - Matter.Body.setVelocity(mob[k], { - x: mob[k].velocity.x - 8 * Math.cos(angle), - y: mob[k].velocity.y - 8 * Math.sin(angle) - }); - return; - } - //bullet mob collisions - if (obj.classType === "bullet" && obj.speed > obj.minDmgSpeed) { - mob[k].foundPlayer(); - const dmg = b.dmgScale * (obj.dmg + 0.15 * obj.mass * Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity))); - // console.log(dmg) - mob[k].damage(dmg); - obj.onDmg(); //some bullets do actions when they hits things, like despawn - game.drawList.push({ - //add dmg to draw queue - x: pairs[i].activeContacts[0].vertex.x, - y: pairs[i].activeContacts[0].vertex.y, - radius: Math.sqrt(dmg) * 40, - color: game.playerDmgColor, - time: game.drawTime - }); - return; - } - //mob and body collisions - if (obj.classType === "body" && obj.speed > 5) { - const v = Matter.Vector.magnitude(Matter.Vector.sub(mob[k].velocity, obj.velocity)); - if (v > 8) { - let dmg = b.dmgScale * v * Math.sqrt(obj.mass) * 0.05; - mob[k].damage(dmg); - if (mob[k].distanceToPlayer2() < 1000000) mob[k].foundPlayer(); - game.drawList.push({ - //add dmg to draw queue - x: pairs[i].activeContacts[0].vertex.x, - y: pairs[i].activeContacts[0].vertex.y, - radius: Math.sqrt(dmg) * 40, - color: game.playerDmgColor, - time: game.drawTime - }); - return; - } - } - } - } - } - } -} - -//determine if player is on the ground -Events.on(engine, "collisionStart", function (event) { - playerOnGroundCheck(event); - playerHeadCheck(event); - mobCollisionChecks(event); -}); -Events.on(engine, "collisionActive", function (event) { - playerOnGroundCheck(event); - playerHeadCheck(event); -}); -Events.on(engine, "collisionEnd", function (event) { - playerOffGroundCheck(event); -}); \ No newline at end of file diff --git a/js/game.js b/js/game.js deleted file mode 100644 index d9f5cee..0000000 --- a/js/game.js +++ /dev/null @@ -1,1023 +0,0 @@ -// game Object ******************************************************** -//********************************************************************* -const game = { - loop() { - game.cycle++; //tracks game cycles - mech.cycle++; //tracks player cycles //used to alow time to stop for everything, but the player - if (game.clearNow) { - game.clearNow = false; - game.clearMap(); - level.start(); - } - game.gravity(); - Engine.update(engine, game.delta); - game.wipe(); - game.textLog(); - mech.keyMove(); - level.checkZones(); - level.checkQuery(); - mech.move(); - mech.look(); - game.fallChecks(); - ctx.save(); - game.camera(); - if (game.testing) { - mech.draw(); - game.draw.wireFrame(); - game.draw.cons(); - game.draw.testing(); - game.drawCircle(); - ctx.restore(); - game.getCoords.out(); - game.testingOutput(); - } else { - level.drawFillBGs(); - level.exit.draw(); - level.enter.draw(); - game.draw.powerUp(); - mobs.draw(); - game.draw.cons(); - game.draw.body(); - mobs.loop(); - mech.draw(); - mech.hold(); - level.drawFills(); - game.draw.drawMapPath(); - b.draw(); - b.fire(); - game.drawCircle(); - ctx.restore(); - } - game.drawCursor(); - }, - mouse: { - x: canvas.width / 2, - y: canvas.height / 2 - }, - mouseInGame: { - x: 0, - y: 0 - }, - levelsCleared: 0, - g: 0.001, - dmgScale: 1, - accelScale: 1, - CDScale: 1, - lookFreqScale: 1, - onTitlePage: true, - paused: false, - testing: false, //testing mode: shows wireframe and some variables - cycle: 0, //total cycles, 60 per second - fpsCap: 72, //limits frames per second to 144/2=72, on most monitors the fps is capped at 60fps by the hardware - fpsCapDefault: 72, //use to change fpsCap back to normal after a hit from a mob - cyclePaused: 0, - fallHeight: 3000, //below this y position the player dies - lastTimeStamp: 0, //tracks time stamps for measuring delta - delta: 1000 / 60, //speed of game engine //looks like it has to be 16 to match player input - buttonCD: 0, - // dropFPS(cap = 40, time = 15) { - // game.fpsCap = cap - // game.fpsInterval = 1000 / game.fpsCap; - // game.defaultFPSCycle = game.cycle + time - // const normalFPS = function () { - // if (game.defaultFPSCycle < game.cycle) { - // game.fpsCap = 72 - // game.fpsInterval = 1000 / game.fpsCap; - // } else { - // requestAnimationFrame(normalFPS); - // } - // }; - // requestAnimationFrame(normalFPS); - // }, - drawCursor() { - const size = 10; - ctx.beginPath(); - ctx.moveTo(game.mouse.x - size, game.mouse.y); - ctx.lineTo(game.mouse.x + size, game.mouse.y); - ctx.moveTo(game.mouse.x, game.mouse.y - size); - ctx.lineTo(game.mouse.x, game.mouse.y + size); - ctx.lineWidth = 2; - ctx.strokeStyle = "#000"; //'rgba(0,0,0,0.4)' - ctx.stroke(); // Draw it - }, - drawList: [], //so you can draw a first frame of explosions.. I know this is bad - drawTime: 8, //how long circles are drawn. use to push into drawlist.time - mobDmgColor: "rgba(255,0,0,0.7)", //used top push into drawList.color - playerDmgColor: "rgba(0,0,0,0.7)", //used top push into drawList.color - drawCircle() { - //draws a circle for two cycles, used for showing damage mostly - let i = this.drawList.length; - while (i--) { - ctx.beginPath(); //draw circle - ctx.arc(this.drawList[i].x, this.drawList[i].y, this.drawList[i].radius, 0, 2 * Math.PI); - ctx.fillStyle = this.drawList[i].color; - ctx.fill(); - if (this.drawList[i].time) { - //remove when timer runs out - this.drawList[i].time--; - } else { - this.drawList.splice(i, 1); - } - } - }, - lastLogTime: 0, - lastLogTimeBig: 0, - boldActiveGunHUD() { - if (b.inventory.length > 0) { - for (let i = 0, len = b.inventory.length; i < len; ++i) { - // document.getElementById(b.inventory[i]).style.fontSize = "25px"; - document.getElementById(b.inventory[i]).style.opacity = "0.3"; - } - // document.getElementById(b.activeGun).style.fontSize = "30px"; - if (document.getElementById(b.activeGun)) document.getElementById(b.activeGun).style.opacity = "1"; - } - }, - updateGunHUD() { - for (let i = 0, len = b.inventory.length; i < len; ++i) { - document.getElementById(b.inventory[i]).innerHTML = b.guns[b.inventory[i]].name + " - " + b.guns[b.inventory[i]].ammo; - } - }, - makeGunHUD() { - //remove all nodes - const myNode = document.getElementById("guns"); - while (myNode.firstChild) { - myNode.removeChild(myNode.firstChild); - } - //add nodes - for (let i = 0, len = b.inventory.length; i < len; ++i) { - const node = document.createElement("div"); - node.setAttribute("id", b.inventory[i]); - let textnode = document.createTextNode(b.guns[b.inventory[i]].name + " - " + b.guns[b.inventory[i]].ammo); - node.appendChild(textnode); - document.getElementById("guns").appendChild(node); - } - game.boldActiveGunHUD(); - }, - updateModHUD() { - let text = "" - if (mech.fieldMode !== 0) { - text += mech.fieldUpgrades[mech.fieldMode].name - if (b.mod !== null) text += "
" + b.mods[b.mod].name - } else if (b.mod !== null) { - text += b.mods[b.mod].name - } - document.getElementById("mods").innerHTML = text - }, - makeTextLog(text, time = 180) { - document.getElementById("text-log").innerHTML = text; - document.getElementById("text-log").style.opacity = 1; - game.lastLogTime = mech.cycle + time; - }, - textLog() { - if (game.lastLogTime && game.lastLogTime < mech.cycle) { - game.lastLogTime = 0; - // document.getElementById("text-log").innerHTML = " "; - document.getElementById("text-log").style.opacity = 0; - } - }, - // timing: function() { - // this.cycle++; //tracks game cycles - // //delta is used to adjust forces on game slow down; - // this.delta = (engine.timing.timestamp - this.lastTimeStamp) / 16.666666666666; - // this.lastTimeStamp = engine.timing.timestamp; //track last engine timestamp - // }, - nextGun() { - if (b.inventory.length > 0) { - b.inventoryGun++; - if (b.inventoryGun > b.inventory.length - 1) b.inventoryGun = 0; - game.switchGun(); - } - }, - previousGun() { - if (b.inventory.length > 0) { - b.inventoryGun--; - if (b.inventoryGun < 0) b.inventoryGun = b.inventory.length - 1; - game.switchGun(); - } - }, - switchGun() { - b.activeGun = b.inventory[b.inventoryGun]; - game.updateGunHUD(); - game.boldActiveGunHUD(); - // mech.drop(); - }, - // tips = [ - // "You can throw blocks at dangerous speeds by holding the right mouse or spacebar.", - // "You can use your field to block damage. (right mouse or spacebar)", - // "Explosive weapons, like the grenade are good at clearing groups.", - // "Larger and faster bullets do more damage.", - // "You take more damage from colliding with larger baddies", - // "Holding large blocks slows down the player.", - // "holding blocks prevents the field energy from regenerating.", - // `There are ${mech.fieldUpgrades.length-1} possible field upgrades.`, - // `There are ${b.guns.length} different guns.`, - // "You keep field upgrades after you die.", - // "Unique level bosses always drop a field upgrade if you don't have one.", - // "You jump higher if you hold down the jump button.", - // "Crouching while firing makes bullets go faster, but slows the rate of fire.", - // ] - keyPress() { - if (keys[189]) { - // - key - game.zoomScale /= 0.9; - game.setZoom(); - } else if (keys[187]) { - // = key - game.zoomScale *= 0.9; - game.setZoom(); - } - - //full screen toggle - // if (keys[13]) { - // //enter key - // var doc = window.document; - // var docEl = doc.documentElement; - - // var requestFullScreen = docEl.requestFullscreen || docEl.mozRequestFullScreen || docEl.webkitRequestFullScreen || docEl.msRequestFullscreen; - // var cancelFullScreen = doc.exitFullscreen || doc.mozCancelFullScreen || doc.webkitExitFullscreen || doc.msExitFullscreen; - - // if (!doc.fullscreenElement && !doc.mozFullScreenElement && !doc.webkitFullscreenElement && !doc.msFullscreenElement) { - // requestFullScreen.call(docEl); - // } else { - // cancelFullScreen.call(doc); - // } - // setupCanvas(); - // } - - - if (keys[69]) { - // e swap to next active gun - game.nextGun(); - } else if (keys[81]) { - //q swap to previous active gun - game.previousGun(); - } - - if (keys[80]) { - //p for pause - if (game.paused) { - game.paused = false; - requestAnimationFrame(cycle); - } else { - game.paused = true; - game.makeTextLog("

PAUSED

", 1); - // let text = "

PAUSED


" - // //output current mod, field, and gun info when paused - // if (mech.fieldMode !== 0) text += "

" + mech.fieldUpgrades[mech.fieldMode].name + "
" + mech.fieldUpgrades[mech.fieldMode].description + "

" - // if (b.mod !== null) text += "

" + b.mods[b.mod].name + "
" + b.mods[b.mod].description + "

" - // if (b.activeGun !== null) text += "

" + b.guns[b.activeGun].name + "
" + b.guns[b.activeGun].description + "

" - // text += "
" - // game.makeTextLog(text, 1); - } - } - - //toggle testing mode - if (keys[84]) { - // 84 = t - if (this.testing) { - this.testing = false; - } else { - this.testing = true; - } - } else if (this.testing) { - //only in testing mode - - if (keys[70]) { //cycle fields with F - if (mech.fieldMode === mech.fieldUpgrades.length - 1) { - mech.fieldUpgrades[0].effect() - } else { - mech.fieldUpgrades[mech.fieldMode + 1].effect() - } - } - if (keys[71]) { // give all guns with G - b.giveGuns("all", 1000) - } - if (keys[72]) { // power ups with H - powerUps.spawn(game.mouseInGame.x, game.mouseInGame.y, "gun"); - powerUps.spawn(game.mouseInGame.x, game.mouseInGame.y, "gun"); - powerUps.spawn(game.mouseInGame.x, game.mouseInGame.y, "gun"); - powerUps.spawn(game.mouseInGame.x, game.mouseInGame.y, "field"); - powerUps.spawn(game.mouseInGame.x, game.mouseInGame.y, "mod"); - powerUps.spawn(game.mouseInGame.x, game.mouseInGame.y, "heal"); - powerUps.spawn(game.mouseInGame.x, game.mouseInGame.y, "heal"); - } - if (keys[89]) { //cycle fields with F - if (b.mod === b.mods.length - 1) { - b.mods[0].effect() - } else { - b.mods[b.mod + 1].effect() - } - } - if (keys[82]) { // teleport to mouse with R - Matter.Body.setPosition(player, this.mouseInGame); - Matter.Body.setVelocity(player, { - x: 0, - y: 0 - }); - } - } - }, - zoom: null, - zoomScale: 1000, - setZoom(zoomScale = game.zoomScale) { //use in window resize in index.js - game.zoomScale = zoomScale - game.zoom = canvas.height / zoomScale; //sets starting zoom scale - }, - zoomTransition(newZoomScale, step = 2) { - const isBigger = (newZoomScale - game.zoomScale > 0) ? true : false; - requestAnimationFrame(zLoop); - const currentLevel = level.onLevel - - function zLoop() { - if (currentLevel != level.onLevel) return //stop the zoom if player goes to a new level - - if (isBigger) { - game.zoomScale += step - if (game.zoomScale >= newZoomScale) { - game.setZoom(newZoomScale); - return - } - } else { - game.zoomScale -= step - if (game.zoomScale <= newZoomScale) { - game.setZoom(newZoomScale); - return - } - } - - game.setZoom(); - requestAnimationFrame(zLoop); - } - }, - camera() { - ctx.translate(canvas.width2, canvas.height2); //center - ctx.scale(game.zoom, game.zoom); //zoom in once centered - ctx.translate(-canvas.width2 + mech.transX, -canvas.height2 + mech.transY); //translate - //calculate in game mouse position by undoing the zoom and translations - game.mouseInGame.x = (game.mouse.x - canvas.width2) / game.zoom + canvas.width2 - mech.transX; - game.mouseInGame.y = (game.mouse.y - canvas.height2) / game.zoom + canvas.height2 - mech.transY; - }, - zoomInFactor: 0, - startZoomIn(time = 180) { - game.zoom = 0; - let count = 0; - requestAnimationFrame(zLoop); - - function zLoop() { - game.zoom += canvas.height / game.zoomScale / time; - count++; - if (count < time) { - requestAnimationFrame(zLoop); - } else { - game.setZoom(); - } - } - }, - wipe() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - // ctx.fillStyle = "rgba(255,255,255,1)"; - // ctx.globalCompositeOperation = "difference"; - // ctx.fillRect(0, 0, canvas.width, canvas.height); - // ctx.globalCompositeOperation = "source-over"; - - // ctx.globalAlpha = (mech.health < 0.7) ? (mech.health+0.3)*(mech.health+0.3) : 1 - // if (mech.health < 0.7) { - // ctx.globalAlpha= 0.3 + mech.health - // ctx.fillStyle = document.body.style.backgroundColor - // ctx.fillRect(0, 0, canvas.width, canvas.height); - // ctx.globalAlpha=1; - // } else { - // ctx.clearRect(0, 0, canvas.width, canvas.height); - // } - //ctx.fillStyle = "rgba(255,255,255," + (1 - Math.sqrt(player.speed)*0.1) + ")"; - //ctx.fillStyle = "rgba(255,255,255,0.4)"; - //ctx.fillRect(0, 0, canvas.width, canvas.height); - }, - gravity() { - function addGravity(bodies, magnitude) { - for (var i = 0; i < bodies.length; i++) { - bodies[i].force.y += bodies[i].mass * magnitude; - } - } - addGravity(powerUp, game.g); - addGravity(body, game.g); - player.force.y += player.mass * mech.gravity; - }, - reset() { - b.inventory = []; //removes guns and ammo - for (let i = 0, len = b.guns.length; i < len; ++i) { - b.guns[i].have = false; - if (b.guns[i].ammo != Infinity) b.guns[i].ammo = 0; - } - b.activeGun = null; - game.paused = false; - engine.timing.timeScale = 1; - game.dmgScale = 1; - b.dmgScale = 0.7; - game.makeGunHUD(); - mech.drop(); - mech.addHealth(1); - mech.alive = true; - level.onLevel = 0; - game.levelsCleared = 0; - game.clearNow = true; - document.getElementById("text-log").style.opacity = 0; - document.getElementById("fade-out").style.opacity = 0; - document.title = "n-gon"; - if (!mech.fieldMode) mech.fieldUpgrades[0].effect(); //reset to starting field? or let them keep the field - }, - firstRun: true, - splashReturn() { - game.onTitlePage = true; - // document.getElementById('splash').onclick = 'run(this)'; - document.getElementById("splash").onclick = function () { - game.startGame(); - }; - document.getElementById("controls").style.display = "inline"; - document.getElementById("splash").style.display = "inline"; - document.getElementById("dmg").style.display = "none"; - document.getElementById("health-bg").style.display = "none"; - document.body.style.cursor = "auto"; - }, - fpsInterval: 0, //set in startGame - then: null, - startGame() { - game.onTitlePage = false; - document.getElementById("controls").style.display = "none"; - document.getElementById("splash").onclick = null; //removes the onclick effect so the function only runs once - document.getElementById("splash").style.display = "none"; //hides the element that spawned the function - document.getElementById("dmg").style.display = "inline"; - document.getElementById("health-bg").style.display = "inline"; - - // window.onmousedown = function (e) { - // //mouse up event in set in index.js - - // // game.mouseDown = true; - // if (e.which === 3) { - // game.mouseDownRight = true; - // } else { - // game.mouseDown = true; - // } - // // keep this disabled unless building maps - // // if (!game.mouseDown){ - // // game.getCoords.pos1.x = Math.round(game.mouseInGame.x / 25) * 25; - // // game.getCoords.pos1.y = Math.round(game.mouseInGame.y / 25) * 25; - // // } - - // // mech.throw(); - // }; - - document.body.style.cursor = "none"; - if (this.firstRun) { - mech.spawn(); //spawns the player - b.setModDefaults(); //doesn't run on reset so that gun mods carry over to new runs - level.levels = shuffle(level.levels); //shuffles order of maps - level.levels.unshift("bosses"); //add bosses level to the end of the randomized levels list - } - game.reset(); - game.firstRun = false; - - - //setup FPS cap - game.fpsInterval = 1000 / game.fpsCap; - game.then = Date.now(); - requestAnimationFrame(cycle); //starts game loop - }, - clearNow: false, - clearMap() { - //if player is holding something this remembers it before it gets deleted - let holdTarget; - if (mech.holdingTarget) { - holdTarget = mech.holdingTarget; - } - mech.drop(); - level.fill = []; - level.fillBG = []; - level.zones = []; - level.queryList = []; - this.drawList = []; - - function removeAll(array) { - for (let i = 0; i < array.length; ++i) Matter.World.remove(engine.world, array[i]); - } - removeAll(map); - map = []; - removeAll(body); - body = []; - removeAll(mob); - mob = []; - removeAll(powerUp); - powerUp = []; - removeAll(cons); - cons = []; - removeAll(consBB); - consBB = []; - removeAll(bullet); - bullet = []; - // if player was holding something this makes a new copy to hold - if (holdTarget) { - len = body.length; - body[len] = Matter.Bodies.fromVertices(0, 0, holdTarget.vertices, { - friction: holdTarget.friction, - frictionAir: holdTarget.frictionAir, - frictionStatic: holdTarget.frictionStatic - }); - mech.holdingTarget = body[len]; - } - }, - getCoords: { - //used when building maps, outputs a draw rect command to console, only works in testing mode - pos1: { - x: 0, - y: 0 - }, - pos2: { - x: 0, - y: 0 - }, - out() { - if (keys[49]) { - this.pos1.x = Math.round(game.mouseInGame.x / 25) * 25; - this.pos1.y = Math.round(game.mouseInGame.y / 25) * 25; - } - if (keys[50]) { - //press 1 in the top left; press 2 in the bottom right;copy command from console - this.pos2.x = Math.round(game.mouseInGame.x / 25) * 25; - this.pos2.y = Math.round(game.mouseInGame.y / 25) * 25; - window.getSelection().removeAllRanges(); - var range = document.createRange(); - range.selectNode(document.getElementById("test")); - window.getSelection().addRange(range); - document.execCommand("copy"); - window.getSelection().removeAllRanges(); - console.log(`spawn.mapRect(${this.pos1.x}, ${this.pos1.y}, ${this.pos2.x - this.pos1.x}, ${this.pos2.y - this.pos1.y}); //`); - } - } - }, - fallChecks() { - // if 4000px deep - if (mech.pos.y > game.fallHeight) { - mech.death(); - // if (b.modNonEuclidean) { - // Matter.Body.setPosition(player, { - // x: player.position.x, - // y: player.position.y - 12000 - // }); - // Matter.Body.setVelocity(player, { - // x: player.velocity.x, - // y: player.velocity.y * 0 - // }); - - // mech.pos.x = player.position.x; - // mech.pos.y = playerBody.position.y - mech.yOff; - - // //smoothed mouse look translations - // const scale = 10; - // mech.transSmoothX = canvas.width2 - mech.pos.x - (game.mouse.x - canvas.width2) * scale; - // mech.transSmoothY = canvas.height2 - mech.pos.y - (game.mouse.y - canvas.height2) * scale; - - // mech.transX = mech.transSmoothX - // mech.transY = mech.transSmoothY - - // } else { - // mech.death(); - // } - } - - if (!(mech.cycle % 420)) { - remove = function (who) { - let i = who.length; - while (i--) { - if (who[i].position.y > game.fallHeight) { - Matter.World.remove(engine.world, who[i]); - who.splice(i, 1); - } - } - }; - remove(mob); - remove(body); - remove(powerUp); - } - }, - testingOutput() { - ctx.textAlign = "right"; - ctx.fillStyle = "#000"; - let line = 100; - const x = canvas.width - 5; - ctx.fillText("T: exit testing mode", x, line); - line += 20; - ctx.fillText("R: teleport to mouse", x, line); - line += 20; - ctx.fillText("F: cycle field", x, line); - line += 20; - ctx.fillText("G: give all guns", x, line); - line += 20; - ctx.fillText("H: spawn power ups", x, line); - line += 30; - - ctx.fillText("cycle: " + game.cycle, x, line); - line += 20; - ctx.fillText("player cycle: " + mech.cycle, x, line); - line += 20; - ctx.fillText("x: " + player.position.x.toFixed(0), x, line); - line += 20; - ctx.fillText("y: " + player.position.y.toFixed(0), x, line); - line += 20; - ctx.fillText("Vx: " + mech.Vx.toFixed(2), x, line); - line += 20; - ctx.fillText("Vy: " + mech.Vy.toFixed(2), x, line); - line += 20; - ctx.fillText("Fx: " + player.force.x.toFixed(3), x, line); - line += 20; - ctx.fillText("Fy: " + player.force.y.toFixed(3), x, line); - line += 20; - ctx.fillText("yOff: " + mech.yOff.toFixed(1), x, line); - line += 20; - ctx.fillText("mass: " + player.mass.toFixed(1), x, line); - line += 20; - ctx.fillText("onGround: " + mech.onGround, x, line); - line += 20; - ctx.fillText("crouch: " + mech.crouch, x, line); - line += 20; - ctx.fillText("isHeadClear: " + mech.isHeadClear, x, line); - line += 20; - ctx.fillText("HeadIsSensor: " + headSensor.isSensor, x, line); - line += 20; - ctx.fillText("frictionAir: " + player.frictionAir.toFixed(3), x, line); - line += 20; - ctx.fillText("stepSize: " + mech.stepSize.toFixed(2), x, line); - line += 20; - ctx.fillText("zoom: " + this.zoom.toFixed(4), x, line); - line += 20; - ctx.textAlign = "center"; - ctx.fillText(`(${this.mouseInGame.x.toFixed(1)}, ${this.mouseInGame.y.toFixed(1)})`, this.mouse.x, this.mouse.y - 20); - }, - draw: { - powerUp() { - // draw power up - // ctx.globalAlpha = 0.4 * Math.sin(mech.cycle * 0.15) + 0.6; - // for (let i = 0, len = powerUp.length; i < len; ++i) { - // let vertices = powerUp[i].vertices; - // ctx.beginPath(); - // ctx.moveTo(vertices[0].x, vertices[0].y); - // for (let j = 1; j < vertices.length; j += 1) { - // ctx.lineTo(vertices[j].x, vertices[j].y); - // } - // ctx.lineTo(vertices[0].x, vertices[0].y); - // ctx.fillStyle = powerUp[i].color; - // ctx.fill(); - // } - // ctx.globalAlpha = 1; - ctx.globalAlpha = 0.4 * Math.sin(mech.cycle * 0.15) + 0.6; - for (let i = 0, len = powerUp.length; i < len; ++i) { - ctx.beginPath(); - ctx.arc(powerUp[i].position.x, powerUp[i].position.y, powerUp[i].size, 0, 2 * Math.PI); - ctx.fillStyle = powerUp[i].color; - ctx.fill(); - } - ctx.globalAlpha = 1; - }, - // map: function() { - // ctx.beginPath(); - // for (let i = 0, len = map.length; i < len; ++i) { - // let vertices = map[i].vertices; - // ctx.moveTo(vertices[0].x, vertices[0].y); - // for (let j = 1; j < vertices.length; j += 1) { - // ctx.lineTo(vertices[j].x, vertices[j].y); - // } - // ctx.lineTo(vertices[0].x, vertices[0].y); - // } - // ctx.fillStyle = "#444"; - // ctx.fill(); - // }, - mapPath: null, //holds the path for the map to speed up drawing - setPaths() { - //runs at each new level to store the path for the map since the map doesn't change - this.mapPath = new Path2D(); - for (let i = 0, len = map.length; i < len; ++i) { - let vertices = map[i].vertices; - this.mapPath.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1; j < vertices.length; j += 1) { - this.mapPath.lineTo(vertices[j].x, vertices[j].y); - } - this.mapPath.lineTo(vertices[0].x, vertices[0].y); - } - }, - mapFill: "#444", - bodyFill: "#999", - bodyStroke: "#222", - drawMapPath() { - ctx.fillStyle = this.mapFill; - ctx.fill(this.mapPath); - }, - - seeEdges() { - const eye = { - x: mech.pos.x + 20 * Math.cos(mech.angle), - y: mech.pos.y + 20 * Math.sin(mech.angle) - }; - //find all vertex nodes in range and in LOS - findNodes = function (domain, center) { - let nodes = []; - for (let i = 0; i < domain.length; ++i) { - let vertices = domain[i].vertices; - - for (let j = 0, len = vertices.length; j < len; j++) { - //calculate distance to player - const dx = vertices[j].x - center.x; - const dy = vertices[j].y - center.y; - if (dx * dx + dy * dy < 800 * 800 && Matter.Query.ray(domain, center, vertices[j]).length === 0) { - nodes.push(vertices[j]); - } - } - } - return nodes; - }; - let nodes = findNodes(map, eye); - //sort node list by angle to player - nodes.sort(function (a, b) { - //sub artan2 from player loc - const dx = a.x - eye.x; - const dy = a.y - eye.y; - return Math.atan2(dy, dx) - Math.atan2(dy, dx); - }); - //draw nodes - ctx.lineWidth = 2; - ctx.strokeStyle = "#000"; - ctx.beginPath(); - for (let i = 0; i < nodes.length; ++i) { - ctx.lineTo(nodes[i].x, nodes[i].y); - } - ctx.stroke(); - }, - see() { - const vertexCollision = function ( - v1, - v1End, - domain, - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - } - ) { - 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 && (!domain[i].mob || domain[i].alive)) { - 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 && (!domain[i].mob || domain[i].alive)) { - best = { - x: results.x, - y: results.y, - dist2: dist2, - who: domain[i], - v1: vertices[0], - v2: vertices[len] - }; - } - } - } - return best; - }; - const range = 3000; - ctx.beginPath(); - for (let i = 0; i < Math.PI * 2; i += Math.PI / 2 / 100) { - const cosAngle = Math.cos(mech.angle + i); - const sinAngle = Math.sin(mech.angle + i); - - const start = { - x: mech.pos.x + 20 * cosAngle, - y: mech.pos.y + 20 * sinAngle - }; - const end = { - x: mech.pos.x + range * cosAngle, - y: mech.pos.y + range * sinAngle - }; - let result = vertexCollision(start, end, map); - result = vertexCollision(start, end, body, result); - result = vertexCollision(start, end, mob, result); - - if (result.dist2 < range * range) { - // ctx.arc(result.x, result.y, 2, 0, 2 * Math.PI); - ctx.lineTo(result.x, result.y); - } else { - // ctx.arc(end.x, end.y, 2, 0, 2 * Math.PI); - ctx.lineTo(end.x, end.y); - } - } - // ctx.lineWidth = 1; - // ctx.strokeStyle = "#000"; - // ctx.stroke(); - ctx.fillStyle = "rgba(0,0,0,0.3)"; - ctx.fillStyle = "#fff"; - ctx.fill(); - ctx.clip(); - }, - body() { - ctx.beginPath(); - for (let i = 0, len = body.length; i < len; ++i) { - let vertices = body[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1; j < vertices.length; j += 1) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - } - ctx.lineWidth = 2; - ctx.fillStyle = this.bodyFill; - ctx.fill(); - ctx.strokeStyle = this.bodyStroke; - ctx.stroke(); - }, - cons() { - ctx.beginPath(); - for (let i = 0, len = cons.length; i < len; ++i) { - ctx.moveTo(cons[i].pointA.x, cons[i].pointA.y); - ctx.lineTo(cons[i].bodyB.position.x, cons[i].bodyB.position.y); - } - for (let i = 0, len = consBB.length; i < len; ++i) { - ctx.moveTo(consBB[i].bodyA.position.x, consBB[i].bodyA.position.y); - ctx.lineTo(consBB[i].bodyB.position.x, consBB[i].bodyB.position.y); - } - ctx.lineWidth = 2; - // ctx.strokeStyle = "#999"; - ctx.strokeStyle = "rgba(0,0,0,0.15)"; - ctx.stroke(); - }, - wireFrame() { - ctx.textAlign = "center"; - ctx.textBaseline = "middle"; - ctx.fillStyle = "#999"; - const bodies = Composite.allBodies(engine.world); - ctx.beginPath(); - for (let i = 0; i < bodies.length; ++i) { - //ctx.fillText(bodies[i].id,bodies[i].position.x,bodies[i].position.y); //shows the id of every body - let vertices = bodies[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1; j < vertices.length; j += 1) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - } - ctx.lineWidth = 1; - ctx.strokeStyle = "#000"; - ctx.stroke(); - }, - testing() { - //zones - ctx.beginPath(); - for (let i = 0, len = level.zones.length; i < len; ++i) { - ctx.rect(level.zones[i].x1, level.zones[i].y1 + 70, level.zones[i].x2 - level.zones[i].x1, level.zones[i].y2 - level.zones[i].y1); - } - ctx.fillStyle = "rgba(0, 255, 0, 0.3)"; - ctx.fill(); - //query zones - ctx.beginPath(); - for (let i = 0, len = level.queryList.length; i < len; ++i) { - ctx.rect( - level.queryList[i].bounds.max.x, - level.queryList[i].bounds.max.y, - level.queryList[i].bounds.min.x - level.queryList[i].bounds.max.x, - level.queryList[i].bounds.min.y - level.queryList[i].bounds.max.y - ); - } - ctx.fillStyle = "rgba(0, 0, 255, 0.2)"; - ctx.fill(); - //jump - ctx.beginPath(); - let bodyDraw = jumpSensor.vertices; - ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y); - for (let j = 1; j < bodyDraw.length; ++j) { - ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y); - } - ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y); - ctx.fillStyle = "rgba(255, 0, 0, 0.3)"; - ctx.fill(); - ctx.strokeStyle = "#000"; - ctx.stroke(); - //main body - ctx.beginPath(); - bodyDraw = playerBody.vertices; - ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y); - for (let j = 1; j < bodyDraw.length; ++j) { - ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y); - } - ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y); - ctx.fillStyle = "rgba(0, 255, 255, 0.3)"; - ctx.fill(); - ctx.stroke(); - //head - ctx.beginPath(); - bodyDraw = playerHead.vertices; - ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y); - for (let j = 1; j < bodyDraw.length; ++j) { - ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y); - } - ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y); - ctx.fillStyle = "rgba(255, 255, 0, 0.3)"; - ctx.fill(); - ctx.stroke(); - //head sensor - ctx.beginPath(); - bodyDraw = headSensor.vertices; - ctx.moveTo(bodyDraw[0].x, bodyDraw[0].y); - for (let j = 1; j < bodyDraw.length; ++j) { - ctx.lineTo(bodyDraw[j].x, bodyDraw[j].y); - } - ctx.lineTo(bodyDraw[0].x, bodyDraw[0].y); - ctx.fillStyle = "rgba(0, 0, 255, 0.3)"; - ctx.fill(); - ctx.stroke(); - } - }, - checkLineIntersection(v1, v1End, v2, v2End) { - // if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point - let denominator, a, b, numerator1, numerator2; - let result = { - x: null, - y: null, - onLine1: false, - onLine2: false - }; - denominator = (v2End.y - v2.y) * (v1End.x - v1.x) - (v2End.x - v2.x) * (v1End.y - v1.y); - if (denominator == 0) { - return result; - } - a = v1.y - v2.y; - b = v1.x - v2.x; - numerator1 = (v2End.x - v2.x) * a - (v2End.y - v2.y) * b; - numerator2 = (v1End.x - v1.x) * a - (v1End.y - v1.y) * b; - a = numerator1 / denominator; - b = numerator2 / denominator; - - // if we cast these lines infinitely in both directions, they intersect here: - result.x = v1.x + a * (v1End.x - v1.x); - result.y = v1.y + a * (v1End.y - v1.y); - // if line1 is a segment and line2 is infinite, they intersect if: - if (a > 0 && a < 1) result.onLine1 = true; - // if line2 is a segment and line1 is infinite, they intersect if: - if (b > 0 && b < 1) result.onLine2 = true; - // if line1 and line2 are segments, they intersect if both of the above are true - return result; - }, - //was used in level design - buildingUp(e) { - if (game.mouseDown) { - game.getCoords.pos2.x = Math.round(game.mouseInGame.x / 25) * 25; - game.getCoords.pos2.y = Math.round(game.mouseInGame.y / 25) * 25; - let out; - - //body rect mode - out = `spawn.mapRect(${game.getCoords.pos1.x}, ${game.getCoords.pos1.y}, ${game.getCoords.pos2.x - game.getCoords.pos1.x}, ${game.getCoords.pos2.y - - game.getCoords.pos1.y});`; - - //mob spawn - //out = `spawn.randomMob(${game.getCoords.pos1.x}, ${game.getCoords.pos1.y}, 0.3);` - - //draw foreground - //out = `level.fill.push({ x: ${game.getCoords.pos1.x}, y: ${game.getCoords.pos1.y}, width: ${game.getCoords.pos2.x-game.getCoords.pos1.x}, height: ${game.getCoords.pos2.y-game.getCoords.pos1.y}, color: "rgba(0,0,0,0.1)"});`; - - //draw background fill - //out = `level.fillBG.push({ x: ${game.getCoords.pos1.x}, y: ${game.getCoords.pos1.y}, width: ${game.getCoords.pos2.x-game.getCoords.pos1.x}, height: ${game.getCoords.pos2.y-game.getCoords.pos1.y}, color: "#ccc"});`; - - //svg mode - //out = 'rect x="'+game.getCoords.pos1.x+'" y="'+ game.getCoords.pos1.y+'" width="'+(game.getCoords.pos2.x-game.getCoords.pos1.x)+'" height="'+(game.getCoords.pos2.y-game.getCoords.pos1.y)+'"'; - - console.log(out); - // document.getElementById("copy-this").innerHTML = out - // - // window.getSelection().removeAllRanges(); - // var range = document.createRange(); - // range.selectNode(document.getElementById('copy-this')); - // window.getSelection().addRange(range); - // document.execCommand('copy') - // window.getSelection().removeAllRanges(); - } - } -}; \ No newline at end of file diff --git a/js/index.js b/js/index.js deleted file mode 100644 index 53b2065..0000000 --- a/js/index.js +++ /dev/null @@ -1,233 +0,0 @@ -"use strict"; -/* TODO: ******************************************* -***************************************************** - -make power ups keep moving to player if the field is turned off - -levels spawn by having the map aspects randomly fly into place - -new map with repeating endlessness - get ideas from Manifold Garden game - if falling, get teleported above the map - I tried it, but had trouble getting the camera to adjust - this can apply to blocks mobs, and power ups as well - -Find a diegetic way to see player damage (and or field meter too) - a health meter, like the field meter above player? (doesn't work with the field meter) - -Add field upgrade, and mod to a permanent display - left side - separate box below guns - - -cap guns to 3 - can up the drop rate on guns, and lower ammo amount or drop rate -cap mods to 2 - can up the drop rate a bit - check if there are any double mod compatibility issues -cap field to 1 - -what about no cap to mods? - mods without caps can't have major negatives - do I want to support a power ramping game play? - more upgrades are OK as long as they change game play - no flat damage, or flat defense buffs - This makes skipping content a bad idea for the player - Is that maybe good? No need to nerf content skipping buffs - content skipping is a cool play style, but not core game play - - -field power up effects - field produces a whirlpool effect of force around player - field allows player to hold and throw living mobs - -Move mods, to power up object - mods can be about more than the gun, defensive, traversal mods -gun mod power ups - bullet on mob damage effects - add to the array mob.do new mob behaviors - add a damage over time - add a freeze - fire a few smaller bullets - killing a mob triggers: a spore bullet - maybe you could replace the power method with a new one to get this to work -negative mods for balancing - self damage on fire - knock back - lower fire rate - smaller bullets - smaller explosions - shorter lasting bullets - -give mobs more animal-like behaviors - like rainworld - give mobs something to do when they don't see player - explore map - eat power ups - drop power up (if killed after eating one) - mobs some times aren't aggressive - when low on life or after taking a large hit - mobs can fight each other - this might be hard to code - isolated mobs try to group up. - -game mechanics - mechanics that support the physics engine - add rope/constraint - get ideas from game: limbo / inside - environmental hazards - laser - lava - button / switch - door - fizzler - moving platform - map zones - water - low friction ground - bouncy ground - -track foot positions with velocity better as the player walks/crouch/runs - -Boss ideas - boss grows and spilt, if you don't kill it fast - sensor that locks you in after you enter the boss room - boss that eats other mobs and gains stats from them - chance to spawn on any level (past level 5) - boss that knows how to shoot (player) bullets that collide with player - overwrite custom engine collision bullet mob function. - - - -// collision info: - category mask -powerUp: 0x100000 0x100001 -body: 0x010000 0x011111 -player: 0x001000 0x010011 -bullet: 0x000100 0x010011 -mob: 0x000010 0x011111 -mobBullet: 0x000010 0x011101 -mobShield: 0x000010 0x001100 -map: 0x000001 0x111111 - - - - -*/ - -//set up canvas -var canvas = document.getElementById("canvas"); -//using "const" causes problems in safari when an ID shares the same name. -const ctx = canvas.getContext("2d"); -document.body.style.backgroundColor = "#fff"; - -//disable pop up menu on right click -document.oncontextmenu = function () { - return false; -} - -function setupCanvas() { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - canvas.width2 = canvas.width / 2; //precalculated because I use this often (in mouse look) - canvas.height2 = canvas.height / 2; - canvas.diagonal = Math.sqrt(canvas.width2 * canvas.width2 + canvas.height2 * canvas.height2); - ctx.font = "15px Arial"; - ctx.lineJoin = "round"; - ctx.lineCap = "round"; - // ctx.lineCap='square'; - game.setZoom(); -} -setupCanvas(); -window.onresize = () => { - setupCanvas(); -}; - -//mouse move input -document.body.addEventListener("mousemove", (e) => { - game.mouse.x = e.clientX; - game.mouse.y = e.clientY; -}); - -document.body.addEventListener("mouseup", (e) => { - // game.buildingUp(e); //uncomment when building levels - game.mouseDown = false; - // console.log(e) - if (e.which === 3) { - game.mouseDownRight = false; - } else { - game.mouseDown = false; - } -}); - -document.body.addEventListener("mousedown", (e) => { - if (e.which === 3) { - game.mouseDownRight = true; - } else { - game.mouseDown = true; - } -}); - -//keyboard input -const keys = []; -document.body.addEventListener("keydown", (e) => { - keys[e.keyCode] = true; - game.keyPress(); -}); - -document.body.addEventListener("keyup", (e) => { - keys[e.keyCode] = false; -}); - -document.body.addEventListener("wheel", (e) => { - if (e.deltaY > 0) { - game.nextGun(); - } else { - game.previousGun(); - } -}, { - passive: true -}); - - -// function playSound(id) { -// //play sound -// if (false) { -// //sounds are turned off for now -// // if (document.getElementById(id)) { -// var sound = document.getElementById(id); //setup audio -// sound.currentTime = 0; //reset position of playback to zero //sound.load(); -// sound.play(); -// } -// } - -function shuffle(array) { - var currentIndex = array.length, - temporaryValue, - randomIndex; - // While there remain elements to shuffle... - while (0 !== currentIndex) { - // Pick a remaining element... - randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex -= 1; - // And swap it with the current element. - temporaryValue = array[currentIndex]; - array[currentIndex] = array[randomIndex]; - array[randomIndex] = temporaryValue; - } - return array; -} - - - -//main loop ************************************************************ -//********************************************************************** -function cycle() { - if (!game.paused) requestAnimationFrame(cycle); - const now = Date.now(); - const elapsed = now - game.then; // calc elapsed time since last loop - if (elapsed > game.fpsInterval) { // if enough time has elapsed, draw the next frame - game.then = now - (elapsed % game.fpsInterval); // Get ready for next frame by setting then=now. Also, adjust for fpsInterval not being multiple of 16.67 - game.loop(); - } -} \ No newline at end of file diff --git a/js/level.js b/js/level.js deleted file mode 100644 index 1a62c4b..0000000 --- a/js/level.js +++ /dev/null @@ -1,1593 +0,0 @@ -//global game variables -let body = []; //non static bodies -let map = []; //all static bodies -let cons = []; //all constraints between a point and a body -let consBB = []; //all constraints between two bodies -//main object for spawning levels -const level = { - maxJump: 390, - defaultZoom: 1400, - boostScale: 0.000023, - levels: ["skyscrapers", "rooftops", "warehouse", "highrise", "office", "aerie"], - onLevel: 0, - start() { - if (game.levelsCleared === 0) { - // game.levelsCleared = 16; //for testing to simulate possible mobs spawns - // b.giveGuns("all", 1000) - // b.giveGuns(3) // set a starting gun for testing - // mech.fieldUpgrades[2].effect(); //give a field power up for testing - // b.mods[7].effect(); //give specific mod - - this.intro(); //starting level - // this.testingMap(); - // this.bosses(); - // this.aerie(); - // this.rooftops(); - // this.warehouse(); - // this.highrise(); - // this.office(); - } else { - spawn.setSpawnList(); //picks a couple mobs types for a themed random mob spawns - level[level.levels[level.onLevel]](); //picks the current map from the the levels array - level.levelAnnounce(); - } - game.setZoom(); - level.addToWorld(); //add bodies to game engine - game.draw.setPaths(); - }, - difficultyIncrease() { - game.dmgScale += 0.35; //damage done by mobs increases each level - b.dmgScale *= 0.92; //damage done by player decreases each level - game.accelScale *= 1.05 //mob acceleration increases each level - game.lookFreqScale *= 0.95 //mob cycles between looks decreases each level - game.CDScale *= 0.95 //mob CD time decreases each level - }, - //****************************************************************************************************************** - //****************************************************************************************************************** - testingMap() { - //start with all guns - b.giveGuns("all", 1000) - game.zoomScale = 1400 //1400 is normal - spawn.setSpawnList(); - game.levelsCleared = 3; //for testing to simulate all possible mobs spawns - for (let i = 0; i < game.levelsCleared; i++) { - level.difficultyIncrease() - } - mech.setPosToSpawn(-75, -60); //normal spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - - level.exit.x = 3500; - level.exit.y = -870; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - document.body.style.backgroundColor = "#dcdcde"; - - - - - // this.addZone(250, -1000, 500, 1500, "laser"); - //spawn.debris(0, -900, 4500, 10); //15 debris per level - // setTimeout(function() { - // document.body.style.backgroundColor = "#eee"; - // }, 1); - // this.addQueryRegion(550, -25, 100, 50, "bounce", { Vx: 0, Vy: -25 }); - // level.fillBG.push({ x: 550, y: -25, width: 100, height: 50, color: "#ff0" }); - - spawn.mapRect(-1200, 0, 2200, 300); //left ground - spawn.mapRect(3500, -860, 100, 50); //ground bump wall - spawn.mapVertex(1250, 0, "0 0 0 300 -500 600 -500 300"); - spawn.mapRect(1500, -300, 2000, 300); //upper ground - spawn.mapVertex(3750, 0, "0 600 0 300 -500 0 -500 300"); - spawn.mapRect(4000, 0, 1000, 300); //right lower ground - spawn.mapRect(2200, -600, 600, 50); //center platform - spawn.mapRect(1300, -850, 700, 50); //center platform - spawn.mapRect(3000, -850, 700, 50); //center platform - // spawn.mapRect(0, -2000, 3000, 50); //center platform - spawn.spawnBuilding(-200, -250, 275, 240, false, true, "left"); //far left; player spawns in side - // spawn.boost(350, 0, -1000); - // for (let i = 0; i < 10; i++) { - // powerUps.spawn(950, -425, "gun", false); - // } - // for (let i = 0; i < 5; i++) { - // powerUps.spawn(2500 + i * 20, -1300, "gun", false); - // powerUps.spawn(2500 + i * 20, -1100, "ammo", false); - // } - // spawn.nodeBoss(-500, -600, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); - // spawn.lineBoss(-500, -600, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); - // spawn.bodyRect(-135, -50, 50, 50); - // spawn.bodyRect(-140, -100, 50, 50); - // spawn.bodyRect(-145, -150, 60, 50); - // spawn.bodyRect(-140, -200, 50, 50); - // spawn.bodyRect(-95, -50, 40, 50); - // spawn.bodyRect(-90, -100, 60, 50); - // spawn.bodyRect(300, -150, 140, 50); - // spawn.bodyRect(300, -150, 30, 30); - // spawn.bodyRect(300, -150, 20, 20); - // spawn.bodyRect(300, -150, 40, 100); - // spawn.bodyRect(300, -150, 40, 90); - // spawn.bodyRect(300, -150, 30, 60); - // spawn.bodyRect(300, -150, 40, 70); - // spawn.bodyRect(300, -150, 40, 60); - // spawn.bodyRect(300, -150, 20, 20); - // spawn.bodyRect(500, -150, 140, 110); - // spawn.bodyRect(600, -150, 140, 100); - // spawn.bodyRect(400, -150, 140, 160); - // spawn.bodyRect(500, -150, 110, 110); - // powerUps.spawn(340, -400, "heal", false); - // powerUps.spawn(370, -400, "gun", false); - // powerUps.spawn(400, -400, "field", false, 2); - // powerUps.spawn(420, -400, "ammo", false); - powerUps.spawn(450, -400, "mod", false, 6); - // powerUps.spawn(450, -400, "mod", false); - // spawn.bodyRect(-45, -100, 40, 50); - // spawn.focuser(800, -1150); - // spawn.groupBoss(-600, -550); - spawn.starter(800, -150, 100); - // spawn.grower(800, -250); - // spawn.blinker(800, -250, 40); - // spawn.groupBoss(900, -1070); - // for (let i = 0; i < 20; i++) { - // spawn.randomBoss(-100, -1470); - // } - }, - bosses() { - level.defaultZoom = 1500 - game.zoomTransition(level.defaultZoom) - - // spawn.setSpawnList(); - // spawn.setSpawnList(); - // game.levelsCleared = 7; //for testing to simulate all possible mobs spawns - // for (let i = 0; i < game.levelsCleared; i++) { - // game.dmgScale += 0.4; //damage done by mobs increases each level - // b.dmgScale *= 0.9; //damage done by player decreases each level - // } - - document.body.style.backgroundColor = "#ddd"; - - // level.fillBG.push({ - // x: -150, - // y: -1150, - // width: 7000, - // height: 1200, - // color: "#eee" - // }); - - level.fill.push({ - x: 6400, - y: -550, - width: 300, - height: 350, - color: "rgba(0,255,255,0.1)" - }); - - mech.setPosToSpawn(0, -750); //normal spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - level.exit.x = 6500; - level.exit.y = -230; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - - spawn.mapRect(-950, 0, 8200, 800); //ground - spawn.mapRect(-950, -1200, 800, 1400); //left wall - spawn.mapRect(-950, -1800, 8200, 800); //roof - spawn.mapRect(-250, -700, 1000, 900); // shelf - spawn.mapRect(-250, -1200, 1000, 250); // shelf roof - powerUps.spawnStartingPowerUps(600, -800); - - function blockDoor(x, y, blockSize = 58) { - spawn.mapRect(x, y - 290, 40, 60); // door lip - spawn.mapRect(x, y, 40, 50); // door lip - for (let i = 0; i < 4; ++i) { - spawn.bodyRect(x + 5, y - 260 + i * blockSize, 30, blockSize); - } - } - blockDoor(710, -710); - - spawn[spawn.pickList[0]](1500, -200, 100 + game.levelsCleared * 8); - spawn.mapRect(2500, -1200, 200, 750); //right wall - blockDoor(2585, -210) - spawn.mapRect(2500, -200, 200, 300); //right wall - - spawn.nodeBoss(3500, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); - spawn.mapRect(4500, -1200, 200, 750); //right wall - blockDoor(4585, -210) - spawn.mapRect(4500, -200, 200, 300); //right wall - - spawn.lineBoss(5000, -200, spawn.allowedBossList[Math.floor(Math.random() * spawn.allowedBossList.length)]); - spawn.mapRect(6400, -1200, 400, 750); //right wall - spawn.mapRect(6400, -200, 400, 300); //right wall - spawn.mapRect(6700, -1800, 800, 2600); //right wall - spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump - - for (let i = 0; i < 5; ++i) { - if (game.levelsCleared * Math.random() > 3 * i) { - spawn.randomBoss(2000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); - } - if (game.levelsCleared * Math.random() > 2.6 * i) { - spawn.randomBoss(3500 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); - } - if (game.levelsCleared * Math.random() > 2.4 * i) { - spawn.randomBoss(5000 + 500 * (Math.random() - 0.5), -800 + 200 * (Math.random() - 0.5), Infinity); - } - } - }, - //empty map for testing mobs - intro() { - // b.giveGuns(0, 1000) - game.zoomScale = 1000 //1400 is normal - level.defaultZoom = 1600 - game.zoomTransition(level.defaultZoom, 1) - - mech.setPosToSpawn(460, -100); //normal spawn - level.enter.x = -1000000; //offscreen - level.enter.y = -400; - level.exit.x = 2800; - level.exit.y = -335; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - document.body.style.backgroundColor = "#fff"; - level.fillBG.push({ - x: 2600, - y: -600, - width: 400, - height: 500, - color: "#edf9f9" - }); - - level.fillBG.push({ - x: 1600, - y: -500, - width: 100, - height: 100, - color: "#eee" - }); - - level.fillBG.push({ - x: -55, - y: -283, - width: 12, - height: 100, - color: "#eee" - }); - - //faster way to draw a wire - function wallWire(x, y, width, height, front = false) { - if (front) { - level.fill.push({ - x: x, - y: y, - width: width, - height: height, - color: "#aaa" - }); - } else { - level.fillBG.push({ - x: x, - y: y, - width: width, - height: height, - color: "#eee" - }); - } - } - - for (let i = 0; i < 3; i++) { - wallWire(100 - 10 * i, -1050 - 10 * i, 5, 800); - wallWire(100 - 10 * i, -255 - 10 * i, -300, 5); - } - for (let i = 0; i < 5; i++) { - wallWire(1000 + 10 * i, -1050 - 10 * i, 5, 600); - wallWire(1000 + 10 * i, -450 - 10 * i, 150, 5); - wallWire(1150 + 10 * i, -450 - 10 * i, 5, 500); - } - for (let i = 0; i < 3; i++) { - wallWire(2650 - 10 * i, -700 - 10 * i, -300, 5); - wallWire(2350 - 10 * i, -700 - 10 * i, 5, 800); - } - for (let i = 0; i < 5; i++) { - wallWire(1625 + 10 * i, -1050, 5, 1200); - } - for (let i = 0; i < 4; i++) { - wallWire(1650, -470 + i * 10, 670 - i * 10, 5); - wallWire(1650 + 670 - i * 10, -470 + i * 10, 5, 600); - } - for (let i = 0; i < 3; i++) { - wallWire(-200 - i * 10, -245 + i * 10, 1340, 5); - wallWire(1140 - i * 10, -245 + i * 10, 5, 300); - wallWire(-200 - i * 10, -215 + i * 10, 660, 5); - wallWire(460 - i * 10, -215 + i * 10, 5, 300); - } - spawn.mapRect(-250, 0, 3600, 1800); //ground - spawn.mapRect(-2750, -2800, 2600, 4600); //left wall - spawn.mapRect(3000, -2800, 2600, 4600); //right wall - spawn.mapRect(-250, -2800, 3600, 1800); //roof - spawn.mapRect(2600, -300, 500, 500); //exit shelf - spawn.mapRect(2600, -1200, 500, 600); //exit roof - spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 100); //exit bump - spawn.mapRect(-95, -1100, 80, 110); //wire source - spawn.mapRect(410, -10, 90, 20); //small platform for player - - // spawn.bodyRect(-35, -50, 50, 50); - // spawn.bodyRect(-40, -100, 50, 50); - // spawn.bodyRect(-45, -150, 60, 50); - // spawn.bodyRect(-40, -200, 50, 50); - // spawn.bodyRect(5, -50, 40, 50); - // spawn.bodyRect(10, -100, 60, 50); - // spawn.bodyRect(-10, -150, 40, 50); - // spawn.bodyRect(55, -100, 40, 50); - // spawn.bodyRect(-150, -300, 100, 100); - // spawn.bodyRect(-150, -200, 100, 100); - // spawn.bodyRect(-150, -100, 100, 100); - - // spawn.bodyRect(1790, -50, 40, 50); - // spawn.bodyRect(1875, -100, 200, 90); - spawn.bodyRect(2425, -120, 70, 50); - spawn.bodyRect(2400, -100, 100, 60); - spawn.bodyRect(2500, -150, 100, 150); //exit step - - mech.health = 0.25; - mech.displayHealth(); - powerUps.spawn(-100, 0, "heal", false); //starting gun - powerUps.spawn(1900, -150, "heal", false); //starting gun - powerUps.spawn(2050, -150, "heal", false); //starting gun - // powerUps.spawn(2050, -150, "field", false); //starting gun - powerUps.spawn(2300, -150, "gun", false); //starting gun - - spawn.wireFoot(); - spawn.wireFootLeft(); - spawn.wireKnee(); - spawn.wireKneeLeft(); - spawn.wireHead(); - // spawn.mapRect(1400, -700, 50, 300); //ground - // spawn.healer(1600, -500) - // spawn.healer(1600, -500) - // spawn.healer(1900, -500) - // spawn.healer(1000, -500) - // spawn.healer(1000, -400) - }, - rooftops() { - level.defaultZoom = 1700 - game.zoomTransition(level.defaultZoom) - document.body.style.backgroundColor = "#dcdcde"; - - if (Math.random() < 0.75) { - //normal direction start in top left - mech.setPosToSpawn(-450, -2050); - level.exit.x = 3600; - level.exit.y = -300; - spawn.mapRect(3600, -285, 100, 50); //ground bump wall - //mobs that spawn in exit room - spawn.randomSmallMob(4100, -100); - spawn.randomSmallMob(4600, -100); - spawn.randomMob(3765, -450, 0.3); - level.fill.push({ - x: -650, - y: -2300, - width: 450, - height: 300, - color: "rgba(0,0,0,0.15)" - }); - } else { - //reverse direction, start in bottom right - mech.setPosToSpawn(3650, -310); - level.exit.x = -550; - level.exit.y = -2030; - spawn.mapRect(-550, -2015, 100, 50); //ground bump wall - spawn.boost(4950, 0, 1600); - level.fillBG.push({ - x: -650, - y: -2300, - width: 450, - height: 300, - color: "#d4f4f4" - }); - } - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - - spawn.debris(1650, -1800, 3800, 20); //20 debris per level - powerUps.spawnStartingPowerUps(2450, -1675); - - //foreground - - level.fill.push({ - x: 3450, - y: -1250, - width: 1100, - height: 1250, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 4550, - y: -725, - width: 900, - height: 725, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 3400, - y: 100, - width: 2150, - height: 900, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: -700, - y: -1950, - width: 2100, - height: 2950, - color: "rgba(0,0,0,0.1)" - }); - - level.fill.push({ - x: 1950, - y: -1950, - width: 600, - height: 350, - color: "rgba(0,0,0,0.1)" - }); - - level.fill.push({ - x: 1950, - y: -1550, - width: 1025, - height: 550, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 1600, - y: -900, - width: 1650, - height: 1900, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 3450, - y: -1550, - width: 350, - height: 300, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 700, - y: -2225, - width: 700, - height: 225, - color: "rgba(0,0,0,0.1)" - }); - - //spawn.mapRect(-700, 0, 6250, 100); //ground - spawn.mapRect(3400, 0, 2150, 100); //ground - spawn.mapRect(-700, -2000, 2100, 50); //Top left ledge - spawn.bodyRect(1300, -2125, 50, 125, 0.8); - spawn.bodyRect(1307, -2225, 50, 100, 0.8); - spawn.mapRect(-700, -2350, 50, 400); //far left starting left wall - spawn.mapRect(-700, -2010, 500, 50); //far left starting ground - spawn.mapRect(-700, -2350, 500, 50); //far left starting ceiling - spawn.mapRect(-250, -2350, 50, 200); //far left starting right part of wall - spawn.bodyRect(-240, -2150, 30, 36); //door to starting room - spawn.bodyRect(-240, -2115, 30, 36); //door to starting room - spawn.bodyRect(-240, -2080, 30, 35); //door to starting room - spawn.bodyRect(-240, -2045, 30, 35); //door to starting room - spawn.mapRect(1950, -2000, 600, 50); - spawn.bodyRect(200, -2150, 200, 220, 0.8); - spawn.mapRect(700, -2275, 700, 50); - spawn.bodyRect(1050, -2350, 30, 30, 0.8); - spawn.boost(1800, -1000, 1200); - spawn.bodyRect(1625, -1100, 100, 75); - spawn.bodyRect(1350, -1025, 400, 25); // ground plank - spawn.mapRect(-725, -1000, 2150, 100); //lower left ledge - spawn.bodyRect(350, -1100, 200, 100, 0.8); - spawn.bodyRect(370, -1200, 100, 100, 0.8); - spawn.bodyRect(360, -1300, 100, 100, 0.8); - spawn.bodyRect(950, -1050, 300, 50, 0.8); - spawn.bodyRect(-600, -1250, 400, 250, 0.8); - spawn.mapRect(1575, -1000, 1700, 100); //middle ledge - spawn.mapRect(3400, -1000, 75, 25); - spawn.bodyRect(2600, -1950, 100, 250, 0.8); - spawn.bodyRect(2700, -1125, 125, 125, 0.8); - spawn.bodyRect(2710, -1250, 125, 125, 0.8); - spawn.bodyRect(2705, -1350, 75, 100, 0.8); - spawn.mapRect(3450, -1600, 350, 50); - spawn.mapRect(1950, -1600, 1025, 50); - spawn.bodyRect(3100, -1015, 375, 15); - spawn.bodyRect(3500, -850, 75, 125, 0.8); - spawn.mapRect(3450, -1000, 50, 580); //left building wall - spawn.bodyRect(3460, -420, 30, 144); - spawn.mapRect(5450, -775, 100, 875); //right building wall - spawn.bodyRect(4850, -750, 300, 25, 0.8); - spawn.bodyRect(3925, -1400, 100, 150, 0.8); - spawn.mapRect(3450, -1250, 1100, 50); - spawn.mapRect(3450, -1225, 50, 75); - spawn.mapRect(4500, -1225, 50, 390); - spawn.mapRect(3450, -725, 1500, 50); - spawn.mapRect(5100, -725, 400, 50); - spawn.mapRect(4500, -735, 50, 635); - spawn.bodyRect(4510, -100, 30, 100, 0.8); - spawn.mapRect(4500, -885, 100, 50); - spawn.spawnStairs(3800, 0, 3, 150, 206); //stairs top exit - spawn.mapRect(3400, -275, 450, 275); //exit platform - - spawn.randomSmallMob(2200, -1775); - spawn.randomSmallMob(4000, -825); - spawn.randomSmallMob(-350, -2400); - spawn.randomMob(4250, -1350, 0.8); - spawn.randomMob(2550, -1350, 0.8); - spawn.randomMob(1225, -2400, 0.3); - spawn.randomMob(1120, -1200, 0.3); - spawn.randomMob(3000, -1150, 0.2); - spawn.randomMob(3200, -1150, 0.3); - spawn.randomMob(3300, -1750, 0.3); - spawn.randomMob(3650, -1350, 0.3); - spawn.randomMob(3600, -1800, 0.1); - spawn.randomMob(5200, -100, 0.3); - spawn.randomMob(5275, -900, 0.2); - spawn.randomMob(900, -2125, 0.3); - spawn.randomBoss(600, -1575, 0); - spawn.randomBoss(2225, -1325, 0.4); - spawn.randomBoss(4900, -1200, 0); - //spawn.randomBoss(4850, -1250,0.7); - if (game.levelsCleared > 4) spawn.bomber(2500, -2400, 100); - }, - aerie() { - // game.setZoom(3000); - // game.levelsCleared = 4; //for testing to simulate possible mobs spawns - level.defaultZoom = 2100 - game.zoomTransition(level.defaultZoom) - - const backwards = (Math.random() < 0.75) ? false : true; - if (backwards) { - mech.setPosToSpawn(4000, -3300); //normal spawn - level.exit.x = -100; - level.exit.y = -1025; - } else { - mech.setPosToSpawn(-50, -1050); //normal spawn - level.exit.x = 3950; - level.exit.y = -3275; - } - // mech.setPosToSpawn(2250, -900); - // game.zoomTransition(1500) //1400 is normal - - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - powerUps.spawnStartingPowerUps(1075, -550); - spawn.debris(-250, 50, 1650, 2); //20 debris per level - spawn.debris(2475, 0, 750, 2); //20 debris per level - spawn.debris(3450, 0, 2000, 20); //20 debris per level - spawn.debris(3500, -2350, 1500, 2); //20 debris per level - document.body.style.backgroundColor = "#dcdcde"; - - //foreground - level.fill.push({ - x: -100, - y: -1000, - width: 1450, - height: 1400, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 2000, - y: -1110, - width: 450, - height: 1550, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 3700, - y: -3150, - width: 1100, - height: 900, - color: "rgba(0,0,0,0.1)" - }); - - //background - level.fillBG.push({ - x: 4200, - y: -2250, - width: 100, - height: 2600, - color: "#c7c7ca" - }); - if (!backwards) { - level.fillBG.push({ - x: 3750, - y: -3650, - width: 550, - height: 400, - color: "#d4f4f4" - }); - level.fill.push({ - x: -275, - y: -1275, - width: 425, - height: 300, - color: "rgba(0,0,0,0.1)" - }); - } else { - level.fill.push({ - x: 3750, - y: -3650, - width: 550, - height: 400, - color: "rgba(0,0,0,0.1)" - }); - level.fillBG.push({ - x: -275, - y: -1275, - width: 425, - height: 300, - color: "#d4f4f4" - }); - } - - // starting room - spawn.mapRect(-100, -1010, 100, 30); - spawn.mapRect(-300, -1000, 600, 50); - spawn.mapRect(-300, -1300, 450, 50); - spawn.mapRect(-300, -1300, 50, 350); - if (!backwards) spawn.bodyRect(100, -1250, 200, 240); //remove on backwards - //left building - spawn.mapRect(-100, -975, 100, 975); - spawn.mapRect(-500, 100, 1950, 400); - spawn.boost(-425, 100, 1400); - spawn.mapRect(600, -1000, 750, 50); - spawn.mapRect(900, -500, 550, 50); - spawn.mapRect(1250, -975, 100, 375); - spawn.bodyRect(1250, -600, 100, 100, 0.7); - spawn.mapRect(1250, -450, 100, 450); - if (!backwards) spawn.bodyRect(1250, -1225, 100, 200); //remove on backwards - if (!backwards) spawn.bodyRect(1200, -1025, 350, 25); //remove on backwards - //middle super tower - if (backwards) { - spawn.bodyRect(2000, -800, 700, 35); - } else { - spawn.bodyRect(1750, -800, 700, 35); - } - spawn.mapVertex(2225, -2100, "0 0 450 0 300 -2500 150 -2500") - spawn.mapRect(2000, -700, 450, 300); - spawn.bodyRect(2360, -450, 100, 300, 0.6); - spawn.mapRect(2000, -75, 450, 275); - spawn.bodyRect(2450, 150, 150, 150, 0.4); - spawn.mapRect(1550, 300, 4600, 200); //ground - //floor below right tall tower - spawn.bodyRect(3000, 50, 150, 250, 0.9); - spawn.bodyRect(4500, -500, 300, 250, 0.7); - spawn.bodyRect(3500, -100, 100, 150, 0.7); - spawn.bodyRect(4200, -500, 110, 30, 0.7); - spawn.bodyRect(3800, -500, 150, 130, 0.7); - spawn.bodyRect(4000, 50, 200, 150, 0.9); - spawn.bodyRect(4500, 50, 300, 200, 0.9); - spawn.bodyRect(4200, -350, 200, 50, 0.9); - spawn.bodyRect(4700, -350, 50, 200, 0.9); - spawn.bodyRect(4900, -100, 300, 300, 0.7); - spawn.boost(5350, 275, 2850); - spawn.mapRect(6050, -700, 600, 1200); - //right tall tower - spawn.mapRect(3700, -3200, 100, 800); - spawn.mapRect(4700, -2910, 100, 510); - spawn.mapRect(3700, -2600, 300, 50); - spawn.mapRect(4100, -2900, 900, 50); - spawn.mapRect(3450, -2300, 1650, 100); - //exit room on top of tower - spawn.mapRect(3700, -3700, 600, 50); - spawn.mapRect(3700, -3700, 50, 500); - spawn.mapRect(4250, -3700, 50, 300); - spawn.mapRect(3700, -3250, 1100, 100); - spawn.mapRect(3950, -3260, 100, 30); - - spawn.randomSmallMob(-225, 25); - spawn.randomSmallMob(1000, -1100); - spawn.randomSmallMob(4000, -250); - spawn.randomSmallMob(4450, -3000); - spawn.randomSmallMob(5600, 100); - spawn.randomMob(4275, -2600, 0.8); - spawn.randomMob(1050, -700, 0.8) - spawn.randomMob(6050, -850, 0.7); - spawn.randomMob(2150, -300, 0.6) - spawn.randomMob(3900, -2700, 0.8); - spawn.randomMob(3600, -500, 0.8); - spawn.randomMob(3400, -200, 0.8); - spawn.randomMob(1650, -1300, 0.7) - spawn.randomMob(-4100, -50, 0.7); - spawn.randomMob(4100, -50, 0.5); - spawn.randomMob(1700, -50, 0.3) - spawn.randomMob(2350, -900, 0.3) - spawn.randomMob(4700, -150, 0.2); - spawn.randomBoss(350, -500, 1) - spawn.randomBoss(4000, -350, 0.6); - spawn.randomBoss(2750, -550, 0.1); - if (game.levelsCleared > 2) spawn.suckerBoss(4500, -400); - - //add mini boss, giant hopper? or a black hole that spawns hoppers? - }, - skyscrapers() { - level.defaultZoom = 2000 - game.zoomTransition(level.defaultZoom) - - mech.setPosToSpawn(-50, -50); //normal spawn - //mech.setPosToSpawn(1550, -1200); //spawn left high - //mech.setPosToSpawn(1800, -2000); //spawn near exit - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - level.exit.x = 1500; - level.exit.y = -1875; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - - powerUps.spawnStartingPowerUps(1475, -1175); - spawn.debris(0, -2200, 4500, 20); //20 debris per level - document.body.style.backgroundColor = "#dcdcde"; - - //foreground - level.fill.push({ - x: 2500, - y: -1100, - width: 450, - height: 250, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 2400, - y: -550, - width: 600, - height: 150, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 2550, - y: -1650, - width: 250, - height: 200, - color: "rgba(0,0,0,0.1)" - }); - //level.fill.push({ x: 1350, y: -2100, width: 400, height: 250, color: "rgba(0,255,255,0.1)" }); - level.fill.push({ - x: 700, - y: -110, - width: 400, - height: 110, - color: "rgba(0,0,0,0.2)" - }); - level.fill.push({ - x: 3600, - y: -110, - width: 400, - height: 110, - color: "rgba(0,0,0,0.2)" - }); - level.fill.push({ - x: -250, - y: -300, - width: 450, - height: 300, - color: "rgba(0,0,0,0.15)" - }); - - //background - level.fillBG.push({ - x: 1300, - y: -1800, - width: 750, - height: 1800, - color: "#d4d4d7" - }); - level.fillBG.push({ - x: 3350, - y: -1325, - width: 50, - height: 1325, - color: "#d4d4d7" - }); - level.fillBG.push({ - x: 1350, - y: -2100, - width: 400, - height: 250, - color: "#d4f4f4" - }); - - spawn.mapRect(-300, 0, 5000, 300); //***********ground - spawn.mapRect(-300, -350, 50, 400); //far left starting left wall - spawn.mapRect(-300, -10, 500, 50); //far left starting ground - spawn.mapRect(-300, -350, 500, 50); //far left starting ceiling - spawn.mapRect(150, -350, 50, 200); //far left starting right part of wall - spawn.bodyRect(170, -130, 14, 140, 1, spawn.propsFriction); //door to starting room - spawn.boost(475, 0, 1300); - spawn.mapRect(700, -1100, 400, 990); //far left building - spawn.mapRect(1600, -400, 1500, 500); //long center building - spawn.mapRect(1345, -1100, 250, 25); //left platform - spawn.mapRect(1755, -1100, 250, 25); //right platform - spawn.mapRect(1300, -1850, 750, 50); //left higher platform - spawn.mapRect(1300, -2150, 50, 350); //left higher platform left edge wall - spawn.mapRect(1300, -2150, 450, 50); //left higher platform roof - spawn.mapRect(1500, -1860, 100, 50); //ground bump wall - spawn.mapRect(2400, -850, 600, 300); //center floating large square - //spawn.bodyRect(2500, -1100, 25, 250); //wall before chasers - spawn.mapRect(2500, -1450, 450, 350); //higher center floating large square - spawn.mapRect(2500, -1675, 50, 300); //left wall on higher center floating large square - spawn.mapRect(2500, -1700, 300, 50); //roof on higher center floating large square - spawn.mapRect(3300, -850, 150, 25); //ledge by far right building - spawn.mapRect(3300, -1350, 150, 25); //higher ledge by far right building - spawn.mapRect(3600, -1100, 400, 990); //far right building - spawn.boost(4150, 0, 1300); - - spawn.bodyRect(3200, -1375, 300, 25, 0.9); - spawn.bodyRect(1825, -1875, 400, 25, 0.9); - // spawn.bodyRect(1800, -575, 250, 150, 0.8); - spawn.bodyRect(1800, -600, 250, 200, 0.8); - spawn.bodyRect(2557, -450, 35, 55, 0.7); - spawn.bodyRect(2957, -450, 30, 15, 0.7); - spawn.bodyRect(2900, -450, 60, 45, 0.7); - spawn.bodyRect(915, -1200, 60, 100, 0.95); - spawn.bodyRect(925, -1300, 50, 100, 0.95); - if (Math.random() < 0.9) { - spawn.bodyRect(2300, -1720, 400, 20); - spawn.bodyRect(2590, -1780, 80, 80); - } - spawn.bodyRect(2925, -1100, 25, 250, 0.8); - spawn.bodyRect(3325, -1550, 50, 200, 0.3); - if (Math.random() < 0.8) { - spawn.bodyRect(1400, -75, 200, 75); //block to get up ledge from ground - spawn.bodyRect(1525, -125, 50, 50); //block to get up ledge from ground - } - spawn.bodyRect(1025, -1110, 400, 25, 0.9); //block on far left building - spawn.bodyRect(1425, -1110, 115, 25, 0.9); //block on far left building - spawn.bodyRect(1540, -1110, 300, 25, 0.9); //block on far left building - - if (game.levelsCleared > 2) spawn.shooterBoss(2200, -1300); - spawn.randomSmallMob(1300, -70); - spawn.randomSmallMob(3200, -100); - spawn.randomSmallMob(4450, -100); - spawn.randomSmallMob(2700, -475); - spawn.randomMob(2650, -975, 0.8); - spawn.randomMob(2650, -1550, 0.8); - spawn.randomMob(4150, -200, 0.15); - spawn.randomMob(1700, -1300, 0.2); - spawn.randomMob(1850, -1950, 0.25); - spawn.randomMob(2610, -1880, 0.25); - spawn.randomMob(3350, -950, 0.25); - spawn.randomMob(1690, -2250, 0.25); - spawn.randomMob(2200, -600, 0.2); - spawn.randomMob(850, -1300, 0.25); - spawn.randomMob(-100, -900, -0.2); - spawn.randomBoss(3700, -1500, 0.4); - spawn.randomBoss(1700, -900, 0.4); - }, - highrise() { - level.defaultZoom = 1500 - game.zoomTransition(level.defaultZoom) - - document.body.style.backgroundColor = "#dcdcde" //"#fafcff"; - mech.setPosToSpawn(0, -700); //normal spawn - //mech.setPosToSpawn(-2000, -1700); // left ledge spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - level.exit.x = -4275; - level.exit.y = -2805; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - powerUps.spawnStartingPowerUps(-2550, -700); - - // spawn.laserZone(-550, -350, 10, 400, 0.3) - // spawn.deathQuery(-550, -350, 50, 400) - - // spawn.debris(-3950, -2575, 1050, 4); //20 debris per level - spawn.debris(-2325, -1825, 2400); //20 debris per level - spawn.debris(-2625, -600, 600, 6); //20 debris per level - spawn.debris(-2000, -60, 1200, 6); //20 debris per level - // if (!game.levelsCleared) powerUps.spawn(2450, -1675, "gun", false); - //background - level.fillBG.push({ - x: -4425, - y: -3050, - width: 425, - height: 275, - color: "#cff" - }); - //foreground - level.fill.push({ - x: -1650, - y: -1575, - width: 550, - height: 425, - color: "rgba(0,0,0,0.12)" - }); - level.fill.push({ - x: -2600, - y: -2400, - width: 450, - height: 1800, - color: "rgba(0,0,0,0.12)" - }); - level.fill.push({ - x: -3425, - y: -2150, - width: 525, - height: 1550, - color: "rgba(0,0,0,0.12)" - }); - level.fill.push({ - x: -1850, - y: -1150, - width: 2025, - height: 1150, - color: "rgba(0,0,0,0.12)" - }); - - //hidden zone - level.fill.push({ - x: -4450, - y: -955, - width: 1025, - height: 360, - color: "rgba(64,64,64,0.97)" - }); - // level.fill.push({ - // x: -4050, - // y: -955, - // width: 625, - // height: 360, - // color: "#444" - // }); - powerUps.spawn(-4300, -700, "heal"); - powerUps.spawn(-4200, -700, "ammo"); - powerUps.spawn(-4100, -700, "gun"); - spawn.mapRect(-4450, -1000, 100, 500); - spawn.bodyRect(-3576, -750, 150, 150); - - - //building 1 - spawn.bodyRect(-1000, -675, 25, 25); - spawn.mapRect(-2225, 0, 2475, 150); - spawn.mapRect(175, -1000, 75, 1100); - - spawn.mapRect(-175, -985, 25, 175); - spawn.bodyRect(-170, -810, 14, 160, 1, spawn.propsFriction); //door to starting room - spawn.mapRect(-600, -650, 825, 50); - spawn.mapRect(-1300, -650, 500, 50); - spawn.mapRect(-175, -250, 425, 300); - spawn.bodyRect(-75, -300, 50, 50); - - // spawn.boost(-750, 0, 0, -0.01); - spawn.boost(-750, 0, 1700); - spawn.bodyRect(-425, -1375, 400, 225); - spawn.mapRect(-1125, -1575, 50, 475); - spawn.bodyRect(-1475, -1275, 250, 125); - spawn.bodyRect(-825, -1160, 250, 10); - - spawn.mapRect(-1650, -1575, 400, 50); - spawn.mapRect(-600, -1150, 850, 175); - - spawn.mapRect(-1850, -1150, 1050, 175); - spawn.bodyRect(-1907, -1600, 550, 25); - if (game.levelsCleared < 4) { - spawn.bodyRect(-1600, -125, 125, 125); - spawn.bodyRect(-1560, -200, 75, 75); - } else { - spawn.bodyRect(-1200, -125, 125, 125); - spawn.bodyRect(-1160, -200, 75, 75); - } - // spawn.bodyRect(-1100, -125, 150, 125); - - // spawn.bodyRect(-1200, -75, 75, 75); - - //building 2 - spawn.mapRect(-4450, -600, 2300, 750); - spawn.mapRect(-2225, -500, 175, 550); - spawn.boost(-2800, -600, 1150); - spawn.mapRect(-3450, -1325, 550, 50); - spawn.mapRect(-3425, -2200, 525, 50); - spawn.mapRect(-2600, -1750, 450, 50); - spawn.mapRect(-2600, -2450, 450, 50); - spawn.bodyRect(-2275, -2700, 50, 60); - spawn.bodyRect(-2600, -1975, 250, 225); - spawn.bodyRect(-3415, -1425, 100, 100); - spawn.bodyRect(-3400, -1525, 100, 100); - spawn.bodyRect(-3305, -1425, 100, 100); - - //building 3 - spawn.mapRect(-4450, -1750, 1025, 1000); - spawn.mapRect(-3750, -2000, 175, 275); - spawn.mapRect(-4000, -2350, 275, 675); - // spawn.mapRect(-4450, -2650, 475, 1000); - spawn.mapRect(-4450, -2775, 475, 1125); - spawn.bodyRect(-3715, -2050, 50, 50); - spawn.bodyRect(-3570, -1800, 50, 50); - spawn.bodyRect(-2970, -2250, 50, 50); - - if (game.levelsCleared < 4) spawn.bodyRect(-3760, -2400, 50, 50); - - spawn.bodyRect(-3080, -2250, 40, 40); - spawn.bodyRect(-3420, -650, 50, 50); - - //exit - spawn.mapRect(-4450, -3075, 25, 300); - spawn.mapRect(-4450, -3075, 450, 25); - spawn.mapRect(-4025, -3075, 25, 100); - spawn.mapRect(-4275, -2785, 100, 25); - - //mobs - spawn.randomMob(-2500, -2700, 1); - spawn.randomMob(-3200, -750, 1); - spawn.randomMob(-1875, -775, 0.2); - spawn.randomMob(-950, -1675, 0.2); - spawn.randomMob(-1525, -1750, 0.2); - spawn.randomMob(-1375, -1400, 0.2); - spawn.randomMob(-1625, -1275, 0.2); - spawn.randomMob(-1900, -1250, 0.2); - spawn.randomMob(-2250, -1850, 0.2); - spawn.randomMob(-2475, -2200, 0.2); - spawn.randomMob(-3000, -1475, 0.2); - spawn.randomMob(-3850, -2500, 0.2); - spawn.randomMob(-3650, -2125, 0.2); - spawn.randomMob(-4010, -3200, 0.2); - spawn.randomMob(-3500, -1825, 0.2); - spawn.randomMob(-975, -100, 0); - spawn.randomMob(-1050, -725, 0.2); - spawn.randomMob(-1525, -100, 0); - spawn.randomMob(-525, -1700, -0.1); - spawn.randomMob(-125, -1500, -0.1); - spawn.randomMob(-325, -1900, -0.1); - spawn.randomMob(-550, -100, -0.1); - spawn.randomBoss(-3250, -2700, 0.2); - spawn.randomBoss(-2450, -1100, 0); - }, - warehouse() { - level.defaultZoom = 1300 - game.zoomTransition(level.defaultZoom) - - document.body.style.backgroundColor = "#f2f5f3"; - mech.setPosToSpawn(25, -60); //normal spawn - //mech.setPosToSpawn(-2000, -1700); // left ledge spawn - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - level.exit.x = 425; - level.exit.y = -35; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - //level.addQueryRegion(-600, -250, 180, 420, "death", [[player]],{}); - - spawn.debris(-2250, 1330, 3000, 7); //20 debris per level - spawn.debris(-3000, -800, 3280, 7); //20 debris per level - spawn.debris(-1400, 410, 2300, 6); //20 debris per level - powerUps.spawnStartingPowerUps(25, 500); - - //foreground - // level.fill.push({ x: -3025, y: 50, width: 4125, height: 1350, color: "rgba(0,0,0,0.05)"}); - // level.fill.push({ x: -1800, y: -500, width: 1975, height: 550, color: "rgba(0,0,0,0.05)"}); - // level.fill.push({ x: -2600, y: -150, width: 700, height: 200, color: "rgba(0,0,0,0.05)"}); - //background - const BGColor = "rgba(0,0,0,0.1)"; - level.fill.push({ - x: -3025, - y: 50, - width: 4125, - height: 1350, - color: BGColor - }); - level.fill.push({ - x: -1800, - y: -500, - width: 1625, - height: 550, - color: BGColor - }); - level.fill.push({ - x: -175, - y: -250, - width: 350, - height: 300, - color: BGColor - }); - level.fill.push({ - x: -2600, - y: -150, - width: 700, - height: 200, - color: BGColor - }); - level.fillBG.push({ - x: 300, - y: -250, - width: 350, - height: 250, - color: "#cff" - }); - spawn.mapRect(-1500, 0, 2750, 100); - spawn.mapRect(175, -270, 125, 300); - spawn.mapRect(-1900, -600, 1775, 100); - spawn.mapRect(-1900, -600, 100, 1300); - //house - spawn.mapRect(-175, -550, 50, 400); - spawn.mapRect(-175, -15, 350, 50); - spawn.mapRect(-25, -25, 100, 50); - // spawn.mapRect(-175, -275, 350, 25); - // spawn.mapRect(-175, -250, 25, 75); - // spawn.bodyRect(-170, -175, 14, 160, 1, spawn.propsFriction); //door to starting room - //exit house - spawn.mapRect(300, -15, 350, 50); - spawn.mapRect(-150, -300, 800, 50); - spawn.mapRect(600, -275, 50, 75); - spawn.mapRect(425, -25, 100, 25); - // spawn.mapRect(-1900, 600, 2700, 100); - spawn.mapRect(1100, 0, 150, 1500); - spawn.mapRect(-2850, 1400, 4100, 100); - spawn.mapRect(-2375, 875, 1775, 75); - spawn.mapRect(-1450, 865, 75, 435); - spawn.mapRect(-1450, 662, 75, 100); - spawn.bodyRect(-1418, 773, 11, 102, 1, spawn.propsFriction); //blocking path - spawn.mapRect(-2950, 1250, 175, 250); - spawn.mapRect(-3050, 1100, 150, 400); - spawn.mapRect(-3150, 50, 125, 1450); - spawn.mapRect(-2375, 600, 3175, 100); - spawn.mapRect(-2125, 400, 250, 275); - // spawn.mapRect(-1950, -400, 100, 25); - spawn.mapRect(-3150, 50, 775, 100); - spawn.mapRect(-2600, -250, 775, 100); - spawn.bodyRect(-1350, -200, 200, 200, 1, spawn.propsSlide); //weight - spawn.bodyRect(-1800, 0, 300, 100, 1, spawn.propsHoist); //hoist - cons[cons.length] = Constraint.create({ - pointA: { - x: -1650, - y: -500 - }, - bodyB: body[body.length - 1], - stiffness: 0.000076, - length: 1 - }); - - spawn.bodyRect(400, 400, 200, 200, 1, spawn.propsSlide); //weight - spawn.bodyRect(800, 600, 300, 100, 1, spawn.propsHoist); //hoist - cons[cons.length] = Constraint.create({ - pointA: { - x: 950, - y: 100 - }, - bodyB: body[body.length - 1], - stiffness: 0.000076, - length: 1 - }); - - spawn.bodyRect(-2700, 1150, 100, 160, 1, spawn.propsSlide); //weight - spawn.bodyRect(-2550, 1150, 200, 100, 1, spawn.propsSlide); //weight - - spawn.bodyRect(-2775, 1300, 400, 100, 1, spawn.propsHoist); //hoist - cons[cons.length] = Constraint.create({ - pointA: { - x: -2575, - y: 150 - }, - bodyB: body[body.length - 1], - stiffness: 0.0002, - length: 566 - }); - - //blocks - //spawn.bodyRect(-155, -150, 10, 140, 1, spawn.propsFriction); - spawn.bodyRect(-165, -150, 30, 35, 1); - spawn.bodyRect(-165, -115, 30, 35, 1); - spawn.bodyRect(-165, -80, 30, 35, 1); - spawn.bodyRect(-165, -45, 30, 35, 1); - - spawn.bodyRect(-750, 400, 150, 150, 0.5); - spawn.bodyRect(-400, 1175, 100, 250, 1); //block to get to top path on bottom level - // spawn.bodyRect(-1450, 737, 75, 103, 0.5); //blocking path - - spawn.bodyRect(-2525, -50, 145, 100, 0.5); - spawn.bodyRect(-2325, -300, 150, 100, 0.5); - spawn.bodyRect(-1275, -750, 200, 150, 0.5); //roof block - spawn.bodyRect(-525, -700, 125, 100, 0.5); //roof block - - //mobs - spawn.randomSmallMob(-1125, 550); - spawn.randomSmallMob(-2325, 800); - spawn.randomSmallMob(-2950, -50); - spawn.randomSmallMob(825, 300); - spawn.randomSmallMob(-900, 825); - spawn.randomMob(-2025, 175, 0.6); - spawn.randomMob(-2325, 450, 0.6); - spawn.randomMob(-2925, 675, 0.5); - spawn.randomMob(-2700, 300, 0.2); - spawn.randomMob(-2500, 300, 0.2); - spawn.randomMob(-2075, -425, 0.2); - spawn.randomMob(-1550, -725, 0.2); - spawn.randomMob(375, 1100, 0.1); - spawn.randomMob(-1425, -100, 0.1); - spawn.randomMob(-800, -750, 0); - spawn.randomMob(400, -350, 0); - spawn.randomMob(650, 1300, 0); - spawn.randomMob(-750, -150, 0); - spawn.randomMob(475, 300, 0); - spawn.randomMob(-75, -700, 0); - spawn.randomMob(900, -200, -0.1); - spawn.randomBoss(-125, 275, -0.2); - spawn.randomBoss(-825, 1000, 0.2); - spawn.randomBoss(-1300, -1100, -0.3); - //spawn.randomBoss(600, -1575, 0); - //spawn.randomMob(1120, -1200, 0.3); - //spawn.randomSmallMob(2200, -1775); - - if (game.levelsCleared > 2) spawn.snaker(-1300 + Math.random() * 2000, -2200); //boss snake with head - }, - office() { - level.defaultZoom = 1400 - game.zoomTransition(level.defaultZoom) - - if (Math.random() < 0.75) { - //normal direction start in top left - mech.setPosToSpawn(1375, -1550); //normal spawn - level.exit.x = 3250; - level.exit.y = -530; - // spawn.randomSmallMob(3550, -550); - } else { - //reverse direction, start in bottom right - mech.setPosToSpawn(3250, -530); //normal spawn - level.exit.x = 1375; - level.exit.y = -1530; - spawn.bodyRect(3655, -650, 40, 150); //door - } - spawn.mapRect(level.exit.x, level.exit.y + 20, 100, 50); //ground bump wall - level.enter.x = mech.spawnPos.x - 50; - level.enter.y = mech.spawnPos.y + 20; - this.addZone(level.exit.x, level.exit.y, 100, 30, "nextLevel"); - - document.body.style.backgroundColor = "#e0e5e0"; - //foreground - level.fill.push({ - x: -550, - y: -1700, - width: 1300, - height: 1700, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 750, - y: -1450, - width: 650, - height: 1450, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 750, - y: -1950, - width: 800, - height: 450, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 3000, - y: -1000, - width: 650, - height: 1000, - color: "rgba(0,0,0,0.1)" - }); - level.fill.push({ - x: 3650, - y: -1300, - width: 1300, - height: 1300, - color: "rgba(0,0,0,0.1)" - }); - - //mech.setPosToSpawn(600, -1200); //normal spawn - //mech.setPosToSpawn(525, -150); //ground first building - //mech.setPosToSpawn(3150, -700); //near exit spawn - spawn.debris(-300, -200, 1000, 5); //ground debris //20 debris per level - spawn.debris(3500, -200, 800, 5); //ground debris //20 debris per level - spawn.debris(-300, -650, 1200, 5); //1st floor debris //20 debris per level - spawn.debris(3500, -650, 800, 5); //1st floor debris //20 debris per level - powerUps.spawnStartingPowerUps(-525, -700); - - spawn.mapRect(-600, 25, 5600, 300); //ground - spawn.mapRect(-600, 0, 2000, 50); //ground - spawn.mapRect(-600, -1700, 50, 2000 - 100); //left wall - spawn.bodyRect(-295, -1540, 40, 40); //center block under wall - spawn.bodyRect(-298, -1580, 40, 40); //center block under wall - spawn.bodyRect(1500, -1540, 30, 30); //left of entrance - - spawn.mapRect(1550, -2000, 50, 550); //right wall - spawn.mapRect(1350, -2000 + 505, 50, 1295); //right wall - spawn.mapRect(-600, -2000 + 250, 2000 - 700, 50); //roof left - spawn.mapRect(-600 + 1300, -2000, 50, 300); //right roof wall - spawn.mapRect(-600 + 1300, -2000, 900, 50); //center wall - map[map.length] = Bodies.polygon(425, -1700, 0, 15); //circle above door - spawn.bodyRect(420, -1675, 15, 170, 1, spawn.propsDoor); // door - body[body.length - 1].isNotHoldable = true; - //makes door swing - consBB[consBB.length] = Constraint.create({ - bodyA: body[body.length - 1], - pointA: { - x: 0, - y: -90 - }, - bodyB: map[map.length - 1], - stiffness: 1 - }); - spawn.mapRect(-600 + 300, -2000 * 0.75, 1900, 50); //3rd floor - spawn.mapRect(-600 + 2000 * 0.7, -2000 * 0.74, 50, 375); //center wall - spawn.bodyRect(-600 + 2000 * 0.7, -2000 * 0.5 - 106, 50, 106); //center block under wall - spawn.mapRect(-600, -1000, 1100, 50); //2nd floor - spawn.mapRect(600, -1000, 500, 50); //2nd floor - spawn.spawnStairs(-600, -1000, 4, 250, 350); //stairs 2nd - spawn.mapRect(350, -600, 350, 150); //center table - spawn.mapRect(-600 + 300, -2000 * 0.25, 2000 - 300, 50); //1st floor - spawn.spawnStairs(-600 + 2000 - 50, -500, 4, 250, 350, true); //stairs 1st - spawn.spawnStairs(-600, 0, 4, 250, 350); //stairs ground - spawn.bodyRect(700, -200, 100, 100); //center block under wall - spawn.bodyRect(700, -300, 100, 100); //center block under wall - spawn.bodyRect(700, -400, 100, 100); //center block under wall - spawn.mapRect(1390, 13, 30, 20); //step left - spawn.mapRect(2980, 13, 30, 20); //step right - spawn.mapRect(3000, 0, 2000, 50); //ground - spawn.bodyRect(4250, -700, 50, 100); - spawn.bodyRect(3000, -200, 50, 200); //door - spawn.mapRect(3000, -1000, 50, 800); //left wall - spawn.mapRect(3000 + 2000 - 50, -1300, 50, 1100); //right wall - spawn.mapRect(4150, -600, 350, 150); //table - spawn.mapRect(3650, -1300, 50, 650); //exit wall - spawn.mapRect(3650, -1300, 1350, 50); //exit wall - - spawn.mapRect(3000, -2000 * 0.5, 700, 50); //exit roof - spawn.mapRect(3000, -2000 * 0.25, 2000 - 300, 50); //1st floor - spawn.spawnStairs(3000 + 2000 - 50, 0, 4, 250, 350, true); //stairs ground - - // tether ball - if (game.levelsCleared > 2) { - level.fillBG.push({ - x: 2495, - y: -500, - width: 10, - height: 525, - color: "#ccc" - }); - spawn.tether(2850, -80) - cons[cons.length] = Constraint.create({ - pointA: { - x: 2500, - y: -500 - }, - bodyB: mob[mob.length - 1], - stiffness: 0.00012 - }); - //chance to spawn a ring of exploding mobs around this boss - if (game.levelsCleared > 4) spawn.nodeBoss(2850, -80, "spawns", 8, 20, 105); - } - - spawn.randomSmallMob(4575, -560, 1); - spawn.randomSmallMob(1315, -880, 1); - spawn.randomSmallMob(800, -600); - spawn.randomSmallMob(-100, -1600); - spawn.randomMob(4100, -225, 0.8); - spawn.randomMob(-250, -700, 0.8); - spawn.randomMob(4500, -225, 0.15); - spawn.randomMob(3250, -225, 0.15); - spawn.randomMob(-100, -225, 0.1); - spawn.randomMob(1150, -225, 0.15); - spawn.randomMob(2000, -225, 0.15); - spawn.randomMob(450, -225, 0.15); - spawn.randomMob(100, -1200, 1); - spawn.randomMob(950, -1150, -0.1); - spawn.randomBoss(1800, -800, -0.2); - spawn.randomBoss(4150, -1000, 0.6); - }, - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - //***************************************************************************************************************** - enter: { - x: 0, - y: 0, - draw() { - ctx.beginPath(); - ctx.moveTo(this.x, this.y + 30); - ctx.lineTo(this.x, this.y - 80); - ctx.bezierCurveTo(this.x, this.y - 170, this.x + 100, this.y - 170, this.x + 100, this.y - 80); - ctx.lineTo(this.x + 100, this.y + 30); - ctx.lineTo(this.x, this.y + 30); - ctx.fillStyle = "#ccc"; - ctx.fill(); - } - }, - exit: { - x: 0, - y: 0, - draw() { - ctx.beginPath(); - ctx.moveTo(this.x, this.y + 30); - ctx.lineTo(this.x, this.y - 80); - ctx.bezierCurveTo(this.x, this.y - 170, this.x + 100, this.y - 170, this.x + 100, this.y - 80); - ctx.lineTo(this.x + 100, this.y + 30); - ctx.lineTo(this.x, this.y + 30); - ctx.fillStyle = "#0ff"; - ctx.fill(); - } - }, - fillBG: [], - drawFillBGs() { - for (let i = 0, len = level.fillBG.length; i < len; ++i) { - const f = level.fillBG[i]; - ctx.fillStyle = f.color; - ctx.fillRect(f.x, f.y, f.width, f.height); - } - }, - - fill: [], - drawFills() { - for (let i = 0, len = level.fill.length; i < len; ++i) { - const f = level.fill[i]; - ctx.fillStyle = f.color; - ctx.fillRect(f.x, f.y, f.width, f.height); - } - }, - zones: [], //zone do actions when player is in a region // to effect everything use a query - checkZones() { - for (let i = 0, len = this.zones.length; i < len; ++i) { - if ( - player.position.x > this.zones[i].x1 && - player.position.x < this.zones[i].x2 && - player.position.y > this.zones[i].y1 && - player.position.y < this.zones[i].y2 - ) { - this.zoneActions[this.zones[i].action](i); - break; - } - } - }, - addZone(x, y, width, height, action, info) { - this.zones[this.zones.length] = { - x1: x, - y1: y - 150, - x2: x + width, - y2: y + height - 70, //-70 to adjust for player height - action: action, - info: info - }; - }, - zoneActions: { - fling(i) { - Matter.Body.setVelocity(player, { - x: level.zones[i].info.Vx, - y: level.zones[i].info.Vy - }); - }, - nextLevel() { - //enter when player isn't falling - if (player.velocity.y < 0.1) { - game.levelsCleared++; - if (game.levelsCleared > 1) level.difficultyIncrease() - //cycles map to next level - level.onLevel++; - if (level.onLevel > level.levels.length - 1) level.onLevel = 0; - - game.clearNow = true; //triggers in the physics engine to remove all physics bodies - } - }, - death() { - mech.death(); - }, - laser(i) { - //draw these in game with spawn.background - mech.damage(level.zones[i].info.dmg); - }, - slow() { - Matter.Body.setVelocity(player, { - x: player.velocity.x * 0.5, - y: player.velocity.y * 0.5 - }); - } - }, - queryList: [], //queries do actions on many objects in regions (for only player use a zone) - checkQuery() { - let bounds, action, info; - - function isInZone(targetArray) { - let results = Matter.Query.region(targetArray, bounds); - for (let i = 0, len = results.length; i < len; ++i) { - level.queryActions[action](results[i], info); - } - } - for (let i = 0, len = level.queryList.length; i < len; ++i) { - bounds = level.queryList[i].bounds; - action = level.queryList[i].action; - info = level.queryList[i].info; - for (let j = 0, l = level.queryList[i].groups.length; j < l; ++j) { - isInZone(level.queryList[i].groups[j]); - } - } - }, - //oddly query regions can't get smaller than 50 width? - addQueryRegion(x, y, width, height, action, groups = [ - [player], body, mob, powerUp, bullet - ], info) { - this.queryList[this.queryList.length] = { - bounds: { - min: { - x: x, - y: y - }, - max: { - x: x + width, - y: y + height - } - }, - action: action, - groups: groups, - info: info - }; - }, - queryActions: { - bounce(target, info) { - //jerky fling upwards - Matter.Body.setVelocity(target, { - x: info.Vx + (Math.random() - 0.5) * 6, - y: info.Vy - }); - target.torque = (Math.random() - 0.5) * 2 * target.mass; - }, - boost(target, info) { - // if (target.velocity.y < 0) { - // mech.undoCrouch(); - // mech.enterAir(); - mech.buttonCD_jump = 0; // reset short jump counter to prevent short jumps on boosts - mech.hardLandCD = 0 // disable hard landing - Matter.Body.setVelocity(target, { - x: target.velocity.x + (Math.random() - 0.5) * 2, - y: info - }); - }, - force(target, info) { - if (target.velocity.y < 0) { - //gently force up if already on the way up - target.force.x += info.Vx * target.mass; - target.force.y += info.Vy * target.mass; - } else { - target.force.y -= 0.0007 * target.mass; //gently fall in on the way down - } - }, - antiGrav(target) { - target.force.y -= 0.0011 * target.mass; - }, - death(target) { - target.death(); - } - }, - levelAnnounce() { - document.title = "n-gon: L" + (game.levelsCleared) + " " + level.levels[level.onLevel]; - game.makeTextLog(`
level ${game.levelsCleared}
${level.levels[level.onLevel]}
`, 300); - // if (game.levelsCleared === 0) text = ""; - // text = "Level " + (game.levelsCleared + 1) + ": " + spawn.pickList[0] + "s + " + spawn.pickList[1] + "s"; - - // text = text + " with population: "; - // for (let i = 0, len = spawn.pickList.length; i < len; ++i) { - // if (spawn.pickList[i] != spawn.pickList[i - 1]) { - // text += spawn.pickList[i] + ", "; - // } - // } - // this.speech(text); - // game.makeTextLog(text, 360); - }, - addToWorld(mapName) { - //needs to be run to put bodies into the world - for (let i = 0; i < body.length; i++) { - //body[i].collisionFilter.group = 0; - body[i].collisionFilter.category = 0x010000; - body[i].collisionFilter.mask = 0x011111; - body[i].classType = "body"; - World.add(engine.world, body[i]); //add to world - } - for (let i = 0; i < map.length; i++) { - //map[i].collisionFilter.group = 0; - map[i].collisionFilter.category = 0x000001; - map[i].collisionFilter.mask = 0x111111; - Matter.Body.setStatic(map[i], true); //make static - World.add(engine.world, map[i]); //add to world - } - for (let i = 0; i < cons.length; i++) { - World.add(engine.world, cons[i]); - } - for (let i = 0; i < consBB.length; i++) { - World.add(engine.world, consBB[i]); - } - } -}; \ No newline at end of file diff --git a/js/mobs.js b/js/mobs.js deleted file mode 100644 index db66bf3..0000000 --- a/js/mobs.js +++ /dev/null @@ -1,986 +0,0 @@ -//create array of mobs -let mob = []; -//method to populate the array above -const mobs = { - loop() { - let i = mob.length; - while (i--) { - if (mob[i].alive) { - mob[i].do(); - } else { - mob[i].replace(i); //removing mob and replace with body, this is done here to avoid an array index bug with drawing I think - } - } - }, - draw() { - ctx.lineWidth = 2; - let i = mob.length; - while (i--) { - ctx.beginPath(); - const vertices = mob[i].vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = mob[i].fill; - ctx.strokeStyle = mob[i].stroke; - ctx.fill(); - ctx.stroke(); - } - }, - alert(range) { - range = range * range; - for (let i = 0; i < mob.length; i++) { - if (mob[i].distanceToPlayer2() < range) mob[i].locatePlayer(); - } - }, - startle(amount) { - for (let i = 0; i < mob.length; i++) { - if (!mob[i].seePlayer.yes) { - mob[i].force.x += amount * mob[i].mass * (Math.random() - 0.5); - mob[i].force.y += amount * mob[i].mass * (Math.random() - 0.5); - } - } - }, - //********************************************************************************************** - //********************************************************************************************** - spawn(xPos, yPos, sides, radius, color) { - let i = mob.length; - mob[i] = Matter.Bodies.polygon(xPos, yPos, sides, radius, { - //inertia: Infinity, //prevents rotation - mob: true, - density: 0.001, - //friction: 0, - frictionAir: 0.005, - //frictionStatic: 0, - restitution: 0.5, - collisionFilter: { - group: 0, - category: 0x000010, - mask: 0x011111 - }, - onHit: undefined, - alive: true, - index: i, - health: 1, - accelMag: 0.001, - cd: 0, //game cycle when cooldown will be over - delay: 60, //static: time between cooldowns - fill: color, - stroke: "#000", - seePlayer: { - yes: false, - recall: 0, - position: { - x: xPos, - y: yPos - } - }, - radius: radius, - spawnPos: { - x: xPos, - y: yPos - }, - seeAtDistance2: 4000000, //sqrt(4000000) = 2000 = max seeing range - distanceToPlayer() { - const dx = this.position.x - player.position.x; - const dy = this.position.y - player.position.y; - return Math.sqrt(dx * dx + dy * dy); - }, - distanceToPlayer2() { - const dx = this.position.x - player.position.x; - const dy = this.position.y - player.position.y; - return dx * dx + dy * dy; - }, - gravity() { - this.force.y += this.mass * this.g; - }, - seePlayerFreq: Math.round((30 + 30 * Math.random()) * game.lookFreqScale), //how often NPC checks to see where player is, lower numbers have better vision - foundPlayer() { - this.locatePlayer(); - if (!this.seePlayer.yes) { - this.alertNearByMobs(); - this.seePlayer.yes = true; - } - }, - lostPlayer() { - this.seePlayer.yes = false; - this.seePlayer.recall -= this.seePlayerFreq; - if (this.seePlayer.recall < 0) this.seePlayer.recall = 0; - }, - memory: 120, //default time to remember player's location - locatePlayer() { - if (!mech.isStealth) { - // updates mob's memory of player location - this.seePlayer.recall = this.memory + Math.round(this.memory * Math.random()); //seconds before mob falls a sleep - this.seePlayer.position.x = player.position.x; - this.seePlayer.position.y = player.position.y; - } - }, - // locatePlayerByDist() { - // if (this.distanceToPlayer2() < this.locateRange) { - // this.locatePlayer(); - // } - // }, - seePlayerCheck() { - if (!(game.cycle % this.seePlayerFreq)) { - if ( - this.distanceToPlayer2() < this.seeAtDistance2 && - Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && - Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0 - ) { - this.foundPlayer(); - } else if (this.seePlayer.recall) { - this.lostPlayer(); - } - } - }, - seePlayerCheckByDistance() { - if (!(game.cycle % this.seePlayerFreq)) { - if (this.distanceToPlayer2() < this.seeAtDistance2) { - this.foundPlayer(); - } else if (this.seePlayer.recall) { - this.lostPlayer(); - } - } - }, - seePlayerByDistOrLOS() { - if (!(game.cycle % this.seePlayerFreq)) { - if ( - this.distanceToPlayer2() < this.seeAtDistance2 || - (Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0) - ) { - this.foundPlayer(); - } else if (this.seePlayer.recall) { - this.lostPlayer(); - } - } - }, - seePlayerByDistAndLOS() { - if (!(game.cycle % this.seePlayerFreq)) { - if ( - this.distanceToPlayer2() < this.seeAtDistance2 && - (Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0) - ) { - this.foundPlayer(); - } else if (this.seePlayer.recall) { - this.lostPlayer(); - } - } - }, - isLookingAtPlayer(threshold) { - const diff = Matter.Vector.normalise(Matter.Vector.sub(player.position, this.position)); - //make a vector for the mob's direction of length 1 - const dir = { - x: Math.cos(this.angle), - y: Math.sin(this.angle) - }; - //the dot product of diff and dir will return how much over lap between the vectors - const dot = Matter.Vector.dot(dir, diff); - // console.log(Math.cos(dot)*180/Math.PI) - if (dot > threshold) { - return true; - } else { - return false; - } - }, - lookRange: 0.2 + Math.random() * 0.2, - lookTorque: 0.0000004 * (Math.random() > 0.5 ? -1 : 1), - seePlayerByLookingAt() { - if (!(game.cycle % this.seePlayerFreq) && (this.seePlayer.recall || this.isLookingAtPlayer(this.lookRange))) { - if ( - this.distanceToPlayer2() < this.seeAtDistance2 && - Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && - Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0 - ) { - this.foundPlayer(); - } else if (this.seePlayer.recall) { - this.lostPlayer(); - } - } - //if you don't recall player location rotate and draw to show where you are looking - if (!this.seePlayer.recall) { - this.torque = this.lookTorque * this.inertia; - //draw - const range = Math.PI * this.lookRange; - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.radius * 2.5, this.angle - range, this.angle + range); - ctx.arc(this.position.x, this.position.y, this.radius * 1.4, this.angle + range, this.angle - range, true); - ctx.fillStyle = "rgba(0,0,0,0.07)"; - ctx.fill(); - } - }, - mechPosRange() { - return { - x: player.position.x, // + (Math.random() - 0.5) * 50, - y: player.position.y + (Math.random() - 0.5) * 110 - }; - //mob vision for testing - // ctx.beginPath(); - // ctx.lineWidth = "5"; - // ctx.strokeStyle = "#ff0"; - // ctx.moveTo(this.position.x, this.position.y); - // ctx.lineTo(targetPos.x, targetPos.y); - // ctx.stroke(); - // return targetPos; - }, - laserBeam() { - if (game.cycle % 7 && this.seePlayer.yes) { - ctx.setLineDash([125 * Math.random(), 125 * Math.random()]); - // ctx.lineDashOffset = 6*(game.cycle % 215); - if (this.distanceToPlayer() < this.laserRange) { - //if (Math.random()>0.2 && this.seePlayer.yes && this.distanceToPlayer2()<800000) { - mech.damage(0.0003 * game.dmgScale); - if (mech.fieldMeter > 0.1) mech.fieldMeter -= 0.005 - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(mech.pos.x, mech.pos.y); - ctx.lineTo(mech.pos.x + (Math.random() - 0.5) * 3000, mech.pos.y + (Math.random() - 0.5) * 3000); - ctx.lineWidth = 2; - ctx.strokeStyle = "rgb(255,0,170)"; - ctx.stroke(); - - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, 40, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(255,0,170,0.15)"; - ctx.fill(); - } - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.laserRange * 0.9, 0, 2 * Math.PI); - ctx.strokeStyle = "rgba(255,0,170,0.5)"; - ctx.lineWidth = 1; - ctx.stroke(); - ctx.setLineDash([]); - } - }, - laser() { - 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 && (!domain[i].mob || domain[i].alive)) { - 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] - }; - } - } - } - }; - if (this.seePlayer.recall) { - this.torque = this.lookTorque * this.inertia * 2; - - const seeRange = 2500; - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - }; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - vertexCollision(this.position, look, body); - vertexCollision(this.position, look, [player]); - // hitting player - if (best.who === player) { - dmg = 0.004 * game.dmgScale; - mech.damage(dmg); - //draw damage - ctx.fillStyle = color; - ctx.beginPath(); - ctx.arc(best.x, best.y, dmg * 2000, 0, 2 * Math.PI); - ctx.fill(); - } - //draw beam - if (best.dist2 === Infinity) { - best = look; - } - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(best.x, best.y); - ctx.strokeStyle = "#f00"; // Purple path - ctx.lineWidth = 1; - ctx.setLineDash([50 + 120 * Math.random(), 50 * Math.random()]); - ctx.stroke(); // Draw it - ctx.setLineDash([0, 0]); - } - }, - searchSpring() { - ctx.beginPath(); - ctx.arc(this.cons.pointA.x, this.cons.pointA.y, 6, 0, 2 * Math.PI); - ctx.arc(this.cons2.pointA.x, this.cons2.pointA.y, 6, 0, 2 * Math.PI); - // ctx.arc(this.cons.bodyB.position.x, this.cons.bodyB.position.y,6,0,2*Math.PI); - ctx.fillStyle = "#222"; - ctx.fill(); - - if (!(game.cycle % this.seePlayerFreq)) { - if ( - (this.seePlayer.recall || this.isLookingAtPlayer(this.lookRange)) && - this.distanceToPlayer2() < this.seeAtDistance2 && - Matter.Query.ray(map, this.position, player.position).length === 0 && - Matter.Query.ray(body, this.position, player.position).length === 0 - ) { - this.foundPlayer(); - if (!(game.cycle % (this.seePlayerFreq * 2))) { - this.springTarget.x = this.seePlayer.position.x; - this.springTarget.y = this.seePlayer.position.y; - this.cons.length = -200; - this.cons2.length = 100 + 1.5 * this.radius; - } else { - this.springTarget2.x = this.seePlayer.position.x; - this.springTarget2.y = this.seePlayer.position.y; - this.cons.length = 100 + 1.5 * this.radius; - this.cons2.length = -200; - } - } else if (this.seePlayer.recall) { - this.lostPlayer(); - } - } - //if you don't recall player location rotate and draw to show where you are looking - if (!this.seePlayer.recall) { - this.torque = this.lookTorque * this.inertia; - //draw - const range = Math.PI * this.lookRange; - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, this.radius * 2.5, this.angle - range, this.angle + range); - ctx.arc(this.position.x, this.position.y, this.radius * 1.4, this.angle + range, this.angle - range, true); - ctx.fillStyle = "rgba(0,0,0,0.07)"; - ctx.fill(); - //spring to random place on map - 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 && (!domain[i].mob || domain[i].alive)) { - 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] - }; - } - } - } - }; - const seeRange = 3000; - if (!(game.cycle % (this.seePlayerFreq * 10))) { - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - }; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - if (best.dist2 != Infinity) { - this.springTarget.x = best.x; - this.springTarget.y = best.y; - this.cons.length = 100 + 1.5 * this.radius; - this.cons2.length = 100 + 1.5 * this.radius; - } - } - if (!((game.cycle + this.seePlayerFreq * 5) % (this.seePlayerFreq * 10))) { - best = { - x: null, - y: null, - dist2: Infinity, - who: null, - v1: null, - v2: null - }; - const look = { - x: this.position.x + seeRange * Math.cos(this.angle), - y: this.position.y + seeRange * Math.sin(this.angle) - }; - vertexCollision(this.position, look, map); - if (best.dist2 != Infinity) { - this.springTarget2.x = best.x; - this.springTarget2.y = best.y; - this.cons.length = 100 + 1.5 * this.radius; - this.cons2.length = 100 + 1.5 * this.radius; - } - } - } - }, - alertNearByMobs() { - //this.alertRange2 is set at the very bottom of this mobs, after mob is made - for (let i = 0; i < mob.length; i++) { - if (!mob[i].seePlayer.recall && Matter.Vector.magnitudeSquared(Matter.Vector.sub(this.position, mob[i].position)) < this.alertRange2) { - mob[i].locatePlayer(); - } - } - //add alert to draw queue - // game.drawList.push({ - // x: this.position.x, - // y: this.position.y, - // radius: Math.sqrt(this.alertRange2), - // color: "rgba(0,0,0,0.02)", - // time: game.drawTime - // }); - }, - zoom() { - this.zoomMode--; - if (this.zoomMode > 150) { - this.drawTrail(); - if (this.seePlayer.recall) { - //attraction to player - const forceMag = this.accelMag * this.mass; - const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); - this.force.x += forceMag * Math.cos(angle); - this.force.y += forceMag * Math.sin(angle); - } - } else if (this.zoomMode < 0) { - this.zoomMode = 300; - this.setupTrail(); - } - }, - setupTrail() { - this.trail = []; - for (let i = 0; i < this.trailLength; ++i) { - this.trail.push({ - x: this.position.x, - y: this.position.y - }); - } - }, - drawTrail() { - //dont' forget to run setupTrail() after mob spawn - const t = this.trail; - const len = t.length; - t.pop(); - t.unshift({ - x: this.position.x, - y: this.position.y - }); - //draw - ctx.strokeStyle = this.trailFill; - ctx.beginPath(); - // ctx.moveTo(t[0].x, t[0].y); - // ctx.lineTo(t[0].x, t[0].y); - // ctx.globalAlpha = 0.2; - // ctx.lineWidth = this.radius * 3; - // ctx.stroke(); - ctx.globalAlpha = 0.5 / len; - ctx.lineWidth = this.radius * 1.95; - for (let i = 0; i < len; ++i) { - // ctx.lineWidth *= 0.96; - ctx.lineTo(t[i].x, t[i].y); - ctx.stroke(); - } - ctx.globalAlpha = 1; - }, - curl(range = 1000, mag = -10) { - //cause all mobs, and bodies to rotate in a circle - applyCurl = function (center, array) { - for (let i = 0; i < array.length; ++i) { - const sub = Matter.Vector.sub(center, array[i].position) - const radius2 = Matter.Vector.magnitudeSquared(sub); - - //if too close, like center mob or shield, don't curl // if too far don't curl - if (radius2 < range * range && radius2 > 10000) { - const curlVector = Matter.Vector.mult(Matter.Vector.perp(Matter.Vector.normalise(sub)), mag) - //apply curl force - Matter.Body.setVelocity(array[i], { - x: array[i].velocity.x * 0.94 + curlVector.x * 0.06, - y: array[i].velocity.y * 0.94 + curlVector.y * 0.06 - }) - // //draw curl - // ctx.beginPath(); - // ctx.moveTo(array[i].position.x, array[i].position.y); - // ctx.lineTo(array[i].position.x + curlVector.x * 10, array[i].position.y + curlVector.y * 10); - // ctx.lineWidth = 2; - // ctx.strokeStyle = "#000"; - // ctx.stroke(); - } - } - } - applyCurl(this.position, mob); - applyCurl(this.position, body); - applyCurl(this.position, powerUp); - // applyCurl(this.position, bullet); // too powerful, just stops all bullets need to write a curl function just for bullets - // applyCurl(this.position, [player]); - - //draw limit - // ctx.beginPath(); - // ctx.arc(this.position.x, this.position.y, range, 0, 2 * Math.PI); - // ctx.fillStyle = "rgba(55,255,255, 0.1)"; - // ctx.fill(); - }, - pullPlayer() { - if (this.seePlayer.yes && Matter.Vector.magnitudeSquared(Matter.Vector.sub(this.position, player.position)) < 1000000) { - const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); - player.force.x -= game.accelScale * 1.13 * Math.cos(angle) * (mech.onGround ? 2 * player.mass * game.g : player.mass * game.g); - player.force.y -= game.accelScale * 0.84 * player.mass * game.g * Math.sin(angle); - - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(mech.pos.x, mech.pos.y); - ctx.lineWidth = Math.min(60, this.radius * 2); - ctx.strokeStyle = "rgba(0,0,0,0.5)"; - ctx.stroke(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, 40, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,0,0,0.3)"; - ctx.fill(); - } - }, - repelBullets() { - if (this.seePlayer.yes) { - ctx.lineWidth = "8"; - ctx.strokeStyle = this.fill; - ctx.beginPath(); - for (let i = 0, len = bullet.length; i < len; ++i) { - const dx = bullet[i].position.x - this.position.x; - const dy = bullet[i].position.y - this.position.y; - const dist = Math.sqrt(dx * dx + dy * dy); - if (dist < 500) { - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(bullet[i].position.x, bullet[i].position.y); - const angle = Math.atan2(dy, dx); - const mag = (1500 * bullet[i].mass * game.g) / dist; - bullet[i].force.x += mag * Math.cos(angle); - bullet[i].force.y += mag * Math.sin(angle); - } - } - ctx.stroke(); - } - }, - attraction() { - //accelerate towards the player - if (this.seePlayer.recall) { - // && dx * dx + dy * dy < 2000000) { - const forceMag = this.accelMag * 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); - } - }, - repulsionRange: 500000, - repulsion() { - //accelerate towards the player - if (this.seePlayer.recall && this.distanceToPlayer2() < this.repulsionRange) { - // && dx * dx + dy * dy < 2000000) { - const forceMag = this.accelMag * this.mass; - const angle = Math.atan2(this.seePlayer.position.y - this.position.y, this.seePlayer.position.x - this.position.x); - this.force.x -= 2 * forceMag * Math.cos(angle); - 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 - const rangeY = 250; - if (this.position.y > this.seePlayer.position.y - this.hoverElevation + rangeY) { - this.force.y -= this.accelMag * this.mass; - } else if (this.position.y < this.seePlayer.position.y - this.hoverElevation - rangeY) { - this.force.y += this.accelMag * this.mass; - } - // horizontal positioning - const rangeX = 150; - if (this.position.x > this.seePlayer.position.x + this.hoverXOff + rangeX) { - this.force.x -= this.accelMag * this.mass; - } else if (this.position.x < this.seePlayer.position.x + this.hoverXOff - rangeX) { - this.force.x += this.accelMag * this.mass; - } - } - // else { - // this.gravity(); - // } - }, - grow() { - if (!mech.isBodiesAsleep) { - if (this.seePlayer.recall) { - if (this.radius < 80) { - const scale = 1.01; - Matter.Body.scale(this, scale, scale); - this.radius *= scale; - // this.torque = -0.00002 * this.inertia; - this.fill = `hsl(144, ${this.radius}%, 50%)`; - } - } else { - if (this.radius > 15) { - const scale = 0.99; - Matter.Body.scale(this, scale, scale); - this.radius *= scale; - this.fill = `hsl(144, ${this.radius}%, 50%)`; - } - } - } - }, - search() { - //be sure to declare searchTarget in mob spawn - //accelerate towards the searchTarget - if (!this.seePlayer.recall) { - const newTarget = function (that) { - if (Math.random() < 0.05) { - that.searchTarget = player.position; //chance to target player - } else { - //target random body - that.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; - } - }; - - const sub = Matter.Vector.sub(this.searchTarget, this.position); - if (Matter.Vector.magnitude(sub) > this.radius * 2) { - // ctx.beginPath(); - // ctx.strokeStyle = "#aaa"; - // ctx.moveTo(this.position.x, this.position.y); - // ctx.lineTo(this.searchTarget.x,this.searchTarget.y); - // ctx.stroke(); - //accelerate at 0.1 of normal acceleration - this.force = Matter.Vector.mult(Matter.Vector.normalise(sub), this.accelMag * this.mass * 0.2); - } else { - //after reaching random target switch to new target - newTarget(this); - } - //switch to a new target after a while - if (!(game.cycle % (this.seePlayerFreq * 15))) { - newTarget(this); - } - } - }, - strike() { - //teleport to player when close enough on CD - if (this.seePlayer.recall && this.cd < game.cycle) { - const dist = Matter.Vector.sub(this.seePlayer.position, this.position); - const distMag = Matter.Vector.magnitude(dist); - if (distMag < 430) { - this.cd = game.cycle + this.delay; - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - Matter.Body.translate(this, Matter.Vector.mult(Matter.Vector.normalise(dist), distMag - 20 - radius)); - ctx.lineTo(this.position.x, this.position.y); - ctx.lineWidth = radius * 2; - ctx.strokeStyle = this.fill; //"rgba(0,0,0,0.5)"; //'#000' - ctx.stroke(); - } - } - }, - blink() { - //teleport towards player as a way to move - if (this.seePlayer.recall && !(game.cycle % this.blinkRate)) { - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - const dist = Matter.Vector.sub(this.seePlayer.position, this.position); - const distMag = Matter.Vector.magnitude(dist); - const unitVector = Matter.Vector.normalise(dist); - const rando = (Math.random() - 0.5) * 50; - if (distMag < this.blinkLength) { - Matter.Body.translate(this, Matter.Vector.mult(unitVector, distMag + rando)); - } else { - Matter.Body.translate(this, Matter.Vector.mult(unitVector, this.blinkLength + rando)); - } - ctx.lineTo(this.position.x, this.position.y); - ctx.lineWidth = radius * 2; - ctx.strokeStyle = this.stroke; //"rgba(0,0,0,0.5)"; //'#000' - ctx.stroke(); - } - }, - drift() { - //teleport towards player as a way to move - if (this.seePlayer.recall && !(game.cycle % this.blinkRate)) { - // && !mech.lookingAtMob(this,0.5)){ - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - const dist = Matter.Vector.sub(this.seePlayer.position, this.position); - const distMag = Matter.Vector.magnitude(dist); - const vector = Matter.Vector.mult(Matter.Vector.normalise(dist), this.blinkLength); - if (distMag < this.blinkLength) { - Matter.Body.setPosition(this, this.seePlayer.position); - Matter.Body.translate(this, { - x: (Math.random() - 0.5) * 50, - y: (Math.random() - 0.5) * 50 - }); - } else { - vector.x += (Math.random() - 0.5) * 200; - vector.y += (Math.random() - 0.5) * 200; - Matter.Body.translate(this, vector); - } - ctx.lineTo(this.position.x, this.position.y); - ctx.lineWidth = radius * 2; - ctx.strokeStyle = this.stroke; - ctx.stroke(); - } - }, - bomb() { - //throw a mob/bullet at player - if ( - !(game.cycle % this.fireFreq) && - Math.abs(this.position.x - this.seePlayer.position.x) < 400 && //above player - Matter.Query.ray(map, this.position, this.mechPosRange()).length === 0 && //see player - Matter.Query.ray(body, this.position, this.mechPosRange()).length === 0 - ) { - spawn.bullet(this.position.x, this.position.y + this.radius * 0.5, 10 + Math.ceil(this.radius / 15), 5); - //add spin and speed - Matter.Body.setAngularVelocity(mob[mob.length - 1], (Math.random() - 0.5) * 0.5); - Matter.Body.setVelocity(mob[mob.length - 1], { - x: this.velocity.x, - y: this.velocity.y - }); - //spin for mob as well - Matter.Body.setAngularVelocity(this, (Math.random() - 0.5) * 0.25); - } - }, - fire() { - if (!mech.isBodiesAsleep) { - const setNoseShape = () => { - const mag = this.radius + this.radius * this.noseLength; - this.vertices[1].x = this.position.x + Math.cos(this.angle) * mag; - this.vertices[1].y = this.position.y + Math.sin(this.angle) * mag; - }; - //throw a mob/bullet at player - if (this.seePlayer.recall) { - //set direction to turn to fire - if (!(game.cycle % this.seePlayerFreq)) { - this.fireDir = Matter.Vector.normalise(Matter.Vector.sub(this.seePlayer.position, this.position)); - this.fireDir.y -= Math.abs(this.seePlayer.position.x - this.position.x) / 1600; //gives the bullet an arc - this.fireAngle = Math.atan2(this.fireDir.y, this.fireDir.x); - } - //rotate towards fireAngle - const angle = this.angle + Math.PI / 2; - c = Math.cos(angle) * this.fireDir.x + Math.sin(angle) * this.fireDir.y; - const threshold = 0.1; - if (c > threshold) { - this.torque += 0.000004 * this.inertia; - } else if (c < -threshold) { - this.torque -= 0.000004 * this.inertia; - } else if (this.noseLength > 1.5) { - //fire - spawn.bullet(this.vertices[1].x, this.vertices[1].y, 5 + Math.ceil(this.radius / 15), 5); - const v = 15; - Matter.Body.setVelocity(mob[mob.length - 1], { - x: this.velocity.x + this.fireDir.x * v + Math.random(), - y: this.velocity.y + this.fireDir.y * v + Math.random() - }); - this.noseLength = 0; - // recoil - this.force.x -= 0.005 * this.fireDir.x * this.mass; - this.force.y -= 0.005 * this.fireDir.y * this.mass; - } - if (this.noseLength < 1.5) this.noseLength += this.fireFreq; - setNoseShape(); - } else if (this.noseLength > 0.1) { - this.noseLength -= this.fireFreq / 2; - setNoseShape(); - } - // else if (this.noseLength < -0.1) { - // this.noseLength += this.fireFreq / 4; - // setNoseShape(); - // } - } - }, - turnToFacePlayer() { - //turn to face player - const dx = player.position.x - this.position.x; - const dy = -player.position.y + this.position.y; - const dist = this.distanceToPlayer(); - const angle = this.angle + Math.PI / 2; - c = Math.cos(angle) * dx - Math.sin(angle) * dy; - // if (c > 0.04) { - // Matter.Body.rotate(this, 0.01); - // } else if (c < 0.04) { - // Matter.Body.rotate(this, -0.01); - // } - if (c > 0.04 * dist) { - this.torque += 0.002 * this.mass; - } else if (c < 0.04) { - this.torque -= 0.002 * this.mass; - } - }, - facePlayer() { - const unitVector = Matter.Vector.normalise(Matter.Vector.sub(this.seePlayer.position, this.position)); - const angle = Math.atan2(unitVector.y, unitVector.x); - Matter.Body.setAngle(this, angle - Math.PI); - }, - explode() { - mech.damage(Math.min(Math.max(0.02 * Math.sqrt(this.mass), 0.01), 0.35) * game.dmgScale); - this.dropPowerUp = false; - this.death(); //death with no power up or body - }, - timeLimit() { - if (!mech.isBodiesAsleep) { - this.timeLeft--; - if (this.timeLeft < 0) { - this.dropPowerUp = false; - this.death(); //death with no power up - } - } - }, - healthBar() { - //draw health bar - if (this.seePlayer.recall) { - // && this.health < 1 - const h = this.radius * 0.3; - const w = this.radius * 2; - const x = this.position.x - w / 2; - const y = this.position.y - w * 0.7; - ctx.fillStyle = "rgba(100, 100, 100, 0.3)"; - ctx.fillRect(x, y, w, h); - ctx.fillStyle = "rgba(255,0,0,0.7)"; - ctx.fillRect(x, y, w * this.health, h); - } - }, - damage(dmg) { - this.health -= dmg / Math.sqrt(this.mass); - //this.fill = this.color + this.health + ')'; - if (this.health < 0.1) this.death(); - this.onDamage(this); //custom damage effects - if (b.modEnergySiphon) mech.fieldMeter += dmg * b.modEnergySiphon - if (b.modHealthDrain) mech.addHealth(dmg * b.modHealthDrain) - }, - onDamage() { - // a placeholder for custom effects on mob damage - //to use declare custom method in mob spawn - }, - onDeath() { - // a placeholder for custom effects on mob death - //to use declare custom method in mob spawn - }, - leaveBody: true, - dropPowerUp: true, - death() { - this.onDeath(this); //custom death effects - this.removeConsBB(); - this.alive = false; - if (this.dropPowerUp) powerUps.spawnRandomPowerUp(this.position.x, this.position.y, this.mass, radius); - }, - removeConsBB() { - for (let i = 0, len = consBB.length; i < len; ++i) { - if (consBB[i].bodyA === this) { - if (consBB[i].bodyB.shield) { - consBB[i].bodyB.do = function () { - this.death(); - }; - } - consBB[i].bodyA = consBB[i].bodyB; - consBB.splice(i, 1); - this.removeConsBB(); - break; - } else if (consBB[i].bodyB === this) { - if (consBB[i].bodyA.shield) { - consBB[i].bodyA.do = function () { - this.death(); - }; - } - consBB[i].bodyB = consBB[i].bodyA; - consBB.splice(i, 1); - this.removeConsBB(); - break; - } - } - }, - removeCons() { - for (let i = 0, len = cons.length; i < len; ++i) { - if (cons[i].bodyA === this) { - cons[i].bodyA = cons[i].bodyB; - cons.splice(i, 1); - this.removeCons(); - break; - } else if (cons[i].bodyB === this) { - cons[i].bodyB = cons[i].bodyA; - cons.splice(i, 1); - this.removeCons(); - break; - } - } - }, - //replace dead mob with a regular body - replace(i) { - if (this.leaveBody) { - const len = body.length; - body[len] = Matter.Bodies.fromVertices(this.position.x, this.position.y, this.vertices); - Matter.Body.setVelocity(body[len], this.velocity); - Matter.Body.setAngularVelocity(body[len], this.angularVelocity); - body[len].collisionFilter.category = 0x010000; - body[len].collisionFilter.mask = 0x011111; - // body[len].collisionFilter.category = body[len].collisionFilter.category //0x000001; - // body[len].collisionFilter.mask = body[len].collisionFilter.mask //0x011111; - - //large mobs or too many bodies go intangible and fall until removed from game to help performance - if (body[len].mass > 10 || 40 + 30 * Math.random() < body.length) { - body[len].collisionFilter.mask = 0x001100; - } - body[len].classType = "body"; - World.add(engine.world, body[len]); //add to world - } - Matter.World.remove(engine.world, this); - mob.splice(i, 1); - } - }); - mob[i].alertRange2 = Math.pow(mob[i].radius * 3 + 200, 2); - World.add(engine.world, mob[i]); //add to world - } -}; \ No newline at end of file diff --git a/js/player.js b/js/player.js deleted file mode 100644 index fee16d8..0000000 --- a/js/player.js +++ /dev/null @@ -1,1445 +0,0 @@ -//global player variables for use in matter.js physics -let player, jumpSensor, playerBody, playerHead, headSensor; - -// player Object Prototype ********************************************* -const mech = { - spawn() { - //load player in matter.js physic engine - // let vector = Vertices.fromPath("0 40 50 40 50 115 0 115 30 130 20 130"); //player as a series of vertices - let vector = Vertices.fromPath("0,40, 50,40, 50,115, 30,130, 20,130, 0,115, 0,40"); //player as a series of vertices - playerBody = Matter.Bodies.fromVertices(0, 0, vector); - jumpSensor = Bodies.rectangle(0, 46, 36, 6, { - //this sensor check if the player is on the ground to enable jumping - sleepThreshold: 99999999999, - isSensor: true - }); - vector = Vertices.fromPath("16 -82 2 -66 2 -37 43 -37 43 -66 30 -82"); - playerHead = Matter.Bodies.fromVertices(0, -55, vector); //this part of the player lowers on crouch - headSensor = Bodies.rectangle(0, -57, 48, 45, { - //senses if the player's head is empty and can return after crouching - sleepThreshold: 99999999999, - isSensor: true - }); - player = Body.create({ - //combine jumpSensor and playerBody - parts: [playerBody, playerHead, jumpSensor, headSensor], - inertia: Infinity, //prevents player rotation - friction: 0.002, - frictionAir: 0.001, - //frictionStatic: 0.5, - restitution: 0, - sleepThreshold: Infinity, - collisionFilter: { - group: 0, - category: 0x001000, - mask: 0x010011 - }, - death() { - mech.death(); - } - }); - Matter.Body.setMass(player, mech.mass); - World.add(engine.world, [player]); - - mech.holdConstraint = Constraint.create({ - //holding body constraint - pointA: { - x: 0, - y: 0 - }, - bodyB: jumpSensor, //setting constraint to jump sensor because it has to be on something until the player picks up things - stiffness: 0.4 - }); - World.add(engine.world, mech.holdConstraint); - }, - cycle: 0, - width: 50, - radius: 30, - fillColor: "#fff", - fillColorDark: "#ccc", - height: 42, - yOffWhen: { - crouch: 22, - stand: 49, - jump: 70 - }, - mass: 5, - Fx: 0.015, //run Force on ground - FxAir: 0.015, //run Force in Air - definePlayerMass(mass = 5) { - Matter.Body.setMass(player, mass); - //reduce air and ground move forces - this.Fx = 0.075 / mass - this.FxAir = 0.375 / mass / mass - //make player stand a bit lower when holding heavy masses - this.yOffWhen.stand = Math.max(this.yOffWhen.crouch, Math.min(49, 49 - (mass - 5) * 6)) - if (this.onGround && !this.crouch) this.yOffGoal = this.yOffWhen.stand; - }, - yOff: 70, - yOffGoal: 70, - onGround: false, //checks if on ground or in air - standingOn: undefined, - numTouching: 0, - crouch: false, - isHeadClear: true, - spawnPos: { - x: 0, - y: 0 - }, - spawnVel: { - x: 0, - y: 0 - }, - pos: { - x: 0, - y: 0 - }, - setPosToSpawn(xPos, yPos) { - this.spawnPos.x = this.pos.x = xPos; - this.spawnPos.y = this.pos.y = yPos; - this.transX = this.transSmoothX = canvas.width2 - this.pos.x; - this.transY = this.transSmoothY = canvas.height2 - this.pos.y; - this.Vx = this.spawnVel.x; - this.Vy = this.spawnVel.y; - player.force.x = 0; - player.force.y = 0; - Matter.Body.setPosition(player, this.spawnPos); - Matter.Body.setVelocity(player, this.spawnVel); - }, - Sy: 0, //adds a smoothing effect to vertical only - Vx: 0, - Vy: 0, - jumpForce: 0.38, - gravity: 0.0019, - friction: { - ground: 0.01, - air: 0.0025 - }, - angle: 0, - walk_cycle: 0, - stepSize: 0, - flipLegs: -1, - hip: { - x: 12, - y: 24 - }, - knee: { - x: 0, - y: 0, - x2: 0, - y2: 0 - }, - foot: { - x: 0, - y: 0 - }, - legLength1: 55, - legLength2: 45, - transX: 0, - transY: 0, - move() { - this.pos.x = player.position.x; - this.pos.y = playerBody.position.y - this.yOff; - this.Vx = player.velocity.x; - this.Vy = player.velocity.y; - }, - transSmoothX: 0, - transSmoothY: 0, - lastGroundedPositionY: 0, - // mouseZoom: 0, - look() { - //always on mouse look - this.angle = Math.atan2( - game.mouseInGame.y - this.pos.y, - game.mouseInGame.x - this.pos.x - ); - //smoothed mouse look translations - const scale = 0.8; - this.transSmoothX = canvas.width2 - this.pos.x - (game.mouse.x - canvas.width2) * scale; - this.transSmoothY = canvas.height2 - this.pos.y - (game.mouse.y - canvas.height2) * scale; - - this.transX += (this.transSmoothX - this.transX) * 0.07; - this.transY += (this.transSmoothY - this.transY) * 0.07; - }, - doCrouch() { - if (!this.crouch) { - this.crouch = true; - this.yOffGoal = this.yOffWhen.crouch; - Matter.Body.translate(playerHead, { - x: 0, - y: 40 - }); - } - }, - undoCrouch() { - if (this.crouch) { - this.crouch = false; - this.yOffGoal = this.yOffWhen.stand; - Matter.Body.translate(playerHead, { - x: 0, - y: -40 - }); - } - }, - hardLandCD: 0, - enterAir() { - //triggered in engine.js on collision - this.onGround = false; - this.hardLandCD = 0 // disable hard landing - if (this.isHeadClear) { - if (this.crouch) { - this.undoCrouch(); - } - this.yOffGoal = this.yOffWhen.jump; - } - }, - //triggered in engine.js on collision - enterLand() { - this.onGround = true; - if (this.crouch) { - if (this.isHeadClear) { - this.undoCrouch(); - } else { - this.yOffGoal = this.yOffWhen.crouch; - } - } else { - //sets a hard land where player stays in a crouch for a bit and can't jump - //crouch is forced in keyMove() on ground section below - const momentum = player.velocity.y * player.mass //player mass is 5 so this triggers at 20 down velocity, unless the player is holding something - if (momentum > 100) { - this.doCrouch(); - this.yOff = this.yOffWhen.jump; - this.hardLandCD = mech.cycle + Math.min(momentum / 6 - 6, 40) - } else { - this.yOffGoal = this.yOffWhen.stand; - } - } - }, - buttonCD_jump: 0, //cool down for player buttons - keyMove() { - if (this.onGround) { //on ground ********************** - if (this.crouch) { - if (!(keys[83] || keys[40]) && this.isHeadClear && this.hardLandCD < mech.cycle) this.undoCrouch(); - } else if (keys[83] || keys[40] || this.hardLandCD > mech.cycle) { - this.doCrouch(); //on ground && not crouched and pressing s or down - } else if ((keys[87] || keys[38]) && this.buttonCD_jump + 20 < mech.cycle && this.yOffWhen.stand > 23) { - this.buttonCD_jump = mech.cycle; //can't jump again until 20 cycles pass - - //apply a fraction of the jump force to the body the player is jumping off of - Matter.Body.applyForce(mech.standingOn, mech.pos, { - x: 0, - y: this.jumpForce * 0.12 * Math.min(mech.standingOn.mass, 5) - }); - - player.force.y = -this.jumpForce; //player jump force - Matter.Body.setVelocity(player, { //zero player y-velocity for consistent jumps - x: player.velocity.x, - y: 0 - }); - } - - //horizontal move on ground - //apply a force to move - if (keys[65] || keys[37]) { //left / a - player.force.x -= this.Fx - if (player.velocity.x > -2) player.force.x -= this.Fx * 0.5 - } else if (keys[68] || keys[39]) { //right / d - player.force.x += this.Fx - if (player.velocity.x < 2) player.force.x += this.Fx * 0.5 - } else { - const stoppingFriction = 0.92; - Matter.Body.setVelocity(player, { - x: player.velocity.x * stoppingFriction, - y: player.velocity.y * stoppingFriction - }); - } - //come to a stop if fast or if no move key is pressed - if (player.speed > 4) { - const stoppingFriction = (this.crouch) ? 0.65 : 0.89; // this controls speed when crouched - Matter.Body.setVelocity(player, { - x: player.velocity.x * stoppingFriction, - y: player.velocity.y * stoppingFriction - }); - } - - } else { // in air ********************************** - //check for short jumps - if ( - this.buttonCD_jump + 60 > mech.cycle && //just pressed jump - !(keys[87] || keys[38]) && //but not pressing jump key - this.Vy < 0 //moving up - ) { - Matter.Body.setVelocity(player, { - //reduce player y-velocity every cycle - x: player.velocity.x, - y: player.velocity.y * 0.94 - }); - } - const limit = 125 / player.mass / player.mass - if (keys[65] || keys[37]) { - if (player.velocity.x > -limit) player.force.x -= this.FxAir; // move player left / a - } else if (keys[68] || keys[39]) { - if (player.velocity.x < limit) player.force.x += this.FxAir; //move player right / d - } - } - - //smoothly move leg height towards height goal - this.yOff = this.yOff * 0.85 + this.yOffGoal * 0.15; - }, - gamepadMove() { - if (this.onGround) { //on ground ********************** - if (this.crouch) { - if (game.gamepad.leftAxis.y !== -1 && this.isHeadClear && this.hardLandCD < mech.cycle) this.undoCrouch(); - } else if (game.gamepad.leftAxis.y === -1 || this.hardLandCD > mech.cycle) { - this.doCrouch(); //on ground && not crouched and pressing s or down - } else if (game.gamepad.jump && this.buttonCD_jump + 20 < mech.cycle && this.yOffWhen.stand > 23) { - this.buttonCD_jump = mech.cycle; //can't jump again until 20 cycles pass - - //apply a fraction of the jump force to the body the player is jumping off of - Matter.Body.applyForce(mech.standingOn, mech.pos, { - x: 0, - y: this.jumpForce * 0.12 * Math.min(mech.standingOn.mass, 5) - }); - - player.force.y = -this.jumpForce; //player jump force - Matter.Body.setVelocity(player, { //zero player y-velocity for consistent jumps - x: player.velocity.x, - y: 0 - }); - } - - //horizontal move on ground - //apply a force to move - if (game.gamepad.leftAxis.x === -1) { //left / a - player.force.x -= this.Fx - if (player.velocity.x > -2) player.force.x -= this.Fx * 0.5 - } else if (game.gamepad.leftAxis.x === 1) { //right / d - player.force.x += this.Fx - if (player.velocity.x < 2) player.force.x += this.Fx * 0.5 - } else { - const stoppingFriction = 0.92; - Matter.Body.setVelocity(player, { - x: player.velocity.x * stoppingFriction, - y: player.velocity.y * stoppingFriction - }); - } - //come to a stop if fast or if no move key is pressed - if (player.speed > 4) { - const stoppingFriction = (this.crouch) ? 0.65 : 0.89; - Matter.Body.setVelocity(player, { - x: player.velocity.x * stoppingFriction, - y: player.velocity.y * stoppingFriction - }); - } - - } else { // in air ********************************** - //check for short jumps - if ( - this.buttonCD_jump + 60 > mech.cycle && //just pressed jump - !game.gamepad.jump && //but not pressing jump key - this.Vy < 0 //moving up - ) { - Matter.Body.setVelocity(player, { - //reduce player y-velocity every cycle - x: player.velocity.x, - y: player.velocity.y * 0.94 - }); - } - const limit = 125 / player.mass / player.mass - if (game.gamepad.leftAxis.x === -1) { - if (player.velocity.x > -limit) player.force.x -= this.FxAir; // move player left / a - } else if (game.gamepad.leftAxis.x === 1) { - if (player.velocity.x < limit) player.force.x += this.FxAir; //move player right / d - } - } - - //smoothly move leg height towards height goal - this.yOff = this.yOff * 0.85 + this.yOffGoal * 0.15; - }, - alive: true, - death() { - if (b.modIsImmortal) { //if player has the immortality buff, spawn on the same level with randomized stats - //remove mods - b.mod = null - b.setModDefaults(); - b.modText(); - - function randomizeField() { - if (game.levelsCleared > 5) { - mech.fieldUpgrades[Math.floor(Math.random() * (mech.fieldUpgrades.length))].effect(); - } else { - mech.fieldUpgrades[0].effect(); - } - } - - mech.addHealth(1); - spawn.setSpawnList(); //new mob types - game.clearNow = true; //triggers a map reset - - //randomize guns - function randomizeGuns() { - b.activeGun = null; - b.inventory = []; //removes guns and ammo - for (let i = 0, len = b.guns.length; i < len; ++i) { - b.guns[i].have = false; - if (b.guns[i].ammo !== Infinity) b.guns[i].ammo = 0; - } - if (game.levelsCleared > 0) powerUps.gun.effect(); - if (game.levelsCleared > 1) powerUps.gun.effect(); - if (game.levelsCleared > 3) powerUps.gun.effect(); - if (game.levelsCleared > 6) powerUps.gun.effect(); - //randomize ammo - for (let i = 0, len = b.inventory.length; i < len; i++) { - if (b.guns[b.inventory[i]].ammo !== Infinity) { - b.guns[b.inventory[i]].ammo = Math.max(0, Math.floor(2.2 * b.guns[b.inventory[i]].ammo * (Math.random() - 0.15))) - } - } - game.makeGunHUD(); //update gun HUD - } - - game.wipe = function () { //set wipe to have trails - ctx.fillStyle = "rgba(255,255,255,0)"; - ctx.fillRect(0, 0, canvas.width, canvas.height); - } - - randomizeGuns() - for (let i = 0; i < 7; i++) { - setTimeout(function () { - randomizeGuns() - randomizeField() - game.makeTextLog(`probability amplitude will synchronize in ${7-i} seconds`, 1000); - game.wipe = function () { //set wipe to have trails - ctx.fillStyle = `rgba(255,255,255,${(i+1)*(i+1)*0.003})`; - ctx.fillRect(0, 0, canvas.width, canvas.height); - } - }, (i + 1) * 1000); - } - - setTimeout(function () { - game.wipe = function () { //set wipe to normal - ctx.clearRect(0, 0, canvas.width, canvas.height); - } - game.makeTextLog("your quantum probability has stabilized", 1000); - document.title = "n-gon: L" + (game.levelsCleared) + " " + level.levels[level.onLevel]; - }, 8000); - - } else if (this.alive) { //normal death code here - this.alive = false; - game.paused = true; - this.health = 0; - this.displayHealth(); - document.getElementById("text-log").style.opacity = 0; //fade out any active text logs - document.getElementById("fade-out").style.opacity = 1; //slowly fades out - setTimeout(function () { - game.splashReturn(); - }, 5000); - } - }, - health: 0, - // regen() { - // if (this.health < 1 && mech.cycle % 15 === 0) { - // this.addHealth(0.01); - // } - // }, - drawHealth() { - if (this.health < 1) { - ctx.fillStyle = "rgba(100, 100, 100, 0.5)"; - ctx.fillRect(this.pos.x - this.radius, this.pos.y - 50, 60, 10); - ctx.fillStyle = "#f00"; - ctx.fillRect( - this.pos.x - this.radius, - this.pos.y - 50, - 60 * this.health, - 10 - ); - } - }, - displayHealth() { - id = document.getElementById("health"); - id.style.width = Math.floor(300 * this.health) + "px"; - //css animation blink if health is low - if (this.health < 0.3) { - id.classList.add("low-health"); - } else { - id.classList.remove("low-health"); - } - }, - addHealth(heal) { - this.health += heal; - if (this.health > 1) this.health = 1; - this.displayHealth(); - }, - defaultFPSCycle: 0, //tracks when to return to normal fps - damage(dmg) { - this.health -= dmg; - if (this.health < 0) { - this.health = 0; - this.death(); - return; - } - this.displayHealth(); - document.getElementById("dmg").style.transition = "opacity 0s"; - document.getElementById("dmg").style.opacity = 0.1 + Math.min(0.6, dmg * 4); - - //drop block if holding - if (dmg > 0.07) { - this.drop(); - } - - // freeze game and display a full screen red color - if (dmg > 0.05) { - game.fpsCap = 4 //40 - Math.min(25, 100 * dmg) - game.fpsInterval = 1000 / game.fpsCap; - } else { - game.fpsCap = game.fpsCapDefault - game.fpsInterval = 1000 / game.fpsCap; - } - mech.defaultFPSCycle = mech.cycle - - const normalFPS = function () { - if (mech.defaultFPSCycle < mech.cycle) { //back to default values - game.fpsCap = game.fpsCapDefault - game.fpsInterval = 1000 / game.fpsCap; - document.getElementById("dmg").style.transition = "opacity 1s"; - document.getElementById("dmg").style.opacity = "0"; - } else { - requestAnimationFrame(normalFPS); - } - }; - requestAnimationFrame(normalFPS); - }, - damageImmune: 0, - hitMob(i, dmg) { - //prevents damage happening too quick - }, - buttonCD: 0, //cooldown for player buttons - usePowerUp(i) { - powerUp[i].effect(); - Matter.World.remove(engine.world, powerUp[i]); - powerUp.splice(i, 1); - }, - // ********************************************* - // **************** holding ******************** - // ********************************************* - closest: { - dist: 1000, - index: 0 - }, - isHolding: false, - isStealth: false, - throwCharge: 0, - fireCDcycle: 0, - fieldCDcycle: 0, - fieldMode: 0, //basic field mode before upgrades - // these values are set on reset by setHoldDefaults() - fieldMeter: 0, - fieldRegen: 0, - fieldMode: 0, - fieldFire: false, - holdingMassScale: 0, - throwChargeRate: 0, - throwChargeMax: 0, - fieldFireCD: 0, - fieldDamage: 0, - fieldShieldingScale: 0, - grabRange: 0, - fieldArc: 0, - fieldThreshold: 0, - calculateFieldThreshold() { - this.fieldThreshold = Math.cos(this.fieldArc * Math.PI) - }, - setHoldDefaults() { - this.fieldMeter = 1; - this.fieldRegen = 0.001; - this.fieldFire = false; - this.fieldCDcycle = 0; - this.isStealth = false; - player.collisionFilter.mask = 0x010011 //0x010011 is normal - this.holdingMassScale = 0.5; - this.throwChargeRate = 2; - this.throwChargeMax = 50; - this.fieldFireCD = 15; - this.fieldDamage = 0; // a value of 1.0 kills a small mob in 2-3 hits on level 1 - this.fieldShieldingScale = 1; //scale energy loss after collision with mob - this.grabRange = 175; - this.fieldArc = 0.2; - this.calculateFieldThreshold(); - this.jumpForce = 0.38; - this.Fx = 0.015; //run Force on ground - this.FxAir = 0.015; //run Force in Air - this.gravity = 0.0019; - mech.isBodiesAsleep = true; - mech.wakeCheck(); - // this.phaseBlocks(0x011111) - }, - drawFieldMeter(range = 60) { - if (this.fieldMeter < 1) { - mech.fieldMeter += mech.fieldRegen; - ctx.fillStyle = "rgba(0, 0, 0, 0.4)"; - ctx.fillRect(this.pos.x - this.radius, this.pos.y - 50, range, 10); - ctx.fillStyle = "rgb(50,220,255)"; - ctx.fillRect(this.pos.x - this.radius, this.pos.y - 50, range * this.fieldMeter, 10); - } else { - mech.fieldMeter = 1 - } - }, - lookingAt(who) { - //calculate a vector from body to player and make it length 1 - const diff = Matter.Vector.normalise(Matter.Vector.sub(who.position, mech.pos)); - //make a vector for the player's direction of length 1 - const dir = { - x: Math.cos(mech.angle), - y: Math.sin(mech.angle) - }; - //the dot product of diff and dir will return how much over lap between the vectors - // console.log(Matter.Vector.dot(dir, diff)) - if (Matter.Vector.dot(dir, diff) > this.fieldThreshold) { - return true; - } - return false; - }, - drop() { - if (this.isHolding) { - this.isHolding = false; - this.definePlayerMass() - this.holdingTarget.collisionFilter.category = 0x010000; - this.holdingTarget.collisionFilter.mask = 0x011111; - this.holdingTarget = null; - this.throwCharge = 0; - } - }, - drawHold(target, stroke = true) { - const eye = 15; - const len = target.vertices.length - 1; - ctx.fillStyle = "rgba(110,170,200," + (0.2 + 0.4 * Math.random()) + ")"; - ctx.lineWidth = 1; - ctx.strokeStyle = "#000"; - ctx.beginPath(); - ctx.moveTo( - mech.pos.x + eye * Math.cos(this.angle), - mech.pos.y + eye * Math.sin(this.angle) - ); - ctx.lineTo(target.vertices[len].x, target.vertices[len].y); - ctx.lineTo(target.vertices[0].x, target.vertices[0].y); - ctx.fill(); - if (stroke) ctx.stroke(); - for (let i = 0; i < len; i++) { - ctx.beginPath(); - ctx.moveTo( - mech.pos.x + eye * Math.cos(this.angle), - mech.pos.y + eye * Math.sin(this.angle) - ); - ctx.lineTo(target.vertices[i].x, target.vertices[i].y); - ctx.lineTo(target.vertices[i + 1].x, target.vertices[i + 1].y); - ctx.fill(); - if (stroke) ctx.stroke(); - } - }, - holding() { - this.fieldMeter -= this.fieldRegen; - if (this.fieldMeter < 0) this.fieldMeter = 0; - Matter.Body.setPosition(this.holdingTarget, { - x: mech.pos.x + 70 * Math.cos(this.angle), - y: mech.pos.y + 70 * Math.sin(this.angle) - }); - Matter.Body.setVelocity(this.holdingTarget, player.velocity); - Matter.Body.rotate(this.holdingTarget, 0.01 / this.holdingTarget.mass); //gently spin the block - }, - throw () { - if ((keys[32] || game.mouseDownRight)) { - if (this.fieldMeter > 0.002) { - this.fieldMeter -= 0.002; - this.throwCharge += this.throwChargeRate;; - //draw charge - const x = mech.pos.x + 15 * Math.cos(this.angle); - const y = mech.pos.y + 15 * Math.sin(this.angle); - const len = this.holdingTarget.vertices.length - 1; - const edge = this.throwCharge * this.throwCharge * 0.02; - const grd = ctx.createRadialGradient(x, y, edge, x, y, edge + 5); - grd.addColorStop(0, "rgba(255,50,150,0.3)"); - grd.addColorStop(1, "transparent"); - ctx.fillStyle = grd; - ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(this.holdingTarget.vertices[len].x, this.holdingTarget.vertices[len].y); - ctx.lineTo(this.holdingTarget.vertices[0].x, this.holdingTarget.vertices[0].y); - ctx.fill(); - for (let i = 0; i < len; i++) { - ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(this.holdingTarget.vertices[i].x, this.holdingTarget.vertices[i].y); - ctx.lineTo(this.holdingTarget.vertices[i + 1].x, this.holdingTarget.vertices[i + 1].y); - ctx.fill(); - } - } else { - this.drop() - } - } else if (this.throwCharge > 0) { - //throw the body - this.fireCDcycle = mech.cycle + this.fieldFireCD; - this.isHolding = false; - //bullet-like collisions - this.holdingTarget.collisionFilter.category = 0x000100; - this.holdingTarget.collisionFilter.mask = 0x110111; - //check every second to see if player is away from thrown body, and make solid - const solid = function (that) { - const dx = that.position.x - player.position.x; - const dy = that.position.y - player.position.y; - if (dx * dx + dy * dy > 10000 && that.speed < 3 && that !== mech.holdingTarget) { - that.collisionFilter.category = 0x010000; //make solid - that.collisionFilter.mask = 0x011111; - } else { - setTimeout(solid, 50, that); - } - }; - setTimeout(solid, 400, this.holdingTarget); - //throw speed scales a bit with mass - const speed = Math.min(85, Math.min(54 / this.holdingTarget.mass + 5, 48) * Math.min(this.throwCharge, this.throwChargeMax) / 50); - - this.throwCharge = 0; - Matter.Body.setVelocity(this.holdingTarget, { - x: player.velocity.x + Math.cos(this.angle) * speed, - y: player.velocity.y + Math.sin(this.angle) * speed - }); - //player recoil //stronger in x-dir to prevent jump hacking - Matter.Body.setVelocity(player, { - x: player.velocity.x - Math.cos(this.angle) * speed / 20 * Math.sqrt(this.holdingTarget.mass), - y: player.velocity.y - Math.sin(this.angle) * speed / 80 * Math.sqrt(this.holdingTarget.mass) - }); - this.definePlayerMass() //return to normal player mass - } - }, - drawField() { - //draw field - const range = this.grabRange - 20; - ctx.beginPath(); - ctx.arc(this.pos.x, this.pos.y, range, this.angle - Math.PI * this.fieldArc, this.angle + Math.PI * this.fieldArc, false); - let eye = 13; - ctx.lineTo(mech.pos.x + eye * Math.cos(this.angle), mech.pos.y + eye * Math.sin(this.angle)); - if (this.holdingTarget) { - ctx.fillStyle = "rgba(110,170,200," + (0.05 + 0.1 * Math.random()) + ")"; - } else { - ctx.fillStyle = "rgba(110,170,200," + (0.15 + 0.15 * Math.random()) + ")"; - } - ctx.fill(); - //draw random lines in field for cool effect - let offAngle = this.angle + 2 * Math.PI * this.fieldArc * (Math.random() - 0.5); - ctx.beginPath(); - eye = 15; - ctx.moveTo(mech.pos.x + eye * Math.cos(this.angle), mech.pos.y + eye * Math.sin(this.angle)); - ctx.lineTo(this.pos.x + range * Math.cos(offAngle), this.pos.y + range * Math.sin(offAngle)); - ctx.strokeStyle = "rgba(120,170,255,0.4)"; - ctx.lineWidth = 1; - ctx.stroke(); - }, - grabPowerUp() { - //look for power ups to grab - if (mech.fieldCDcycle < mech.cycle) { - const grabPowerUpRange2 = (this.grabRange + 220) * (this.grabRange + 220) - for (let i = 0, len = powerUp.length; i < len; ++i) { - const dxP = mech.pos.x - powerUp[i].position.x; - const dyP = mech.pos.y - powerUp[i].position.y; - const dist2 = dxP * dxP + dyP * dyP; - // float towards player if looking at and in range or if very close to player - if (dist2 < grabPowerUpRange2 && this.lookingAt(powerUp[i]) || dist2 < 16000) { - if (dist2 < 5000) { //use power up if it is close enough - Matter.Body.setVelocity(player, { //player knock back, after grabbing power up - x: player.velocity.x + ((powerUp[i].velocity.x * powerUp[i].mass) / player.mass) * 0.3, - y: player.velocity.y + ((powerUp[i].velocity.y * powerUp[i].mass) / player.mass) * 0.3 - }); - mech.usePowerUp(i); - return; - } - this.fieldMeter -= this.fieldRegen * 0.5; - powerUp[i].force.x += 7 * (dxP / dist2) * powerUp[i].mass; - powerUp[i].force.y += 7 * (dyP / dist2) * powerUp[i].mass - powerUp[i].mass * game.g; //negate gravity - //extra friction - Matter.Body.setVelocity(powerUp[i], { - x: powerUp[i].velocity.x * 0.11, - y: powerUp[i].velocity.y * 0.11 - }); - } - } - } - }, - pushMobs() { - // push all mobs in range - for (let i = 0, len = mob.length; i < len; ++i) { - if (this.lookingAt(mob[i]) && Matter.Vector.magnitude(Matter.Vector.sub(mob[i].position, this.pos)) < this.grabRange && Matter.Query.ray(map, mob[i].position, this.pos).length === 0) { - const fieldBlockCost = Math.max(0.02, mob[i].mass * 0.012) //0.012 - if (this.fieldMeter > fieldBlockCost) { - this.fieldMeter -= fieldBlockCost * this.fieldShieldingScale; - if (this.fieldMeter < 0) this.fieldMeter = 0; - if (this.fieldDamage) mob[i].damage(b.dmgScale * this.fieldDamage); - mob[i].locatePlayer(); - this.drawHold(mob[i]); - //mob and player knock back - const angle = Math.atan2(player.position.y - mob[i].position.y, player.position.x - mob[i].position.x); - const mass = Math.min(Math.sqrt(mob[i].mass), 4); - Matter.Body.setVelocity(mob[i], { - x: player.velocity.x - (15 * Math.cos(angle)) / mass, - y: player.velocity.y - (15 * Math.sin(angle)) / mass - }); - Matter.Body.setVelocity(player, { - x: player.velocity.x + 5 * Math.cos(angle) * mass, - y: player.velocity.y + 5 * Math.sin(angle) * mass - }); - } - } - } - }, - pushMobs360(range = this.grabRange * 0.75) { - // push all mobs in range - for (let i = 0, len = mob.length; i < len; ++i) { - if (Matter.Vector.magnitude(Matter.Vector.sub(mob[i].position, this.pos)) < range && Matter.Query.ray(map, mob[i].position, this.pos).length === 0) { - const fieldBlockCost = Math.max(0.02, mob[i].mass * 0.012) - if (this.fieldMeter > fieldBlockCost) { - this.fieldMeter -= fieldBlockCost * this.fieldShieldingScale; - if (this.fieldMeter < 0) this.fieldMeter = 0 - - if (this.fieldDamage) mob[i].damage(b.dmgScale * this.fieldDamage); - mob[i].locatePlayer(); - this.drawHold(mob[i]); - //mob and player knock back - const angle = Math.atan2(player.position.y - mob[i].position.y, player.position.x - mob[i].position.x); - const mass = Math.min(Math.sqrt(mob[i].mass), 4); - // console.log(mob[i].mass, Math.sqrt(mob[i].mass), mass) - Matter.Body.setVelocity(mob[i], { - x: player.velocity.x - (15 * Math.cos(angle)) / mass, - y: player.velocity.y - (15 * Math.sin(angle)) / mass - }); - Matter.Body.setVelocity(player, { - x: player.velocity.x + 5 * Math.cos(angle) * mass, - y: player.velocity.y + 5 * Math.sin(angle) * mass - }); - } - } - } - }, - lookForPickUp(range = this.grabRange) { //find body to pickup - this.fieldMeter -= this.fieldRegen; - const grabbing = { - targetIndex: null, - targetRange: range, - // lookingAt: false //false to pick up object in range, but not looking at - }; - for (let i = 0, len = body.length; i < len; ++i) { - if (Matter.Query.ray(map, body[i].position, this.pos).length === 0) { - //is this next body a better target then my current best - const dist = Matter.Vector.magnitude(Matter.Vector.sub(body[i].position, this.pos)); - const looking = this.lookingAt(body[i]); - // if (dist < grabbing.targetRange && (looking || !grabbing.lookingAt) && !body[i].isNotHoldable) { - if (dist < grabbing.targetRange && looking && !body[i].isNotHoldable) { - grabbing.targetRange = dist; - grabbing.targetIndex = i; - // grabbing.lookingAt = looking; - } - } - } - // set pick up target for when mouse is released - if (body[grabbing.targetIndex]) { - this.holdingTarget = body[grabbing.targetIndex]; - // - ctx.beginPath(); //draw on each valid body - let vertices = this.holdingTarget.vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1; j < vertices.length; j += 1) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = "rgba(190,215,230," + (0.3 + 0.7 * Math.random()) + ")"; - ctx.fill(); - - ctx.globalAlpha = 0.2; - this.drawHold(this.holdingTarget); - ctx.globalAlpha = 1; - } else { - this.holdingTarget = null; - } - }, - pickUp() { - //triggers when a hold target exits and field button is released - this.isHolding = true; - this.definePlayerMass(5 + this.holdingTarget.mass * this.holdingMassScale) - //collide with nothing - this.holdingTarget.collisionFilter.category = 0x000000; - this.holdingTarget.collisionFilter.mask = 0x000000; - // if (this.holdingTarget) { - // this.holdingTarget.collisionFilter.category = 0x010000; - // this.holdingTarget.collisionFilter.mask = 0x011111; - // } - // combine momentum // this doesn't feel right in game - // const px = player.velocity.x * player.mass + this.holdingTarget.velocity.x * this.holdingTarget.mass; - // const py = player.velocity.y * player.mass + this.holdingTarget.velocity.y * this.holdingTarget.mass; - // Matter.Body.setVelocity(player, { - // x: px / (player.mass + this.holdingTarget.mass), - // y: py / (player.mass + this.holdingTarget.mass) - // }); - }, - wakeCheck() { - if (mech.isBodiesAsleep) { - mech.isBodiesAsleep = false; - - function wake(who) { - for (let i = 0, len = who.length; i < len; ++i) { - Matter.Sleeping.set(who[i], false) - if (who[i].storeVelocity) { - Matter.Body.setVelocity(who[i], { - x: who[i].storeVelocity.x, - y: who[i].storeVelocity.y - }) - Matter.Body.setAngularVelocity(who[i], who[i].storeAngularVelocity) - } - } - } - wake(mob); - wake(body); - wake(bullet); - for (let i = 0, len = cons.length; i < len; i++) { - if (cons[i].stiffness === 0) { - cons[i].stiffness = cons[i].storeStiffness - } - } - // wake(powerUp); - } - }, - hold() {}, - fieldText() { - game.makeTextLog(`${mech.fieldUpgrades[mech.fieldMode].name}
(right click or space bar)

${mech.fieldUpgrades[mech.fieldMode].description}

`, 1200); - game.updateModHUD() - }, - fieldUpgrades: [{ - name: "Field Emitter", - description: "lets you pick up and throw objects
shields you from damage", - effect: () => { - mech.fieldMode = 0; - mech.fieldText(); - // game.makeTextLog("
(right click or space bar)

", 1200); - mech.setHoldDefaults(); - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed - mech.drawField(); - mech.grabPowerUp(); - mech.pushMobs(); - mech.lookForPickUp(); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - } - } - }, - { - name: "Time Dilation Field", - description: "stop time while field is active
can fire while field is active", - effect: () => { - mech.fieldMode = 1; - mech.fieldText(); - mech.setHoldDefaults(); - mech.fieldFire = true; - mech.grabRange = 130 - mech.isBodiesAsleep = false; - mech.hold = function () { - if (mech.isHolding) { - mech.wakeCheck(); - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { - const DRAIN = 0.0027 - if (mech.fieldMeter > DRAIN) { - mech.fieldMeter -= DRAIN; - - //draw field everywhere - ctx.fillStyle = "rgba(110,170,200," + (0.19 + 0.16 * Math.random()) + ")"; - ctx.fillRect(-100000, -100000, 200000, 200000) - - //stop time - mech.isBodiesAsleep = true; - - function sleep(who) { - for (let i = 0, len = who.length; i < len; ++i) { - if (!who[i].isSleeping) { - who[i].storeVelocity = who[i].velocity - who[i].storeAngularVelocity = who[i].angularVelocity - } - Matter.Sleeping.set(who[i], true) - } - } - sleep(mob); - sleep(body); - sleep(bullet); - //doesn't really work, just slows down constraints - for (let i = 0, len = cons.length; i < len; i++) { - if (cons[i].stiffness !== 0) { - cons[i].storeStiffness = cons[i].stiffness; - cons[i].stiffness = 0; - } - } - game.cycle--; //pause all functions that depend on game cycle increasing - - mech.grabPowerUp(); - mech.lookForPickUp(180); - } else { - mech.wakeCheck(); - mech.fieldCDcycle = mech.cycle + 120; - } - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.wakeCheck(); - mech.pickUp(); - } else { - mech.wakeCheck(); - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - if (mech.fieldMode !== 1) { - //wake up if this is no longer the current field mode, like after a new power up - mech.wakeCheck(); - - } - } - } - }, - { - name: "Electrostatic Field", - description: "field does damage on contact
blocks are thrown at a higher velocity
increased field regeneration", - effect: () => { - mech.fieldMode = 2; - mech.fieldText(); - mech.setHoldDefaults(); - //throw quicker and harder - mech.grabRange = 225; - mech.fieldShieldingScale = 2; - mech.fieldRegen *= 2; - mech.throwChargeRate = 3; - mech.throwChargeMax = 140; - mech.fieldDamage = 5; //passive field does extra damage - // mech.fieldArc = 0.11 - // mech.calculateFieldThreshold(); //run after setting fieldArc, used for powerUp grab and mobPush with lookingAt(mob) - - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldMeter > 0.15) { //not hold but field button is pressed - //draw electricity - const Dx = Math.cos(mech.angle); - const Dy = Math.sin(mech.angle); - let x = mech.pos.x + 20 * Dx; - let y = mech.pos.y + 20 * Dy; - ctx.beginPath(); - ctx.moveTo(x, y); - for (let i = 0; i < 8; i++) { - x += 18 * (Dx + 2 * (Math.random() - 0.5)) - y += 18 * (Dy + 2 * (Math.random() - 0.5)) - ctx.lineTo(x, y); - } - ctx.lineWidth = 1 //0.5 + 2 * Math.random(); - ctx.strokeStyle = `rgba(100,20,50,${0.5+0.5*Math.random()})`; - ctx.stroke(); - - //draw field - const range = 170; - const arc = Math.PI * 0.11 - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, range, mech.angle - arc, mech.angle + arc, false); - ctx.lineTo(mech.pos.x + 13 * Math.cos(mech.angle), mech.pos.y + 13 * Math.sin(mech.angle)); - if (mech.holdingTarget) { - ctx.fillStyle = "rgba(255,50,150," + (0.05 + 0.1 * Math.random()) + ")"; - } else { - ctx.fillStyle = "rgba(255,50,150," + (0.13 + 0.18 * Math.random()) + ")"; - } - ctx.fill(); - - //draw random lines in field for cool effect - // eye = 15; - // ctx.beginPath(); - // ctx.moveTo(mech.pos.x + eye * Math.cos(mech.angle), mech.pos.y + eye * Math.sin(mech.angle)); - // const offAngle = mech.angle + 2 * Math.PI * mech.fieldArc * (Math.random() - 0.5); - // ctx.lineTo(mech.pos.x + range * Math.cos(offAngle), mech.pos.y + range * Math.sin(offAngle)); - // ctx.strokeStyle = "rgba(100,20,50,0.2)"; - // ctx.stroke(); - - mech.grabPowerUp(); - mech.pushMobs(); - mech.lookForPickUp(); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - } - } - }, - { - name: "Negative Mass Field", - description: "field nullifies gravity
player can hold more massive objects
can fire while field is active", - effect: () => { - mech.fieldMode = 3; - mech.fieldText(); - //
decreased field shielding efficiency - mech.setHoldDefaults(); - mech.fieldFire = true; - mech.holdingMassScale = 0.05; //can hold heavier blocks with lower cost to jumping - mech.fieldShieldingScale = 2; - - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { //push away - const DRAIN = 0.0006 - if (mech.fieldMeter > DRAIN) { - mech.pushMobs360(170); - mech.grabPowerUp(); - mech.lookForPickUp(170); - //look for nearby objects to make zero-g - function zeroG(who) { - for (let i = 0, len = who.length; i < len; ++i) { - sub = Matter.Vector.sub(who[i].position, mech.pos); - dist = Matter.Vector.magnitude(sub); - if (dist < mech.grabRange) { - who[i].force.y -= who[i].mass * (game.g * 1.06); //add a bit more then standard gravity - } - } - } - zeroG(powerUp); - zeroG(body); - // zeroG(bullet); //works fine, but not that noticeable and maybe not worth the possible performance hit - // zeroG(mob); //mobs are too irregular to make this work? - - Matter.Body.setVelocity(player, { - x: player.velocity.x, - y: player.velocity.y * 0.97 - }); - - if (keys[83] || keys[40]) { //down - player.force.y -= 0.8 * player.mass * mech.gravity; - mech.grabRange = mech.grabRange * 0.97 + 400 * 0.03; - } else if (keys[87] || keys[38]) { //up - mech.fieldMeter -= 3 * DRAIN; - mech.grabRange = mech.grabRange * 0.97 + 750 * 0.03; - player.force.y -= 1.2 * player.mass * mech.gravity; - } else { - mech.fieldMeter -= DRAIN; - mech.grabRange = mech.grabRange * 0.97 + 650 * 0.03; - player.force.y -= 1.07 * player.mass * mech.gravity; // slow upward drift - } - - //add extra friction for horizontal motion - if (keys[65] || keys[68] || keys[37] || keys[39]) { - Matter.Body.setVelocity(player, { - x: player.velocity.x * 0.85, - y: player.velocity.y - }); - } - - //draw zero-G range - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, mech.grabRange, 0, 2 * Math.PI); - ctx.fillStyle = "#f5f5ff"; - ctx.globalCompositeOperation = "difference"; - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; - } else { - //trigger cool down - mech.fieldCDcycle = mech.cycle + 120; - } - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - mech.grabRange = 0 - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - mech.grabRange = 0 - } - mech.drawFieldMeter() - } - } - }, - { - name: "Standing Wave Harmonics", - description: "oscillating shields always surround player
decreased field regeneration", - effect: () => { - mech.fieldMode = 4; - mech.fieldText(); - mech.setHoldDefaults(); - // mech.fieldShieldingScale = 0.5; - mech.fieldRegen *= 0.2; - - mech.hold = function () { - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed - mech.grabPowerUp(); - mech.lookForPickUp(180); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - if (mech.fieldMeter > 0.1) { - const grabRange1 = 90 + 60 * Math.sin(mech.cycle / 23) - const grabRange2 = 85 + 70 * Math.sin(mech.cycle / 37) - const grabRange3 = 80 + 80 * Math.sin(mech.cycle / 47) - const netGrabRange = Math.max(grabRange1, grabRange2, grabRange3) - ctx.fillStyle = "rgba(110,170,200," + (0.15 + 0.15 * Math.random()) + ")"; - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, grabRange1, 0, 2 * Math.PI); - ctx.fill(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, grabRange2, 0, 2 * Math.PI); - ctx.fill(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, grabRange3, 0, 2 * Math.PI); - ctx.fill(); - mech.pushMobs360(netGrabRange); - } - mech.drawFieldMeter() - } - } - }, - { - name: "Nano-Scale Manufacturing", - description: "excess field energy used to build drones
increased field regeneration", - effect: () => { - mech.fieldMode = 5; - mech.fieldText(); - mech.setHoldDefaults(); - mech.fieldRegen *= 3.5; - mech.hold = function () { - if (mech.fieldMeter === 1) { - mech.fieldMeter -= 0.5; - b.guns[12].fire() //spawn drone - } - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight && mech.fieldMeter > 0.1)) { //not hold but field button is pressed - mech.pushMobs(); - mech.drawField(); - mech.grabPowerUp(); - mech.lookForPickUp(); - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - } - } - }, - { - name: "Phase Decoherence Field", - description: "intangible while field is active
can't see or be seen outside field", - effect: () => { - mech.fieldMode = 6; - mech.fieldText(); - mech.setHoldDefaults(); - // mech.grabRange = 230 - mech.hold = function () { - mech.isStealth = false //isStealth is checked in mob foundPlayer() - player.collisionFilter.mask = 0x010011 //0x010011 is normal - if (mech.isHolding) { - mech.drawHold(mech.holdingTarget); - mech.holding(); - mech.throw(); - } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { - const DRAIN = 0.002 - if (mech.fieldMeter > DRAIN) { - mech.fieldMeter -= DRAIN; - - mech.isStealth = true //isStealth is checked in mob foundPlayer() - player.collisionFilter.mask = 0x000001 //0x010011 is normals - - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, mech.grabRange, 0, 2 * Math.PI); - ctx.globalCompositeOperation = "destination-in"; //in or atop - ctx.fillStyle = "rgba(255,255,255,0.25)"; - ctx.fill(); - ctx.globalCompositeOperation = "source-over"; - ctx.strokeStyle = "#000" - ctx.lineWidth = 2; - ctx.stroke(); - - mech.grabPowerUp(); - mech.lookForPickUp(110); - } else { - mech.fieldCDcycle = mech.cycle + 120; - } - } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - mech.pickUp(); - } else { - mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - } - mech.drawFieldMeter() - } - } - }, - // () => { - // mech.fieldMode = 7; - // game.makeTextLog("Thermal Radiation Field
(right click or space bar)

field grows while active
damages all targets within range, including player
decreased field shielding efficiency

", 1200); - // mech.setHoldDefaults(); - // mech.fieldShieldingScale = 10; - // mech.rangeSmoothing = 0 - // mech.hold = function () { - // if (mech.isHolding) { - // mech.drawHold(mech.holdingTarget); - // mech.holding(); - // mech.throw(); - // } else if ((keys[32] || game.mouseDownRight && mech.fieldCDcycle < mech.cycle)) { //not hold but field button is pressed - // mech.grabPowerUp(); - // mech.lookForPickUp(Math.max(180, mech.grabRange)); - // mech.pushMobs360(140); - - // if (mech.health > 0.1) { - // const DRAIN = 0.0008 - // if (mech.fieldMeter > DRAIN) { - // mech.fieldMeter -= DRAIN; - // mech.damage(0.00005 + 0.00000012 * mech.grabRange) - // //draw damage field - // mech.grabRange = mech.grabRange * 0.997 + (1350 + 150 * Math.cos(mech.cycle / 30)) * 0.003 - // let gradient = ctx.createRadialGradient(this.pos.x, this.pos.y, 0, this.pos.x, this.pos.y, mech.grabRange); - // gradient.addColorStop(0, 'rgba(255,255,255,0.7)'); - // gradient.addColorStop(1, 'rgba(255,0,50,' + (0.6 + 0.2 * Math.random()) + ')'); - - // const angleOff = 2 * Math.PI * Math.random() - // ctx.beginPath(); - // ctx.arc(this.pos.x, this.pos.y, mech.grabRange + Math.sqrt(mech.grabRange) * 0.7 * (Math.random() - 0.5), angleOff, 1.8 * Math.PI + angleOff); - // ctx.fillStyle = gradient //rgba(255,0,0,0.2) - // ctx.fill(); - - // //damage and push away mobs in range - // for (let i = 0, len = mob.length; i < len; ++i) { - // if (mob[i].alive) { - // sub = Matter.Vector.sub(this.pos, mob[i].position); - // dist = Matter.Vector.magnitude(sub); - // if (dist < mech.grabRange) { - // mob[i].damage(0.01); - // mob[i].locatePlayer(); - // mob[i].force = Matter.Vector.mult(Matter.Vector.normalise(sub), -0.0001 * mob[i].mass) //gently push mobs back - // } - // } - // } - // } else { - // mech.fieldCDcycle = mech.cycle + 120; - // } - // } else { - // mech.grabRange = 180; - // mech.drawField(); - // mech.grabPowerUp(); - // mech.lookForPickUp(); - // } - // } else if (mech.holdingTarget && mech.fireCDcycle < mech.cycle && mech.fieldMeter > 0.05) { //holding, but field button is released - // mech.grabRange = 0 - // mech.pickUp(); - // } else { - // mech.grabRange = 0 - // mech.holdingTarget = null; //clears holding target (this is so you only pick up right after the field button is released and a hold target exists) - // } - // mech.drawFieldMeter() - // } - // }, - ], - drawLeg(stroke) { - // if (game.mouseInGame.x > this.pos.x) { - if (mech.angle > -Math.PI / 2 && mech.angle < Math.PI / 2) { - this.flipLegs = 1; - } else { - this.flipLegs = -1; - } - ctx.save(); - ctx.scale(this.flipLegs, 1); //leg lines - ctx.beginPath(); - ctx.moveTo(this.hip.x, this.hip.y); - ctx.lineTo(this.knee.x, this.knee.y); - ctx.lineTo(this.foot.x, this.foot.y); - ctx.strokeStyle = stroke; - ctx.lineWidth = 7; - ctx.stroke(); - - //toe lines - ctx.beginPath(); - ctx.moveTo(this.foot.x, this.foot.y); - ctx.lineTo(this.foot.x - 15, this.foot.y + 5); - ctx.moveTo(this.foot.x, this.foot.y); - ctx.lineTo(this.foot.x + 15, this.foot.y + 5); - ctx.lineWidth = 4; - ctx.stroke(); - - //hip joint - ctx.beginPath(); - ctx.arc(this.hip.x, this.hip.y, 11, 0, 2 * Math.PI); - //knee joint - ctx.moveTo(this.knee.x + 7, this.knee.y); - ctx.arc(this.knee.x, this.knee.y, 7, 0, 2 * Math.PI); - //foot joint - ctx.moveTo(this.foot.x + 6, this.foot.y); - ctx.arc(this.foot.x, this.foot.y, 6, 0, 2 * Math.PI); - ctx.fillStyle = this.fillColor; - ctx.fill(); - ctx.lineWidth = 2; - ctx.stroke(); - ctx.restore(); - }, - calcLeg(cycle_offset, offset) { - this.hip.x = 12 + offset; - this.hip.y = 24 + offset; - //stepSize goes to zero if Vx is zero or not on ground (make this transition cleaner) - this.stepSize = 0.8 * this.stepSize + 0.2 * (7 * Math.sqrt(Math.min(9, Math.abs(this.Vx))) * this.onGround); - //changes to stepsize are smoothed by adding only a percent of the new value each cycle - const stepAngle = 0.034 * this.walk_cycle + cycle_offset; - this.foot.x = 2.2 * this.stepSize * Math.cos(stepAngle) + offset; - this.foot.y = offset + 1.2 * this.stepSize * Math.sin(stepAngle) + this.yOff + this.height; - const Ymax = this.yOff + this.height; - if (this.foot.y > Ymax) this.foot.y = Ymax; - - //calculate knee position as intersection of circle from hip and foot - const d = Math.sqrt((this.hip.x - this.foot.x) * (this.hip.x - this.foot.x) + (this.hip.y - this.foot.y) * (this.hip.y - this.foot.y)); - const l = (this.legLength1 * this.legLength1 - this.legLength2 * this.legLength2 + d * d) / (2 * d); - const h = Math.sqrt(this.legLength1 * this.legLength1 - l * l); - this.knee.x = (l / d) * (this.foot.x - this.hip.x) - (h / d) * (this.foot.y - this.hip.y) + this.hip.x + offset; - this.knee.y = (l / d) * (this.foot.y - this.hip.y) + (h / d) * (this.foot.x - this.hip.x) + this.hip.y; - }, - draw() { - ctx.fillStyle = this.fillColor; - this.walk_cycle += this.flipLegs * this.Vx; - - //draw body - ctx.save(); - ctx.translate(this.pos.x, this.pos.y); - this.calcLeg(Math.PI, -3); - this.drawLeg("#4a4a4a"); - this.calcLeg(0, 0); - this.drawLeg("#333"); - ctx.rotate(this.angle); - - ctx.beginPath(); - ctx.arc(0, 0, 30, 0, 2 * Math.PI); - let grd = ctx.createLinearGradient(-30, 0, 30, 0); - grd.addColorStop(0, this.fillColorDark); - grd.addColorStop(1, this.fillColor); - ctx.fillStyle = grd; - ctx.fill(); - ctx.arc(15, 0, 4, 0, 2 * Math.PI); - ctx.strokeStyle = "#333"; - ctx.lineWidth = 2; - ctx.stroke(); - // ctx.beginPath(); - // ctx.arc(15, 0, 3, 0, 2 * Math.PI); - // ctx.fillStyle = '#9cf' //'#0cf'; - // ctx.fill() - ctx.restore(); - } -}; \ No newline at end of file diff --git a/js/powerups.js b/js/powerups.js deleted file mode 100644 index 6100163..0000000 --- a/js/powerups.js +++ /dev/null @@ -1,233 +0,0 @@ -let powerUp = []; - -const powerUps = { - heal: { - name: "heal", - color: "#0f9", - size() { - return 40 * Math.sqrt(0.1 + Math.random() * 0.5); - }, - effect() { - let heal = (this.size / 40) ** 2 - heal = Math.min(1 - mech.health, heal) - mech.addHealth(heal); - if (!game.lastLogTime && heal > 0) game.makeTextLog('heal for ' + (heal * 100).toFixed(0) + '%', 180) - } - }, - field: { - name: "field", - color: "#f9f", - size() { - return 40; - }, - effect() { - const previousMode = mech.fieldMode - - if (!this.mode) { //this.mode is set if the power up has been ejected from player - mode = mech.fieldMode - while (mode === mech.fieldMode) { - mode = Math.ceil(Math.random() * (mech.fieldUpgrades.length - 1)) - } - mech.fieldUpgrades[mode].effect(); //choose random field upgrade that you don't already have - } else { - mech.fieldUpgrades[this.mode].effect(); //set a predetermined power up - } - //pop the old field out in case player wants to swap back - if (previousMode !== 0) { - mech.fieldCDcycle = mech.cycle + 40; //trigger fieldCD to stop power up grab automatic pick up of spawn - powerUps.spawn(mech.pos.x, mech.pos.y - 15, "field", false, previousMode); - } - } - }, - mod: { - name: "mod", - color: "#479", - size() { - return 42; - }, - effect() { - const previousMode = b.mod - if (this.mode === null) { //this.mode is set if the power up has been ejected from player - mode = b.mod //start with current mob - while (mode === b.mod) { - mode = Math.floor(Math.random() * b.mods.length) - } - b.mods[mode].effect(); //choose random upgrade that you don't already have - } else { - b.mods[this.mode].effect(); //set a predetermined power up - } - if (previousMode != null) { //pop the old field out in case player wants to swap back - mech.fieldCDcycle = mech.cycle + 40; //trigger fieldCD to stop power up grab automatic pick up of spawn - powerUps.spawn(mech.pos.x, mech.pos.y - 15, "mod", false, previousMode); - } - } - }, - ammo: { - name: "ammo", - color: "#467", - size() { - return 17; - }, - effect() { - //only get ammo for guns player has - let target; - // console.log(b.inventory.length) - if (b.inventory.length > 0) { - //add ammo to a gun in inventory - target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]]; - //try 3 more times to give ammo to a gun with ammo, not Infinity - if (target.ammo === Infinity) { - target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]] - if (target.ammo === Infinity) { - target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]] - if (target.ammo === Infinity) target = b.guns[b.inventory[Math.floor(Math.random() * (b.inventory.length))]] - } - } - } else { - //if you don't have any guns just add ammo to a random gun you don't have yet - target = b.guns[Math.floor(Math.random() * b.guns.length)]; - } - if (target.ammo === Infinity) { - mech.fieldMeter = 1; - if (!game.lastLogTime) game.makeTextLog("+energy", 180); - } else { - //ammo given scales as mobs take more hits to kill - const ammo = Math.ceil((target.ammoPack * (0.5 + 0.04 * Math.random())) / b.dmgScale); - target.ammo += ammo; - game.updateGunHUD(); - if (!game.lastLogTime) game.makeTextLog("+" + ammo + " ammo: " + target.name, 180); - } - } - }, - gun: { - name: "gun", - color: "#0bf", - size() { - return 30; - }, - effect() { - //find what guns I don't have - let options = []; - if (b.activeGun === null) { //the first gun is good for the early game - options = [0, 1, 2, 3, 4, 5, 6, 8, 9, 12] - } else { - for (let i = 0; i < b.guns.length; ++i) { - if (!b.guns[i].have) options.push(i); - } - } - //give player a gun they don't already have if possible - if (options.length > 0) { - let newGun = options[Math.floor(Math.random() * options.length)]; - // newGun = 4; //makes every gun you pick up this type //enable for testing one gun - if (b.activeGun === null) { - b.activeGun = newGun //if no active gun switch to new gun - game.makeTextLog( - // "



left mouse: fire weapon
", - "Use left mouse to fire weapon.", - Infinity - ); - } - if (b.inventory.length === 1) { //on the second gun pick up tell player how to change guns - game.makeTextLog(`(Q, E, and mouse wheel change weapons)

${b.guns[newGun].name}
(left click)

${b.guns[newGun].description}

`, 1000); - } else { - game.makeTextLog(`${b.guns[newGun].name}
(left click)

${b.guns[newGun].description}

`, 1000); - } - b.guns[newGun].have = true; - b.inventory.push(newGun); - b.guns[newGun].ammo += b.guns[newGun].ammoPack * 2; - game.makeGunHUD(); - } else { - //if you have all guns then get ammo - const ammoTarget = Math.floor(Math.random() * (b.guns.length)); - const ammo = Math.ceil(b.guns[ammoTarget].ammoPack * 2); - b.guns[ammoTarget].ammo += ammo; - game.updateGunHUD(); - game.makeTextLog("+" + ammo + " ammo: " + b.guns[ammoTarget].name, 180); - } - } - }, - spawnRandomPowerUp(x, y) { //mostly used after mob dies - if (Math.random() * Math.random() - 0.25 > Math.sqrt(mech.health) || Math.random() < 0.04) { //spawn heal chance is higher at low health - powerUps.spawn(x, y, "heal"); - return; - } - if (Math.random() < 0.19) { - if (b.inventory.length > 0) powerUps.spawn(x, y, "ammo"); - return; - } - if (Math.random() < 0.004 * (5 - b.inventory.length)) { //a new gun has a low chance for each not acquired gun to drop - powerUps.spawn(x, y, "gun"); - return; - } - if (Math.random() < 0.005) { - powerUps.spawn(x, y, "field"); - return; - } - if (Math.random() < 0.005) { - powerUps.spawn(x, y, "mod"); - return; - } - }, - spawnBossPowerUp(x, y) { //boss spawns field and gun mod upgrades - if (mech.fieldMode === 0) { - powerUps.spawn(x, y, "field") - } else if (b.mod === null) { - powerUps.spawn(x, y, "mod") - } else if (Math.random() < 0.2) { - powerUps.spawn(x, y, "mod") - } else if (Math.random() < 0.2) { - powerUps.spawn(x, y, "field"); - } else if (Math.random() < 0.15) { - powerUps.spawn(x, y, "gun") - } else if (mech.health < 0.5) { - powerUps.spawn(x, y, "heal"); - } else { - powerUps.spawn(x, y, "ammo"); - } - }, - chooseRandomPowerUp(x, y) { //100% chance to drop a random power up //used in spawn.debris - if (Math.random() < 0.5) { - powerUps.spawn(x, y, "heal", false); - } else { - powerUps.spawn(x, y, "ammo", false); - } - }, - spawnStartingPowerUps(x, y) { - if (b.inventory.length < 2) { - powerUps.spawn(x, y, "gun", false); //starting gun - } else { - powerUps.spawnRandomPowerUp(x, y); - powerUps.spawnRandomPowerUp(x, y); - powerUps.spawnRandomPowerUp(x, y); - powerUps.spawnRandomPowerUp(x, y); - } - }, - spawn(x, y, target, moving = true, mode = null) { - let i = powerUp.length; - target = powerUps[target]; - size = target.size(); - powerUp[i] = Matter.Bodies.polygon(x, y, 0, size, { - density: 0.001, - frictionAir: 0.01, - restitution: 0.8, - inertia: Infinity, //prevents rotation - collisionFilter: { - group: 0, - category: 0x100000, - mask: 0x100001 - }, - color: target.color, - effect: target.effect, - mode: mode, - name: target.name, - size: size - }); - if (moving) { - Matter.Body.setVelocity(powerUp[i], { - x: (Math.random() - 0.5) * 15, - y: Math.random() * -9 - 3 - }); - } - World.add(engine.world, powerUp[i]); //add to world - }, -}; \ No newline at end of file diff --git a/js/spawn.js b/js/spawn.js deleted file mode 100644 index 6ab1a6e..0000000 --- a/js/spawn.js +++ /dev/null @@ -1,1722 +0,0 @@ -//main object for spawning things in a level -const spawn = { - pickList: ["starter", "starter"], - fullPickList: [ - "chaser", "chaser", "chaser", - "striker", "striker", - "spinner", - "hopper", "hopper", "hopper", "hopper", - "grower", - "springer", - "shooter", "shooter", "shooter", "shooter", "shooter", - "beamer", - "focuser", - "laser", "laser", - // "blinker", //make blinker a boss - "sucker", - "exploder", "exploder", "exploder", - "spawner", - "ghoster", - "sneaker", - ], - allowedBossList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter"], //"zoomer", - setSpawnList() { - //this is run at the start of each new level to determine the possible mobs for the level - //each level has 2 mobs: one new mob and one from the last level - spawn.pickList.splice(0, 1); - spawn.pickList.push(spawn.fullPickList[Math.floor(Math.random() * spawn.fullPickList.length)]); - }, - randomMob(x, y, chance = 1) { - if (Math.random() < chance + 0.09 * (game.levelsCleared - 1) && mob.length < 4 + game.levelsCleared * 1.7) { - const pick = this.pickList[Math.floor(Math.random() * this.pickList.length)]; - this[pick](x, y); - } - }, - randomSmallMob(x, y, - num = Math.max(Math.min(Math.round(Math.random() * (game.levelsCleared - 1) * 0.45 - 0.4), 4), 0), - size = 16 + Math.ceil(Math.random() * 15), - chance = 1) { - if (Math.random() < chance + (game.levelsCleared - 1) * 0.03 && mob.length < 4 + game.levelsCleared * 1.7) { - for (let i = 0; i < num; ++i) { - const pick = this.pickList[Math.floor(Math.random() * this.pickList.length)]; - this[pick](x + Math.round((Math.random() - 0.5) * 20) + i * size * 2.5, y + Math.round((Math.random() - 0.5) * 20), size); - } - } - }, - randomBoss(x, y, chance = 1) { - if (Math.random() < chance + (game.levelsCleared - 1) * 0.14 && game.levelsCleared !== 1 && mob.length < 4 + game.levelsCleared * 2 || chance == Infinity) { - //choose from the possible picklist - let pick = this.pickList[Math.floor(Math.random() * this.pickList.length)]; - //is the pick able to be a boss? - let canBeBoss = false; - for (let i = 0, len = this.allowedBossList.length; i < len; ++i) { - if (this.allowedBossList[i] === pick) { - canBeBoss = true; - break; - } - } - if (canBeBoss) { - if (Math.random() < 0.55) { - this.nodeBoss(x, y, pick); - } else { - this.lineBoss(x, y, pick); - } - } else { - if (Math.random() < 0.07) { - this[pick](x, y, 90 + Math.random() * 40); //one extra large mob - } else if (Math.random() < 0.35) { - this.groupBoss(x, y) //hidden grouping blocks - } else { - pick = (Math.random() < 0.5) ? "randomList" : "random"; - if (Math.random() < 0.55) { - this.nodeBoss(x, y, pick); - } else { - this.lineBoss(x, y, pick); - } - } - } - } - }, - - //mob templates ********************************************************************************************* - //*********************************************************************************************************** - groupBoss(x, y, num = 5 + Math.random() * 8) { - for (let i = 0; i < num; i++) { - const radius = 25 + Math.floor(Math.random() * 20) - spawn.grouper(x + Math.random() * radius, y + Math.random() * radius, radius); - } - }, - grouper(x, y, radius = 27 + Math.floor(Math.random() * 10)) { - mobs.spawn(x, y, 4, radius, "#777"); - let me = mob[mob.length - 1]; - me.g = 0.0002; //required if using 'gravity' - me.accelMag = 0.0007 * game.accelScale; - me.groupingRangeMax = 250000 + Math.random() * 100000; - me.groupingRangeMin = (radius * 8) * (radius * 8); - me.groupingStrength = 0.0005 - me.memory = 200; - - me.do = function () { - this.gravity(); - if (this.seePlayer.recall) { - this.seePlayerByDistAndLOS(); - this.healthBar(); - this.attraction(); - //tether to other blocks - ctx.beginPath(); - for (let i = 0, len = mob.length; i < len; i++) { - if (mob[i] != this && mob[i].dropPowerUp) { //don't tether to self, bullets, shields, ... - const distance2 = Matter.Vector.magnitudeSquared(Matter.Vector.sub(this.position, mob[i].position)) - if (distance2 < this.groupingRangeMax) { - if (!mob[i].seePlayer.recall) mob[i].seePlayerByDistAndLOS(); //wake up sleepy mobs - if (distance2 > this.groupingRangeMin) { - const angle = Math.atan2(mob[i].position.y - this.position.y, mob[i].position.x - this.position.x); - const forceMag = this.groupingStrength * mob[i].mass; - mob[i].force.x -= forceMag * Math.cos(angle); - mob[i].force.y -= forceMag * Math.sin(angle); - } - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(mob[i].position.x, mob[i].position.y); - } - } - } - ctx.strokeStyle = "#000"; - ctx.lineWidth = 1; - ctx.stroke(); - } - } - }, - starter(x, y, radius = 30) { - //easy mob for on level 1 - mobs.spawn(x, y, 8, radius, "#9ccdc6"); - let me = mob[mob.length - 1]; - me.accelMag = 0.00055 * game.accelScale; - me.memory = 60; - Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback - - me.do = function () { - this.healthBar(); - this.seePlayerByLookingAt(); - this.attraction(); - }; - }, - healer(x, y, radius = 20) { - //easy mob for on level 1 - mobs.spawn(x, y, 3, radius, "rgba(50,255,200,0.4)"); - let me = mob[mob.length - 1]; - me.frictionAir = 0.02; - me.accelMag = 0.0004 * game.accelScale; - if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search - me.lookFrequency = 160 + Math.floor(57 * Math.random()) - me.lockedOn = null; - Matter.Body.setDensity(me, 0.003) // normal density is 0.001 - - me.do = function () { - this.healthBar(); - - if (!(game.cycle % this.lookFrequency)) { - //slow self heal - this.health += 0.02; - if (this.health > 1) this.health = 1; - - //target mobs with low health - let closeDist = Infinity; - for (let i = 0; i < mob.length; i++) { - if (mob[i] != this && Matter.Query.ray(map, this.position, mob[i].position).length === 0) { - const TARGET_VECTOR = Matter.Vector.sub(this.position, mob[i].position) - const DIST = Matter.Vector.magnitude(TARGET_VECTOR) * mob[i].health * mob[i].health * mob[i].health; //distance is multiplied by mob health to prioritize low health mobs - if (DIST < closeDist) { - closeDist = DIST; - this.lockedOn = mob[i] - } - } - } - } - - //move away from player if too close - if (this.distanceToPlayer2() < 400000) { - const TARGET_VECTOR = Matter.Vector.sub(this.position, player.position) - this.force = Matter.Vector.mult(Matter.Vector.normalise(TARGET_VECTOR), this.mass * this.accelMag * 1.4) - if (this.lockedOn) this.lockedOn = null - } else if (this.lockedOn && this.lockedOn.alive) { - //move towards and heal locked on target - const TARGET_VECTOR = Matter.Vector.sub(this.position, this.lockedOn.position) - const DIST = Matter.Vector.magnitude(TARGET_VECTOR); - if (DIST > 250) { - this.force = Matter.Vector.mult(Matter.Vector.normalise(TARGET_VECTOR), -this.mass * this.accelMag) - } else { - if (this.lockedOn.health < 1) { - this.lockedOn.health += 0.002; - if (this.lockedOn.health > 1) this.lockedOn.health = 1; - //spin when healing - this.torque = 0.000005 * this.inertia; - //draw heal - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(this.lockedOn.position.x, this.lockedOn.position.y); - ctx.lineWidth = 10 - ctx.strokeStyle = "rgba(50,255,200,0.4)" - ctx.stroke(); - } - } - } else { - //wander if no heal targets visible - //be sure to declare searchTarget in mob spawn - const newTarget = function (that) { - that.searchTarget = mob[Math.floor(Math.random() * (mob.length - 1))].position; - }; - - const sub = Matter.Vector.sub(this.searchTarget, this.position); - if (Matter.Vector.magnitude(sub) > this.radius * 2) { - ctx.beginPath(); - ctx.strokeStyle = "#aaa"; - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(this.searchTarget.x, this.searchTarget.y); - ctx.stroke(); - //accelerate at 0.6 of normal acceleration - this.force = Matter.Vector.mult(Matter.Vector.normalise(sub), this.accelMag * this.mass * 0.6); - } else { - //after reaching random target switch to new target - newTarget(this); - } - //switch to a new target after a while - if (!(game.cycle % (this.lookFrequency * 15))) { - newTarget(this); - } - - } - }; - }, - chaser(x, y, radius = 35 + Math.ceil(Math.random() * 40)) { - mobs.spawn(x, y, 8, radius, "#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; - me.frictionAir = 0; - me.accelMag = 0.001 * game.accelScale;; - me.g = me.accelMag * 0.6; //required if using 'gravity' - me.memory = 50; - if (Math.random() < Math.min((game.levelsCleared - 1) * 0.1, 0.7)) spawn.shield(me, x, y); - me.do = function () { - this.healthBar(); - this.gravity(); - this.seePlayerCheck(); - this.attraction(); - }; - }, - grower(x, y, radius = 15) { - mobs.spawn(x, y, 7, radius, "hsl(144, 15%, 50%)"); - let me = mob[mob.length - 1]; - me.big = false; //required for grow - me.accelMag = 0.00045 * game.accelScale; - me.do = function () { - this.healthBar(); - this.seePlayerByLookingAt(); - this.attraction(); - this.grow(); - }; - }, - springer(x, y, radius = 20 + Math.ceil(Math.random() * 35)) { - mobs.spawn(x, y, 8, radius, "#b386e8"); - let me = mob[mob.length - 1]; - me.friction = 0; - me.frictionAir = 0.1; - me.lookTorque = 0.000005; - me.g = 0.0002; //required if using 'gravity' - me.seePlayerFreq = Math.round((40 + 25 * Math.random()) * game.lookFreqScale); - const springStiffness = 0.002; - const springDampening = 0.1; - - me.springTarget = { - x: me.position.x, - y: me.position.y - }; - const len = cons.length; - cons[len] = Constraint.create({ - pointA: me.springTarget, - bodyB: me, - stiffness: springStiffness, - damping: springDampening - }); - cons[len].length = 100 + 1.5 * radius; - me.cons = cons[len]; - - me.springTarget2 = { - x: me.position.x, - y: me.position.y - }; - const len2 = cons.length; - cons[len2] = Constraint.create({ - pointA: me.springTarget2, - bodyB: me, - stiffness: springStiffness, - damping: springDampening - }); - cons[len2].length = 100 + 1.5 * radius; - me.cons2 = cons[len2]; - - me.onDeath = function () { - this.removeCons(); - }; - if (Math.random() < Math.min((game.levelsCleared - 1) * 0.1, 0.7)) spawn.shield(me, x, y); - me.do = function () { - this.healthBar(); - this.gravity(); - this.searchSpring(); - }; - }, - zoomer(x, y, radius = 20 + Math.ceil(Math.random() * 30)) { - mobs.spawn(x, y, 6, radius, "#ffe2fd"); - let me = mob[mob.length - 1]; - me.trailLength = 20; //required for trails - me.setupTrail(); //fill trails array up with the current position of mob - me.trailFill = "#ff00f0"; - me.g = 0.001; //required if using 'gravity' - me.frictionAir = 0.02; - me.accelMag = 0.004 * game.accelScale; - me.memory = 30; - me.zoomMode = 150; - me.onHit = function () { - this.zoomMode = 150; - }; - me.do = function () { - this.healthBar(); - this.seePlayerByDistAndLOS(); - this.zoom(); - this.gravity(); - }; - }, - hopper(x, y, radius = 30 + Math.ceil(Math.random() * 30)) { - mobs.spawn(x, y, 5, radius, "rgb(0,200,180)"); - let me = mob[mob.length - 1]; - me.accelMag = 0.04 * game.accelScale; - me.g = 0.0015; //required if using 'gravity' - me.frictionAir = 0.018; - me.restitution = 0; - me.delay = 110; - me.randomHopFrequency = 50 + Math.floor(Math.random() * 1000); - me.randomHopCD = game.cycle + me.randomHopFrequency; - me.do = function () { - this.healthBar(); - this.gravity(); - this.seePlayerCheck(); - 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 - } - }; - }, - spinner(x, y, radius = 30 + Math.ceil(Math.random() * 35)) { - mobs.spawn(x, y, 5, radius, "#000000"); - let me = mob[mob.length - 1]; - me.fill = "#28b"; - me.rememberFill = me.fill; - me.cdBurst1 = 0; //must add for burstAttraction - me.cdBurst2 = 0; //must add for burstAttraction - me.delay = 0; - me.burstDir = { - x: 0, - y: 0 - }; - me.accelMag = 0.16 * game.accelScale; - me.frictionAir = 0.022; - me.lookTorque = 0.0000014; - me.restitution = 0; - me.do = function () { - this.healthBar(); - this.seePlayerByLookingAt(); - //accelerate towards the player after a delay - if (this.seePlayer.recall) { - if (this.cdBurst2 < game.cycle && this.angularSpeed < 0.01) { - this.cdBurst2 = Infinity; - this.cdBurst1 = game.cycle + 40; - this.burstDir = Matter.Vector.normalise(Matter.Vector.sub(this.seePlayer.position, this.position)); - } else if (this.cdBurst1 < game.cycle) { - this.cdBurst2 = game.cycle + this.delay; - this.cdBurst1 = Infinity; - this.force = Matter.Vector.mult(this.burstDir, this.mass * 0.25); - this.fill = this.rememberFill; - } else if (this.cdBurst1 != Infinity) { - this.torque += 0.000035 * this.inertia; - this.fill = randomColor({ - hue: "blue" - }); - //draw attack vector - const mag = this.radius * 2 + 200; - const gradient = ctx.createRadialGradient(this.position.x, this.position.y, 0, this.position.x, this.position.y, mag); - gradient.addColorStop(0, "rgba(0,0,0,0.2)"); - gradient.addColorStop(1, "transparent"); - ctx.strokeStyle = gradient; - ctx.lineWidth = 5; - ctx.setLineDash([10, 20]); //30 - const dir = Matter.Vector.add(this.position, Matter.Vector.mult(this.burstDir, mag)); - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(dir.x, dir.y); - ctx.stroke(); - ctx.setLineDash([]); - } else { - this.fill = this.rememberFill; - } - } else { - this.cdBurst2 = 0; - } - }; - }, - sucker(x, y, radius = 30 + Math.ceil(Math.random() * 70)) { - radius = 9 + radius / 8; //extra small - mobs.spawn(x, y, 6, radius, "#000"); - let me = mob[mob.length - 1]; - me.stroke = "transparent"; //used for drawSneaker - me.eventHorizon = radius * 23; //required for blackhole - me.seeAtDistance2 = (me.eventHorizon + 500) * (me.eventHorizon + 500); //vision limit is event horizon - me.accelMag = 0.00009 * game.accelScale; - // me.frictionAir = 0.005; - me.memory = 600; - Matter.Body.setDensity(me, 0.004); //extra dense //normal is 0.001 //makes effective life much larger - me.do = function () { - //keep it slow, to stop issues from explosion knock backs - if (this.speed > 5) { - Matter.Body.setVelocity(this, { - x: this.velocity.x * 0.99, - y: this.velocity.y * 0.99 - }); - } - this.seePlayerByDistOrLOS(); - if (this.seePlayer.recall) { - //eventHorizon waves in and out - eventHorizon = this.eventHorizon * (0.93 + 0.17 * Math.sin(game.cycle * 0.011)) - - //accelerate towards the player - const forceMag = this.accelMag * 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); - - //draw darkness - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon * 0.25, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,0,0,0.9)"; - ctx.fill(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon * 0.55, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,0,0,0.5)"; - ctx.fill(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,0,0,0.1)"; - ctx.fill(); - - this.healthBar(); - //when player is inside event horizon - if (Matter.Vector.magnitude(Matter.Vector.sub(this.position, player.position)) < eventHorizon) { - mech.damage(0.00015 * game.dmgScale); - if (mech.fieldMeter > 0.1) mech.fieldMeter -= 0.01 - const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); - player.force.x -= 1.25 * Math.cos(angle) * player.mass * game.g * (mech.onGround ? 1.8 : 1); - player.force.y -= 0.96 * player.mass * game.g * Math.sin(angle); - //draw line to player - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(mech.pos.x, mech.pos.y); - ctx.lineWidth = Math.min(60, this.radius * 2); - ctx.strokeStyle = "rgba(0,0,0,0.5)"; - ctx.stroke(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, 40, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,0,0,0.3)"; - ctx.fill(); - } - } - } - }, - suckerBoss(x, y, radius = 20) { - mobs.spawn(x, y, 12, radius, "#000"); - let me = mob[mob.length - 1]; - me.stroke = "transparent"; //used for drawSneaker - me.eventHorizon = 1100; //required for black hole - me.seeAtDistance2 = (me.eventHorizon + 1000) * (me.eventHorizon + 1000); //vision limit is event horizon - me.accelMag = 0.00003 * game.accelScale; - me.collisionFilter.mask = 0x001100 - // me.frictionAir = 0.005; - me.memory = 1600; - Matter.Body.setDensity(me, 0.05); //extra dense //normal is 0.001 //makes effective life much larger - me.onDeath = function () { - //applying forces to player doesn't seem to work inside this method, not sure why - powerUps.spawnBossPowerUp(this.position.x, this.position.y) - if (game.levelsCleared > 5) { - for (let i = 0; i < (game.levelsCleared - 3); ++i) { - spawn.sucker(this.position.x + (Math.random() - 0.5) * radius * 2, this.position.y + (Math.random() - 0.5) * radius * 2, 70 * Math.random()); - Matter.Body.setVelocity(mob[mob.length - 1], { - x: (Math.random() - 0.5) * 70, - y: (Math.random() - 0.5) * 70 - }); - } - } - }; - me.do = function () { - //keep it slow, to stop issues from explosion knock backs - if (this.speed > 1) { - Matter.Body.setVelocity(this, { - x: this.velocity.x * 0.95, - y: this.velocity.y * 0.95 - }); - } - this.seePlayerByDistOrLOS(); - if (this.seePlayer.recall) { - //accelerate towards the player - const forceMag = this.accelMag * 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); - - //eventHorizon waves in and out - eventHorizon = this.eventHorizon * (1 + 0.2 * Math.sin(game.cycle * 0.008)) - // zoom camera in and out with the event horizon - - //draw darkness - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon * 0.2, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,20,40,0.6)"; - ctx.fill(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon * 0.4, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,20,40,0.4)"; - ctx.fill(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon * 0.6, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,20,40,0.3)"; - ctx.fill(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon * 0.8, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,20,40,0.2)"; - ctx.fill(); - ctx.beginPath(); - ctx.arc(this.position.x, this.position.y, eventHorizon, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,0,0,0.05)"; - ctx.fill(); - //when player is inside event horizon - if (Matter.Vector.magnitude(Matter.Vector.sub(this.position, player.position)) < eventHorizon) { - mech.damage(0.00015 * game.dmgScale); - if (mech.fieldMeter > 0.1) mech.fieldMeter -= 0.01 - const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); - player.force.x -= 1.3 * Math.cos(angle) * player.mass * game.g * (mech.onGround ? 1.7 : 1); - player.force.y -= 1.2 * Math.sin(angle) * player.mass * game.g; - //draw line to player - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - ctx.lineTo(mech.pos.x, mech.pos.y); - ctx.lineWidth = Math.min(60, this.radius * 2); - ctx.strokeStyle = "rgba(0,0,0,0.5)"; - ctx.stroke(); - ctx.beginPath(); - ctx.arc(mech.pos.x, mech.pos.y, 40, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(0,0,0,0.3)"; - ctx.fill(); - } - this.healthBar(); - this.curl(eventHorizon); - } - } - }, - beamer(x, y, radius = 15 + Math.ceil(Math.random() * 15)) { - mobs.spawn(x, y, 4, radius, "rgb(255,0,190)"); - let me = mob[mob.length - 1]; - me.repulsionRange = 73000; //squared - me.laserRange = 370; - me.accelMag = 0.0005 * game.accelScale; - me.frictionStatic = 0; - me.friction = 0; - if (Math.random() < Math.min(0.2 + (game.levelsCleared - 1) * 0.1, 0.7)) spawn.shield(me, x, y); - me.do = function () { - this.healthBar(); - this.seePlayerByLookingAt(); - this.attraction(); - this.repulsion(); - //laser beam - this.laserBeam(); - }; - }, - focuser(x, y, radius = 30 + Math.ceil(Math.random() * 10)) { - radius = Math.ceil(radius * 0.7); - mobs.spawn(x, y, 4, radius, "rgb(0,0,255)"); - let me = mob[mob.length - 1]; - Matter.Body.setDensity(me, 0.003); //extra dense //normal is 0.001 - me.restitution = 0; - me.laserPos = me.position; //required for laserTracking - me.repulsionRange = 1200000; //squared - me.accelMag = 0.0002 * game.accelScale; - me.frictionStatic = 0; - me.friction = 0; - me.onDamage = function () { - this.laserPos = this.position; - }; - // if (Math.random() < Math.min(0.2 + game.levelsCleared * 0.1, 0.7)) spawn.shield(me, x, y); - me.do = function () { - this.healthBar(); - if (!mech.isBodiesAsleep) { - this.seePlayerByLookingAt(); - const dist2 = this.distanceToPlayer2(); - //laser Tracking - if (this.seePlayer.yes && dist2 < 4000000 && !mech.isStealth) { - this.attraction(); - const rangeWidth = 2000; //this is sqrt of 4000000 from above if() - //targeting laser will slowly move from the mob to the player's position - this.laserPos = Matter.Vector.add(this.laserPos, Matter.Vector.mult(Matter.Vector.sub(player.position, this.laserPos), 0.1)); - let targetDist = Matter.Vector.magnitude(Matter.Vector.sub(this.laserPos, mech.pos)); - const r = 10; - - // ctx.setLineDash([15, 200]); - // ctx.lineDashOffset = 20*(game.cycle % 215); - ctx.beginPath(); - ctx.moveTo(this.position.x, this.position.y); - if (targetDist < r + 15) { - // || dist2 < 80000 - targetDist = r + 10; - //charge at player - const forceMag = this.accelMag * 40 * 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); - } else { - //high friction if can't lock onto player - Matter.Body.setVelocity(this, { - x: this.velocity.x * 0.96, - y: this.velocity.y * 0.96 - }); - } - if (dist2 > 80000) { - const laserWidth = 0.002; - let laserOffR = Matter.Vector.rotateAbout(this.laserPos, (targetDist - r) * laserWidth, this.position); - let sub = Matter.Vector.normalise(Matter.Vector.sub(laserOffR, this.position)); - laserOffR = Matter.Vector.add(laserOffR, Matter.Vector.mult(sub, rangeWidth)); - ctx.lineTo(laserOffR.x, laserOffR.y); - - let laserOffL = Matter.Vector.rotateAbout(this.laserPos, (targetDist - r) * -laserWidth, this.position); - sub = Matter.Vector.normalise(Matter.Vector.sub(laserOffL, this.position)); - laserOffL = Matter.Vector.add(laserOffL, Matter.Vector.mult(sub, rangeWidth)); - ctx.lineTo(laserOffL.x, laserOffL.y); - // ctx.fillStyle = "rgba(0,0,255,0.15)"; - var gradient = ctx.createRadialGradient(this.position.x, this.position.y, 0, this.position.x, this.position.y, rangeWidth); - gradient.addColorStop(0, `rgba(0,0,255,${((r + 5) * (r + 5)) / (targetDist * targetDist)})`); - gradient.addColorStop(1, "transparent"); - ctx.fillStyle = gradient; - ctx.fill(); - } - } else { - this.laserPos = this.position; - } - }; - } - }, - laser(x, y, radius = 30) { - //only on level 1 - mobs.spawn(x, y, 3, radius, "#f00"); - let me = mob[mob.length - 1]; - me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front - Matter.Body.rotate(me, Math.random() * Math.PI * 2); - me.accelMag = 0.00007 * game.accelScale; - me.onHit = function () { - //run this function on hitting player - this.explode(); - }; - me.do = function () { - this.healthBar(); - this.seePlayerByLookingAt(); - this.attraction(); - this.laser(); - }; - }, - striker(x, y, radius = 15 + Math.ceil(Math.random() * 25)) { - mobs.spawn(x, y, 5, radius, "rgb(221,102,119)"); - let me = mob[mob.length - 1]; - me.accelMag = 0.0004 * game.accelScale; - me.g = 0.0002; //required if using 'gravity' - me.frictionStatic = 0; - me.friction = 0; - me.delay = 60; - Matter.Body.rotate(me, Math.PI * 0.1); - me.onDamage = function () { - this.cd = game.cycle + this.delay; - }; - me.do = function () { - this.healthBar(); - this.seePlayerCheck(); - this.attraction(); - this.gravity(); - this.strike(); - }; - }, - sneaker(x, y, radius = 15 + Math.ceil(Math.random() * 25)) { - let me; - mobs.spawn(x, y, 5, radius, "transparent"); - me = mob[mob.length - 1]; - me.accelMag = 0.0007 * game.accelScale; - me.g = 0.0002; //required if using 'gravity' - me.stroke = "transparent"; //used for drawSneaker - me.alpha = 1; //used in drawSneaker - // me.leaveBody = false; - me.canTouchPlayer = false; //used in drawSneaker - me.collisionFilter.mask = 0x010111; //can't touch player - // me.memory = 420; - me.do = function () { - - this.seePlayerCheck(); - this.attraction(); - this.gravity(); - //draw - if (!mech.isBodiesAsleep) { - if (this.seePlayer.yes) { - if (this.alpha < 1) this.alpha += 0.01; - } else { - if (this.alpha > 0) this.alpha -= 0.03; - } - } - if (this.alpha > 0) { - if (this.alpha > 0.95) { - this.healthBar(); - if (!this.canTouchPlayer) { - this.canTouchPlayer = true; - this.collisionFilter.mask = 0x011111; //can touch player - } - } - //draw body - ctx.beginPath(); - const vertices = this.vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.fillStyle = `rgba(0,0,0,${this.alpha * this.alpha})`; - ctx.fill(); - } else if (this.canTouchPlayer) { - this.canTouchPlayer = false; - this.collisionFilter.mask = 0x000111; //can't touch player - } - }; - }, - ghoster(x, y, radius = 40 + Math.ceil(Math.random() * 100)) { - let me; - mobs.spawn(x, y, 7, radius, "transparent"); - me = mob[mob.length - 1]; - me.seeAtDistance2 = 1000000; - me.accelMag = 0.00014 * game.accelScale; - if (map.length) me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search - Matter.Body.setDensity(me, 0.00065); //normal is 0.001 //makes effective life much lower - me.stroke = "transparent"; //used for drawGhost - me.alpha = 1; //used in drawGhost - me.canTouchPlayer = false; //used in drawGhost - // me.leaveBody = false; - me.collisionFilter.mask = 0x000100; //move through walls and player - me.memory = 480; - me.do = function () { - //cap max speed - if (this.speed > 5) { - Matter.Body.setVelocity(mob[mob.length - 1], { - x: this.velocity.x * 0.8, - y: this.velocity.y * 0.8 - }); - } - this.seePlayerCheckByDistance(); - this.attraction(); - this.search(); - //draw - if (this.distanceToPlayer2() - this.seeAtDistance2 < 0) { - if (this.alpha < 1) this.alpha += 0.004; - } else { - if (this.alpha > 0) this.alpha -= 0.03; - } - if (this.alpha > 0) { - if (this.alpha > 0.9) { - this.healthBar(); - if (!this.canTouchPlayer) { - this.canTouchPlayer = true; - this.collisionFilter.mask = 0x001100; //can touch player but not walls - } - } - //draw body - ctx.beginPath(); - const vertices = this.vertices; - ctx.moveTo(vertices[0].x, vertices[0].y); - for (let j = 1, len = vertices.length; j < len; ++j) { - ctx.lineTo(vertices[j].x, vertices[j].y); - } - ctx.lineTo(vertices[0].x, vertices[0].y); - ctx.lineWidth = 1; - ctx.strokeStyle = `rgba(0,0,0,${this.alpha * this.alpha})`; - ctx.stroke(); - } else if (this.canTouchPlayer) { - this.canTouchPlayer = false; - this.collisionFilter.mask = 0x000100; //can't touch player or walls - } - }; - }, - blinker(x, y, radius = 45 + Math.ceil(Math.random() * 70)) { - mobs.spawn(x, y, 6, radius, "transparent"); - let me = mob[mob.length - 1]; - Matter.Body.setDensity(me, 0.0005); //normal is 0.001 //makes effective life much lower - me.stroke = "rgb(0,200,255)"; //used for drawGhost - Matter.Body.rotate(me, Math.random() * 2 * Math.PI); - me.blinkRate = 40 + Math.round(Math.random() * 60); //required for blink - me.blinkLength = 150 + Math.round(Math.random() * 200); //required for blink - me.isStatic = true; - me.memory = 360; - me.seePlayerFreq = Math.round((40 + 30 * Math.random()) * game.lookFreqScale); - me.isBig = false; - me.scaleMag = Math.max(5 - me.mass, 1.75); - me.onDeath = function () { - if (this.isBig) { - Matter.Body.scale(this, 1 / this.scaleMag, 1 / this.scaleMag); - this.isBig = false; - } - }; - me.do = function () { - this.healthBar(); - this.seePlayerCheck(); - this.blink(); - //strike by expanding - if (this.isBig) { - if (this.cd - this.delay + 15 < game.cycle) { - Matter.Body.scale(this, 1 / this.scaleMag, 1 / this.scaleMag); - this.isBig = false; - } - } else if (this.seePlayer.yes && this.cd < game.cycle) { - const dist = Matter.Vector.sub(this.seePlayer.position, this.position); - const distMag2 = Matter.Vector.magnitudeSquared(dist); - if (distMag2 < 80000) { - this.cd = game.cycle + this.delay; - Matter.Body.scale(this, this.scaleMag, this.scaleMag); - this.isBig = true; - } - } - }; - }, - bomber(x, y, radius = 120 + Math.ceil(Math.random() * 70)) { - //boss that drops bombs from above and holds a set distance from player - mobs.spawn(x, y, 3, radius, "transparent"); - let me = mob[mob.length - 1]; - Matter.Body.setDensity(me, 0.0015 + 0.0005 * Math.sqrt(game.levelsCleared)); //extra dense //normal is 0.001 //makes effective life much larger - - me.stroke = "rgba(255,0,200)"; //used for drawGhost - me.seeAtDistance2 = 2000000; - me.fireFreq = Math.ceil(30 + 2000 / radius); - me.searchTarget = map[Math.floor(Math.random() * (map.length - 1))].position; //required for search - me.hoverElevation = 400 + (Math.random() - 0.5) * 200; //squared - me.hoverXOff = (Math.random() - 0.5) * 100; - me.accelMag = Math.floor(10 * (Math.random() + 5)) * 0.00001 * game.accelScale; - me.g = 0.0002; //required if using 'gravity' // gravity called in hoverOverPlayer - me.frictionStatic = 0; - me.friction = 0; - me.frictionAir = 0.01; - // me.memory = 300; - // Matter.Body.setDensity(me, 0.0015); //extra dense //normal is 0.001 - me.collisionFilter.mask = 0x001100; //move through walls - spawn.shield(me, x, y); - me.onDeath = function () { - powerUps.spawnBossPowerUp(this.position.x, this.position.y) - }; - me.do = function () { - this.healthBar(); - this.seePlayerCheckByDistance(); - this.hoverOverPlayer(); - this.bomb(); - this.search(); - }; - }, - shooter(x, y, radius = 25 + Math.ceil(Math.random() * 50)) { - mobs.spawn(x, y, 3, radius, "rgb(255,100,150)"); - let me = mob[mob.length - 1]; - me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front - me.memory = 120; - me.fireFreq = 0.007 + Math.random() * 0.005; - me.noseLength = 0; - me.fireAngle = 0; - me.accelMag = 0.0005 * game.accelScale; - me.frictionAir = 0.05; - me.lookTorque = 0.0000025 * (Math.random() > 0.5 ? -1 : 1); - me.fireDir = { - x: 0, - y: 0 - }; - if (Math.random() < Math.min(0.15 + (game.levelsCleared - 1) * 0.1, 0.7)) spawn.shield(me, x, y); - me.do = function () { - this.healthBar(); - this.seePlayerByLookingAt(); - this.fire(); - }; - }, - shooterBoss(x, y, radius = 85 + Math.ceil(Math.random() * 50)) { - //boss spawns on skyscraper level - mobs.spawn(x, y, 3, radius, "rgb(255,70,180)"); - let me = mob[mob.length - 1]; - me.vertices = Matter.Vertices.rotate(me.vertices, Math.PI, me.position); //make the pointy side of triangle the front - me.memory = 240; - me.fireFreq = 0.02; - me.noseLength = 0; - me.fireAngle = 0; - me.accelMag = 0.005 * game.accelScale; - me.frictionAir = 0.1; - me.lookTorque = 0.000005 * (Math.random() > 0.5 ? -1 : 1); - me.fireDir = { - x: 0, - y: 0 - }; - Matter.Body.setDensity(me, 0.001 + 0.0005 * Math.sqrt(game.levelsCleared)); //extra dense //normal is 0.001 //makes effective life much larger - spawn.shield(me, x, y); - me.onDeath = function () { - powerUps.spawnBossPowerUp(this.position.x, this.position.y) - }; - me.do = function () { - this.healthBar(); - this.seePlayerByLookingAt(); - this.fire(); - }; - }, - bullet(x, y, radius = 6, sides = 0) { - //bullets - mobs.spawn(x, y, sides, radius, "rgb(255,0,0)"); - let me = mob[mob.length - 1]; - me.stroke = "transparent"; - me.onHit = function () { - this.explode(); - }; - Matter.Body.setDensity(me, 0.001); //normal is 0.001 - me.timeLeft = 240; - me.g = 0.001; //required if using 'gravity' - me.frictionAir = 0; - me.restitution = 0.8; - me.leaveBody = false; - me.dropPowerUp = false; - me.collisionFilter.category = 0x000010; - me.collisionFilter.mask = 0x011101; - me.do = function () { - this.gravity(); - this.timeLimit(); - }; - }, - spawner(x, y, radius = 55 + Math.ceil(Math.random() * 50)) { - mobs.spawn(x, y, 4, radius, "rgb(255,150,0)"); - let me = mob[mob.length - 1]; - me.g = 0.0004; //required if using 'gravity' - me.leaveBody = false; - // me.dropPowerUp = false; - me.onDeath = function () { //run this function on death - for (let i = 0; i < Math.ceil(this.mass * 0.2 + Math.random() * 3); ++i) { - spawn.spawns(this.position.x + (Math.random() - 0.5) * radius * 2, this.position.y + (Math.random() - 0.5) * radius * 2); - Matter.Body.setVelocity(mob[mob.length - 1], { - x: (Math.random() - 0.5) * 25, - y: (Math.random() - 0.5) * 25 - }); - } - }; - if (Math.random() < Math.min((game.levelsCleared - 1) * 0.1, 0.5)) spawn.shield(me, x, y); - me.do = function () { - this.healthBar(); - this.gravity(); - this.seePlayerCheck(); - this.attraction(); - }; - }, - spawns(x, y, radius = 15 + Math.ceil(Math.random() * 5)) { - mobs.spawn(x, y, 4, radius, "rgb(255,0,0)"); - let me = mob[mob.length - 1]; - me.onHit = function () { - //run this function on hitting player - this.explode(); - }; - me.g = 0.0001; //required if using 'gravity' - me.accelMag = 0.0003 * game.accelScale; - me.memory = 30; - me.leaveBody = false; - me.seePlayerFreq = Math.round((80 + 50 * Math.random()) * game.lookFreqScale); - me.frictionAir = 0.002; - me.do = function () { - this.healthBar(); - this.gravity(); - this.seePlayerCheck(); - this.attraction(); - }; - }, - exploder(x, y, radius = 25 + Math.ceil(Math.random() * 50)) { - mobs.spawn(x, y, 4, radius, "rgb(255,0,0)"); - let me = mob[mob.length - 1]; - me.onHit = function () { - //run this function on hitting player - this.explode(); - }; - me.g = 0.0004; //required if using 'gravity' - me.do = function () { - this.healthBar(); - this.gravity(); - this.seePlayerCheck(); - this.attraction(); - }; - }, - snaker(x, y, radius = 80) { - //snake boss with a laser head - mobs.spawn(x, y, 8, radius, "rgb(255,50,130)"); - let me = mob[mob.length - 1]; - me.accelMag = 0.0012 * game.accelScale; - me.memory = 200; - me.laserRange = 500; - Matter.Body.setDensity(me, 0.001 + 0.0005 * Math.sqrt(game.levelsCleared)); //extra dense //normal is 0.001 //makes effective life much larger - spawn.shield(me, x, y); - if (Math.random() < Math.min((game.levelsCleared - 1) * 0.1, 0.7)) spawn.shield(me, x, y); - me.onDeath = function () { - powerUps.spawnBossPowerUp(this.position.x, this.position.y) - }; - me.do = function () { - this.healthBar(); - this.seePlayerCheck(); - this.attraction(); - this.laserBeam(); - }; - - //snake tail - const nodes = Math.min(3 + Math.ceil(Math.random() * game.levelsCleared + 2), 8) - spawn.lineBoss(x + 105, y, "spawns", nodes); - //constraint boss with first 3 mobs in lineboss - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - nodes], - bodyB: mob[mob.length - 1 - nodes], - stiffness: 0.05 - }); - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - nodes + 1], - bodyB: mob[mob.length - 1 - nodes], - stiffness: 0.05 - }); - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - nodes + 2], - bodyB: mob[mob.length - 1 - nodes], - stiffness: 0.05 - }); - - }, - tether(x, y, radius = 90) { - // constrained mob boss for the towers level - // often has a ring of mobs around it - mobs.spawn(x, y, 8, radius, "rgb(0,60,80)"); - let me = mob[mob.length - 1]; - me.g = 0.0001; //required if using 'gravity' - me.accelMag = 0.002 * game.accelScale; - me.memory = 20; - Matter.Body.setDensity(me, 0.001 + 0.0005 * Math.sqrt(game.levelsCleared)); //extra dense //normal is 0.001 //makes effective life much larger - spawn.shield(me, x, y); - if (Math.random() < Math.min((game.levelsCleared - 1) * 0.1, 0.7)) spawn.shield(me, x, y); - - me.onDeath = function () { - powerUps.spawnBossPowerUp(this.position.x, this.position.y) - this.removeCons(); //remove constraint - }; - me.do = function () { - this.healthBar(); - this.gravity(); - this.seePlayerCheck(); - this.attraction(); - }; - }, - shield(target, x, y, stiffness = 0.4) { - if (this.allowShields) { - mobs.spawn(x, y, 9, target.radius + 20, "rgba(220,220,255,0.6)"); - let me = mob[mob.length - 1]; - me.stroke = "rgb(220,220,255)"; - Matter.Body.setDensity(me, 0.0001) //very low density to not mess with the original mob's motion - me.shield = true; - me.collisionFilter.mask = 0x000100; //don't collide with bodies, map, player, and mobs, only bullets - consBB[consBB.length] = Constraint.create({ - //attach shield to last spawned mob - bodyA: me, - bodyB: target, - stiffness: stiffness, - damping: 0.1 - }); - me.onDamage = function () { - //make sure the mob that owns the shield can tell when damage is done - this.alertNearByMobs(); - }; - me.leaveBody = false; - me.dropPowerUp = false; - //swap order of shield and mob, so that mob is behind shield graphically - mob[mob.length - 1] = mob[mob.length - 2]; - mob[mob.length - 2] = me; - me.do = function () {}; - } - }, - bossShield(nodes, x, y, radius) { - mobs.spawn(x, y, 9, radius, "rgba(220,220,255,0.65)"); - let me = mob[mob.length - 1]; - me.stroke = "rgb(220,220,255)"; - Matter.Body.setDensity(me, 0.00005) //very low density to not mess with the original mob's motion - me.frictionAir = 0; - me.shield = true; - me.collisionFilter.mask = 0x000100; //don't collide with bodies, map, and mobs, only bullets and player - //constrain to all mob nodes in boss - for (let i = 0; i < nodes; ++i) { - consBB[consBB.length] = Constraint.create({ - bodyA: me, - bodyB: mob[mob.length - i - 2], - stiffness: 0.4, - damping: 0.1 - }); - } - me.onDamage = function () { - //make sure the mob that owns the shield can tell when damage is done - this.alertNearByMobs(); - }; - me.leaveBody = false; - me.dropPowerUp = false; - mob[mob.length - 1] = mob[mob.length - 1 - nodes]; - mob[mob.length - 1 - nodes] = me; - me.do = function () {}; - }, - //complex constrained mob templates********************************************************************** - //******************************************************************************************************* - allowShields: true, - nodeBoss( - x, - y, - spawn = "striker", - nodes = Math.min(2 + Math.ceil(Math.random() * (game.levelsCleared + 2)), 8), - //Math.ceil(Math.random() * 3) + Math.min(4,Math.ceil(game.levelsCleared/2)), - radius = Math.ceil(Math.random() * 10) + 17, // radius of each node mob - sideLength = Math.ceil(Math.random() * 100) + 70, // distance between each node mob - stiffness = Math.random() * 0.03 + 0.005 - ) { - this.allowShields = false; //don't want shields on boss mobs - const angle = 2 * Math.PI / nodes - for (let i = 0; i < nodes; ++i) { - let whoSpawn = spawn; - if (spawn === "random") { - whoSpawn = this.fullPickList[Math.floor(Math.random() * this.fullPickList.length)]; - } else if (spawn === "randomList") { - whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)]; - } - this[whoSpawn](x + sideLength * Math.sin(i * angle), y + sideLength * Math.cos(i * angle), radius); - } - if (Math.random() < 0.3) { - this.constrain2AdjacentMobs(nodes, stiffness * 2, true); - } else { - this.constrainAllMobCombos(nodes, stiffness); - } - //spawn shield for entire boss - if (nodes > 2 && Math.random() < 0.998) { - this.bossShield(nodes, x, y, sideLength + 2.5 * radius + nodes * 6 - 25); - // this.bossShield(nodes, x, y, sideLength / (2 * Math.sin(Math.PI / nodes))); - } - this.allowShields = true; - }, - // nodeBoss( - // x, - // y, - // spawn = "striker", - // nodes = Math.min(2 + Math.round(Math.random() * game.levelsCleared), 8), - // //Math.ceil(Math.random() * 3) + Math.min(4,Math.ceil(game.levelsCleared/2)), - // radius = Math.ceil(Math.random() * 10) + 17, // radius of each node mob - // l = Math.ceil(Math.random() * 100) + 70, // distance between each node mob - // stiffness = Math.random() * 0.03 + 0.005 - // ) { - // this.allowShields = false; //dont' want shields on boss mobs - // let px = 0; - // let py = 0; - // let a = (2 * Math.PI) / nodes; - // for (let i = 0; i < nodes; ++i) { - // px += l * Math.cos(a * i); - // py += l * Math.sin(a * i); - // let whoSpawn = spawn; - // if (spawn === "random") { - // whoSpawn = this.fullPickList[Math.floor(Math.random() * this.fullPickList.length)]; - // } else if (spawn === "randomList") { - // whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)]; - // } - // this[whoSpawn](x + px, y + py, radius); - // } - // if (Math.random() < 0.3) { - // this.constrain2AdjacentMobs(nodes, stiffness * 2, true); - // } else { - // this.constrainAllMobCombos(nodes, stiffness); - // } - // this.allowShields = true; - // }, - lineBoss( - x, - y, - spawn = "striker", - nodes = Math.min(3 + Math.ceil(Math.random() * game.levelsCleared + 2), 8), - //Math.ceil(Math.random() * 3) + Math.min(4,Math.ceil(game.levelsCleared/2)), - radius = Math.ceil(Math.random() * 10) + 17, - l = Math.ceil(Math.random() * 80) + 30, - stiffness = Math.random() * 0.06 + 0.01 - ) { - this.allowShields = false; //dont' want shields on boss mobs - for (let i = 0; i < nodes; ++i) { - let whoSpawn = spawn; - if (spawn === "random") { - whoSpawn = this.fullPickList[Math.floor(Math.random() * this.fullPickList.length)]; - } else if (spawn === "randomList") { - whoSpawn = this.pickList[Math.floor(Math.random() * this.pickList.length)]; - } - this[whoSpawn](x + i * radius + i * l, y, radius); - } - this.constrain2AdjacentMobs(nodes, stiffness); - this.allowShields = true; - }, - //constraints ************************************************************************************************ - //************************************************************************************************************* - constrainAllMobCombos(nodes, stiffness) { - //runs through every combination of last 'num' bodies and constrains them - for (let i = 1; i < nodes + 1; ++i) { - for (let j = i + 1; j < nodes + 1; ++j) { - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - i], - bodyB: mob[mob.length - j], - stiffness: stiffness - }); - } - } - }, - constrain2AdjacentMobs(nodes, stiffness, loop = false) { - //runs through every combination of last 'num' bodies and constrains them - for (let i = 0; i < nodes - 1; ++i) { - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - i - 1], - bodyB: mob[mob.length - i - 2], - stiffness: stiffness - }); - } - if (nodes > 2) { - for (let i = 0; i < nodes - 2; ++i) { - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - i - 1], - bodyB: mob[mob.length - i - 3], - stiffness: stiffness - }); - } - } - //optional connect the tail to head - if (loop && nodes > 3) { - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - 1], - bodyB: mob[mob.length - nodes], - stiffness: stiffness - }); - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - 2], - bodyB: mob[mob.length - nodes], - stiffness: stiffness - }); - consBB[consBB.length] = Constraint.create({ - bodyA: mob[mob.length - 1], - bodyB: mob[mob.length - nodes + 1], - stiffness: stiffness - }); - } - }, - constraintPB(x, y, bodyIndex, stiffness) { - cons[cons.length] = Constraint.create({ - pointA: { - x: x, - y: y - }, - bodyB: body[bodyIndex], - stiffness: stiffness - }); - }, - constraintBB(bodyIndexA, bodyIndexB, stiffness) { - consBB[consBB.length] = Constraint.create({ - bodyA: body[bodyIndexA], - bodyB: body[bodyIndexB], - stiffness: stiffness - }); - }, - // body and map spawns ****************************************************************************** - //********************************************************************************************** - wireHead() { - //not a mob, just a graphic for level 1 - const breakingPoint = 1300 - mobs.spawn(breakingPoint, -100, 0, 7.5, "transparent"); - let me = mob[mob.length - 1]; - //touch nothing - me.collisionFilter.category = 0x010000; //act like a body - me.collisionFilter.mask = 0x000101; //only collide with map - me.inertia = Infinity; - me.g = 0.0004; //required for gravity - me.restitution = 0; - me.stroke = "transparent" - me.freeOfWires = false; - me.frictionStatic = 1; - me.friction = 1; - me.frictionAir = 0.01; - - me.do = function () { - let wireX = -50; - let wireY = -1000; - if (this.freeOfWires) { - this.gravity(); - } else { - if (mech.pos.x > breakingPoint) { - this.freeOfWires = true; - this.fill = "#000" - this.force.x += -0.003; - player.force.x += 0.06; - // player.force.y -= 0.15; - } - - //player is extra heavy from wires - Matter.Body.setVelocity(player, { - x: player.velocity.x, - y: player.velocity.y + 0.3 - }) - - //player friction from the wires - if (mech.pos.x > 700 && player.velocity.x > -2) { - let wireFriction = 0.75 * Math.min(0.6, Math.max(0, 100 / (breakingPoint - mech.pos.x))); - if (!mech.onGround) wireFriction *= 3 - Matter.Body.setVelocity(player, { - x: player.velocity.x - wireFriction, - y: player.velocity.y - }) - } - //move to player - Matter.Body.setPosition(this, { - x: mech.pos.x + (42 * Math.cos(mech.angle + Math.PI)), - y: mech.pos.y + (42 * Math.sin(mech.angle + Math.PI)) - }) - } - //draw wire - ctx.beginPath(); - ctx.moveTo(wireX, wireY); - ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y); - if (!this.freeOfWires) ctx.lineTo(mech.pos.x + (30 * Math.cos(mech.angle + Math.PI)), mech.pos.y + (30 * Math.sin(mech.angle + Math.PI))); - ctx.lineCap = "butt"; - ctx.lineWidth = 15; - ctx.strokeStyle = "#000"; - ctx.stroke(); - ctx.lineCap = "round"; - }; - }, - wireKnee() { - //not a mob, just a graphic for level 1 - const breakingPoint = 1425 - mobs.spawn(breakingPoint, -100, 0, 2, "transparent"); - let me = mob[mob.length - 1]; - //touch nothing - me.collisionFilter.category = 0x010000; //act like a body - me.collisionFilter.mask = 0x000101; //only collide with map - me.g = 0.0003; //required for gravity - // me.restitution = 0; - me.stroke = "transparent" - // me.inertia = Infinity; - me.restitution = 0; - me.freeOfWires = false; - me.frictionStatic = 1; - me.friction = 1; - me.frictionAir = 0.01; - - me.do = function () { - let wireX = -50 - 20; - let wireY = -1000; - - if (this.freeOfWires) { - this.gravity(); - } else { - if (mech.pos.x > breakingPoint) { - this.freeOfWires = true; - this.force.x -= 0.0004; - this.fill = "#222"; - } - //move mob to player - mech.calcLeg(0, 0); - Matter.Body.setPosition(this, { - x: mech.pos.x + mech.flipLegs * mech.knee.x - 5, - y: mech.pos.y + mech.knee.y - }) - } - //draw wire - ctx.beginPath(); - ctx.moveTo(wireX, wireY); - ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y); - ctx.lineWidth = 5; - ctx.strokeStyle = "#222"; - ctx.lineCap = "butt"; - ctx.stroke(); - ctx.lineCap = "round"; - }; - }, - wireKneeLeft() { - //not a mob, just a graphic for level 1 - const breakingPoint = 1400 - mobs.spawn(breakingPoint, -100, 0, 2, "transparent"); - let me = mob[mob.length - 1]; - //touch nothing - me.collisionFilter.category = 0x010000; //act like a body - me.collisionFilter.mask = 0x000101; //only collide with map - me.g = 0.0003; //required for gravity - // me.restitution = 0; - me.stroke = "transparent" - // me.inertia = Infinity; - me.restitution = 0; - me.freeOfWires = false; - me.frictionStatic = 1; - me.friction = 1; - me.frictionAir = 0.01; - - me.do = function () { - let wireX = -50 - 35; - let wireY = -1000; - - if (this.freeOfWires) { - this.gravity(); - } else { - if (mech.pos.x > breakingPoint) { - this.freeOfWires = true; - this.force.x += -0.0003; - this.fill = "#333"; - } - //move mob to player - mech.calcLeg(Math.PI, -3); - Matter.Body.setPosition(this, { - x: mech.pos.x + mech.flipLegs * mech.knee.x - 5, - y: mech.pos.y + mech.knee.y - }) - } - //draw wire - ctx.beginPath(); - ctx.moveTo(wireX, wireY); - ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y); - ctx.lineWidth = 5; - ctx.lineCap = "butt"; - ctx.strokeStyle = "#333"; - ctx.stroke(); - ctx.lineCap = "round"; - }; - }, - wireFoot() { - //not a mob, just a graphic for level 1 - const breakingPoint = 1350 - mobs.spawn(breakingPoint, -100, 0, 2, "transparent"); - let me = mob[mob.length - 1]; - //touch nothing - me.collisionFilter.category = 0x010000; //act like a body - me.collisionFilter.mask = 0x000101; //only collide with map - me.g = 0.0003; //required for gravity - me.restitution = 0; - me.stroke = "transparent" - // me.inertia = Infinity; - me.freeOfWires = false; - // me.frictionStatic = 1; - // me.friction = 1; - me.frictionAir = 0.01; - - me.do = function () { - let wireX = -50 + 16; - let wireY = -1000; - - if (this.freeOfWires) { - this.gravity(); - } else { - if (mech.pos.x > breakingPoint) { - this.freeOfWires = true; - this.force.x += -0.0006; - this.fill = "#222"; - } - //move mob to player - mech.calcLeg(0, 0); - Matter.Body.setPosition(this, { - x: mech.pos.x + mech.flipLegs * mech.foot.x - 5, - y: mech.pos.y + mech.foot.y - 1 - }) - } - //draw wire - ctx.beginPath(); - ctx.moveTo(wireX, wireY); - ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y); - ctx.lineWidth = 5; - ctx.lineCap = "butt"; - ctx.strokeStyle = "#222"; - ctx.stroke(); - ctx.lineCap = "round"; - }; - }, - wireFootLeft() { - //not a mob, just a graphic for level 1 - const breakingPoint = 1325 - mobs.spawn(breakingPoint, -100, 0, 2, "transparent"); - let me = mob[mob.length - 1]; - //touch nothing - me.collisionFilter.category = 0x010000; //act like a body - me.collisionFilter.mask = 0x000101; //only collide with map - me.g = 0.0003; //required for gravity - me.restitution = 0; - me.stroke = "transparent" - // me.inertia = Infinity; - me.freeOfWires = false; - // me.frictionStatic = 1; - // me.friction = 1; - me.frictionAir = 0.01; - - me.do = function () { - let wireX = -50 + 26; - let wireY = -1000; - - if (this.freeOfWires) { - this.gravity(); - } else { - if (mech.pos.x > breakingPoint) { - this.freeOfWires = true; - this.force.x += -0.0005; - this.fill = "#333"; - } - //move mob to player - mech.calcLeg(Math.PI, -3); - Matter.Body.setPosition(this, { - x: mech.pos.x + mech.flipLegs * mech.foot.x - 5, - y: mech.pos.y + mech.foot.y - 1 - }) - } - //draw wire - ctx.beginPath(); - ctx.moveTo(wireX, wireY); - ctx.quadraticCurveTo(wireX, 0, this.position.x, this.position.y); - ctx.lineWidth = 5; - ctx.strokeStyle = "#333"; - ctx.lineCap = "butt"; - ctx.stroke(); - ctx.lineCap = "round"; - }; - }, - boost(x, y, height = 1000) { - spawn.mapVertex(x + 50, y + 35, "120 40 -120 40 -50 -40 50 -40"); - // level.addZone(x, y, 100, 30, "fling", {Vx:Vx, Vy: Vy}); - level.addQueryRegion(x, y - 20, 100, 20, "boost", [ - [player], body, mob, powerUp, bullet - ], -1.1 * Math.sqrt(Math.abs(height))); - let color = "rgba(200,0,255,"; - level.fillBG.push({ - x: x, - y: y - 25, - width: 100, - height: 25, - color: color + "0.2)" - }); - level.fillBG.push({ - x: x, - y: y - 55, - width: 100, - height: 55, - color: color + "0.1)" - }); - level.fillBG.push({ - x: x, - y: y - 120, - width: 100, - height: 120, - color: color + "0.05)" - }); - }, - laserZone(x, y, width, height, dmg) { - level.addZone(x, y, width, height, "laser", { - dmg - }); - level.fill.push({ - x: x, - y: y, - width: width, - height: height, - color: "#f00" - }); - }, - deathQuery(x, y, width, height) { - level.addQueryRegion(x, y, width, height, "death", [ - [player], mob - ]); - level.fill.push({ - x: x, - y: y, - width: width, - height: height, - color: "#f00" - }); - }, - platform(x, y, width, height) { - const size = 20; - spawn.mapRect(x, y + height, width, 30); - level.fillBG.push({ - x: x + width / 2 - size / 2, - y: y, - width: size, - height: height, - color: "#f0f0f3" - }); - }, - debris(x, y, width, number = Math.floor(3 + Math.random() * 11)) { - for (let i = 0; i < number; ++i) { - if (Math.random() < 0.15) { - powerUps.chooseRandomPowerUp(x + Math.random() * width, y); - } else { - const size = 18 + Math.random() * 25; - spawn.bodyRect(x + Math.random() * width, y, size * (0.6 + Math.random()), size * (0.6 + Math.random()), 1); - // body[body.length] = Bodies.rectangle(x + Math.random() * width, y, size * (0.6 + Math.random()), size * (0.6 + Math.random())); - } - } - }, - bodyRect(x, y, width, height, chance = 1, properties = { - friction: 0.05, - frictionAir: 0.01 - }) { - if (Math.random() < chance) body[body.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties); - }, - bodyVertex(x, y, vector, properties) { //adds shape to body array - body[body.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(vector), properties); - }, - mapRect(x, y, width, height, properties) { //adds rectangle to map array - map[map.length] = Bodies.rectangle(x + width / 2, y + height / 2, width, height, properties); - }, - mapVertex(x, y, vector, properties) { //adds shape to map array - map[map.length] = Matter.Bodies.fromVertices(x, y, Vertices.fromPath(vector), properties); - }, - //complex map templates - spawnBuilding(x, y, w, h, leftDoor, rightDoor, walledSide) { - this.mapRect(x, y, w, 25); //roof - this.mapRect(x, y + h, w, 35); //ground - if (walledSide === "left") { - this.mapRect(x, y, 25, h); //wall left - } else { - this.mapRect(x, y, 25, h - 150); //wall left - if (leftDoor) { - this.bodyRect(x + 5, y + h - 150, 15, 150, this.propsFriction); //door left - } - } - if (walledSide === "right") { - this.mapRect(x - 25 + w, y, 25, h); //wall right - } else { - this.mapRect(x - 25 + w, y, 25, h - 150); //wall right - if (rightDoor) { - this.bodyRect(x + w - 20, y + h - 150, 15, 150, this.propsFriction); //door right - } - } - }, - spawnStairs(x, y, num, w, h, stepRight) { - w += 50; - if (stepRight) { - for (let i = 0; i < num; i++) { - this.mapRect(x - (w / num) * (1 + i), y - h + (i * h) / num, w / num + 50, h - (i * h) / num + 50); - } - } else { - for (let i = 0; i < num; i++) { - this.mapRect(x + (i * w) / num, y - h + (i * h) / num, w / num + 50, h - (i * h) / num + 50); - } - } - }, - //pre-made property options************************************************************************************* - //************************************************************************************************************* - //Object.assign({}, propsHeavy, propsBouncy, propsNoRotation) //will combine properties into a new object - propsFriction: { - friction: 0.5, - frictionAir: 0.02, - frictionStatic: 1 - }, - propsFrictionMedium: { - friction: 0.15, - frictionStatic: 1 - }, - propsBouncy: { - friction: 0, - frictionAir: 0, - frictionStatic: 0, - restitution: 1 - }, - propsSlide: { - friction: 0.003, - frictionStatic: 0.4, - restitution: 0, - density: 0.002 - }, - propsLight: { - density: 0.001 - }, - propsOverBouncy: { - friction: 0, - frictionAir: 0, - frictionStatic: 0, - restitution: 1.05 - }, - propsHeavy: { - density: 0.01 //default density is 0.001 - }, - propsIsNotHoldable: { - isNotHoldable: true - }, - propsNoRotation: { - inertia: Infinity //prevents rotation - }, - propsHoist: { - inertia: Infinity, //prevents rotation - frictionAir: 0.001, - friction: 0.0001, - frictionStatic: 0, - restitution: 0, - isNotHoldable: true - // density: 0.0001 - }, - propsDoor: { - density: 0.001, //default density is 0.001 - friction: 0, - frictionAir: 0.03, - frictionStatic: 0, - restitution: 0 - }, - sandPaper: { - friction: 1, - frictionStatic: 1, - restitution: 0 - } -}; \ No newline at end of file diff --git a/style.css b/style.css deleted file mode 100644 index 57fd9cd..0000000 --- a/style.css +++ /dev/null @@ -1,237 +0,0 @@ -body { - font-family: "Helvetica", "Arial", sans-serif; - margin: 0; - overflow: hidden; - background-color: #fff; - user-select: none; - /*cursor: crosshair;*/ -} - -canvas { - position: absolute; - top: 0; - left: 0; - z-index: 0; -} - -#splash { - user-select: none; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: 2; -} - -*:focus { - outline: none; -} - -table { - border-collapse: collapse; - /* border: 1px solid #eee; */ - width: 360px; - /* background-color: #ddd; */ -} - -summary { - font-size: 1.2em; -} - -#controls { - position: absolute; - bottom: 0px; - left: 1px; - z-index: 12; - font-size: 1.3em; - /* background-color: #ccc; */ - /* border-radius: 5px; */ -} - -#controls-div { - padding: 10px; - border-radius: 8px; - background-color: #ddd; -} - -#dmg { - position: absolute; - z-index: 2; - width: 100%; - height: 100%; - display: none; - background-color: #f67; - opacity: 0; - transition: opacity 1s; -} - -#health-bg { - position: absolute; - top: 15px; - left: 15px; - height: 20px; - width: 300px; - background-color: #000; - opacity: 0.1; - z-index: 1; - pointer-events: none; - display: none; -} - -#health { - position: absolute; - top: 15px; - left: 15px; - height: 20px; - width: 0px; - transition: width 1s ease-out; - opacity: 0.6; - z-index: 2; - pointer-events: none; - background-color: #f00; -} - -.low-health { - animation: blink 250ms infinite alternate; -} - -@keyframes blink { - from { - opacity: 0.9; - } - - to { - opacity: 0.2; - } -} - -#fade-out { - position: absolute; - z-index: 2; - width: 100%; - height: 100%; - background-color: #fff; - opacity: 0; - transition: opacity 5s; - pointer-events: none; -} - -#guns { - position: absolute; - top: 40px; - left: 15px; - z-index: 2; - font-size: 23px; - color: #111; - background-color: rgba(255, 255, 255, 0.4); - user-select: none; - pointer-events: none; - padding: 0px 5px 0px 5px; - border-radius: 5px; - /*border: 2px solid rgba(0, 0, 0, 0.4);*/ -} - -#mods { - position: absolute; - top: 15px; - right: 15px; - z-index: 2; - font-size: 20px; - color: #000; - text-align: right; - opacity: 0.5; - line-height: 140%; - background-color: rgba(255, 255, 255, 0.4); - user-select: none; - pointer-events: none; - padding: 0px 5px 0px 5px; - border-radius: 5px; - /*border: 2px solid rgba(0, 0, 0, 0.4);*/ -} - -#text-log { - position: absolute; - top: 20px; - left: 0; - width: 100%; - line-height: 150%; - text-align: center; - z-index: 2; - font-size: 1.25em; - color: #000; - opacity: 0; - transition: opacity 0.5s; - pointer-events: none; - user-select: none; -} - -.box { - padding: 3px 8px 3px 8px; - border: 2px solid #444; - border-radius: 4px; - background-color: rgba(255, 255, 255, 0.5); -} - -.faded { - opacity: 0.5; - font-size: 85%; -} - -.wrapper { - display: grid; - grid-template-columns: 360px 10px; - align-self: center; - justify-content: center; -} - -.grid-box { - align-self: center; - justify-self: center; -} - -.mouse { - color: #ccc; - position: relative; - padding: 37px 30px 37px 30px; - border-radius: 25px; - border: 2px solid #444; - background-color: rgba(255, 255, 255, 0.5); -} - -.mouse:after { - content: ""; - position: absolute; - z-index: 1; - top: 4px; - left: 26px; - border-radius: 25px; - /* background: #444; */ - border: 2px solid #444; - - width: 4px; - height: 20px; - border-radius: 10px / 25px; -} - -.mouse-line { - position: relative; - top: 30px; - left: 0px; -} - -.mouse-line:after { - content: ""; - position: absolute; - z-index: 1; - top: -35px; - left: -30px; - width: 60px; - height: 2px; - border-radius: 8px; - background: #444; -} - -.right { - text-align: right; -} \ No newline at end of file