«Танчики» на HTML5
Примитивный ИИ врагов
Всем причастных с праздником!
Я тут вспомнил, что в прошлом посте забыл добавить планы на будущее. Планами было: добавить врагов.
Соответственно: точки спавна, их перемещение по карте, стрельба.
Давайте посмотрим на результат.
Появился новый класс, отвечающий за поведение врагов
export class EnemyAI {
constructor(tank) {
this.tank = tank;
// Таймер смены направления
this.changeDirectionTimer = 0;
this.changeDirectionInterval = 60; // ~2 сек при 30 FPS
// Cooldown стрельбы
this.shootCooldown = 0;
this.shootInterval = 30; // ~1 сек при 30 FPS
// Флаг застревания (для смены направления при коллизии)
this.wasBlocked = false;
}
randomDirection() {
const directions = [Direction.UP, Direction.RIGHT, Direction.DOWN, Direction.LEFT];
return directions[Math.floor(Math.random() * 4)];
}
update(allTanks, gameMap, bullets) {
const tank = this.tank;
if (tank.destroyed) return;
// === 1. Логика смены направления ===
this.changeDirectionTimer++;
// Смена направления по таймеру
if (this.changeDirectionTimer >= this.changeDirectionInterval) {
tank.direction = this.randomDirection();
this.changeDirectionTimer = 0;
// Рандомизируем интервал (40-80 кадров)
this.changeDirectionInterval = 40 + Math.floor(Math.random() * 40);
}
// === 2. Попытка движения ===
const prevX = tank.x;
const prevY = tank.y;
tank.move(tank.direction);
// Проверка: застрял ли танк (не сдвинулся)
const stuck = (tank.x === prevX && tank.y === prevY && !tank.moving);
if (stuck && !this.wasBlocked) {
// Танк только что застрял — меняем направление
tank.direction = this.randomDirection();
this.wasBlocked = true;
this.changeDirectionTimer = 0;
} else if (!stuck) {
this.wasBlocked = false;
}
// === 3. Автоматическая стрельба ===
this.shootCooldown--;
if (this.shootCooldown <= 0 && tank.canShoot()) {
const bullet = tank.shoot();
if (bullet) {
bullets.push(bullet);
// Рандомизируем cooldown (20-50 кадров)
this.shootCooldown = 20 + Math.floor(Math.random() * 30);
}
}
}
}
Он простой как три рубля, так что, думаю, можно обойтись без объяснений (тем более что комментариев в коде и так предостаточно).
К файле main появились коллекции врагов и их "мозгов"
/** @type {Array<Tank>} */
let enemies = [];
/** @type {Array<EnemyAI>} */
let enemyAIs = [];
Спавн врагов при старте игры
spawnEnemy(0, 0); // Левый угол
spawnEnemy(12 * 8, 0); // Центр (96px)
spawnEnemy(24 * 8 - 16, 0); // Правый угол (176px, учитываем размер танка)
// Пока спавню сразу все три, а не по очереди, как в оригинале
function spawnEnemy(x, y) {
const enemy = new Tank(x, y, TankType.ENEMY_BASIC);
enemy.direction = Direction.DOWN; // Враги всегда смотрят вниз
enemy.setMap(gameMap);
// Создаём AI для врага
const ai = new EnemyAI(enemy);
enemies.push(enemy);
enemyAIs.push(ai);
console.log(`Enemy spawned at (${x}, ${y})`);
}
И рисуем это
for (const enemy of enemies) {
if (!enemy.destroyed) {
enemy.render();
}
}
Там ещё есть обновление ссылок чтоб чистить из памяти уничтоженные танки, но в целом ничего больше интересного.
Оптимистичный план на следующий этап вот такой:
Как понимаю, в асихронность разработчик не умеет. Метод update синхронный и будет замедлять код там, где это лишнее.
Как понимаю, в асихронность разработчик не умеет. Метод update синхронный и будет замедлять код там, где это лишнее.
Госпидя... Гуру, ну немножечко мозг включи пожалуйста. В асинхронность я не умею. Не надо пихать её везде просто потому что. Если ты вдруг выучил какую-то классную штуку, не надо думать, что её нужно везде пихать теперь
Госпидя... Гуру, ну немножечко мозг включи пожалуйста. В асинхронность я не умею. Не надо пихать её везде просто потому что. Если ты вдруг выучил какую-то классную штуку, не надо думать, что её нужно...
Я даже с выключенным мозгом понимаю, что для танчиков на хтмл достаточно массива NxM объектов, а не вот это вот всё.
Проверка условий уровня O(1): север, юг, восток, запад. Для пуль так вообще одно направление.
События по таймеру отдать на откуп лямбдам. Реакт в помощь.
Я даже с выключенным мозгом понимаю, что для танчиков на хтмл достаточно массива NxM объектов, а не вот это вот всё.
Проверка условий уровня O(1): север, юг, восток, запад. Для пуль так вообще одно нап...
Поздравляю тебя с реактом головного мозга)
Искренне и торжественно клянусь, что попрошу прощения за свой снобизм и спесь, как только прочитаю хоть одну умную мысль от тебя. А ещё лучше хоть один похожий на правду кусок кода.
Ну а для честности просто запили сам свои танки и покажи как надо. Всем польза будет.
Поздравляю тебя с реактом головного мозга)
Искренне и торжественно клянусь, что попрошу прощения за свой снобизм и спесь, как только прочитаю хоть одну умную мысль от тебя. А ещё лучше хоть один похожи...
Пользы никому не будет. Код Танчиков уже давно вылизан. И размещать очередной клон нет смысла.
Я лишь указываю на очевидные недоработки.
Не хотите совершенствоваться - ваше право.
Пользы никому не будет. Код Танчиков уже давно вылизан. И размещать очередной клон нет смысла.
Я лишь указываю на очевидные недоработки.
Не хотите совершенствоваться - ваше право.
Всё, что было написано исключительно далеко от понятия «совершенствоваться».
Я могу с полной уверенностью заявить, что прежде чем писать всю эту историю, прошёл весьма не малый путь разработки и могу отличить потенциально хороший совет от откровенно бреда.
А привычка считать себя по умолчанию умнее других весьма пагубна.
Всё, что было написано исключительно далеко от понятия «совершенствоваться».
Я могу с полной уверенностью заявить, что прежде чем писать всю эту историю, прошёл весьма не малый путь разработки и могу о...
Дональду Кнуту и Роберту Мартину это расскажи.
Комментарий