I Built a Tower Defense Game With Zero Dependencies — AI Art, Procedural Audio, and ~3,200 Lines of Vanilla JS

від

у

Я побудував гру у захист замку з нуль залежностями — штучне інтелектуальне мистецтво, процедурний звук та близько 3 200 рядків чистого JS
https://ift.tt/lv2ZMYq

Немає React. Немає Phaser. Немає Pixi.js. Немає npm install. Просто <canvas>, ванільний JS та Web Audio API.

🎮 Грати тут · 📖 Повний щоденник розробки

Що я збудував

Arcane Bastion — це кристалічний шутер захисту замку з:

  • 5 елементних веж (Вогонь / Лід / Електрика / Лоза / Аркан) × 3 рівні апгрейду
  • 10 типів ворогів з ефектами стану (замерзання, обпалення, отруєння)
  • Ін-art AI — кожний спрайт та фон карти згенеровані штучним інтелектом
  • Процедурний звук — кожен звуковий ефект синтезований з осциляторів, жодних аудіофайлів
  • Динамічна орієнтація вежі — плавне слідкування з відгуком відбиття

Уся історія складається з 9 скриптових файлів, завантажених за допомогою тегів <script> у порядку залежностей. Старомодно, але працює.

Архітектура

arcane-bastion/
├── js/
│   ├── sprites.js    ← асинхронний завантажувач зображень (18 активів)
│   ├── map.js        ← 20×14 плиткова сітка + фони для AI
│   ├── tower.js      ← 5 типів, цілепокладання, плавне обертання
│   ├── enemy.js      ← 10 типів, навігація за шляхом
│   ├── projectile.js ← вогнепальні ракети з наведенням, ланцюгова блискавка
│   ├── audio.js      ← синтез за допомогою Web Audio (~400 рядків)
│   ├── ui.js         ← HUD, панелі, накладка на біографію
│   ├── game.js       ← цикл 60fps, стан хвилі
│   └── demo-mode.js  ← запрограмований авто-демо + MediaRecorder

Найважчий баг: політика автоплей Chrome 🔇

Цей баг з’їв чимало годин. Мій аудіо-двигун відпрацював нормально у локальному тестуванні, але після розгортання в Chrome став повністю тишею.

Проблема коріння: створення AudioContext до першого руху користувача переводить його у стан сну — назавжди. Мій Game.init() викликав AudioEngine.init() під час завантаження сторінки.

Виправлення:

// ❌ ПОГАНО: створює AudioContext під час завантаження сторінки
function init() {
    ctx = new AudioContext(); // замовкне назавжди!
}

// ✅ ДОБРЕ: ліниве створення при першій взаємодії користувача
function init() {
    document.addEventListener('click', () => {
        if (!ctx) {
            ctx = new AudioContext();
            // тепер працює, бо користувач вперше тиснув
        }
    });
}

І найважливіше — кожна звукова функція повинна викликати ensureContext() перед охороною if (!ctx) return, а не після. Якщо порядок помилковий — контекст ніколи не створиться.

AI Art: не підключається “з коробки”

Я згенерував усі 18 візуальних елементів (5 веж, 10 ворогів, 3 карти) за допомогою генерації зображень за штучним інтелектом. Звучить легко, так?

Реальність:

  • Послідовність — кожен запит потребував однакового стилістичного якоря: “темне фентезі, піксель-арт, зверху вниз, сяючі магічні ефекти”
  • Прозорість — ранні спрайти мали видимі прямокутні фони. Кожен потребував ручного очищення
  • Контраст — спрайти, які добре виглядали на білому тлі, зникали на темних фонах карти. Потрібно було додати сяйво ореолів та підсвітку
  • Масштаб — красивий 512×512 спрайт на ігровому масштабі стає розмитим 50px штучкою

AI-арт зберіг тижні ілюстраційної праці, але інтеграційна “остання миля” все одно вимагала значної ручної роботи.

Процедурний звук: математика → звук

Найбільш задовольняюча система для розробки. У кожному звуці гри використовується синтез з формами хвилі OscillatorNode

// Аттак вежі frost: кристалічний “пінг”
function frostShoot() {
    playTone(1200, 0.15, 'sine', 0.12);    // високий блиск
    playTone(800, 0.2, 'triangle', 0.08); // гармоніка
    playNoise(0.08, 0.1);                  // лідяний тріск
}

Вогонь, лід, блискавка, ліана, аркан — у кожному елементі унікальна аудіо-підпис створена шляхом поєднання типів осциляторів (sine, triangle, sawtooth, square) на різних частотах та тривалостях.

Фоновий музичний супровід — це багатопроцесорний амбієнтний дрон, який еволюціонує з часом. Загалом аудіо-система близько 400 рядків — жодних аудіо-активів не завантажується.

Три зміни, які зробили найбільшу візуальну різницю

  • Замінені процедурні фони карт AI на атмосферні
  • Сяйво ореолів на спрайтах веж (радіальна градієнтна кола позаду кожної вежі) — миттєва глибина
  • Плавне обертання вежы за допомогою Math.atan2 + лерп-інтерполяція — усе стало живим

Жодна з цих змін не вплинула на геймплей. Усі вони змінили відчуття від гри.

Остаточна статистика

Показник Значення
Рядків JS ~3 200
Модулі коду 9
AI-генеровані активи 18
Зовнішні залежності 0
Аудіо-файли 0
Інструменти збірки 0

Я написав набагато глибший технічний розбір, що охоплює системи сіток, пошук шляхів, реалізацію ланцюгової блискавки, синергію веж та те, як я записував демонстраційне відео з аудіо за допомогою API MediaRecorder у браузері.

📖 Прочитати повний розбір розробки понад 3000 слів

🎮 Грати Arcane Bastion

HI-FI News

через DEV Community https://dev.to

16 березня 2026 р. о 13:39PM

March 16, 2026 at 01:39PM