This document describes the current Tower Defense implementation (see levels/towerDefense/towerDefense.js), how the core Game class works, and how to add towers, enemies, and features.
For this project, keep gameplay code in the same file for now. When adding new behavior, add new classes in towerDefense.js rather than creating new folders.
Overview
The Game class manages board state (grid, path), rendering, and input. The board is a grid of boardHeight × boardWidth cells. The path for enemies is generated by drawEnemyPath() and stored in this.path as an array of [row, col] coordinates. Towers and enemies are plain objects stored in this.towers and this.enemies.
Key responsibilities in Game:
resize() computes cellSize, offsetX, offsetY.reset() and drawEnemyPath().drawBackground(), drawPath(), draw().handleCanvasClick() → handleClick() (translates canvas coords to row/col).addTower(tower) and addEnemy(enemy).Coordinate system
row (0..boardHeight-1) and col (0..boardWidth-1).offsetX, offsetY, and cellSize.Rendering notes
drawPath() using the this.board markers.Data shapes (conventions)
Tower (example shape)
{
id: 'basic-1', // unique id
row: 4, // integer board row
col: 2, // integer board col
range: 2.5, // in cells (floating OK)
fireRate: 1.0, // shots per second
damage: 1, // damage per shot
update: function(game, dt) { ... } // optional per-tower update method
}
Enemy (example shape)
{
id: 'goblin-1', // unique id
hp: 3, // hit points
speed: 1.0, // cells per second (recommended)
pathIndex: 0, // index into game.path (which cell the enemy is moving toward)
progress: 0.0, // 0..1 progress between path[pathIndex] and path[pathIndex+1]
update: function(game, dt) { ... } // advance along path, handle death
}
How enemies should work (recommended)
pathIndex (current segment) and progress (0..1) or a position in canvas pixels.progress by speed * dt / 1cellLength.progress >= 1 increment pathIndex and set progress -= 1.pathIndex reaches game.path.length - 1, the enemy reached the base → apply damage/coin penalty and remove enemy.hp <= 0, remove it and award coins as appropriate.How towers should work (recommended)
range, fireRate, damage and a local cooldown timer (use lastShotAt or cooldown value).1/fireRate.Where to implement behaviors
Towers — tower classes/factories (e.g. basicTower, sniperTower)enemies — enemy classes/factories (e.g. goblin, troll)projectiles — projectile behaviors. (e.g. cool bullets)spawners — code to spawn waves/levels of enemiesgame.addTower(createBasicTower(4,2)) or via click-handling code.Best practices and conventions
update() and draw in draw().levels/towerDefense/ to avoid namespace collisions.Planned features and notes (ideas to implement next)
Game.coins).Testing locally
drawEnemyPath() currently logs out the generated path.Contact & ownership
If you’d like, I can also:
Enemy and Tower class in towerDefense.js and wire them into Game.update() as a concrete example,