От имени своего журнала @VariusSoft выкладывал посты про то, как тетрис запилить и сейчас серия постов о том как воссоздать танчики. В процессе разработки осознал, что в них надо играть вдвоём, а как же это делать, если сесть за одну денди и взять в руки два джойстика нет возможности?
Ну, онлайн, чё тупить. Но как организовать онлайн? В общем покумекал я немного и решил, что для этого необходим сервер. Но писать полноценный сервер для игры в танчики – это, как будто, прям из пушки по воробьям. Поэтому я решил написать универсальный сервер, который одновременно может обслуживать несколько игр, каждая на пару-тройку десятков одновременных игроков.
Выглядит это безобразие так:
Да, вот такая скукотища, просто буковки
Написан он на Шарпе и скомпилирован под 8 дот нет, чтоб была возможность запустить и на маках и на линях. Но ещё, для пущей уверенности, завернул к херам в докер это безобразие.
Каков же алгоритм работы?
Первый игрок, который хочет с кем-то поиграть, нажимает кнопочку «Создать комнату» в интерфейсе игры, игры стучится на сервер и получает идентификатор комнаты. Дальше и эта игра и другие клиенты подключаются к этой же комнате. Первый клиент выступает в роли хоста. То есть вся обработка геймплея и игрового мира происходит на нём. Как это всегда было в КС, Халфе и прочих сессионных зарубах.
Также написал SDK на JS для встраивания работы с сервером в любую HTML5 игру.
Математически при хорошем канале данный сервер способен вытянуть одну игру на 400-500 человек или 10 игр по 40. Как на практике будет работать, посмотрим. Хотя, сэмулировать нагрузку в 500 человек я даже если очень хочу, не смогу)
Но! Если вы вдруг увлекаетесь игронаписанием, я могу вам выдать сервак на растерзание, ну или просто для своей игры себе чтоб подняли и использовали.
И да, я уже предвижу комментарии из цикла: «Нахер изобретать велосипед», но мне насрать, серьёзно. Я хотел написать, я написал.
Происходило это в весьма позднем детстве. Лето. Мне почти четырнадцать лет. Моя сестра поступила в вуз — и не абы куда, а в Москву! Гордость всей семьи!
Я тогда была созданием более чем невинным и далёким от глубоких познаний дворовых мальчишек о человеческих пороках.
Иду из магазина — и вдруг за мной увязались трое пацанов на пару лет младше. Докапываются: то уродкой назовут, то дурочкой, то лохушкой. Сначала их шугала, а потом стала за ними гоняться с обещаниями поймать и отлупить. А им только этого и надо: разбегаются в разные стороны, хохочут и продолжают дразниться. И тут среди прочих обидных эпитетов вылетает: «Праститутка!»
Я остановилась. Слово это слышала и раньше во дворе — применяли его к уже взрослым и красивым девочкам. Таким же взрослым и красивым, как моя сестра! Так кто же такая праСТИТУТка?.. Наверное, это та, кто учится в инСТИТУТе! — решила я и продолжила гоняться за шпаной, но теперь уже выкрикивая на весь двор:
«Не обзывайтесь так! Праституткой быть хорошо! У меня сестра — праститутка в Москве! И я, когда вырасту, тоже стану праституткой! А вы глупые и ничего не понимаете!»
С одной стороны, мне бы хотелось попробовать голосование за слово для фотофокс проводить с их помощью, чтобы в одном посте сразу были выкачены слова и там на месте уже бы все могли проголосовать, а не искали пост и не разворачивали комменты, чтобы глянуть все выдвинутые слова и поставить им оценку, как это делается сейчас…
Мне это кажется удобным. Но есть одно НО :D
Я не могу сообразить, как изменить механику начала выбора этих слов. Ибо если оставить всё так же, то получится странно, ведь по привычке, скорее всего, люди будут голосовать +/- в комментах и если я буду выкатывать эти слова потом опросом для повторного голосования - тоже неправильно.
Может быть, у кого-то найдутся мысли, как можно переебать систему, чтобы подрубить к выбору слова опросы? У меня чёт пока не приходит в голову.
Ну что, дорогие мои детишечки, пришло время заняться серьезными вещами и немножечко напрячь свой мозг, который у вас большой, огромный, как у доцентов.
Давайте-ка начнем с чего-нибудь простого и всем известного. Так сказать, разомнем ваши пальчики. Хорошо? нет
Вот вам первый вопрос в качестве тренировки. Давайте думать вместе. Рассуждения и обсуждения, конечно же, происходят в комментариях. Потому что тс может нести хуйню... Уже начал есичо
Но если вы не хотите обсуждать и рассуждать, то просто молча ткните кнопку и идите по своим делам дальше, скролить бесконечную ленту.
Итак.
Фая!
ВикторинаВыберите 1 вариант
Правильный ответ задан автором.
Что из перечисленного, согласно самой строгой лингвистической трактовке, НЕ является исконно русским матерным корнем (основой трёхэтажной конструкции)?
Следующим этапом сделаем систему отображения тайлов на игровом поле. Мы предполагаем, что у нас есть тайлы разных типов: кирпичи там, бетон, вода, лёд, кусты.
И чтобы эти самые блоки рисовать на игровом поле, нужно ввести сущность карты и самих блоков.
Сущность карты:
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 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;
}
}
И вот такой вот получается итог
В целом, уже похоже на правду и с этим можно работать.
хуя порог горячего прыгнул...
@kimpokom чёт щас на винте нашла это и вспомнила твои подсчёты
технопрон!)