#[Сокровищница]

«Танчики» на html5

Коллизии

33

В прошлый раз мы нарисовали наш танк и научили его передвигаться. Теперь необходимо научить его врезаться в стены/воду.

Для этого создаём сущность коллизии и после инициализации уровня храним в памяти все коллизии и в момент попытки двигаться проверяем столкновение коллизий.

Это некая базовая версия физического движка. Нужно понимать логику: то, что игрок видит на экране не имеет никакого значения. Физика просто работает и говорит можно ехать дальше или нет. В какой-то мере это почти тоже самое, что происходит, например, в Unity. Но там система сложнее и она работает скорее подобно тому, как у меня сделано в тетрисе:

  • Двигаем
  • Проверяем пересечение
  • Если оно есть, то двигаем обратно

Здесь же я просчёт сделал по принципу экстраполяции (С Юнити тоже есть такой вариант у коллизий), когда просчёт пересечений происходит как бы с взглядом в будущее, просчёт потенциального пересечение ещё до того, как оно произошло.

Давайте же посмотрим, как это выглядит.

Коллизия – это не класс как таковой, это просто набор общедоступных методов.

/**
 * Получить список субтайлов, покрываемых прямоугольником
 *
 * @returns {Array<{tx: number, ty: number}>} Массив координат субтайлов
 */
export function getTilesUnderEntity(x, y, width, height) {
  const left = Math.floor(x / TILE_SIZE);
  const right = Math.floor((x + width - 1) / TILE_SIZE);
  const top = Math.floor(y / TILE_SIZE);
  const bottom = Math.floor((y + height - 1) / TILE_SIZE);

  const tiles = [];
  for (let ty = top; ty <= bottom; ty++) {
    for (let tx = left; tx <= right; tx++) {
      // Проверяем границы сетки
      if (tx >= 0 && tx < GRID_SIZE && ty >= 0 && ty < GRID_SIZE) {
        tiles.push({ tx, ty });
      }
    }
  }

  return tiles;
}

/**
 * Проверить, может ли танк войти на данный тайл
 *
 * @returns {boolean} true если танк может войти
 */
export function canTankEnter(tileDef, tank) {
  if (!tileDef) return true;

  // Вода: проходима только с бонусом "лодка"
  if (tileDef.id === TileType.WATER) {
    return tank && tank.hasBoat;
  }

  return !tileDef.blocksTank;
}

/**
 * Проверить коллизию танка с картой при движении в новую позицию
 * та самая экстраполяция
 *
 * @returns {boolean} true если коллизия есть (нельзя двигаться)
 */
export function checkTankMapCollision(tank, newX, newY, gameMap) {
  // Получаем субтайлы под новой позицией танка
  const tiles = getTilesUnderEntity(newX, newY, TANK_SIZE, TANK_SIZE);

  // Проверяем каждый субтайл
  for (const { tx, ty } of tiles) {
    const tileId = gameMap.getTile(tx, ty);
    const tileDef = TILE_DEFS[tileId];

    if (!canTankEnter(tileDef, tank)) {
      return true; // Есть пересечение
    }
  }

  return false; // Нет пересечений
}

/**
 * Проверить коллизию двух AABB (Axis-Aligned Bounding Box)
 *
 * @returns {boolean} true если боксы пересекаются
 */
export function checkAABBCollision(a, b) {
  return (
    a.x < b.x + b.width &&
    a.x + a.width > b.x &&
    a.y < b.y + b.height &&
    a.y + a.height > b.y
  );
}

/**
 * Проверить коллизию двух танков
 *
 * @returns {boolean} true если есть коллизия с другим танком
 */
export function checkTankTankCollision(tank, newX, newY, tanks) {
  const tankBox = {
    x: newX,
    y: newY,
    width: TANK_SIZE,
    height: TANK_SIZE
  };

  for (const other of tanks) {
    // Пропускаем себя и уничтоженных
    if (other === tank || other.destroyed) continue;

    const otherBox = other.getBounds();
    if (checkAABBCollision(tankBox, otherBox)) {
      return true; // Коллизия с другим танком
    }
  }

  return false;
}

А ещё с прошлого поста был проведён рефакторинг. У меня чесалось нёбо от неудобных некрасивых констант, с которыми были вездесущие сравнения. В целом, не магические числа – уже хорошо, но тем не менее. Енамки JS не поддерживает, поэтому делаем костыль через замороженные объекты.

// Было
export const TILE_EMPTY = 0;
export const TILE_BRICK = 1;
export const TILE_STEEL = 2;
export const TILE_WATER = 3;
export const TILE_FOREST = 4;
export const TILE_ICE = 5;
export const TILE_BASE = 6;
// Стало
export const TileType = Object.freeze({
  EMPTY: 0,
  BRICK: 1,
  STEEL: 2,
  WATER: 3,
  FOREST: 4,
  ICE: 5,
  BASE: 6
});

Проверка самих коллизий происходит в методе передвижения танка

newX = Math.max(0, Math.min(newX, LOGICAL_FIELD_SIZE - TANK_SIZE));
        newY = Math.max(0, Math.min(newY, LOGICAL_FIELD_SIZE - TANK_SIZE));

        if (gameMap && checkTankMapCollision(this, newX, newY, gameMap)) {
            return; // не применяем результат передвижения, просто выходим
        }

Ну и в сам метод передаётся информация о карте в инпут менеджере

if (gp.buttons[12]?.pressed) player.move(Direction.UP, gameMap);
if (gp.buttons[13]?.pressed) player.move(Direction.DOWN, gameMap);
if (gp.buttons[14]?.pressed) player.move(Direction.LEFT, gameMap);
if (gp.buttons[15]?.pressed) player.move(Direction.RIGHT, gameMap);

А сам gameMap у нас и главного скрипта, а там он формируется как и раньше в

loadLevel(TEST_LEVEL_1);

Результат:

Далее по плану научить танк стрелять и, в идеале, отрабатывать попадания снарядов в стены.

Всем хороших игр

NGC 2336

28

Галактика NGC 2336 — типичный пример крупной, красивой и голубоватой спиральной галактики. Её запечатлел телескоп «Хаббл». Это спиральная галактика с перемычкой имеет диаметр около 200 000 световых лет и находится примерно в 100 миллионах световых лет от Земли, в северном созвездии Жирафа.

Её спиральные рукава усыпаны молодыми звёздами, которые излучают яркий голубой свет. В отличие от них, центральная область галактики выглядит красноватой, поскольку там преобладают старые звёзды.

NGC 2336 была открыта в 1876 году немецким астрономом Вильгельмом Темпелем с помощью телескопа с диаметром зеркала 28 сантиметров. Изображение «Хаббла» значительно превосходит то, что мог видеть Темпель: главное зеркало «Хаббла» имеет диаметр 2,4 метра — почти в десять раз больше.

Песочные пироженки с творогом

Или очередной эксперимент в 3 часа ночи...

32

Есть у нас в одной сети пекарен прикольные пирожные-корзиночки, а тут ебнуло мне, что можно ж самой такие попробовать сделать, чтоб не покупать их.

Купила, распробовала, вроде поняла, что должно быть в начинке и накатала себе список недостающего. Ну и как обычно - время 3 часа ночи, а значит, пора ебашить :D

(Ради любопытства полезла в галерею и убедилась, что по чистой случайности у меня многие кухонные пиздопляски происходят примерно в это время)

Корзинки там были с ладоху, у меня таких форм не оказалось, поэтому, сегодня они будут тарталетками :D

Итак...


Для теста:

- яйцо - 1 шт.

- мёд - 50 гр.

- сливочное масло (мягкое) - 60 гр.

- сахар - 40 гр.

- мука - 160 гр.

- разрыхлитель - 1 ч.л.

- ванилин по вкусу

Для творожного крема:

- творог 9% - 180 гр.

- яйцо - 1 шт.

- сгущёнка - 60 гр.

- мука - 20 гр.

- сахар - 20 гр.

- ванилин по вкусу.

В тех самых корзинках был ещё джем на дне (в каждой точке пекарни разный кладут) и ягоды в самом креме (раньше была вишня, сейчас чёрная смородина). У меня дома был черничный джем и чёрная смородина в морозилке. Взяла их.


Процесс лёгкий:

Смешать все ингредиенты для теста

Замесить в комочек

Брать по шарику и размазывать по формочке, чтоб с бортиками было

А потом смешать всё для крема

Сделать ВЖЖЖБЖЖББЖЖЖЖ блендером

Ну и всё, можно собирать одно в другое))

Черничный джем
Черничный джем
Крем
Крем
Смородинка
Смородинка

Поставила на 180° и ушла мыть посуду...

Так как в моём случае тарталетки были тонкие, за 15 минут всё уже было готово :)

Сделала вывод, что мне всё-таки нужны алюминиевые формочки для таких штук, ибо если выпекать в них, то корзинки будут более хрустящие, чем после силиконовых. И я бы разрыхлителя поменьше чуть добавила, чёт дохуя его как-то, имхо.

Закажу формочки и буду исправляться)

Города как двигатели эволюции

34

Города — это не просто среда обитания человека, а целая новая экосистема, в рамках которой виды эволюционируют быстрее, чем в дикой природе.

© eurekalert.org
© eurekalert.org

Комары лондонского метро (лат. Culex pipiens molestus) генетически отличаются от своих "деревенских" родственников настолько, что практически с ними не скрещиваются. Кроме того, они не впадают в зимнюю спячку, активны круглый год и эффективно размножаются в замкнутых пространствах туннелей. Кровь для развития яиц самки "добывают" у людей и крыс.

Птицы в городах поют громче и на более высоких частотах, чтобы пробиться сквозь шум транспорта и строек. Они меньше боятся людей и меняют суточный ритм из-за многочисленных источников искусственного освещения. Вороны вообще научились использовать автомобили как щелкунчики: кладут орехи на дорогу и ждут, пока проезжающая машина раздавит скорлупу.

Микробы тем более не стоят на месте. Бактерии на бетоне, пластике и металле смогли приспособиться к материалам, которых никогда не было в природе. Они учатся разлагать синтетические полимеры и выживать в присутствии всевозможных дезинфицирующих средств.

Город — это огромная лаборатория, где эволюцию можно наблюдать в "прямом эфире".

140226•10609/День Святого Валентина и Альпака

Или Дневник его состояния

38
Читалка

Я несколько дней думал насчёт того, чтобы формат дневника привязать к данному лисьему ресурсу, где это соберёт отклик и движ, ежели отдавать ВК, где примерно никому интересно. Итак: сегодня день не претендовал на хороший или плохой, он просто случился: вроде бы и негатива не испытал, но и позитива особо не было.

Жёлтый цвет значит средне, оранжевый близкий к плохому, красный плохой, зелёный хорошо, а фиолетовый отлично
Жёлтый цвет значит средне, оранжевый близкий к плохому, красный плохой, зелёный хорошо, а фиолетовый отлично
Тут типа пост моего отчаяния я закатил, где я всё уже решил и буду опускать свой хвост надежды и чуда
Настал День Всех Влюблённых... и новый пост идёт на эту стенку, где буду крайне редко что-то писать, для этого есть другие ресурсы, где я вспоминаю свою практику знакомств с 2012 по 2026 год, являющимся последним, где моя социализация активна. Он знаменуется тем, что возвращаюсь к истокам: знакомясь с людьми напрямую в ЛС, как это было на заре моего пребывания тут, даже не зная, что можно было писать анкеты в группы знакомств, чего стал практиковать в 2018, которые оказались наменее эффективны, где хоть десяток их напиши в разные места, и никто не заметит... зато обосрут в комментариях, ибо особенных белых ворон в российском ДНОбществе принято травить. Кто-то, конечно, приходит, но картинка сильно не меняется: выясняется, что мы разные, несовместимые либо вовсе пропадают без вести, оказываясь у разбитого корыта снова и снова. Однажды, один человек и правда пришёл, состыковались так, что поехал к нему в другой город за 600 км от дома.. но это оказалось сладкой сказкой с горькой правдой. Поэтому способ нерабочий, можно уже сейчас кидать в мусорку от отсутствия в этом смысла...
Но и способ навязываться в ЛС тоже оказался очень грязным, где тратится уйма ресурса, а результат тот же: сообщения по типу «привет как дела», короткие/длинные, с позитивом, вкладывая душу, каждому пишешь что-то своё... и это может совсем не найти ответа, отдачи, а время/ресурс уже потрачены, учитывая мою слабую социальную батарейку. Люди отвергают, просто молча игнорируют, кидают в чёрный список, могут ответить односложно и на отвали, могут несколько минут уделить переписке, чтобы я плохо не думал, и пропасть (ага, и подумаю об этом очень хорошо потом (нет)), а кто-то и вовсе агрессивен и жалуется на страницу, чтобы заблокировали.. и это при том, что у меня настоящие снимки, всё открыто для чтения и просмотра, а под псевдонимом я, ибо не люблю настоящие свои ФИО... зато сами сидят с пустых и закрытых страниц, фу, как мерзко. Да, были настоящие вовлечённые диалоги, которые приводили к свиданиям и отношениям, но это было настолько краткосрочно и подобно шквалу, что даже не запоминал никого...
А самое страшное это то, что я подвергся деградации под давлением того самого ДНОбщества, и на данный момент во мне столько скелетов в шкафу, что для новых уже нет места: мои тепло и добро быстро остывают, если это адресату не нужно, и сразу начинаю отталкиваться, блокируя его; на токсичность отвечаю зеркально, со всей ненавистью и желчью; в моём сердце уже есть много гнилых вкраплений и могу сам делать очень больно и дискомфортно; создаю образ лучшего себя, где после можно разочароваться... поэтому и хочу поставить точку в этом всём, такой мой финал, к чему я пришёл за 14 лет. 15-летия уже не хочу, остальную жизнь хочу прожить без страданий и вечных неудобств под боком...
_______________________________
...ну а пока во мне доживает свои последние дни надежда на чудо, которое примет в свои объятия, даже вот такое вот я уставшее и хромое настоящим и приютит в своей жизни как можно дольше, а потом можно это выкинуть и забыть, где мне уже будет абсолютно всё равно. Далее текст будет пересказывать мои ранее опубликованные анкеты:
▲︎ ОСНОВНАЯ ИНФО ▼︎
Мне 29, звать Иваном/Ваней/Альпакой, кочуюсь на севере Москвы, работал курьером с жёлтой/красной сумкой, в пункте выдачи тоже с этими цветами, ищу работу, ищу людей :D. Сложилось так, что у меня не так много увлечений/интересов, и с годами этот список сильно не меняется:
— Увлечения: фото-, видеосъёмка (с 2011) на начальном любительском уровне, люблю электровелосипеды/самокаты, путешествия, отвлекаюсь в игры;
— Интересы: город, транспорт, природа, животные, смартфоны, компьютеры;
— Любимая музыка: Armin Van Buuren, Orbion, Omauha, или транс, электронная музыка, вокал и всё остальное, так как я меломан;
— Любимые фильмы/сериалы: Дедпул и Росомаха, Плохая девочка, Дюна, Очень Странные Дела итд, и то, подруга приучила их смотреть);
— Любимые игры: Battlefield, BeamNG.drive, Grand The Auto, Minecraft, Teardown, The Powder Toy итд, то бишь песочницы, шутеры и гонки;
— Где я есть: Лиспублика, Пикабу, LiveJournal, ВКонтакте, Телеграм, Запретграм х), Ютуб, ТикТок;
— Черты характера: непростой, но договориться мы сможем; добрый, светлый, мягкий, гипертактильный, ранимый, неудержимый, упрямый;
— Темперамент: меланхолик;
— Тип личности: авантюрист — ISFP-T.
⊂︎ КАКАЯ У МЕНЯ ИДЕЯ ⊃︎
Я веду фото/видеоблог от лица человека с расстройством аутистического спектра, где я показываю то, как/что вижу, что мне интересно, что происходит, и мне нужна помощь: кто будет помогать с монтажом, сценарием, подкидывать мне мыслей, как мне показать то, чем я хочу делиться, чтобы получить отдачу. За всё время хобби мне не удалось популизироваться и заинтересовать аудиторию (но тут ещё и другие причины есть), и если тут есть блогеры, давайте объединяться!
╱︎ КОГО Я ИЩУ ╲︎
Ну и, конечно, я в перманентном поиске друзей*/родственной души**, с которыми мы построим крепкое взаимодействие, где мы будем бок о бок, а с человеком жизни и вовсе выйдем в масштабы совместного проживания... как раз сейчас актуально найти мне своё новое убежище. Мне понравиться легко и просто: мы либо находим вайбы и нам комфортно и спокойно, либо не судьба, но лучше дружить/любить всех! :з Ах да, поскольку у меня РАС и есть ритуалы, то один из них — гоу пить молочку как только мы увидимся, а мы обязательно это сделаем :р Локация: Москва для поиска очень желательна, ибо у меня тут родственники, круг общения, работа... но если выяснится, что для тебя представляю большой интерес, то и над этим подумаем (:.
*Разделяю дружбу на классическую/с привилегиями
**С родственной душой можем построить моногамные/полигамные/свободные отношения
▧︎ ПОЖЕЛАНИЯ ▨︎
У меня есть список пожеланий, который при первичной переписке мы согласуем, обговорим и расставим все точки, но перед тем, как мне написать в личку, я кое-чем поделюсь.. чтобы заранее отсечь пустую трату времени:
× Душные и токсичные;
× Резкие и жёсткие;
× Стигматизирующие психические расстройства;
× Которые не идут навстречу и компромиссы;
× Легкомысленные и обесценивающие.

В фотографиях этот день почти не зафиксирован... кроме одной:

Кися застряла в пакете))))
Кися застряла в пакете))))

Гыыы