diff --git a/index.html b/index.html index 8f8db42..c668ee9 100644 --- a/index.html +++ b/index.html @@ -1,488 +1,488 @@ - - - - - - - - - - - - - - - - - - - n-gon - - - - - - -
-
-
-
-
-
-
-
- - - - - - - - - - - - - - - - - -
- - - - custom - - - - - -
-
- settings -
- - -
- - -
- - -
-
-
- - -
-
- about -
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
FIREleft mouse
FIELDright mouse / spacebar
MOVEWASD / arrows
GUNSQ / E / mouse wheel
ZOOM+ / -
PAUSEP
-
-
- - - - - - - - Chat about n-gon in the discord.
Let me know about ideas, or bugs. -
-
-
- - - - - Github - - - - Github hosts the source code for n-gon.
It's written in JavaScript, CSS, and HTML. - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Q - E - W - S - D - A - - - - - - - - - - - - - - switch - guns - move - fire - field - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + n-gon + + + + + + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + +
+ + + + custom + + + + + +
+
+ settings +
+ + +
+ + +
+ + +
+
+
+ + +
+
+ about +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
FIREleft mouse
FIELDright mouse / spacebar
MOVEWASD / arrows
GUNSQ / E / mouse wheel
ZOOM+ / -
PAUSEP
+
+
+ + + + + + + + Chat about n-gon in the discord.
Let me know about ideas, or bugs. +
+
+
+ + + + + Github + + + + Github hosts the source code for n-gon.
It's written in JavaScript, CSS, and HTML. + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Q + E + W + S + D + A + + + + + + + + + + + + + + switch + guns + move + fire + field + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/js/bullets.js b/js/bullets.js index 53954c6..12ce330 100644 --- a/js/bullets.js +++ b/js/bullets.js @@ -25,6 +25,7 @@ const b = { isModLowHealthDmg: null, isModFarAwayDmg: null, isModMonogamy: null, + isModMassEnergy: null, setModDefaults() { b.modCount = 0; b.modFireRate = 1; @@ -47,6 +48,7 @@ const b = { b.isModLowHealthDmg = false; b.isModFarAwayDmg = false; b.isModMonogamy = false; + b.isModMassEnergy = false; mech.Fx = 0.015; mech.jumpForce = 0.38; mech.throwChargeRate = 2; @@ -116,7 +118,7 @@ const b = { }, { name: "zoospore vector", - description: "enemies can discharge spores on death
spores seek out enemies", + description: "enemies can discharge spores on death
spores seek out enemies", have: false, //7 effect: () => { //good late game maybe? b.modSpores = 0.20; @@ -148,7 +150,7 @@ const b = { }, { name: "fluoroantimonic acid", - description: "each bullet does extra chemical damage", + description: "each bullet does extra chemical damage
instant damage, unaffected by momentum", have: false, //11 effect: () => { //good with guns that fire many bullets at low speeds, minigun, drones, junk-bots, shotgun, superballs, wavebeam b.modExtraDmg = 0.1 @@ -156,7 +158,7 @@ const b = { }, { name: "annihilation", - description: "after touching enemies, they are annihilated", + description: "after touching enemies, they are annihilated
doesn't trigger health or energy transfer", have: false, //12 effect: () => { //good with mods that heal: superconductive healing, entropy transfer b.modAnnihilation = true @@ -230,6 +232,14 @@ const b = { b.isModMonogamy = true } }, + { + name: "mass-energy equivalence", + description: "change the mass of power ups into energy
power ups fill your energy and heal for +3%", + have: false, //21 + effect: () => { // good with long term planning + b.isModMassEnergy = true // used in mech.usePowerUp + } + }, ], giveMod(i) { b.mods[i].effect(); //give specific mod @@ -1044,7 +1054,7 @@ const b = { name: "shotgun", //5 description: "fire a burst of short range bullets
crouch to reduce recoil", ammo: 0, - ammoPack: 8, + ammoPack: 9, have: false, isStarterGun: true, fire() { @@ -1055,7 +1065,7 @@ const b = { const me = bullet.length; const dir = mech.angle + (Math.random() - 0.5) * (mech.crouch ? 0.22 : 0.7) 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, 40 + Math.random() * 11, dir, me); //cd , speed + b.fireProps(mech.crouch ? 65 : 45, 40 + Math.random() * 11, dir, me); //cd , speed bullet[me].endCycle = game.cycle + Math.floor(55 * b.isModBulletsLastLonger); bullet[me].frictionAir = 0.03; bullet[me].do = function () { @@ -1070,7 +1080,7 @@ const b = { } }, { name: "fléchettes", //6 - description: "fire a flight of needles
accurate at long range", + description: "fire a flight of long range needles", ammo: 0, ammoPack: 25, have: false, @@ -1218,9 +1228,9 @@ const b = { fire() { b.muzzleFlash(30); const totalBullets = 5 - const angleStep = (mech.crouch ? 0.06 : 0.15) / totalBullets - const SPEED = mech.crouch ? 30 : 25 - const CD = mech.crouch ? 45 : 11 + const angleStep = (mech.crouch ? 0.06 : 0.25) / totalBullets + const SPEED = mech.crouch ? 29 : 25 + const CD = mech.crouch ? 30 : 11 const END = Math.floor((mech.crouch ? 30 : 18) * b.isModBulletsLastLonger); let dir = mech.angle - angleStep * totalBullets / 2; const side1 = 17 * b.modBulletSize @@ -1236,7 +1246,7 @@ const b = { bullet[me].restitution = 0; bullet[me].friction = 1; // bullet[me].dmg = 0.15; - bullet[me].explodeRad = (mech.crouch ? 70 : 45) + (Math.random() - 0.5) * 50; + bullet[me].explodeRad = (mech.crouch ? 70 : 50) + (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 @@ -1461,7 +1471,7 @@ const b = { } }, { name: "spores", //12 - description: "fire orbs that discharge spores
spores seek out enemies", + description: "fire orbs that discharge spores
spores seek out enemies", ammo: 0, ammoPack: 5, have: false, @@ -1677,17 +1687,16 @@ const b = { fire() { const dir = mech.angle; const me = bullet.length; - const RADIUS = (22 + 5 * Math.random()) * b.modBulletSize - const LENGTH = 0.7 + Math.random() - - bullet[me] = Bodies.rectangle(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), RADIUS * LENGTH, RADIUS / LENGTH, { + const RADIUS = (13 + 10 * Math.random()) * b.modBulletSize //(22 + 10 * Math.random()) * b.modBulletSize + bullet[me] = Bodies.polygon(mech.pos.x + 30 * Math.cos(mech.angle), mech.pos.y + 30 * Math.sin(mech.angle), 3, RADIUS, { angle: dir, friction: 0, frictionStatic: 0, - restitution: 0.8, + restitution: 0.5 + 0.5 * Math.random(), dmg: b.modExtraDmg, // 0.14 //damage done in addition to the damage from momentum minDmgSpeed: 2, lookFrequency: 37 + Math.floor(27 * Math.random()), + acceleration: 0.0015 + 0.0013 * Math.random(), range: 500 + Math.floor(200 * Math.random()), endCycle: Infinity, classType: "bullet", @@ -1705,8 +1714,7 @@ const b = { this.lockedOn = null; let closeDist = this.range; for (let i = 0, len = mob.length; i < len; ++i) { - const TARGET_VECTOR = Matter.Vector.sub(this.vertices[0], mob[i].position) - const DIST = Matter.Vector.magnitude(TARGET_VECTOR); + const DIST = Matter.Vector.magnitude(Matter.Vector.sub(this.vertices[0], mob[i].position)); if (DIST - mob[i].radius < closeDist && Matter.Query.ray(map, this.vertices[0], mob[i].position).length === 0 && Matter.Query.ray(body, this.vertices[0], mob[i].position).length === 0) { @@ -1716,13 +1724,12 @@ const b = { } } - const FIELD_DRAIN = 0.001 + const FIELD_DRAIN = 0.0016 if (this.lockedOn && this.lockedOn.alive && mech.fieldMeter > FIELD_DRAIN) { //hit target with laser mech.fieldMeter -= FIELD_DRAIN //make sure you can still see target - const TARGET_VECTOR = Matter.Vector.sub(this.vertices[0], this.lockedOn.position) - const DIST = Matter.Vector.magnitude(TARGET_VECTOR); + const DIST = Matter.Vector.magnitude(Matter.Vector.sub(this.vertices[0], this.lockedOn.position)); if (DIST - this.lockedOn.radius < this.range + 150 && Matter.Query.ray(map, this.vertices[0], this.lockedOn.position).length === 0 && Matter.Query.ray(body, this.vertices[0], this.lockedOn.position).length === 0) { @@ -1744,7 +1751,7 @@ const b = { ctx.beginPath(); ctx.moveTo(this.vertices[0].x, this.vertices[0].y); ctx.lineTo(this.lockedOn.vertices[bestVertex].x, this.lockedOn.vertices[bestVertex].y); - ctx.strokeStyle = "rgb(255,0,40)"; + ctx.strokeStyle = "#f00"; ctx.lineWidth = "2" ctx.lineDashOffset = 300 * Math.random() ctx.setLineDash([50 + 100 * Math.random(), 100 * Math.random()]); @@ -1752,17 +1759,19 @@ const b = { ctx.setLineDash([0, 0]); ctx.beginPath(); ctx.arc(this.lockedOn.vertices[bestVertex].x, this.lockedOn.vertices[bestVertex].y, Math.sqrt(dmg) * 100, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(255,0,40,0.7)" //"#f00" + ctx.fillStyle = "#f00"; ctx.fill(); } } const distanceToPlayer = Matter.Vector.magnitude(Matter.Vector.sub(this.position, mech.pos)) if (distanceToPlayer > this.range * 0.2) { //if far away move towards player - this.force = Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(mech.pos, this.position)), this.mass * 0.002) + this.force = Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(mech.pos, this.position)), this.mass * this.acceleration) this.frictionAir = 0.02 } else { //close to player this.frictionAir = 0 + //add player's velocity + Matter.Body.setVelocity(this, Matter.Vector.add(Matter.Vector.mult(this.velocity, 1), Matter.Vector.mult(player.velocity, 0.02))); } } }) diff --git a/js/game.js b/js/game.js index b6bdb20..b2eb8e8 100644 --- a/js/game.js +++ b/js/game.js @@ -201,6 +201,7 @@ const game = { } }, switchGun() { + if (b.modNoAmmo) b.modNoAmmo = 1 //this prevents hacking the mod by switching guns b.activeGun = b.inventory[b.inventoryGun]; game.updateGunHUD(); game.boldActiveGunHUD(); diff --git a/js/level.js b/js/level.js index 219b33a..186d1ad 100644 --- a/js/level.js +++ b/js/level.js @@ -15,8 +15,8 @@ const level = { if (level.levelsCleared === 0) { // game.difficulty = 6; //for testing to simulate possible mobs spawns // b.giveGuns(14) - // mech.fieldUpgrades[2].effect(); - // b.giveMod(5) + // mech.fieldUpgrades[7].effect(); + // b.giveMod(2) this.intro(); //starting level // this.testingMap(); @@ -107,11 +107,11 @@ const level = { // spawn.bodyRect(-135, -50, 50, 50); // spawn.bodyRect(-140, -100, 50, 50); // powerUps.spawn(420, -400, "ammo", false); - powerUps.spawn(450, -400, "mod", false, 6); + // powerUps.spawn(450, -400, "mod", false, 6); // powerUps.spawn(450, -400, "mod", false); // spawn.bodyRect(-45, -100, 40, 50); - spawn.spawner(800, -1150); - spawn.groupBoss(-600, -550); + spawn.spinner(800, -1150); + // spawn.groupBoss(-600, -550); // spawn.hopper(800, -150); // spawn.beamer(800, -150); // spawn.grower(800, -250); diff --git a/js/mobs.js b/js/mobs.js index e464407..309a52a 100644 --- a/js/mobs.js +++ b/js/mobs.js @@ -225,11 +225,34 @@ const mobs = { // ctx.stroke(); // return targetPos; }, + + hacked() { //set this.hackedTarget variable before running this method + //find a new target + if (!(game.cycle % this.seePlayerFreq)) { + this.hackedTarget = null + for (let i = 0, len = mob.length; i < len; i++) { + if (mob[i] !== this) { + // const DIST = Matter.Vector.magnitude(Matter.Vector.sub(this.position, mob[j])); + if (Matter.Query.ray(map, this.position, mob[i].position).length === 0 && + Matter.Query.ray(body, this.position, mob[i].position).length === 0) { + this.hackedTarget = mob[i] + } + } + } + } + + //acceleration towards targets + if (this.hackedTarget) { + this.force = Matter.Vector.mult(Matter.Vector.normalise(Matter.Vector.sub(this.hackedTarget.position, this.position)), this.mass * 0.0015) + } + + }, + 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 (this.distanceToPlayer() < this.laserRange && !mech.isStealth) { //if (Math.random()>0.2 && this.seePlayer.yes && this.distanceToPlayer2()<800000) { if (b.isModTempResist) { mech.damage(0.00006 * game.dmgScale); @@ -320,7 +343,7 @@ const mobs = { }; vertexCollision(this.position, look, map); vertexCollision(this.position, look, body); - vertexCollision(this.position, look, [player]); + if (!mech.isStealth) vertexCollision(this.position, look, [player]); // hitting player if (best.who === player) { if (b.isModTempResist) { diff --git a/js/player.js b/js/player.js index 2195083..384bd27 100644 --- a/js/player.js +++ b/js/player.js @@ -517,6 +517,10 @@ const mech = { powerUp[i].effect(); Matter.World.remove(engine.world, powerUp[i]); powerUp.splice(i, 1); + if (b.isModMassEnergy) { + mech.fieldMeter = 1; + mech.addHealth(0.03); + } }, drawLeg(stroke) { // if (game.mouseInGame.x > this.pos.x) { @@ -1512,5 +1516,75 @@ const mech = { } } }, + // { + // name: "code injection field", + // description: "capture an enemy in your field for 3 seconds
rewrite thier behavior to target your enemies", + // effect: () => { + // mech.fieldMode = 7; + // mech.fieldText(); + // mech.setHoldDefaults(); + // mech.hackProgress = 0; + // // 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.hackProgress = 0 + // mech.drawHold(mech.holdingTarget); + // mech.holding(); + // mech.throw(); + // } else if ((keys[32] || game.mouseDownRight) && mech.fieldCDcycle < mech.cycle) { + // const DRAIN = 0.0005 + // if (mech.fieldMeter > DRAIN) { + // mech.fieldMeter -= DRAIN; + + // //try to hack a mob + // for (let i = 0, len = mob.length; i < len; ++i) { + // if ( + // Matter.Vector.magnitude(Matter.Vector.sub(mob[i].position, this.pos)) < this.grabRange && + // this.lookingAt(mob[i]) && + // Matter.Query.ray(map, mob[i].position, this.pos).length === 0 + // ) { + // if (mech.hackProgress > 180) { //hack the mob + // mech.fieldMeter = 0; + // mob[i].hackedTarget = null; + // mob[i].seePlayerFreq = Math.round((30 + 30 * Math.random()) * game.lookFreqScale) + // mob[i].do = function () { + // this.healthBar(); + // this.hacked(); + // } + // } else { //hold the mob still + // mech.hackProgress++ + // range = this.grabRange * 0.9 + // Matter.Body.setPosition(mob[i], { + // x: mech.pos.x + range * Math.cos(mech.angle), + // y: mech.pos.y + range * Math.sin(mech.angle), + // }); + // Matter.Body.setVelocity(mob[i], player.velocity); + // } + + // } + // } + + + // mech.pushBodyFacing(); + // mech.drawField(); + // mech.grabPowerUp(); + // mech.lookForPickUp(); + // } else { + // mech.hackProgress = 0 + // 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.hackProgress = 0 + // } else { + // mech.hackProgress = 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() + // } + // } + // }, ], }; \ No newline at end of file diff --git a/js/spawn.js b/js/spawn.js index b1ad4fe..30fc235 100644 --- a/js/spawn.js +++ b/js/spawn.js @@ -12,14 +12,13 @@ const spawn = { "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", + allowedBossList: ["chaser", "spinner", "striker", "springer", "laser", "focuser", "beamer", "exploder", "spawner", "shooter"], 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 @@ -132,6 +131,7 @@ const spawn = { let me = mob[mob.length - 1]; me.accelMag = 0.0005 * game.accelScale; me.memory = 60; + me.seeAtDistance2 = 1400000 //1200 vision range Matter.Body.setDensity(me, 0.0005) // normal density is 0.001 // this reduces life by half and decreases knockback me.do = function () { @@ -140,92 +140,92 @@ const spawn = { this.attraction(); }; }, - healer(x, y, radius = 20) { - 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 + // healer(x, y, radius = 20) { + // 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(); + // me.do = function () { + // this.healthBar(); - if (!(game.cycle % this.lookFrequency)) { - //slow self heal - this.health += 0.02; - if (this.health > 1) this.health = 1; + // 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] - } - } - } - } + // //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; - }; + // //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); - } + // 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]; @@ -304,27 +304,27 @@ const spawn = { 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(); - }; - }, + // 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]; @@ -388,12 +388,9 @@ const spawn = { 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; + const mag = this.radius * 2.5 + 50; + ctx.strokeStyle = "rgba(0,0,0,0.2)"; + ctx.lineWidth = 3; ctx.setLineDash([10, 20]); //30 const dir = Matter.Vector.add(this.position, Matter.Vector.mult(this.burstDir, mag)); ctx.beginPath(); @@ -455,7 +452,7 @@ const spawn = { this.healthBar(); //when player is inside event horizon - if (Matter.Vector.magnitude(Matter.Vector.sub(this.position, player.position)) < eventHorizon) { + if (Matter.Vector.magnitude(Matter.Vector.sub(this.position, player.position)) < eventHorizon && !mech.isStealth) { mech.damage(0.00015 * game.dmgScale); if (mech.fieldMeter > 0.1) mech.fieldMeter -= 0.007 @@ -545,7 +542,7 @@ const spawn = { 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) { + if (Matter.Vector.magnitude(Matter.Vector.sub(this.position, player.position)) < eventHorizon && !mech.isStealth) { mech.damage(0.00015 * game.dmgScale); if (mech.fieldMeter > 0.1) mech.fieldMeter -= 0.007 const angle = Math.atan2(player.position.y - this.position.y, player.position.x - this.position.x); @@ -614,13 +611,9 @@ const spawn = { 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; @@ -645,11 +638,7 @@ const spawn = { 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.fillStyle = `rgba(0,0,255,${Math.max(0,0.3*r/targetDist)})` ctx.fill(); } } else { @@ -801,46 +790,46 @@ const spawn = { } }; }, - 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; - } - } - }; - }, + // 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"); diff --git a/style.css b/style.css index d3f60a9..4ce042d 100644 --- a/style.css +++ b/style.css @@ -1,374 +1,368 @@ -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; */ -} - -th { - text-align: left; -} - -summary { - font-size: 1.2em; -} - -.SVG-button { - border: 2px #333 solid; - border-radius: 9px; - background-color: #fff; -} - -.SVG-button:hover { - background-color: #efeff5; -} - -#build-button { - position: absolute; - top: 3px; - right: 3px; - z-index: 12; -} - -#build-grid { - padding: 10px; - margin: 0px; - border: 0px; - /* border-radius: 8px; */ - background-color: #c4ccd8; - /* #b6bfca; */ - - display: none; - /* display: grid; */ - grid-template-columns: repeat(auto-fit, minmax(292px, 1fr)); - grid-auto-rows: minmax(auto, auto); - grid-gap: 15px; - - position: relative; - bottom: 0px; - /* left: 0px; */ - z-index: 12; - font-size: 1.3em; -} - -.build-grid-module { - /* box-shadow: 0px 1px 4px #234; */ - padding: 7px; - /* margin: 4px; */ - line-height: 150%; - border-radius: 6px; - background: #fff; - font-size: 0.65em; - /* display: flex; */ -} - -.build-grid-module:hover { - background-color: #efeff5; -} - -.gun-module { - background: #d5dde5; -} - -.field-module { - background: #bde; -} - -.mod-module { - background: #fdf; -} - - -/* #build { - position: absolute; - bottom: 0px; - right: 1px; - z-index: 12; - font-size: 1.3em; -} */ -#settings { - position: absolute; - bottom: 0px; - right: 1px; - z-index: 12; - font-size: 1.5em; -} - -#controls { - position: absolute; - bottom: 0px; - left: 1px; - z-index: 12; - font-size: 1.5em; -} - -#details-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: 1; - transition: opacity 3s; - 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);*/ -} - -#field { - position: absolute; - top: 15px; - right: 15px; - z-index: 2; - font-size: 23px; - color: #000; - text-align: right; - opacity: 0.7; - line-height: 140%; - background-color: rgba(190, 210, 245, 0.25); - 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: 60px; - right: 15px; - z-index: 2; - font-size: 20px; - color: #000; - text-align: right; - opacity: 0.35; - 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%; */ - - z-index: 2; - position: absolute; - bottom: 20px; - left: 20px; - /* left: 50%; */ - /* transform: translate(-50%, 0); */ - - padding: 10px; - border-radius: 10px; - - /* text-align: center; */ - line-height: 150%; - font-size: 1.25em; - color: #000; - background-color: rgba(255, 255, 255, 0.23); - - opacity: 0; - transition: opacity 0.5s; - pointer-events: none; - user-select: none; -} - -em { - opacity: 0.7; -} - -.mouse-icon { - margin-bottom: -20px; -} - -.color-f { - color: #0ad; - letter-spacing: 1px; -} - -.color-d { - color: #f03; - letter-spacing: 1px; -} - -.color-h { - color: #0b7; - letter-spacing: 1px; -} - -.color-e { - color: #d60; - letter-spacing: 1px; -} - -.color-s { - color: #055; - font-weight: 900; - letter-spacing: 2px; -} - -.faded { - opacity: 0.7; - font-size: 90%; -} - -.circle { - width: 20px; - height: 20px; - border-radius: 50%; - display: inline-block; - margin-bottom: -2px; -} - -.circle-grid { - width: 20px; - height: 20px; - border-radius: 50%; - display: inline-block; - margin-bottom: -4px; -} - -.field { - background: #0cf; -} - -.mod { - background: #96e; -} - -.gun { - background: #149; -} - -.heal { - background: #0d9; -} - -.box { - padding: 3px 8px 3px 8px; - border: 2px solid #444; - border-radius: 4px; - background-color: rgba(255, 255, 255, 0.5); -} - -.wrapper { - display: grid; - grid-template-columns: 360px 10px; - align-self: center; - justify-content: center; -} - -.grid-box { - align-self: center; - justify-self: center; -} - -.right { - text-align: right; +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; */ +} + +th { + text-align: left; +} + +summary { + font-size: 1.2em; +} + +.SVG-button { + border: 2px #333 solid; + border-radius: 9px; + background-color: #fff; +} + +.SVG-button:hover { + background-color: #efeff5; +} + +#build-button { + position: absolute; + top: 3px; + right: 3px; + z-index: 12; +} + +#build-grid { + padding: 10px; + margin: 0px; + border: 0px; + /* border-radius: 8px; */ + background-color: #c4ccd8; + /* #b6bfca; */ + + display: none; + /* display: grid; */ + grid-template-columns: repeat(auto-fit, minmax(292px, 1fr)); + grid-auto-rows: minmax(auto, auto); + grid-gap: 15px; + + position: relative; + bottom: 0px; + /* left: 0px; */ + z-index: 12; + font-size: 1.3em; +} + +.build-grid-module { + /* box-shadow: 0px 1px 4px #234; */ + padding: 7px; + /* margin: 4px; */ + line-height: 150%; + border-radius: 6px; + background: #fff; + font-size: 0.65em; + /* display: flex; */ +} + +.build-grid-module:hover { + background-color: #efeff5; +} + +.gun-module { + background: #d5dde5; +} + +.field-module { + background: #bde; +} + +.mod-module { + background: #fdf; +} + + +/* #build { + position: absolute; + bottom: 0px; + right: 1px; + z-index: 12; + font-size: 1.3em; +} */ +#settings { + position: absolute; + bottom: 0px; + right: 1px; + z-index: 12; + font-size: 1.5em; +} + +#controls { + position: absolute; + bottom: 0px; + left: 1px; + z-index: 12; + font-size: 1.5em; +} + +#details-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: 1; + transition: opacity 3s; + 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);*/ +} + +#field { + position: absolute; + top: 15px; + right: 15px; + z-index: 2; + font-size: 23px; + color: #000; + text-align: right; + opacity: 0.7; + line-height: 140%; + background-color: rgba(190, 210, 245, 0.25); + 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: 60px; + right: 15px; + z-index: 2; + font-size: 20px; + color: #000; + text-align: right; + opacity: 0.35; + 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%; */ + + z-index: 2; + position: absolute; + bottom: 20px; + left: 20px; + /* left: 50%; */ + /* transform: translate(-50%, 0); */ + + padding: 10px; + border-radius: 10px; + + /* text-align: center; */ + line-height: 150%; + font-size: 1.25em; + color: #000; + background-color: rgba(255, 255, 255, 0.23); + + opacity: 0; + transition: opacity 0.5s; + pointer-events: none; + user-select: none; +} + +em { + opacity: 0.7; +} + +.mouse-icon { + margin-bottom: -20px; +} + +.color-f { + color: #0ad; + letter-spacing: 1px; +} + +.color-d { + color: #f03; + letter-spacing: 1px; +} + +.color-h { + color: #0b7; + letter-spacing: 1px; +} + +.color-e { + color: #d60; + letter-spacing: 1px; +} + +.faded { + opacity: 0.7; + font-size: 90%; +} + +.circle { + width: 20px; + height: 20px; + border-radius: 50%; + display: inline-block; + margin-bottom: -2px; +} + +.circle-grid { + width: 20px; + height: 20px; + border-radius: 50%; + display: inline-block; + margin-bottom: -4px; +} + +.field { + background: #0cf; +} + +.mod { + background: #96e; +} + +.gun { + background: #149; +} + +.heal { + background: #0d9; +} + +.box { + padding: 3px 8px 3px 8px; + border: 2px solid #444; + border-radius: 4px; + background-color: rgba(255, 255, 255, 0.5); +} + +.wrapper { + display: grid; + grid-template-columns: 360px 10px; + align-self: center; + justify-content: center; +} + +.grid-box { + align-self: center; + justify-self: center; +} + +.right { + text-align: right; } \ No newline at end of file