Графуари. День 20-21. Распад. Пауза
Также имеет название "голубая австралийская квакша". И это название ей подходит! Вид у неё аж какой-то фарфоровый.
Для квакши она довольно крупная, до 10 см. Помимо зелёно-бирюзовой расцветки выделяется своим горизонтальным зрачком. На лапках есть присоски.
Кожные выделения литории обладают бактерицидными и противовирусными свойствами (так что вполне можно добавить в список безумных дел на жизнь "помыть руки лягушкой").
Выделения немного восковые, поэтому препятствуют испарению влаги.
Квакша обитает в Австралии и Новой Гвинее. Любит влажные леса, предпочитая селиться в сырых дуплах деревьев. Тем не менее, может вести и наземный образ жизни вдали от водоёмов. Спокойно живёт на болотах и лугах.
Литории совсем не боятся людей, поэтому могут даже забрести в чей-нибудь дом и жевать мух на подоконнике.
Эта квакша — одна из самых популярных и простых в уходе домашних лягушек. В неволе доживает до 20 лет. Единственной проблемой может быть ожирение от перекармливания :D
Что ж. Намеченный план был выполнен полностью.
Было три итерации, сначала сделал так, чтоб танки могли крошить всех (в том числе и враги уничтожали друг друга).
Потом я запретил им убивать друг друга, а на третьем этапе ещё добавил взаимоуничтожение снарядов игрока и врага при попадании.
Давайте посмотрим, что там по коду интересного и не очень.
Из нового: появился файлик effects.js, который отвечает за всякие красивости, из самого заметного: взрывы)
const EFFECT_CONFIG = {
[EffectType.EXPLOSION_SMALL]: {
maxFrames: 3,
frameTime: 3, // 3 игровых кадра на кадр анимации (100ms при 30 FPS)
size: BULLET_SIZE * 2,
colors: ['#FFFF00', '#FFA500', '#FF4500'] // Жёлтый → оранжевый → красный
},
[EffectType.EXPLOSION_BIG]: {
maxFrames: 5,
frameTime: 3,
size: TANK_SIZE * 1.5,
colors: ['#FFFFFF', '#FFFF00', '#FFA500', '#FF4500', '#8B0000'] // Белый → жёлтый → оранжевый → красный → тёмно-красный
},
[EffectType.SPAWN]: {
maxFrames: 4,
frameTime: 4,
size: TANK_SIZE,
colors: ['#FFFFFF', '#888888', '#FFFFFF', '#888888'] // Мигание
}
};
И сам класс эффекта:
export class Effect {
/**
* @param {number} x - Логическая координата X (центр эффекта)
* @param {number} y - Логическая координата Y (центр эффекта)
* @param {string} type - Тип эффекта (EffectType)
*/
constructor(x, y, type = EffectType.EXPLOSION_SMALL) {
this.x = x;
this.y = y;
this.type = type;
// Получаем конфигурацию для этого типа эффекта
const config = EFFECT_CONFIG[type] || EFFECT_CONFIG[EffectType.EXPLOSION_SMALL];
this.maxFrames = config.maxFrames;
this.frameTime = config.frameTime;
this.size = config.size;
this.colors = config.colors;
// Состояние анимации
this.frame = 0;
this.age = 0;
}
/**
* Обновление состояния эффекта
* @param {number} dt - Время кадра (не используется при fixed timestep)
*/
update(dt) {
this.age++;
// Переход к следующему кадру анимации
if (this.age >= this.frameTime) {
this.frame++;
this.age = 0;
}
}
/**
* Проверка завершения анимации
* @returns {boolean} true если анимация закончилась
*/
isDone() {
return this.frame >= this.maxFrames;
}
/**
* Отрисовка эффекта
*/
render() {
if (this.isDone()) return;
const ctx = foregroundCtx;
// Конвертация логических координат в физические
const px = GAME_FIELD_X + this.x * GAME_SCALE;
const py = GAME_FIELD_Y + this.y * GAME_SCALE;
// Размер эффекта меняется в зависимости от кадра
const progress = this.frame / (this.maxFrames - 1);
const currentSize = this.size * GAME_SCALE * (0.5 + progress * 0.5);
// Цвет из массива цветов
const colorIndex = Math.min(this.frame, this.colors.length - 1);
const color = this.colors[colorIndex];
// Рисуем взрыв как круг
ctx.beginPath();
ctx.arc(px, py, currentSize / 2, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
// Внутренний круг (ядро взрыва)
if (this.type === EffectType.EXPLOSION_BIG && this.frame < this.maxFrames - 1) {
ctx.beginPath();
ctx.arc(px, py, currentSize / 4, 0, Math.PI * 2);
ctx.fillStyle = '#FFFFFF';
ctx.fill();
}
}
}
Часть этого кода перепишется, когда я переведу игру на спрайты, оставив только смену кадров и "возраст", а все остальные визуальности удалив.
В файле коллизий появилась ещё пара новых методов:
export function checkBulletTankCollision(bullet, tanks) {
const bulletBox = {
x: bullet.x,
y: bullet.y,
width: BULLET_SIZE,
height: BULLET_SIZE
};
// Определяем, является ли владелец пули врагом
const ownerIsEnemy = bullet.owner && bullet.owner.type !== TankType.PLAYER;
for (const tank of tanks) {
// Пропускаем владельца пули и уничтоженных
if (tank === bullet.owner || tank.destroyed) continue;
// Вражеские пули пролетают сквозь других врагов (как в оригинале)
if (ownerIsEnemy && tank.type !== TankType.PLAYER) continue;
const tankBox = tank.getBounds();
if (checkAABBCollision(bulletBox, tankBox)) {
return tank; // Попадание в танк
}
}
return null;
}
export function checkBulletBulletCollisions(bullets) {
const collisions = [];
for (let i = 0; i < bullets.length; i++) {
const bullet1 = bullets[i];
if (!bullet1.active) continue;
const box1 = {
x: bullet1.x,
y: bullet1.y,
width: BULLET_SIZE,
height: BULLET_SIZE
};
// Определяем, принадлежит ли пуля игроку
const isPlayer1 = bullet1.owner && bullet1.owner.type === TankType.PLAYER;
for (let j = i + 1; j < bullets.length; j++) {
const bullet2 = bullets[j];
if (!bullet2.active) continue;
const isPlayer2 = bullet2.owner && bullet2.owner.type === TankType.PLAYER;
// Сталкиваются только пули разных команд (игрок vs враг)
if (isPlayer1 === isPlayer2) continue;
const box2 = {
x: bullet2.x,
y: bullet2.y,
width: BULLET_SIZE,
height: BULLET_SIZE
};
if (checkAABBCollision(box1, box2)) {
collisions.push({ bullet1, bullet2 });
}
}
}
return collisions;
}
В целом, тут можно было бы выбрать и иные решения, коллизия и методы их проверки могли бы стать более универсальными, как это сделано, скажем, в Unity. Навесить на все объекты box collider'ы и просто проверять их столкновения без отдельных методов (проверить ТанкТанк, проверить ТанкПуля, проверить ПуляПуля). В таком случае логичнее было бы добавить возможность делать коллизии триггерными, для отработки логики уже внутри самих объектов. Но в таком случае для такой простой игры значительно усложнилась бы архитектура. Поэтому в жертву универсальности я пошёл по более прямолинейному пути.
План на следующий этап:
Не было у меня такого инструмента, а теперь есть. Даже где-то в комментариях про него разговор был с @Brainy но сохранений тогда не было, так что это не точно. Ну раз появился надо срочно что-то запилить!
Взял монетку с дыркой, в качестве материала, отмыл. Жаль испорчена, лежала бы в альбомчике...
Не нашел дома тонкие фломастеры чтоб нарисовать прям на металле и ничего умнее наклейки не придумал. Пилить оказалось не суперсложно, полотно порвал всего два раза :) Дальше был процесс шкурения и немного полировки. Достал свои тонкие сверла делать глоза, пусть будут круглые и прикрутил первую попавшуюся цепочку. Там конечно еще много чего исправить и улучшить, но еще не все нужные приспособы у меня есть, да и списочек их теперь вырос. Поэтому...
Готово!
Гигантские щупальца, способные поднимать и раздавливать корабли. Глаза величиной с бочонок. Тело больше синего кита...
Примерно так моряки прошлых веков описывали кракена — чудовище, которое якобы всплывало из морской пучины, сеяло первобытный ужас и утягивало суда на дно. Тут уже не помогали ни опыт, ни закалка — судьба людей оказывалась в щупальцах монстра.
Но насколько такие истории правдивы? Может ли в Мировом океане скрываться нечто подобное с точки зрения современной биологии?
Важно признать, что глубины Мирового океана крайне сложно изучать. По мере погружения давление растет лавинообразно: на нескольких километрах — уже сотни атмосфер, температура падает, видимость почти нулевая, а пространства — колоссальные. Несмотря на это ученые каждый год описывают сотни новых видов, и среди них порой встречаются существа, которые выглядят так, будто сбежали со страниц фантастики.
Гигантизм — нормальное природное явление. Чтобы животное могло стать огромным, ему нужны:
В глубинах океана часть этих факторов действительно имеется. Низкие температуры замедляют обмен веществ у многих организмов, а особенности глубинной среды иногда "подталкивают" эволюцию к порождению крупных форм. Поэтому открытие огромных животных в бездне Мирового океана не удивляет ученых.
Главная проблема не в том, что их не существует, а в том, что их трудно запечатлеть. Погружаемые аппараты и камеры ограничены по времени работы и глубине, текущее финансирование океанологии часто позволяет исследовать лишь ничтожную часть океана, да и гигантские обитатели могут быть редкими и избегать источников света и шума.
И все же прогресс идет. В начале XXI века ученым впервые удалось наблюдать живого гигантского кальмара в естественной среде, а позже находили других крупных морских обитателей, подтверждающих, что "монстры" из легенд моряков имеют реальный прототип.
Наиболее правдоподобное объяснение заключается в том, что рассказы о кракене родились из встреч с гигантскими кальмарами. В шторм, при плохой видимости, среди обломков, пены, ревущего ветра и ударов волн любой контакт с крупным животным мог легко превратиться в историю, которая с каждым пересказом в портовом пабе становилась все более жуткой.
Открытый океан — неестественная для человека среда. И когда в условиях прямой угрозы жизни мы сталкиваемся с чем-то совершенно непривычным, мозг начинает достраивать картину: усиливает детали, преувеличивает масштаб и превращает увиденное в образ чудовища (проще говоря, у страха глаза велики).
Вот тут начинается область ограничений. Существо, превосходящее по размеру синего кита (длина взрослых особей может превышать 33 метра), должно потреблять колоссальное количество энергии. Даже если оно живет в холодной воде и его метаболизм сильно замедлен, ему все равно нужно регулярно находить очень много пищи.
Кроме того, возникает проблема механики: у мягкотелого животного нет жесткого "каркаса", поэтому чем больше оно становится, тем труднее ему сохранять форму и эффективно двигаться — ткани начинают испытывать огромные нагрузки при рывках, маневрах и захвате добычи. Например, резкий бросок в сторону косяка рыб мог бы закончиться травмами и потерей части щупалец.
Другими словами, такой кракен не смог бы эффективно охотиться, а значит — обеспечивать себя энергией. Поэтому подобный вид не удержался бы в природе достаточно долго, чтобы дождаться первых моряков в открытых водах.
Так что кракен как обитатель морских глубин чудовищного размера, поднимающий корабли, почти наверняка — выдумка. Но эта легенда скорее не о конкретном животном, а о первобытной тревоге перед неизвестным: где-то там, под километровой толщей воды, есть нечто, с чем мы еще никогда не сталкивались.
Современные технологии повышают шансы находить крупных и редких обитателей Мирового океана: глубоководные беспилотные аппараты, автономные камеры, акустическое наблюдение, анализ ДНК из проб воды и обработка массивов данных с помощью ИИ позволяют выявлять следы присутствия видов до их прямого обнаружения.
Да, было бы проще все и понятней
Из окна электрички же? Я не прав?
Чехол