some visualization difference
This commit is contained in:
parent
2890d28b38
commit
52a5c7d0a1
197
index.js
197
index.js
@ -1,4 +1,13 @@
|
|||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
|
/*
|
||||||
|
My programming practice notes:
|
||||||
|
* every major feature as part of updating the game (such as towers, enemies)
|
||||||
|
are handeled in a separate 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
|
||||||
|
*/
|
||||||
|
|
||||||
let canvas = document.getElementById('canvas')
|
let canvas = document.getElementById('canvas')
|
||||||
let ctx = canvas.getContext('2d')
|
let ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
@ -27,47 +36,59 @@ window.onload = function () {
|
|||||||
tower: 'simple'
|
tower: 'simple'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
speed - movement speed multiplier - higher: faster
|
||||||
|
node - always 1
|
||||||
|
health - health of the enemy
|
||||||
|
reward - money earned when killed
|
||||||
|
frequency - milliseconds to spawn in
|
||||||
|
icon - currently color of the enemy
|
||||||
|
*/
|
||||||
let Enemies = {
|
let Enemies = {
|
||||||
basic: {
|
basic: {
|
||||||
speed: 10,
|
speed: 10,
|
||||||
node: 1,
|
node: 1,
|
||||||
dmg: 50,
|
|
||||||
health: 50,
|
health: 50,
|
||||||
reward: 10
|
reward: 10,
|
||||||
|
frequency: 1000,
|
||||||
|
icon: '#f00'
|
||||||
},
|
},
|
||||||
speedy: {
|
speedy: {
|
||||||
speed: 20,
|
speed: 20,
|
||||||
node: 1,
|
node: 1,
|
||||||
dmg: 60,
|
|
||||||
health: 60,
|
health: 60,
|
||||||
reward: 15
|
reward: 15,
|
||||||
|
frequency: 500,
|
||||||
|
icon: '#f11'
|
||||||
},
|
},
|
||||||
tough: {
|
tough: {
|
||||||
speed: 5,
|
speed: 5,
|
||||||
node: 1,
|
node: 1,
|
||||||
dmg: 100,
|
|
||||||
health: 100,
|
health: 100,
|
||||||
reward: 20
|
reward: 20,
|
||||||
|
frequency: 1000,
|
||||||
|
icon: '#f40'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Towers = {
|
let Towers = {
|
||||||
simple: {
|
simple: {
|
||||||
range: 6,
|
range: 6, // range in tiles
|
||||||
damage: 15,
|
damage: 15, // damage to deal to enemies when hit
|
||||||
rate: 20,
|
rate: 20, // rate of fire, higher - slower
|
||||||
name: 'Simple',
|
name: 'Simple', // name of the tower
|
||||||
speed: 30,
|
speed: 30, // bullet speed, higher - faster
|
||||||
cost: 50,
|
cost: 50, // cost to place
|
||||||
icon: null
|
icon: '#333' // currently color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let Maps = {
|
let Maps = {
|
||||||
width: 20,
|
width: 20, // Width of the map
|
||||||
height: 20,
|
height: 20, // Height of the map
|
||||||
tile: 32,
|
tile: 32, // Tile size in pixels (each coordinate is multiplied by this number in rendering)
|
||||||
first: {
|
first: {
|
||||||
|
// map rendering data
|
||||||
tiles: [
|
tiles: [
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
@ -90,6 +111,7 @@ window.onload = function () {
|
|||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
],
|
],
|
||||||
|
// enemy follow path
|
||||||
pathgen: [
|
pathgen: [
|
||||||
{x: 1, y: 2, end: false},
|
{x: 1, y: 2, end: false},
|
||||||
{x: 14, y: 2, end: false},
|
{x: 14, y: 2, end: false},
|
||||||
@ -155,21 +177,39 @@ window.onload = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use this function to spawn enemies depending on round
|
||||||
function nextWave () {
|
function nextWave () {
|
||||||
Game.wave++
|
Game.wave++
|
||||||
|
|
||||||
if (Game.wave % 5 === 0) {
|
if (Game.wave < 5) {
|
||||||
addEnemies(Game.wave / 5, Enemies.speedy)
|
addEnemies(10 + Game.wave, Enemies.basic)
|
||||||
} else if (Game.wave % 10 === 0) {
|
} else {
|
||||||
addEnemies(1, Enemies.tough)
|
|
||||||
} else if (Game.wave > 5) {
|
|
||||||
addEnemies(10 + Game.wave, Enemies.speedy)
|
addEnemies(10 + Game.wave, Enemies.speedy)
|
||||||
if (Game.wave > 10) {
|
|
||||||
addEnemies(Game.wave - 10, Enemies.tough)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addEnemies(10 + Game.wave, Enemies.basic)
|
if (Game.wave > 10) {
|
||||||
|
addEnemies(Game.wave - 5, Enemies.tough)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Game.wave % 5 === 0) {
|
||||||
|
addEnemies(Game.wave / 5, Enemies.tough)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
if (fr < 100) {
|
||||||
|
fr = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
enemy.frequency = fr
|
||||||
|
|
||||||
|
// Increase enemy health
|
||||||
|
enemy.health += round * 5
|
||||||
|
|
||||||
|
return enemy
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTileIn (map, x, y) {
|
function getTileIn (map, x, y) {
|
||||||
@ -315,17 +355,25 @@ window.onload = function () {
|
|||||||
|
|
||||||
function addEnemies (cnt, type) {
|
function addEnemies (cnt, type) {
|
||||||
Game.enemySpawn += cnt
|
Game.enemySpawn += cnt
|
||||||
|
|
||||||
|
let path = Game.map.pathgen[0]
|
||||||
|
let enemyCopy = Object.assign({
|
||||||
|
x: path.x,
|
||||||
|
y: path.y
|
||||||
|
}, type)
|
||||||
|
|
||||||
|
enemyCopy = waveEnemyModifer(enemyCopy, Game.wave)
|
||||||
|
enemyCopy.dmg = enemyCopy.health
|
||||||
|
|
||||||
let ect = setInterval(() => {
|
let ect = setInterval(() => {
|
||||||
if (Game.enemySpawn === 0) return clearInterval(ect)
|
if (Game.enemySpawn === 0) return clearInterval(ect)
|
||||||
Game.enemySpawn--
|
Game.enemySpawn--
|
||||||
|
|
||||||
Game.enemies.push(Object.assign({
|
Game.enemies.push(Object.assign({}, enemyCopy))
|
||||||
x: Game.map.pathgen[0].x, y: Game.map.pathgen[0].y
|
}, enemyCopy.frequency)
|
||||||
}, type))
|
|
||||||
}, 1000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function towerAt (x, y) {
|
function getTowerAt (x, y) {
|
||||||
for (let i in Game.towers) {
|
for (let i in Game.towers) {
|
||||||
let tower = Game.towers[i]
|
let tower = Game.towers[i]
|
||||||
if (tower.x === x && tower.y === y) return tower
|
if (tower.x === x && tower.y === y) return tower
|
||||||
@ -334,13 +382,46 @@ window.onload = function () {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canPlaceTowerAt (x, y) {
|
||||||
|
let tileAt = getTileIn(Game.map.tiles, x, y)
|
||||||
|
if (tileAt !== 0) return false
|
||||||
|
|
||||||
|
// Do not overlap towers
|
||||||
|
if (getTowerAt(x, y) !== null) return false
|
||||||
|
|
||||||
|
// Prevent towers from being placed right next to each-other
|
||||||
|
let can = true
|
||||||
|
for (let i in Game.towers) {
|
||||||
|
if (can === false) break
|
||||||
|
let tower = Game.towers[i]
|
||||||
|
|
||||||
|
// tower placement restriction visualization
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
if (can === false) break
|
||||||
|
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 (ax === x && ay === y) can = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return can
|
||||||
|
}
|
||||||
|
|
||||||
function placeTower (tower, x, y) {
|
function placeTower (tower, x, y) {
|
||||||
if (tower.cost > Game.money) return // no money
|
if (tower.cost > Game.money) return // no money
|
||||||
|
|
||||||
let tileAt = getTileIn(Game.map.tiles, x, y)
|
|
||||||
if (tileAt !== 0) return
|
|
||||||
|
|
||||||
if (towerAt(x, y)) return
|
if (!canPlaceTowerAt(x, y)) return
|
||||||
|
|
||||||
Game.money -= tower.cost
|
Game.money -= tower.cost
|
||||||
Game.towers.push(Object.assign({
|
Game.towers.push(Object.assign({
|
||||||
@ -408,15 +489,37 @@ window.onload = function () {
|
|||||||
*/
|
*/
|
||||||
for (let i in Game.towers) {
|
for (let i in Game.towers) {
|
||||||
let tower = Game.towers[i]
|
let tower = Game.towers[i]
|
||||||
ctx.fillStyle = '#333'
|
ctx.fillStyle = tower.icon
|
||||||
ctx.fillRect(tower.x * mt + 2, tower.y * mt + 2, 28, 28)
|
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) {
|
for (let i in Game.enemies) {
|
||||||
let enemy = Game.enemies[i]
|
let enemy = Game.enemies[i]
|
||||||
let rx = (enemy.x * mt) + mt / 8
|
let rx = (enemy.x * mt) + mt / 8
|
||||||
let ry = (enemy.y * mt) + mt / 8
|
let ry = (enemy.y * mt) + mt / 8
|
||||||
ctx.fillStyle = '#f00'
|
ctx.fillStyle = enemy.icon
|
||||||
ctx.fillRect(rx, ry, 16, 16)
|
ctx.fillRect(rx, ry, 16, 16)
|
||||||
|
|
||||||
// health bars
|
// health bars
|
||||||
@ -435,16 +538,20 @@ window.onload = function () {
|
|||||||
ctx.fillRect(tower.x * mt + mt / 16, tower.y * mt + mt / 16, 8, 8)
|
ctx.fillRect(tower.x * mt + mt / 16, tower.y * mt + mt / 16, 8, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tower range visualization
|
// tower placement
|
||||||
if (Game.state === 2 && Game.tower && mX < Maps.width && mY < Maps.height) {
|
if (Game.state === 2 && Game.tower && mX < Maps.width && mY < Maps.height) {
|
||||||
|
// tower range visualization
|
||||||
let towerData = Towers[Game.tower]
|
let towerData = Towers[Game.tower]
|
||||||
ctx.strokeStyle = '#ddd'
|
if (towerData.cost <= Game.money && canPlaceTowerAt (mX, mY)) {
|
||||||
ctx.fillStyle = 'rgba(200, 200, 200, 0.25)'
|
let towerData = Towers[Game.tower]
|
||||||
ctx.beginPath()
|
ctx.strokeStyle = '#ddd'
|
||||||
ctx.arc(mX * mt + mt / 2, mY * mt + mt / 2, towerData.range * mt, 0, 2 * Math.PI)
|
ctx.fillStyle = 'rgba(200, 200, 200, 0.25)'
|
||||||
ctx.stroke()
|
ctx.beginPath()
|
||||||
ctx.fill()
|
ctx.arc(mX * mt + mt / 2, mY * mt + mt / 2, towerData.range * mt, 0, 2 * Math.PI)
|
||||||
ctx.closePath()
|
ctx.stroke()
|
||||||
|
ctx.fill()
|
||||||
|
ctx.closePath()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.fillStyle = '#996633'
|
ctx.fillStyle = '#996633'
|
||||||
|
Loading…
Reference in New Issue
Block a user