From 323333172238878514ce130eec43ecfb71364516 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Mon, 21 Aug 2017 16:12:20 -0400 Subject: [PATCH 01/16] Fix overlap in the "tower placement restriction visualization" by drawing it for each tile, instead of for each tower --- index.js | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index e3b580e..122eeeb 100644 --- a/index.js +++ b/index.js @@ -575,7 +575,7 @@ window.onload = function () { let index = parseInt(i) let y = Math.floor(index / Maps.width) let x = Math.floor(index % Maps.height) - + if (tile === 1) { ctx.fillStyle = '#fdd' } else if (tile === 2) { @@ -587,6 +587,11 @@ window.onload = function () { } ctx.fillRect(x * mt, y * mt, mt, mt) + + if(tile != 1 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { + ctx.fillStyle = 'rgba(255, 0, 0, 0.45)' + ctx.fillRect(x * mt, y * mt, mt, mt) + } } /* for (let i in Game.map.pathgen) { @@ -599,28 +604,6 @@ window.onload = function () { let tower = Game.towers[i] ctx.fillStyle = tower.icon ctx.fillRect(tower.x * mt + 2, tower.y * mt + 2, 28, 28) - - if (Game.state === 2 && Game.tower) { - // tower placement restriction visualization - for (let i = 0; i < 4; i++) { - let ax = tower.x - let ay = tower.y - if (i == 0) { - ax -= 1 - } else if (i == 1) { - ax += 1 - } else if (i == 2) { - ay -= 1 - } else if (i == 3) { - ay += 1 - } - - if (ax < 0 || ay < 0 || ay > Maps.height || ax > Maps.width) continue - if (getTileIn(Game.map.tiles, ax, ay) !== 0) continue - ctx.fillStyle = 'rgba(255, 0, 0, 0.45)' - ctx.fillRect(ax * mt, ay * mt, mt, mt) - } - } } for (let i in Game.enemies) { From f8d532b4aec6abc986b1d029256e2580951b1fc9 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Mon, 21 Aug 2017 16:19:57 -0400 Subject: [PATCH 02/16] Draw the background color seperately instead of drawing each grass tile individually --- index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index e3b580e..1484b99 100644 --- a/index.js +++ b/index.js @@ -568,13 +568,15 @@ window.onload = function () { function render () { let mt = Maps.tile - ctx.clearRect(0, 0, canvas.width, canvas.height) + ctx.fillStyle = '#0fa' + ctx.fillRect(0, 0, canvas.width, canvas.height) for (let i in Game.map.tiles) { let tile = Game.map.tiles[i] let index = parseInt(i) let y = Math.floor(index / Maps.width) let x = Math.floor(index % Maps.height) + var draw_tile = true if (tile === 1) { ctx.fillStyle = '#fdd' @@ -583,10 +585,12 @@ window.onload = function () { } else if (tile === 3) { ctx.fillStyle = '#f3a' } else { - ctx.fillStyle = '#0fa' + draw_tile = false } - ctx.fillRect(x * mt, y * mt, mt, mt) + if(draw_tile) { + ctx.fillRect(x * mt, y * mt, mt, mt) + } } /* for (let i in Game.map.pathgen) { From efa6939d054adf9b7ffa20e7725982ec183cfd6d Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Mon, 21 Aug 2017 14:19:37 -0400 Subject: [PATCH 03/16] Added ability to sell towers (right click) --- index.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index e3b580e..6521cbe 100644 --- a/index.js +++ b/index.js @@ -33,7 +33,8 @@ window.onload = function () { pace: 1, wave: 0, waveTimer: 0, - tower: 'simple' + tower: 'simple', + sellRatio: .8 } /** @@ -533,6 +534,16 @@ window.onload = function () { }, tower)) } + function sellTower (x, y) { + var tower = getTowerAt(x, y) + if(tower) { + Game.money += tower.cost * Game.sellRatio + return Game.towers.splice(Game.towers.indexOf(tower), 1) + }else{ + return null + } + } + function update (dt) { fpsCount++ fpsCount %= 20 @@ -729,6 +740,13 @@ window.onload = function () { clickBtn() }) + + canvas.addEventListener('contextmenu', (e) => { + if (Game.state === 2 && mX < Maps.width && mY < Maps.height && + sellTower(mX, mY)) { + e.preventDefault() + } + }) canvas.addEventListener('mousemove', (e) => { if (e.changedTouches) { From dcf51a74ae461012f992f903c31c7aa61d22fccf Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Mon, 21 Aug 2017 17:02:21 -0400 Subject: [PATCH 04/16] Hide tower restriction visualization when not in build phase --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 122eeeb..d983944 100644 --- a/index.js +++ b/index.js @@ -588,7 +588,7 @@ window.onload = function () { ctx.fillRect(x * mt, y * mt, mt, mt) - if(tile != 1 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { + if(Game.state == 2 && tile != 1 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { ctx.fillStyle = 'rgba(255, 0, 0, 0.45)' ctx.fillRect(x * mt, y * mt, mt, mt) } From c66fcf217e930c98ec9d565d7321de94619e5290 Mon Sep 17 00:00:00 2001 From: Taizo 'Tsa6' Simpson Date: Mon, 21 Aug 2017 17:07:46 -0400 Subject: [PATCH 05/16] Fixed visualization showing on some non-grass tiles --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index d983944..dc4fe6a 100644 --- a/index.js +++ b/index.js @@ -588,7 +588,7 @@ window.onload = function () { ctx.fillRect(x * mt, y * mt, mt, mt) - if(Game.state == 2 && tile != 1 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { + if(Game.state == 2 && tile == 0 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { ctx.fillStyle = 'rgba(255, 0, 0, 0.45)' ctx.fillRect(x * mt, y * mt, mt, mt) } From 700adb228c0d2c45fc7b35c886890f2035124fb8 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 10:53:36 +0300 Subject: [PATCH 06/16] fix some conflicts for real --- index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/index.js b/index.js index 22d3084..1a3e4f2 100644 --- a/index.js +++ b/index.js @@ -602,6 +602,11 @@ window.onload = function () { if(draw_tile) { ctx.fillRect(x * mt, y * mt, mt, mt) } + + if(Game.state == 2 && tile == 0 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { + ctx.fillStyle = 'rgba(255, 0, 0, 0.45)' + ctx.fillRect(x * mt, y * mt, mt, mt) + } } /* for (let i in Game.map.pathgen) { From 3f8e517a2d495689f5e4137b4cdc761dc7d53f18 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 11:09:55 +0300 Subject: [PATCH 07/16] sell text --- index.js | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 1a3e4f2..0cca728 100644 --- a/index.js +++ b/index.js @@ -26,6 +26,7 @@ window.onload = function () { enemies: [], towers: [], particles: [], + selltext: [], map: null, health: 100, money: 100, @@ -448,6 +449,19 @@ window.onload = function () { } } + function tickSellText () { + for (let i in Game.selltext) { + let txt = Game.selltext[i] + txt.tick++ + txt.tick %= 30 + if (txt.tick === 0) { + Game.selltext.splice(i, 1) + } + + txt.y -= 0.05 + } + } + // Total enemy spawn count is used to determine that the round is over // Local (in-function) determines how many there are left to spawn as ordered by the function call function addEnemies (cnt, type) { @@ -537,7 +551,14 @@ window.onload = function () { function sellTower (x, y) { var tower = getTowerAt(x, y) if(tower) { - Game.money += tower.cost * Game.sellRatio + let amount = tower.cost * Game.sellRatio + Game.money += amount + Game.selltext.push({ + x: x, + y: y, + amount: amount, + tick: 0 + }) return Game.towers.splice(Game.towers.indexOf(tower), 1) }else{ return null @@ -554,6 +575,7 @@ window.onload = function () { tickTowers() updateEnemyMovements() tickParticles() + tickSellText() for (let i in Components) { let btn = Components[i] @@ -660,6 +682,13 @@ window.onload = function () { } } + for (let i in Game.selltext) { + let txt = Game.selltext[i] + ctx.font = '12px Helvetica' + ctx.fillStyle = '#0f0' + ctx.fillText('+ $' + txt.amount, txt.x * mt, txt.y * mt) + } + ctx.fillStyle = '#996633' ctx.fillRect(640, 0, 240, 640) From b1d9f469bcc73b56d0974aaeac5d04db765557ac Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 11:11:20 +0300 Subject: [PATCH 08/16] visibility fix --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 0cca728..ff4ace4 100644 --- a/index.js +++ b/index.js @@ -685,7 +685,7 @@ window.onload = function () { for (let i in Game.selltext) { let txt = Game.selltext[i] ctx.font = '12px Helvetica' - ctx.fillStyle = '#0f0' + ctx.fillStyle = '#0a0' ctx.fillText('+ $' + txt.amount, txt.x * mt, txt.y * mt) } From 9d1aac4a73e8a0dbd393f9813a8fca2e82cbaf35 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 11:57:48 +0300 Subject: [PATCH 09/16] tower selection and info box --- index.js | 134 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 26 deletions(-) diff --git a/index.js b/index.js index ff4ace4..f862a8f 100644 --- a/index.js +++ b/index.js @@ -35,6 +35,7 @@ window.onload = function () { wave: 0, waveTimer: 0, tower: 'simple', + towerSel: null, sellRatio: .8 } @@ -155,6 +156,7 @@ window.onload = function () { class Component { constructor (x, y) { + this.visible = true this.x = x this.y = y } @@ -179,6 +181,7 @@ window.onload = function () { } draw () { + if (!this.visible) return if (this.font) ctx.font = this.font ctx.fillStyle = this.color ctx.fillRect(this.x, this.y, this.w, this.h) @@ -226,6 +229,7 @@ window.onload = function () { } draw () { + if (!this.visible) return if (this.active) { ctx.fillStyle = '#afa' ctx.fillRect(this.x - 2, this.y - 2, this.w + 4, this.h + 4) @@ -263,14 +267,17 @@ window.onload = function () { } function clickBtn () { + let click = false for (let i in Components) { let btn = Components[i] if (!(btn instanceof ButtonComponent)) continue - if (btn.disabled) continue + if (btn.disabled || !btn.visible) continue if (mXr > btn.x && mYr > btn.y && mXr < btn.x + btn.w && mYr < btn.y + btn.h) { btn.fn() + click = true } } + return click } // Use this function to spawn enemies depending on round @@ -394,12 +401,14 @@ window.onload = function () { Game.particles.push({ x: tower.x, y: tower.y, + tower: {x: tower.x, y: tower.y}, velX: (target.x - tower.x) / target.dist * 1.24, velY: (target.y - tower.y) / target.dist * 1.24, dmg: tower.damage, speed: tower.speed, life: 100 }) + tower.fires++ } function tickTowers () { @@ -440,6 +449,11 @@ window.onload = function () { if (enemy.dmg <= 0) { Game.enemies.splice(j, 1) Game.money += 10 + + let tower = getTowerAt(parti.tower.x, parti.tower.y) + if (tower) { + tower.killcount++ + } } // remove particle @@ -449,6 +463,8 @@ window.onload = function () { } } + // Render text telling the amount of money received when selling a tower + // Disappears after 30 game ticks function tickSellText () { for (let i in Game.selltext) { let txt = Game.selltext[i] @@ -456,12 +472,18 @@ window.onload = function () { txt.tick %= 30 if (txt.tick === 0) { Game.selltext.splice(i, 1) + continue } txt.y -= 0.05 } } + function selectTower (x, y) { + let tower = getTowerAt(x, y) + Game.towerSel = tower + } + // Total enemy spawn count is used to determine that the round is over // Local (in-function) determines how many there are left to spawn as ordered by the function call function addEnemies (cnt, type) { @@ -544,12 +566,14 @@ window.onload = function () { x: x, y: y, tick: tower.rate, - setting: 1 + setting: 1, + fires: 0, + killcount: 0 }, tower)) } function sellTower (x, y) { - var tower = getTowerAt(x, y) + let tower = getTowerAt(x, y) if(tower) { let amount = tower.cost * Game.sellRatio Game.money += amount @@ -559,6 +583,11 @@ window.onload = function () { amount: amount, tick: 0 }) + + if (Game.towerSel && Game.towerSel.x === x && Game.towerSel.y === y) { + Game.towerSel = null + } + return Game.towers.splice(Game.towers.indexOf(tower), 1) }else{ return null @@ -597,6 +626,8 @@ window.onload = function () { if (Game.state === 1) { Game.waveTimer++ } + + Components.sell.visible = Game.towerSel !== null } function render () { @@ -609,7 +640,7 @@ window.onload = function () { let index = parseInt(i) let y = Math.floor(index / Maps.width) let x = Math.floor(index % Maps.height) - var draw_tile = true + let draw_tile = true if (tile === 1) { ctx.fillStyle = '#fdd' @@ -666,20 +697,31 @@ window.onload = function () { ctx.fillRect(tower.x * mt + mt / 16, tower.y * mt + mt / 16, 8, 8) } - // tower placement - if (Game.state === 2 && Game.tower && mX < Maps.width && mY < Maps.height) { - // tower range visualization - let towerData = Towers[Game.tower] - if (towerData.cost <= Game.money && canPlaceTowerAt (mX, mY)) { - let towerData = Towers[Game.tower] - ctx.strokeStyle = '#ddd' - ctx.fillStyle = 'rgba(200, 200, 200, 0.25)' - ctx.beginPath() - ctx.arc(mX * mt + mt / 2, mY * mt + mt / 2, towerData.range * mt, 0, 2 * Math.PI) - ctx.stroke() - ctx.fill() - ctx.closePath() - } + // tower range visualization + let towerData = Towers[Game.tower] + let vX = null + let vY = null + + // Render the currently selected tower's range if present + if (Game.towerSel) { + towerData = Game.towerSel + vX = towerData.x + vY = towerData.y + } else if (towerData != null && towerData.cost <= Game.money && canPlaceTowerAt (mX, mY) && + mX < Maps.width && mY < Maps.height && Game.state === 2) { + vX = mX + vY = mY + } + + // Render range + if (vX != null && vY != null && towerData) { + ctx.strokeStyle = '#ddd' + ctx.fillStyle = 'rgba(200, 200, 200, 0.25)' + ctx.beginPath() + ctx.arc(vX * mt + mt / 2, vY * mt + mt / 2, towerData.range * mt, 0, 2 * Math.PI) + ctx.stroke() + ctx.fill() + ctx.closePath() } for (let i in Game.selltext) { @@ -699,11 +741,6 @@ window.onload = function () { ctx.fillText('Health: ' + Game.health, 645, 45) ctx.fillText('Money: ' + Game.money, 645, 65) - for (let i in Components) { - let btn = Components[i] - btn.draw() - } - if (Game.state === -1) { ctx.font = '80px Helvetica' ctx.fillStyle = '#f00' @@ -714,6 +751,34 @@ window.onload = function () { ctx.fillStyle = 'rgba(255, 0, 0, 0.24)' ctx.fillRect(mX * mt, mY * mt, mt, mt) } + + // Render a selection information box + // TODO: component + if (Game.towerSel) { + let by = (Maps.height - 5) * Maps.tile + let ts = Game.towerSel + + ctx.fillStyle = 'rgba(0, 0, 0, 0.45)' + ctx.fillRect(0, by, Maps.width * Maps.tile, 5 * Maps.tile) + + ctx.fillStyle = '#fff' + ctx.font = '25px Helvetica' + ctx.fillText(ts.name + ' Tower', 5, by + 25) + + ctx.font = '15px Helvetica' + ctx.fillText(ts.description, 5, by + 42) + + ctx.fillText('Range: ' + ts.range + ' tiles', 5, by + 70) + ctx.fillText('Damage: ' + ts.damage + ' HP', 5, by + 85) + ctx.fillText('Fire Rate: ' + ts.rate, 5, by + 100) + ctx.fillText('Kills: ' + ts.killcount, 5, by + 115) + ctx.fillText('Fired ' + ts.fires + ' times', 5, by + 130) + } + + for (let i in Components) { + let btn = Components[i] + btn.draw() + } } let lastTime = Date.now() @@ -736,10 +801,18 @@ window.onload = function () { function initialize () { Game.map = Maps.first + // Next wave button Components.wave = new ButtonComponent('Next Wave', '#fff', '#11f', 650, 570, 200, 60, () => { updateGameState(1) }) + // Tower sell button + Components.sell = new ButtonComponent('Sell Tower', '#fff', '#f11', 490, 590, 140, 40, () => { + if (Game.towerSel) { + sellTower(Game.towerSel.x, Game.towerSel.y) + } + }) + let index = 0 for (let i in Towers) { Components[i] = new TowerButton(i, index) @@ -750,11 +823,20 @@ window.onload = function () { } canvas.addEventListener('click', (e) => { - if (Game.state === 2 && mX < Maps.width && mY < Maps.height && Game.tower) { + if (clickBtn()) return + if (mX < Maps.width && mY < Maps.height) { + // Select a tower if present + if (getTowerAt(mX, mY)) { + return selectTower(mX, mY) + } else if (Game.towerSel) { + Game.towerSel = null + return + } + + // Place a tower + if (!Game.tower || Game.state !== 2) return placeTower(Towers[Game.tower], mX, mY) } - - clickBtn() }) canvas.addEventListener('contextmenu', (e) => { From 818971ccdb888d5a4382f90064e3eb68b487df41 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 12:00:24 +0300 Subject: [PATCH 10/16] add default font to btns --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index f862a8f..ba8b5f2 100644 --- a/index.js +++ b/index.js @@ -178,6 +178,7 @@ window.onload = function () { this.color = color this.disabled = false this.hovered = false + this.font = '20px Helvetica' } draw () { @@ -324,6 +325,7 @@ window.onload = function () { if (Game.state !== -1 && Game.health <= 0) { Game.health = 0 Game.state = -1 + Game.towerSel = null } if (Game.state === 2 && gst === 1) { From 87aea4bd6f5e9e05bc04d2ce24e547c62f72f848 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 12:08:12 +0300 Subject: [PATCH 11/16] don't tick towers in play/game over state --- index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index ba8b5f2..3e92efc 100644 --- a/index.js +++ b/index.js @@ -603,7 +603,11 @@ window.onload = function () { fpsDraw = fps } - tickTowers() + // Only tick towers when the game is in the play state + if (Game.state === 1) { + tickTowers() + } + updateEnemyMovements() tickParticles() tickSellText() From c00dacd4cb387159f53f42084a466346432ebfb6 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 15:39:45 +0300 Subject: [PATCH 12/16] components and new tower --- index.js | 417 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 323 insertions(+), 94 deletions(-) diff --git a/index.js b/index.js index 3e92efc..759c2f9 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,9 @@ window.onload = function () { * I use Object.assign to copy objects in order to eliminate references when spawning enemies and to get the ability to modify them individually * Components such as buttons or selections within the canvas are classes + * if, function and else have spaces between both '(' and '{' + `if (thing) {}` not `if(thing){}` + * Keep all variables local to their scope (in other words, use `let` instead of `var`) */ let canvas = document.getElementById('canvas') @@ -36,6 +39,7 @@ window.onload = function () { waveTimer: 0, tower: 'simple', towerSel: null, + debug: false, sellRatio: .8 } @@ -67,7 +71,7 @@ window.onload = function () { tough: { speed: 5, node: 1, - health: 100, + health: 150, reward: 20, frequency: 1000, icon: '#f40' @@ -80,30 +84,44 @@ window.onload = function () { damage: 15, // damage to deal to enemies when hit rate: 20, // rate of fire, higher - slower name: 'Simple', // name of the tower - description: 'Basic tower', + description: 'Medium rate and damage', speed: 30, // bullet speed, higher - faster cost: 50, // cost to place - icon: '#333' // currently color + icon: '#333', // currently color + bullet: 1 // The type of bullet. 1: damage, 2: slow down by damage, 3: instant kill }, rapid: { range: 3, damage: 5, rate: 5, name: 'Rapid', - description: 'Rapid-firing tower', + description: 'Rapid-firing but low damage', speed: 30, cost: 250, - icon: '#303' + icon: '#303', + bullet: 1 }, - snipe: { - range: 5, - damage: 150, - rate: 100, - name: 'Sniper', - description: 'Slow but powerful shots', + sticky: { + range: 3, + damage: 10, + rate: 30, + name: 'Sticky', + description: 'Slow down enemies by damage', speed: 50, cost: 500, - icon: '#4f3' + icon: '#4f3', + bullet: 2 + }, + snipe: { + range: 10, + damage: 1500, + rate: 100, + name: 'Sniper', + description: 'Slow firing but always kills', + speed: 50, + cost: 1000, + icon: '#4f3', + bullet: 1 } } @@ -157,12 +175,114 @@ window.onload = function () { class Component { constructor (x, y) { this.visible = true + this.elements = [] this.x = x this.y = y } - draw () {} - update() {} + elDraw() { + for (let i in this.elements) { + let elem = this.elements[i] + if (elem instanceof Component) { + elem.draw() + } + } + } + + elUpdate() { + for (let i in this.elements) { + let elem = this.elements[i] + if (elem instanceof Component) { + elem.update() + } + } + } + + addElement (el) { + if (!(el instanceof Component)) return + this.elements.push(el) + } + + draw () { + this.elDraw() + } + + update() { + this.elUpdate() + } + } + + class Tooltip extends Component { + constructor () { + super(0, 0) + this.font = '20px Helvetica' + this.text = '' + this.w = 0 + this.h = 24 + this.components = [] + this.visible = false + } + + static assign (tooltip, component, text) { + tooltip.addComponent(component, text) + } + + setText (str) { + if (this.text === str) return + this.text = str + if (this.font) ctx.font = this.font + this.w = ctx.measureText(this.text).width + this.h + } + + draw () { + if (!this.visible) return + if (this.text === '') return + if (this.font) ctx.font = this.font + + let aX = this.x + let aY = this.y + + if (aX + this.w > canvas.width) { + aX -= this.w + 5 + } + + ctx.fillStyle = 'rgba(255, 255, 255, 0.5)' + ctx.fillRect(aX, aY, this.w, this.h) + + ctx.fillStyle = '#000' + ctx.fillText(this.text, aX + this.h / 2, aY + this.h / 2 + 5) + } + + setPosition (x, y) { + this.x = x + this.y = y + } + + update () { + if (this.components.length) { + let cmps = false + for (let i in this.components) { + let cmp = this.components[i] + if (mXr > cmp.x && mYr > cmp.y && + mXr < cmp.x + cmp.w && mYr < cmp.y + cmp.h) { + this.setPosition(mXr, mYr) + this.setText(cmp.text) + cmps = true + } + } + this.visible = cmps + } + } + + addComponent (component, text) { + this.components.push({ + x: component.x, + y: component.y, + w: component.w, + h: component.h, + text: text + }) + } } class ButtonComponent extends Component { @@ -197,9 +317,19 @@ window.onload = function () { ctx.fillStyle = 'rgba(0, 0, 0, 0.45)' ctx.fillRect(this.x, this.y, this.w, this.h) } else if (this.hovered) { - ctx.fillStyle = 'rgba(255, 255, 255, 0.25)' + ctx.fillStyle = 'rgba(255, 255, 255, 0.15)' ctx.fillRect(this.x, this.y, this.w, this.h) } + this.elDraw() + } + + update () { + if (!this.visible || this.disabled) return + if (mXr > this.x && mYr > this.y && mXr < this.x + this.w && mYr < this.y + this.h) { + this.hovered = true + } else if (this.hovered) { + this.hovered = false + } } setDisabled (disable) { @@ -222,13 +352,23 @@ window.onload = function () { this.textColor = '#fff' this.color = '#995522' this.fn = this.select - this.font = '14px Helvetica' } select () { Game.tower = this.tower } + addTooltip () { + Tooltip.assign(Components.tooltip, this, this.towerObj.description) + } + + update () { + super.update() + this.disabled = this.towerObj.cost > Game.money + this.active = Game.tower === this.tower + this.elUpdate() + } + draw () { if (!this.visible) return if (this.active) { @@ -261,26 +401,113 @@ window.onload = function () { ctx.fillStyle = 'rgba(0, 0, 0, 0.45)' ctx.fillRect(this.x, this.y, this.w, this.h) } else if (this.hovered) { - ctx.fillStyle = 'rgba(255, 255, 255, 0.25)' + ctx.fillStyle = 'rgba(255, 255, 255, 0.15)' ctx.fillRect(this.x, this.y, this.w, this.h) } + this.elDraw() } } - function clickBtn () { + class InfoDialog extends Component { + constructor () { + super() + this.x = 0 + this.y = (Maps.height - 5) * Maps.tile + this.w = Maps.width * Maps.tile + this.h = 5 * Maps.tile + this.createButton() + } + + createButton () { + let btn = new ButtonComponent('Sell Tower', '#fff', '#f11', 490, 590, 140, 40, () => { + if (Game.towerSel) { + sellTower(Game.towerSel.x, Game.towerSel.y) + } + }) + + btn.update = function () { + this.visible = Game.towerSel !== null + if (!this.visible) return + if (mXr > this.x && mYr > this.y && mXr < this.x + this.w && mYr < this.y + this.h) { + this.hovered = true + } else if (this.hovered) { + this.hovered = false + } + } + + this.addElement(btn) + } + + draw () { + if (Game.towerSel) { + let ts = Game.towerSel + + ctx.fillStyle = 'rgba(0, 0, 0, 0.45)' + ctx.fillRect(this.x, this.y, this.w, this.h) + + ctx.fillStyle = '#fff' + ctx.font = '25px Helvetica' + ctx.fillText(ts.name + ' Tower', 5, this.y + 25) + + ctx.font = '15px Helvetica' + ctx.fillText(ts.description, 5, this.y + 42) + + ctx.fillText('Range: ' + ts.range + ' tiles', 5, this.y + 70) + ctx.fillText('Damage: ' + ts.damage + ' HP', 5, this.y + 85) + ctx.fillText('Fire Rate: ' + ts.rate, 5, this.y + 100) + ctx.fillText('Kills: ' + ts.killcount, 5, this.y + 115) + ctx.fillText('Fired ' + ts.fires + ' times', 5, this.y + 130) + } + this.elDraw() + } + } + + function clickBtn (cmp) { let click = false - for (let i in Components) { - let btn = Components[i] - if (!(btn instanceof ButtonComponent)) continue - if (btn.disabled || !btn.visible) continue - if (mXr > btn.x && mYr > btn.y && mXr < btn.x + btn.w && mYr < btn.y + btn.h) { - btn.fn() - click = true + let compList = cmp != null && cmp instanceof Component ? cmp.elements : null + if (cmp == null && compList == null) { + compList = Components + } + + for (let i in compList) { + let btn = compList[i] + + if (!(btn instanceof ButtonComponent)) { + // Loop through sub-components of components + if (btn.elements.length) { + click = clickBtn(btn) + } else { + continue + } + } else { + // Click the button if its in bounds, visible and not disabled + if (btn.disabled || !btn.visible) continue + if (mXr > btn.x && mYr > btn.y && mXr < btn.x + btn.w && mYr < btn.y + btn.h && btn) { + btn.fn() + click = true + } } } return click } + function updateComponents (cmp) { + // Determine which object of components to update + let compList = cmp != null && cmp instanceof Component ? cmp.elements : null + if (cmp == null && compList == null) { + compList = Components + } + + for (let i in compList) { + let component = compList[i] + component.update() + + if (component.elements.length) { + updateComponents(component) + } + } + } + // Use this function to spawn enemies depending on round function nextWave () { Game.wave++ @@ -303,7 +530,7 @@ window.onload = function () { // Use this function to modify the enemies spawned each round function waveEnemyModifer (enemy, round) { // Reduce the time between enemy spawns - let fr = enemy.frequency - 2 * round + let fr = enemy.frequency - 5 * round if (fr < 100) { fr = 100 } @@ -400,6 +627,8 @@ window.onload = function () { target = enemiesProxima[enemiesProxima.length - 1] } + tower.fires++ + Game.particles.push({ x: tower.x, y: tower.y, @@ -408,9 +637,9 @@ window.onload = function () { velY: (target.y - tower.y) / target.dist * 1.24, dmg: tower.damage, speed: tower.speed, - life: 100 + type: tower.bullet || 1, + life: 30 }) - tower.fires++ } function tickTowers () { @@ -446,15 +675,22 @@ window.onload = function () { if (parti.x >= enemy.x - 0.25 && parti.y >= enemy.y - 0.25 && parti.x <= enemy.x + 0.5 && parti.y <= enemy.y + 0.5) { // damage enemy - enemy.dmg -= parti.dmg + if (parti.type === 1) { + enemy.dmg -= parti.dmg - if (enemy.dmg <= 0) { - Game.enemies.splice(j, 1) - Game.money += 10 + if (enemy.dmg <= 0) { + Game.enemies.splice(j, 1) + Game.money += 10 - let tower = getTowerAt(parti.tower.x, parti.tower.y) - if (tower) { - tower.killcount++ + let tower = getTowerAt(parti.tower.x, parti.tower.y) + if (tower) { + tower.killcount++ + } + } + } else if (parti.type === 2) { + enemy.speed -= parti.dmg + if (enemy.speed < 2) { + enemy.speed = 2 } } @@ -576,7 +812,7 @@ window.onload = function () { function sellTower (x, y) { let tower = getTowerAt(x, y) - if(tower) { + if (tower) { let amount = tower.cost * Game.sellRatio Game.money += amount Game.selltext.push({ @@ -591,12 +827,13 @@ window.onload = function () { } return Game.towers.splice(Game.towers.indexOf(tower), 1) - }else{ + } else { return null } } function update (dt) { + // Update FPS count for drawing (Don't render a new number every frame, it changes too fast) fpsCount++ fpsCount %= 20 if (fpsCount === 0) { @@ -608,32 +845,25 @@ window.onload = function () { tickTowers() } + // Move enemies updateEnemyMovements() + + // Move bullets tickParticles() + + // Move sell texts tickSellText() - for (let i in Components) { - let btn = Components[i] - if (btn instanceof ButtonComponent) { - if (mXr > btn.x && mYr > btn.y && mXr < btn.x + btn.w && mYr < btn.y + btn.h) { - btn.hovered = true - } else if (btn.hovered) { - btn.hovered = false - } - - if (btn instanceof TowerButton) { - btn.disabled = btn.towerObj.cost > Game.money - btn.active = Game.tower === i - } - } - } + // Update all components (eg buttons) + updateComponents() + // Set the state updateGameState() + + // Increment game clock if (Game.state === 1) { Game.waveTimer++ } - - Components.sell.visible = Game.towerSel !== null } function render () { @@ -641,6 +871,7 @@ window.onload = function () { ctx.fillStyle = '#0fa' ctx.fillRect(0, 0, canvas.width, canvas.height) + // Draw the map for (let i in Game.map.tiles) { let tile = Game.map.tiles[i] let index = parseInt(i) @@ -658,28 +889,34 @@ window.onload = function () { draw_tile = false } - if(draw_tile) { + if (draw_tile) { ctx.fillRect(x * mt, y * mt, mt, mt) } - if(Game.state == 2 && tile == 0 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { + // Draw obstructed tiles + if (Game.state == 2 && tile == 0 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { ctx.fillStyle = 'rgba(255, 0, 0, 0.45)' ctx.fillRect(x * mt, y * mt, mt, mt) } } -/* - for (let i in Game.map.pathgen) { - let node = Game.map.pathgen[i] - ctx.fillStyle = '#00f' - ctx.fillRect((node.x * mt) + mt / 3, (node.y * mt) + mt / 3, 8, 8) + + // Show the enemy movement path + if (Game.debug) { + for (let i in Game.map.pathgen) { + let node = Game.map.pathgen[i] + ctx.fillStyle = '#00f' + ctx.fillRect((node.x * mt) + mt / 3, (node.y * mt) + mt / 3, 8, 8) + } } -*/ + + // Draw towers for (let i in Game.towers) { let tower = Game.towers[i] ctx.fillStyle = tower.icon ctx.fillRect(tower.x * mt + 2, tower.y * mt + 2, 28, 28) } + // Draw enemies for (let i in Game.enemies) { let enemy = Game.enemies[i] let rx = (enemy.x * mt) + mt / 8 @@ -697,13 +934,14 @@ window.onload = function () { ctx.fillRect(hx, hy, (16 + 12) * enemy.dmg / enemy.health, 5) } + // Draw bullets for (let i in Game.particles) { let tower = Game.particles[i] ctx.fillStyle = '#f33' ctx.fillRect(tower.x * mt + mt / 16, tower.y * mt + mt / 16, 8, 8) } - // tower range visualization + // Tower range visualization let towerData = Towers[Game.tower] let vX = null let vY = null @@ -730,6 +968,7 @@ window.onload = function () { ctx.closePath() } + // Render sell text for (let i in Game.selltext) { let txt = Game.selltext[i] ctx.font = '12px Helvetica' @@ -737,9 +976,11 @@ window.onload = function () { ctx.fillText('+ $' + txt.amount, txt.x * mt, txt.y * mt) } + // Render sidebar background ctx.fillStyle = '#996633' ctx.fillRect(640, 0, 240, 640) + // Render sidebar text ctx.font = '20px Helvetica' ctx.fillStyle = '#fff' ctx.fillText('FPS: ' + fpsDraw.toFixed(2), 0, 20) @@ -747,43 +988,24 @@ window.onload = function () { ctx.fillText('Health: ' + Game.health, 645, 45) ctx.fillText('Money: ' + Game.money, 645, 65) + // Game Over text if (Game.state === -1) { ctx.font = '80px Helvetica' ctx.fillStyle = '#f00' ctx.fillText('Game Over', 100, canvas.height / 2 - 80 / 2) } + // Draw mouse cursor if (mX < Maps.width && mY < Maps.height) { ctx.fillStyle = 'rgba(255, 0, 0, 0.24)' ctx.fillRect(mX * mt, mY * mt, mt, mt) } - // Render a selection information box - // TODO: component - if (Game.towerSel) { - let by = (Maps.height - 5) * Maps.tile - let ts = Game.towerSel - - ctx.fillStyle = 'rgba(0, 0, 0, 0.45)' - ctx.fillRect(0, by, Maps.width * Maps.tile, 5 * Maps.tile) - - ctx.fillStyle = '#fff' - ctx.font = '25px Helvetica' - ctx.fillText(ts.name + ' Tower', 5, by + 25) - - ctx.font = '15px Helvetica' - ctx.fillText(ts.description, 5, by + 42) - - ctx.fillText('Range: ' + ts.range + ' tiles', 5, by + 70) - ctx.fillText('Damage: ' + ts.damage + ' HP', 5, by + 85) - ctx.fillText('Fire Rate: ' + ts.rate, 5, by + 100) - ctx.fillText('Kills: ' + ts.killcount, 5, by + 115) - ctx.fillText('Fired ' + ts.fires + ' times', 5, by + 130) - } - + // Draw all components for (let i in Components) { - let btn = Components[i] - btn.draw() + let cmp = Components[i] + if (!(cmp) instanceof Component) continue + cmp.draw() } } @@ -795,6 +1017,7 @@ window.onload = function () { update() render() + // Update FPS let cfps = 1000 / ((now = new Date) - lastTime) if (now != lastTime) { fps += (cfps - fps) / fpsRes @@ -812,19 +1035,25 @@ window.onload = function () { updateGameState(1) }) - // Tower sell button - Components.sell = new ButtonComponent('Sell Tower', '#fff', '#f11', 490, 590, 140, 40, () => { - if (Game.towerSel) { - sellTower(Game.towerSel.x, Game.towerSel.y) - } - }) + // Tower information box + Components.info = new InfoDialog() + // Add buy buttons to every tower let index = 0 for (let i in Towers) { Components[i] = new TowerButton(i, index) index++ } + // Tooltip + Components.tooltip = new Tooltip() + for (let i in Towers) { + let cmp = Components[i] + if (!cmp) continue + Components.tooltip.addComponent(cmp, cmp.towerObj.description) + } + + // Start the game gameLoop() } From 2284ddd28a5a459cccd8c09cadc10f3349691fa2 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 15:40:53 +0300 Subject: [PATCH 13/16] forgot to change the color --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 759c2f9..ede641d 100644 --- a/index.js +++ b/index.js @@ -109,7 +109,7 @@ window.onload = function () { description: 'Slow down enemies by damage', speed: 50, cost: 500, - icon: '#4f3', + icon: '#e27c06', bullet: 2 }, snipe: { From fc9193251342d3a651569d7d873c848f8c459c1e Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 19:19:00 +0300 Subject: [PATCH 14/16] new round system, debug mode --- index.js | 266 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 199 insertions(+), 67 deletions(-) diff --git a/index.js b/index.js index ede641d..e8b65b0 100644 --- a/index.js +++ b/index.js @@ -27,14 +27,13 @@ window.onload = function () { let Game = { state: 2, enemies: [], + enemySpawnList: [], towers: [], particles: [], selltext: [], map: null, health: 100, money: 100, - enemySpawn: 0, - pace: 1, wave: 0, waveTimer: 0, tower: 'simple', @@ -57,7 +56,7 @@ window.onload = function () { node: 1, health: 50, reward: 10, - frequency: 1000, + frequency: 40, icon: '#f00' }, speedy: { @@ -65,15 +64,15 @@ window.onload = function () { node: 1, health: 60, reward: 15, - frequency: 500, + frequency: 35, icon: '#f11' }, tough: { speed: 5, node: 1, - health: 150, + health: 80, reward: 20, - frequency: 1000, + frequency: 40, icon: '#f40' } } @@ -166,6 +165,72 @@ window.onload = function () { {x: 5, y: 12, end: false}, {x: 1, y: 12, end: false}, {x: 1, y: 17, end: true}, + ], + waves: [ + { + type: 'recurring', + waveLow: 0, + waveHigh: 10, + enemies: [{ + type: 'basic', + count: 5, + inclCount: true, + inclHealth: true + }] + }, + { + type: 'recurring', + waveLow: 10, + waveHigh: 15, + enemies: [{ + type: 'basic', + count: 5, + inclCount: true, + inclHealth: true + }, + { + type: 'speedy', + count: 10, + inclCount: true, + inclHealth: true + }] + }, + { + type: 'recurring', + waveLow: 15, + enemies: [{ + type: 'basic', + count: 5, + inclCount: true, + inclHealth: true, + inclSpeed: true + }, + { + type: 'speedy', + count: 10, + inclCount: true, + inclHealth: true, + inclSpeed: true + }] + }, + { + type: 'once-every', + every: 5, + enemies: [{ + type: 'tough', + count: 5, + inclCount: true, + inclHealth: true + }] + }, + { + type: 'once', + wave: 5, + enemies: [{ + type: 'tough', + count: 2 + }] + } ] } } @@ -364,7 +429,7 @@ window.onload = function () { update () { super.update() - this.disabled = this.towerObj.cost > Game.money + this.disabled = this.towerObj.cost > Game.money && !Game.debug this.active = Game.tower === this.tower this.elUpdate() } @@ -508,39 +573,92 @@ window.onload = function () { } } - // Use this function to spawn enemies depending on round - function nextWave () { - Game.wave++ - - if (Game.wave < 5) { - addEnemies(10 + Game.wave, Enemies.basic) - } else { - addEnemies(10 + Game.wave, Enemies.speedy) + // Total enemy spawn count is used to determine that the round is over + // Local (in-function) determines how many there are left to spawn as ordered by the function call + function addEnemies (enemies, type, specs) { + let path = Game.map.pathgen[0] + let enemy = Enemies[type] + // Copy the enemy and add x and y coordinates + let enemyCopy = Object.assign({ + x: path.x, + y: path.y + }, enemy) + + // Modify the enemy according to wave settings + if (specs.healthIncrease) { + enemyCopy.health += specs.healthIncrease } - if (Game.wave > 10) { - addEnemies(Game.wave - 5, Enemies.tough) + if (specs.speedIncrease) { + enemyCopy.speed += specs.speedIncrease } - if (Game.wave % 5 === 0) { - addEnemies(Game.wave / 5, Enemies.tough) + enemyCopy.dmg = enemyCopy.health + + // Insert them into the spawn queue + for (let i = 0; i < enemies; i++) { + if (Game.debug) { + console.log('added %s to spawn at %d', type, enemyCopy.frequency * i) + } + Game.enemySpawnList.push(Object.assign({ + time: enemyCopy.frequency * i + }, enemyCopy)) } } - // Use this function to modify the enemies spawned each round - function waveEnemyModifer (enemy, round) { - // Reduce the time between enemy spawns - let fr = enemy.frequency - 5 * round - if (fr < 100) { - fr = 100 + function nextWave () { + Game.wave++ + + for (let i in Game.map.waves) { + let wv = Game.map.waves[i] + let eSpawn = false + if (wv.type === 'once-every' && Game.wave % wv.every === 0) { + eSpawn = true + } else if (wv.type === 'once' && Game.wave === wv.wave) { + eSpawn = true + } else if (wv.type === 'recurring' && Game.wave >= wv.waveLow && (wv.waveHigh ? Game.wave < wv.waveHigh : true)) { + eSpawn = true + } + + if (!eSpawn) continue + for (let i in wv.enemies) { + let e = wv.enemies[i] + let eCount = e.count || 5 + let eHealthIncl = 0 + let eSpeedIncl = 0 + + if (e.inclCount === true) { + eCount += Game.wave + } + + if (e.baseHealth) { + eHealthIncl = e.baseHealth + } + + if (e.baseSpeed) { + eSpeedIncl = e.baseSpeed + } + + if (e.inclHealth === true) { + eHealthIncl = Game.wave * 5 + if (eHealthIncl > 500) { + eHealthIncl = 500 + } + } + + if (e.inclSpeed === true) { + eSpeedIncl = Game.wave / 5 + if (eSpeedIncl > 5) { + eSpeedIncl = 5 + } + } + + addEnemies(eCount, e.type, { + healthIncrease: eHealthIncl, + speedIncrease: eSpeedIncl + }) + } } - - enemy.frequency = fr - - // Increase enemy health - enemy.health += round * 5 - - return enemy } function getTileIn (map, x, y) { @@ -584,8 +702,8 @@ window.onload = function () { } if (enemy.velocity.dist > 0.1) { - enemy.x += (enemy.velocity.x * 0.01) * enemy.speed * Game.pace - enemy.y += (enemy.velocity.y * 0.01) * enemy.speed * Game.pace + enemy.x += (enemy.velocity.x * 0.01) * enemy.speed + enemy.y += (enemy.velocity.y * 0.01) * enemy.speed } else { if (Game.map.pathgen[enemy.node + 1]) { enemy.node += 1 @@ -599,7 +717,7 @@ window.onload = function () { } } - if (Game.state === 1 && Game.enemies.length === 0 && Game.enemySpawn === 0) { + if (Game.state === 1 && Game.enemies.length === 0 && Game.enemySpawnList.length === 0) { updateGameState(2) } } @@ -722,31 +840,16 @@ window.onload = function () { Game.towerSel = tower } - // Total enemy spawn count is used to determine that the round is over - // Local (in-function) determines how many there are left to spawn as ordered by the function call - function addEnemies (cnt, type) { - Game.enemySpawn += cnt // Total amount of enemies to spawn - let enemies = cnt // Local amount of enemies to spawn - - let path = Game.map.pathgen[0] - // Copy the enemy and add x and y coordinates - let enemyCopy = Object.assign({ - x: path.x, - y: path.y - }, type) - - // Modify the enemy according to wave settings - enemyCopy = waveEnemyModifer(enemyCopy, Game.wave) - enemyCopy.dmg = enemyCopy.health - - // Copy the enemy at an interval and spawn it - let ect = setInterval(() => { - if (enemies === 0) return clearInterval(ect) - Game.enemySpawn-- // Reduce total spawn count - enemies-- // Reduce local spawn count - - Game.enemies.push(Object.assign({}, enemyCopy)) - }, enemyCopy.frequency) + function spawnQueue () { + if (Game.enemySpawnList.length) { + for (let i in Game.enemySpawnList) { + let ef = Game.enemySpawnList[i] + if (ef.time < Game.waveTimer) { + Game.enemies.push(ef) + Game.enemySpawnList.splice(i, 1) + } + } + } } function getTowerAt (x, y) { @@ -767,9 +870,9 @@ window.onload = function () { // Prevent towers from being placed right next to each-other let can = true - for (let i in Game.towers) { + for (let j in Game.towers) { if (can === false) break - let tower = Game.towers[i] + let tower = Game.towers[j] // tower placement restriction visualization for (let i = 0; i < 4; i++) { @@ -795,11 +898,14 @@ window.onload = function () { } function placeTower (tower, x, y) { - if (tower.cost > Game.money) return // no money + if (tower.cost > Game.money && !Game.debug) return // no money if (!canPlaceTowerAt(x, y)) return - Game.money -= tower.cost + if (!Game.debug) { + Game.money -= tower.cost + } + Game.towers.push(Object.assign({ x: x, y: y, @@ -864,8 +970,11 @@ window.onload = function () { if (Game.state === 1) { Game.waveTimer++ } + + spawnQueue() } + let lastRenderTime = Date.now() function render () { let mt = Maps.tile ctx.fillStyle = '#0fa' @@ -894,8 +1003,8 @@ window.onload = function () { } // Draw obstructed tiles - if (Game.state == 2 && tile == 0 && !getTowerAt(x, y) && !canPlaceTowerAt(x, y)) { - ctx.fillStyle = 'rgba(255, 0, 0, 0.45)' + if (Game.state === 2 && tile === 0 && !canPlaceTowerAt(x, y)) { + ctx.fillStyle = '#738c5d' ctx.fillRect(x * mt, y * mt, mt, mt) } } @@ -914,6 +1023,12 @@ window.onload = function () { let tower = Game.towers[i] ctx.fillStyle = tower.icon ctx.fillRect(tower.x * mt + 2, tower.y * mt + 2, 28, 28) + + if (Game.debug) { + ctx.fillStyle = '#f11' + ctx.font = '10px Helvetica' + ctx.fillText(tower.tick, tower.x * mt + 10, tower.y * mt + 25) + } } // Draw enemies @@ -932,6 +1047,12 @@ window.onload = function () { ctx.fillStyle = '#0f0' ctx.fillRect(hx, hy, (16 + 12) * enemy.dmg / enemy.health, 5) + + if (Game.debug) { + ctx.fillStyle = '#511' + ctx.font = '10px Helvetica' + ctx.fillText(enemy.dmg, hx + 10, hy + 25) + } } // Draw bullets @@ -951,7 +1072,7 @@ window.onload = function () { towerData = Game.towerSel vX = towerData.x vY = towerData.y - } else if (towerData != null && towerData.cost <= Game.money && canPlaceTowerAt (mX, mY) && + } else if (towerData != null && towerData.cost <= Game.money && canPlaceTowerAt(mX, mY) && mX < Maps.width && mY < Maps.height && Game.state === 2) { vX = mX vY = mY @@ -1007,6 +1128,17 @@ window.onload = function () { if (!(cmp) instanceof Component) continue cmp.draw() } + + if (Game.debug) { + ctx.fillStyle = '#f11' + ctx.font = '10px Helvetica' + ctx.fillText('enemy queue length ' + Game.enemySpawnList.length, 5, 580) + ctx.fillText('enemy count ' + Game.enemies.length, 5, 590) + ctx.fillText('tower count ' + Game.towers.length, 5, 600) + ctx.fillText('particle count ' + Game.particles.length, 5, 610) + ctx.fillText('render tick ms ' + (Date.now() - lastRenderTime), 5, 620) + lastRenderTime = Date.now() + } } let lastTime = Date.now() From 693e8c4e0fe2d24377deae823d44b3a75ca550e3 Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 19:40:18 +0300 Subject: [PATCH 15/16] add one after another and remove speed increase --- index.js | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index e8b65b0..21b0cd3 100644 --- a/index.js +++ b/index.js @@ -34,7 +34,7 @@ window.onload = function () { map: null, health: 100, money: 100, - wave: 0, + wave: 15, waveTimer: 0, tower: 'simple', towerSel: null, @@ -171,6 +171,7 @@ window.onload = function () { type: 'recurring', waveLow: 0, waveHigh: 10, + oneAfterAnother: false, enemies: [{ type: 'basic', count: 5, @@ -182,6 +183,7 @@ window.onload = function () { type: 'recurring', waveLow: 10, waveHigh: 15, + oneAfterAnother: false, enemies: [{ type: 'basic', count: 5, @@ -198,24 +200,24 @@ window.onload = function () { { type: 'recurring', waveLow: 15, + oneAfterAnother: false, enemies: [{ type: 'basic', count: 5, inclCount: true, - inclHealth: true, - inclSpeed: true + inclHealth: true }, { type: 'speedy', count: 10, inclCount: true, - inclHealth: true, - inclSpeed: true + inclHealth: true }] }, { type: 'once-every', every: 5, + oneAfterAnother: false, enemies: [{ type: 'tough', count: 5, @@ -225,7 +227,7 @@ window.onload = function () { }, { type: 'once', - wave: 5, + wave: 3, enemies: [{ type: 'tough', count: 2 @@ -578,6 +580,7 @@ window.onload = function () { function addEnemies (enemies, type, specs) { let path = Game.map.pathgen[0] let enemy = Enemies[type] + // Copy the enemy and add x and y coordinates let enemyCopy = Object.assign({ x: path.x, @@ -597,11 +600,13 @@ window.onload = function () { // Insert them into the spawn queue for (let i = 0; i < enemies; i++) { + let spawnTime = enemyCopy.frequency * i + (specs.multiply ? (specs.multiply * (enemies * enemyCopy.frequency)) : 0) if (Game.debug) { - console.log('added %s to spawn at %d', type, enemyCopy.frequency * i) + console.log('added %s to spawn at %d', type, spawnTime) } + Game.enemySpawnList.push(Object.assign({ - time: enemyCopy.frequency * i + time: spawnTime }, enemyCopy)) } } @@ -625,7 +630,7 @@ window.onload = function () { let e = wv.enemies[i] let eCount = e.count || 5 let eHealthIncl = 0 - let eSpeedIncl = 0 + let multiply = wv.oneAfterAnother != null ? wv.oneAfterAnother : false if (e.inclCount === true) { eCount += Game.wave @@ -635,10 +640,6 @@ window.onload = function () { eHealthIncl = e.baseHealth } - if (e.baseSpeed) { - eSpeedIncl = e.baseSpeed - } - if (e.inclHealth === true) { eHealthIncl = Game.wave * 5 if (eHealthIncl > 500) { @@ -646,16 +647,9 @@ window.onload = function () { } } - if (e.inclSpeed === true) { - eSpeedIncl = Game.wave / 5 - if (eSpeedIncl > 5) { - eSpeedIncl = 5 - } - } - addEnemies(eCount, e.type, { healthIncrease: eHealthIncl, - speedIncrease: eSpeedIncl + multiply: multiply ? parseInt(i) : false }) } } From 345214d789fdcb7d4c87853aa67a24fa603d807a Mon Sep 17 00:00:00 2001 From: Evert Date: Tue, 22 Aug 2017 19:41:55 +0300 Subject: [PATCH 16/16] oops --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 21b0cd3..2e290c4 100644 --- a/index.js +++ b/index.js @@ -34,7 +34,7 @@ window.onload = function () { map: null, health: 100, money: 100, - wave: 15, + wave: 0, waveTimer: 0, tower: 'simple', towerSel: null,