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

Шаурма

или донер

45

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

И перчик!
И перчик!

Подмаринуем мясо и пожарим без всяких грилей, прям в сковороде.

Картохи нарежем и нажарим.
Картохи нарежем и нажарим.
Намешаем кетчунез!
Намешаем кетчунез!

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

Всем приятного аппетита и спасибо за внимание!

Универсальный игровой сервер

для любой несложной игры

40
Читалка

От имени своего журнала @VariusSoft выкладывал посты про то, как тетрис запилить и сейчас серия постов о том как воссоздать танчики. В процессе разработки осознал, что в них надо играть вдвоём, а как же это делать, если сесть за одну денди и взять в руки два джойстика нет возможности?

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

Выглядит это безобразие так:

Да, вот такая скукотища, просто буковки
Да, вот такая скукотища, просто буковки

Написан он на Шарпе и скомпилирован под 8 дот нет, чтоб была возможность запустить и на маках и на линях. Но ещё, для пущей уверенности, завернул к херам в докер это безобразие.

Каков же алгоритм работы?

Первый игрок, который хочет с кем-то поиграть, нажимает кнопочку «Создать комнату» в интерфейсе игры, игры стучится на сервер и получает идентификатор комнаты. Дальше и эта игра и другие клиенты подключаются к этой же комнате. Первый клиент выступает в роли хоста. То есть вся обработка геймплея и игрового мира происходит на нём. Как это всегда было в КС, Халфе и прочих сессионных зарубах.

Также написал SDK на JS для встраивания работы с сервером в любую HTML5 игру.

Математически при хорошем канале данный сервер способен вытянуть одну игру на 400-500 человек или 10 игр по 40. Как на практике будет работать, посмотрим. Хотя, сэмулировать нагрузку в 500 человек я даже если очень хочу, не смогу)

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

И да, я уже предвижу комментарии из цикла: «Нахер изобретать велосипед», но мне насрать, серьёзно. Я хотел написать, я написал.

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

Ответ на пост: Ответ на пост: На волне "Нелицеприятный"

40

Ответ на пост Ответ на пост: На волне "Нелицеприятный"

@Alida а я вспомнила!

У меня всё без длинной истории, но всё же волна так волна))

Будучи мелкой школьницей услышала два похожих друг на друга слова и они у меня слились в одно...

Поэтому, "медитировать" и "мастурбировать" - были для меня словами с одинаковым значением))

Ответ на пост: На волне "Нелицеприятный"

41

Ответ на пост На волне "Нелицеприятный"

Воспоминание разблокировано!

Происходило это в весьма позднем детстве. Лето. Мне почти четырнадцать лет. Моя сестра поступила в вуз — и не абы куда, а в Москву! Гордость всей семьи!

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

Иду из магазина — и вдруг за мной увязались трое пацанов на пару лет младше. Докапываются: то уродкой назовут, то дурочкой, то лохушкой. Сначала их шугала, а потом стала за ними гоняться с обещаниями поймать и отлупить. А им только этого и надо: разбегаются в разные стороны, хохочут и продолжают дразниться. И тут среди прочих обидных эпитетов вылетает: «Праститутка!»

Я остановилась. Слово это слышала и раньше во дворе — применяли его к уже взрослым и красивым девочкам. Таким же взрослым и красивым, как моя сестра! Так кто же такая праСТИТУТка?.. Наверное, это та, кто учится в инСТИТУТе! — решила я и продолжила гоняться за шпаной, но теперь уже выкрикивая на весь двор:

«Не обзывайтесь так! Праституткой быть хорошо! У меня сестра — праститутка в Москве! И я, когда вырасту, тоже стану праституткой! А вы глупые и ничего не понимаете!»

Народ, к вам вопрос))

Про фотофокс

39

У нас появилась функция опросов.

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

Мне это кажется удобным. Но есть одно НО :D

Я не могу сообразить, как изменить механику начала выбора этих слов. Ибо если оставить всё так же, то получится странно, ведь по привычке, скорее всего, люди будут голосовать +/- в комментах и если я буду выкатывать эти слова потом опросом для повторного голосования - тоже неправильно.

Может быть, у кого-то найдутся мысли, как можно переебать систему, чтобы подрубить к выбору слова опросы? У меня чёт пока не приходит в голову.

Или, может, вообще не стоит ничего менять?

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

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

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;
  }
}

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

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

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