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

Обкатаем спрашивалку?

ВНИМАНИЕ!!!! ВАРНИНГ!!! МАТЮКИ!!!!

36

Ну что, дорогие мои детишечки, пришло время заняться серьезными вещами и немножечко напрячь свой мозг, который у вас большой, огромный, как у доцентов.

Давайте-ка начнем с чего-нибудь простого и всем известного. Так сказать, разомнем ваши пальчики. Хорошо? нет

Вот вам первый вопрос в качестве тренировки. Давайте думать вместе. Рассуждения и обсуждения, конечно же, происходят в комментариях. Потому что тс может нести хуйню... Уже начал есичо

Но если вы не хотите обсуждать и рассуждать, то просто молча ткните кнопку и идите по своим делам дальше, скролить бесконечную ленту.

Итак.

Фая!

Викторина Выберите 1 вариант

Правильный ответ задан автором.

Что из перечисленного, согласно самой строгой лингвистической трактовке, НЕ является исконно русским матерным корнем (основой трёхэтажной конструкции)?

Хуй
Пизда
Джигурда
Ебать
Блядь

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

Отображение карты уровня

41

Следующим этапом сделаем систему отображения тайлов на игровом поле. Мы предполагаем, что у нас есть тайлы разных типов: кирпичи там, бетон, вода, лёд, кусты.

И чтобы эти самые блоки рисовать на игровом поле, нужно ввести сущность карты и самих блоков.

Сущность карты:

class GameMap {
  constructor() {
    // Сетка 26x26 субтайлов
    this.tileGrid = [];
    for (let y = 0; y < GRID_SIZE; y++) {
      this.tileGrid[y] = new Array(GRID_SIZE).fill(TILE_EMPTY);
    }

    // Карта для хранения состояния повреждений разрушаемых тайлов
    this.damageMask = new Map();

    // Флаг необходимости перерисовки фона
    this.dirty = true;
  }
}

Ну и в нашем основном классе надо карту создать:

/** @type {GameMap} */
let gameMap = null;
...
// в методе init
// Создаём и загружаем карту
  gameMap = new GameMap();
  gameMap.loadLevel(TEST_LEVEL_1);

  // Рисуем фон (карта + рамка)
  renderBackground(gameMap);
  gameMap.dirty = false;

При это тестовый уровень сейчас выглядит вот так:

export const TEST_LEVEL_1 = [
  '..........................',  // 0   верхний ряд пустой (под спавн врагов)
  '..........................',  // 1
  '..BB..BB..BB..BB..BB..BB..',  // 2   кирпичные стены
  '..BB..BB..BB..BB..BB..BB..',  // 3
  '..BB..BB..BB..BB..BB..BB..',  // 4
  '..BB..BB..SS..BB..BB..BB..',  // 5   сталь/бетон
  '..BB..FF..SS..FF..BB..BB..',  // 6   лес
  '..BB..FF......FF..BB..BB..',  // 7
  '..BB..BB..BB..BB..BB..BB..',  // 8
  '..BB..BB..BB..BB..BB..BB..',  // 9
  '..........BB..BB..........',  // 10  
  '..........BB..BB..........',  // 11
  '..BB..BB..........BB..BB..',  // 12  
  '..BB..BB..........BB..BB..',  // 13
  '..BB..BB..BB..BB..BB..BB..',  // 14
  '..BB..BB..BB..BB..BB..BB..',  // 15
  '......WW..BB..BB..WW......',  // 16  вода
  '......WW..BB..BB..WW......',  // 17
  '..BB..BB..II..II..BB..BB..',  // 18  лёд
  '..BB..BB..II..II..BB..BB..',  // 19
  '..BB..BB..BB..BB..BB..BB..',  // 20
  '..BB..BB..BB..BB..BB..BB..',  // 21
  '..........BBBBBB..........',  // 22  защита базы
  '..........BBBBBB..........',  // 23
  '..........BBEEBB..........',  // 24  база
  '..........BBEEBB..........',  // 25
];

Не знаю, пока, на сколько такой формат хранения данных корректен и будет удобен в использовании в дальнейшем, но сейчас он по крайне мере очень нагляден и удобен для ручного левел дизайна.

Рисование блоков достаточно просто:

export function renderBackground(gameMap) {
  const ctx = backgroundCtx;

  // Очищаем весь фон
  clearBackground();

  // Рамка игрового поля
  renderGameFieldBorder();

  // Рисуем все непустые тайлы
  for (let y = 0; y < GRID_SIZE; y++) {
    for (let x = 0; x < GRID_SIZE; x++) {
      const tileId = gameMap.getTile(x, y);
      if (tileId === TILE_EMPTY) continue;

      const tileDef = TILE_DEFS[tileId];
      if (!tileDef) continue;

      // Логические координаты → физические координаты на canvas
      const px = GAME_FIELD_X + x * TILE_SIZE * GAME_SCALE;
      const py = GAME_FIELD_Y + y * TILE_SIZE * GAME_SCALE;
      const size = TILE_SIZE * GAME_SCALE;

      ctx.fillStyle = tileDef.color; // цвет в самих тайлах пока храню
      ctx.fillRect(px, py, size, size); // потом буду спрайты рисовать
    }
  }
}

Хранятся тайлы у меня вот таким образом:

TILE_DEFS = {
  [TILE_EMPTY]: {
    id: TILE_EMPTY,
    name: 'empty',
    blocksTank: false,
    blocksBullet: false,
    destructible: false,
    overlay: false,
    color: COLOR_EMPTY // эта вся фигня в константах забита
  },
...

У сущности карты есть метод для загрузки из вот того текстового бреда, который чуть выше скинут

loadLevel(levelData) {
    for (let y = 0; y < GRID_SIZE; y++) {
      for (let x = 0; x < GRID_SIZE; x++) {
        const char = levelData[y]?.[x] || '.';
        this.tileGrid[y][x] = charToTile(char);
      }
    }

    // Инициализируем damageMask для всех разрушаемых тайлов
    this.damageMask.clear();
    for (let y = 0; y < GRID_SIZE; y++) {
      for (let x = 0; x < GRID_SIZE; x++) {
        const tileDef = TILE_DEFS[this.tileGrid[y][x]];
        if (tileDef && tileDef.destructible) {
          this.damageMask.set(`${x},${y}`, DAMAGE_FULL);
        }
      }
    }

    this.dirty = true;
    console.log(`Level loaded. Destructible tiles: ${this.damageMask.size}`);
  }

function charToTile(char) {
  switch (char) {
    case 'B': return TILE_BRICK;
    case 'S': return TILE_STEEL;
    case 'W': return TILE_WATER;
    case 'F': return TILE_FOREST;
    case 'I': return TILE_ICE;
    case 'E': return TILE_BASE;
    default:  return TILE_EMPTY;
  }
}

И вот такой вот получается итог

В целом, уже похоже на правду и с этим можно работать.

план на следующий этап:

ВОТ БЛИН! ЭКСТРЕННОЕ МАСЛЕНИЧНОЕ ОБЪЯВЛЕНИЕ, СОСТАВЛЕННОЕ В СОСТОЯНИИ АГОНИИ ОТ ПЕРЕЕДАНИЯ БЛИНАМИ.

47

Ситуация, товарищи, критическая. ЧП локального, но очень маслянистого масштаба!

ЧТО ПРОИЗОШЛО:

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

Нужна цепь. Длинная, прочная, из постов.

ЧТО ДЕЛАТЬ (ПРАВИЛА БЛИННОЙ ЭСТАФЕТЫ):

Это гонка. Не на скорость, а на длину. Смысл в цепочке.

Ты делаешь пост.

Содержание: Всё, что связано с Масленицей или блинами.

Это может быть:

* Фото своего блина (идеального, комом или угольком).

* Смешная/стыдная история про готовку.

* Исторический экскурс в традиции.

* Стих про сметану.

* Что угодно! Главное — тема.

ОБЯЗАТЕЛЬНЫЙ РИТУАЛ:

В начале поста чётко пишешь: «Эстафету принял(а) у @[имя того, кто тебя позвал]».

В конце поста зовёшь ОДНОГО следующего. Пишешь что-то вроде: «А теперь эстафету передаю тебе, @[имя следующего]! Давай, спасаем лису!»

Твоя миссия завершена. Жди, не позовут ли тебя в другой цепочке или... начни свою цепочку!

Потому что НАЧАТЬ может каждый! Если тебя пока не позвали, но душа требует блинов и славы — просто начни новую цепочку. Напиши пост и позови первого смельчака. Поздравляю, вы уже команда!

ВАЖНЫЕ НЮАНСЫ (ЧИТАТЬ, А ТО ЛИСА НЕ ВЫБЕРЕТСЯ):

Звать можно ЛЮБОГО, даже если он уже бежит в другой цепочке. Это не саботаж, это стратегическое сшивание цепей! Если ты позвал Петю из параллельной ветки, ваши две цепочки мгновенно сливаются в одну мега-цепь. Так и побеждаем.

НЕЛЬЗЯ звать того, кто уже есть в твоей собственной ветке. Это создаст временную петлю, Лиса будет ходить кругами вокруг картошки, и мы все опоздаем к празднику.

ПОДВЕДЕНИЕ ИТОГОВ:

Всё закончится 22 февраля вечером. Мы измерим все цепочки, которые удалось сшить.

Команда с самой длинной цепью получает почётное звание «ВОТ БЛИН ПЕРВОЙ СТЕПЕНИ», а также всеобщее уважение и право первыми есть блины в следующем году.

А Лиса? Чем длиннее общая цепь из всех постов в конце, тем больше у неё шансов ухватиться и выкарабкаться. Так что в выигрыше все. Особенно Лиса. И особенно блины.

Давай, спасем лису! Ей там, среди картошки, одиноко и голодно (все блины остались наверху).

P.S. Если не хотите помогать Лисе, просто представьте: там, в подвале, вместе с ней теперь и всё масло, и последняя банка сгущёнки. Действуйте!

Столица с высоты 400 км — такой её видят космонавты с борта МКС

35
Космонавт Сергей Кудь-Сверчков запечатлел огни Москвы и полярное сияние над контуром ночной Земли.
Космонавт Сергей Кудь-Сверчков запечатлел огни Москвы и полярное сияние над контуром ночной Земли.

Всем привет!

Дорогие лиспубликанцы, встречайте обновления!

59
Читалка

Видеохостинг в шапке страницы

В верхнем меню справа появилась ссылка "Видео", которая ведёт на видеохостинг FoxFrame.

В мобильной версии она находится в левом меню.

Теперь не нужно сохранять сайт в закладках или держать его в отдельной вкладке - доступ к видеохостингу всегда под рукой.

Вставка видео в посты

В редакторе поста появился инструмент "Видео с FoxFrame". Он позволяет удобнее вставлять видео в пост.

Инструмент доступен через кнопку “+” при создании или редактировании поста.

В окне добавления есть краткая инструкция:

Ответ на пост из комментариев

Под постами в форме комментариев добавлена кнопка "Ответить постом".

Она открывает редактор с уже заполненным заголовком и ссылкой на исходную публикацию.

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

Заявки на журнал

В настройках профиля появился раздел "Журнал", где можно подать заявку на создание собственного журнала.

После одобрения в шапке страницы станет доступно переключение между личным аккаунтом и журналом.

Журнал может публиковать посты и оставлять комментарии, но не может оценивать посты, участвовать в опросах и влиять на рейтинг контента.

Подробнее про журнал
Журнал на Лиспублике - это как блог, который ты создаёшь рядом со своим основным аккаунтом. Он как отдельная сущность, но при этом всё равно принадлежит тебе. Это не новый пользователь с нуля, а дочерний аккаунт, который привязан к твоему основному.
Зачем он вообще нужен? Чтобы ты мог публиковать контент под другим именем и не мешать своему личному профилю. Представь: основной аккаунт - это ты как человек. С мемами, спорами в комментариях, личными постами. А журнал - это ты как автор, бренд или тематический канал. Например, "Новости ИТ", "Кинообзоры" или "Лисий гараж".
Что журнал может? Почти всё, что обычный аккаунт: он может создавать посты, писать комментарии, на него могут подписываться люди, у него есть свой профиль с названием и описанием. По сути, это полноценная страница для публикаций.
Но есть ограничения. Журнал не может ставить оценки постам и комментариям, не может участвовать в опросах и вообще никак не влияет на рейтинг контента. Это сделано специально. Он как нейтральный издатель: публикует - да, но не участвует в голосованиях и не крутит рейтинги. То есть это не инструмент для накрутки, а просто витрина для контента.
Теперь самое главное - зачем всё это нужно на практике. Во-первых, чтобы разделить личное и публичное. Ты можешь в основном аккаунте общаться как обычный пользователь, а в журнале вести, например, новостной канал. Во-вторых, нейтральность: раз журнал не влияет на рейтинг, его удобно использовать для новостей или тематических публикаций, где важно не "воевать" в оценках. В-третьих, брендинг: у журнала своё имя и описание - можно оформить его как отдельный проект.
Как это работает технически, но тоже по-простому. Ты заходишь в настройки и подаёшь заявку: пишешь название журнала и описание. Администратор смотрит и одобряет. После этого создаётся дочерний аккаунт, который связан с твоим основным. В интерфейсе появляется стрелка или переключатель - ты можешь быстро менять, от чьего имени публикуешь: от себя или от журнала. И важный момент: у одного пользователя может быть только один журнал. Не десять, не пять - один.
Если совсем коротко: журнал - это твой личный мини-канал внутри сайта. Отдельное имя, отдельная витрина, но без влияния на рейтинги и без риска для твоего основного аккаунта.

Опросы в постах

Теперь в постах можно добавлять опросы трёх типов.

Сделать это можно через кнопку “+” в редакторе поста, выбрав соответствующий инструмент и настроив параметры.

Свободный опрос позволяет изменить голос после выбора варианта и подходит для неформальных или любых других обсуждений.

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

Викторина даёт возможность указать правильный или неправильный ответ: после голосования пользователю показывается, верно ли он ответил.

Автор опроса может как сам принять участие в голосовании, так и просто посмотреть его результаты.

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

А ещё теперь ссылки на профиль пользователя в удобном человекочитаемом формате!

Но для сохранения совместимости, предыдущий вариант ссылки с номером так же работает!

Также на длиннопосты и посты с опросом теперь будут автоматически добавляться соответствующие теги.

Кажется, мы так торопились вам обо всем рассказать, что о чем-то забыли...

О чем-то важном...

Но вы же найдете сами, да?