Tower Defence. Часть 1
Tower Defence. Часть 1: Фундамент игры
Ты начинаешь проект, который очень похож на реальную frontend-разработку: есть состояние (state), цикл обновления, рендер на canvas и действия пользователя.
В этой части мы создаем основу, без которой игра не сможет работать: поле, маршрут, стартовые данные и первый спавн врагов.
Посмотри целевой результат
Ниже встроена демо-игра, к которой мы идем по шагам:
[tower-defense-iframe]
Карта технологий всей линии Tower Defence (части 1-5)
- 2D-координаты и сетка (
{ x, y }, клетки и пиксели). - Математика движения (направление, расстояние, шаг по времени).
- Структуры данных JS (
Array,Object,Set). - Игровое состояние и его сброс (
state,reset). - Wave-система (очередь врагов, таймер спавна).
- События пользователя (
click, кнопки). - Выбор целей и приоритеты.
- Анимационный цикл (
requestAnimationFrame,dt). - Подготовка draw-data для рендера.
- Финальные метрики, прогресс, итоговый счет.
Технологии именно этого урока (lesson-10-12)
- Координатная сетка 2D и точки маршрута.
- Линейный проход по сегментам пути (
for,while). - Направление движения по оси через
Math.sign. - Хранение клеток маршрута в
Setдля быстрых проверок. - Инициализация объекта состояния игры.
- Перевод клетки в пиксели (
toWorld). - Формулы скейлинга врага по волне (
hp/speed/reward). - Таймерный спавн в
updateWave. - Guard-проверки (ранний
return) для стабильной логики.
Фундамент: 2D-пространство простыми словами
Игровое поле делится на клетки. У клетки есть адрес { x, y }:
xпоказывает позицию по горизонтали (влево/вправо);yпоказывает позицию по вертикали (вверх/вниз);{ x: 0, y: 0 }— верхний левый угол.
Пример:
const a = { x: 0, y: 3 };
const b = { x: 3, y: 3 };
const c = { x: 3, y: 1 };
a -> b это движение вправо, b -> c это движение вверх.
Фундамент: как строится маршрут врагов
Маршрут — массив опорных точек path. Враг идет не «по диагонали куда угодно», а по сегментам:
- от
path[0]кpath[1], - от
path[1]кpath[2], - и так далее.
Направление сегмента:
const dx = Math.sign(to.x - from.x);
const dy = Math.sign(to.y - from.y);
dx = 1значит идем вправо,dx = -1влево,dx = 0поxне двигаемся;dy = 1вниз,dy = -1вверх,dy = 0поyне двигаемся.
Что именно ты реализуешь в задачах
createBoardConfig: создаешь конфиг поля (cellSize,cols,rows,width,height).createPath: возвращаешь 6 точек маршрута в правильном порядке, как в демо-игре.buildPathCells: проходишь по сегментам и заполняешьSetстроками вида"x,y".createInitialState: задаешь стартовые значения (lives,money,wave, массивы и флаги).resetGame: полностью возвращаешьstateк старту.toWorld: переводишь координату клетки в центр клетки в пикселях.spawnEnemy: создаешь врага в начале пути с параметрами, зависящими отwave.startWave: запускаешь волну только в валидном состоянии.updateWave: по таймеру спавнишь врагов из очереди.getModeLabel: собираешь понятный режим для HUD: ожидание/волна/game over.
Почему это важно
Если сделать фундамент неаккуратно, дальше игра ломается везде: путь неверный, враги спавнятся не там, волны не стартуют, данные состояния конфликтуют.
Эта часть учит тебя главному инженерному принципу: сначала базовые контракты и чистые helper-функции, потом остальная механика.
Мини-примеры из практики урока
function toWorld(cellX, cellY, cellSize) {
return {
x: cellX * cellSize + cellSize / 2,
y: cellY * cellSize + cellSize / 2,
};
}
function startWave(state) {
// Guard: не стартуем, если уже game over, волна уже идет или враги еще на поле
if (state.gameOver || state.waveQueue > 0 || state.enemies.length > 0) return state;
state.wave += 1;
state.waveQueue = 5 + state.wave * 2;
state.spawnTimer = 0;
return state;
}
Смотри, что важно: в этом уроке waveQueue — это счетчик (сколько врагов еще нужно заспавнить), а spawnTimer — таймер до следующего спавна (обычно в секундах).
Результат после Part 1
У тебя готова основа TD-игры: поле, маршрут, состояние, волны и спавн. Это база для Part 2, где добавим постановку башен.