Graphuary, день 11
Утро
И откуда срисовывала)
Ответ на пост Пыталась нарисовать лису, а получилась недобелка :D
Ладньнко, спасать лису и Кошь - так спасать. Выложу немножко совсем олдово-кринжовых зарисовок на масленичную тему. Цепочку взяла зубами у @Kukabara
Моя первая поделка, показанная вам ещё в старом доме
БЛИННЫЙ СТОЛ
а передаю цепочку (также зубами) сестре моей @Linda_M ❤
Ну и мой повтор
Ответ на пост Ответ на пост: Замутим ещё одну цепочку?
Принимаю эстафету у @Rian
*Арёт @etoshtrudel* !! Бегом лису спасать!!))
Ответ на пост Замутим ещё одну цепочку?
Меня позвала @capybarystic Продолжим предаваться блинным воспоминаниям.
Стараюсь каждую масленицу напечь побольше блинов(больших, тонких, на дрожжах) и наделать кучу начинок(капуста, фарш, рыба, творог, икра, варенья, мед...). Всю неделю питаемся блинами. В другое время года практически не пеку их, если только внезапно захочется.
С юности умела печь тонкие блины. Другие не так интересны, а в тонкие можно завернуть все, что хочешь! Но для этого нужна простая советская раскаленная сковородка (а лучше 2-3 для скорости). И вот, переехав лет 12 назад на новую квартиру, я столкнулась с проблемой: индукционная плита прекрасна, но она не любит тонких блинов :( - раскаленная сковорода, это " алярм, алярм, я выключаюсь ой все!". И стою я с почти двумя литрами теста и пищащей плитой. Выкрутилась я тогда с помощью духовки. Если вы любите толстые, очень толстые блины - то духовка и силиконовые формы - ваш выбор. Были у меня тогда "блины" в форме котят, зайцев и медведей.
А потом попросила на др электроблинницу и по старой традиции задвоения подарков мне их две подарили! И это прекрасно. Да, блины не такие ажурные/зажаристые, зато большие и почти ровные. Почувствуй себя поваром в "Теремке"! Особенно когда рядом скачет ребенок: "мне Фермерский, мне Фермерский".
@Kukabara , хватайся за хвост!
Всем завтрак!
Вкусный и, возможно, даже полезный.
За основу берём тесто вот из этого рецепта. Прям грамм в грамм.
А потом катаем из него небольшие шарики и кидает в разогретое где-то до 170 градусов масло
Ждём три минуты.
Получаем бомбический десерт
Это изобретение моей мамы. Она говорила, что когда лень было заморачиваться с сырникам делала такие пончики.
Возможно, это блюдо даже на самом деле существует, кто знает
У нас есть заготовка для рендера и отрисовка игрового уровня. Пора по нему побегать.
В инициализации появилась пара новых строчек
// Инициализация обработчика ввода
initInput();
Так внутри всё достаточно просто
export function initInput() {
// Слушатели клавиатуры
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
// Слушатели геймпада
window.addEventListener('gamepadconnected', handleGamepadConnected);
window.addEventListener('gamepaddisconnected', handleGamepadDisconnected);
console.log('Input handler initialized');
}
Изначально я хотел добавить поддержку геймпада только на финальном этапе разработки, но получилось так, что это делается достаточно просто, поэтому засунул сразу.
Пойдём по порядку
function handleKeyDown(e) {
keys[e.code] = true; // аккумулируем все нажатия, чтоб потом обработать
// Предотвращаем прокрутку страницы стрелками и пробелом
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space'].includes(e.code)) {
e.preventDefault();
}
}
function handleKeyUp(e) {
keys[e.code] = false; // "забываем" отпущенную кнопку
}
function handleGamepadConnected(e) {
console.log(`Gamepad connected: ${e.gamepad.id}`);
gamepadIndex = e.gamepad.index;
}
function handleGamepadDisconnected(e) {
console.log(`Gamepad disconnected: ${e.gamepad.id}`);
if (gamepadIndex === e.gamepad.index) {
gamepadIndex = null;
}
}
В отличии от клавиатуры, которая отдаёт браузеру события о нажатии на кнопка, с геймпадом такой финт ушами не прокатывает и надо опрашивать его состояние самостоятельно (прям как на привычных движках в старые добрые времена).
Дальше заспавним наш "танк" на игровой сцене
const spawnX = 4 * CELL_SIZE; // 4 клетки от левого края = 64 px
const spawnY = 24 * 8 - 32; // Чуть выше базы = 160 px
player = new Tank(spawnX, spawnY, TANK_PLAYER);
Класс танка достаточно большой, он ко конструкторе принимает значения координат спавна и типа танка (танк игрока или тип врага). Ему устанавливается "здоровье" (сколько раз в него надо попасть, чтобы убить), сколько активных патронов есть и т.д.
constructor(x, y, type = TANK_PLAYER) {
this.x = x;
this.y = y;
// Направление (0=вверх, 1=вправо, 2=вниз, 3=влево)
this.direction = DIR_UP;
this.speed = TANK_SPEED_NORMAL; // в пекселях за кадр
// Тип танка
this.type = type;
this.health = 1;
this.destroyed = false;
// Флаг движения в текущем кадре
this.moving = false; // Пока только задаётся, но нигде не используется. Есть мысли на будущее, но если не понадобится, удалю
// Апгрейды (для игрока)
this.bulletLevel = 0; // 0=обычная, 1=быстрая, 2=усиленная
this.bulletCount = 1; // Макс. пуль на экране
this.hasShield = false; // Временная защита
this.hasBoat = false; // Движение по воде
// Активные пули (для подсчёта лимита)
this.activeBullets = 0;
}
Непосредственно движение выгляди таким образом:
move(direction) {
// Сначала поворачиваем, если нужно
if (this.direction !== direction) {
this.turn(direction);
return; // В оригинале, если повернуть, танк не двигается в этом кадре, может уберу, если плейтесты покажут необходимость
}
// Вычисляем смещение по направлению
let dx = 0;
let dy = 0;
switch (direction) {
case DIR_UP: dy = -this.speed; break;
case DIR_DOWN: dy = this.speed; break;
case DIR_LEFT: dx = -this.speed; break;
case DIR_RIGHT: dx = this.speed; break;
}
// Новая позиция
let newX = this.x + dx;
let newY = this.y + dy;
// Ограничение границами игрового поля
newX = Math.max(0, Math.min(newX, LOGICAL_FIELD_SIZE - TANK_SIZE));
newY = Math.max(0, Math.min(newY, LOGICAL_FIELD_SIZE - TANK_SIZE));
// TODO: Проверка коллизий с тайлами (Этап 4)
// TODO: Проверка коллизий с другими танками (Этап 7)
// Применяем новую позицию
this.x = newX;
this.y = newY;
this.moving = true;
}
Ну и рисование танка на игровом поле
render() {
if (this.destroyed) return;
const ctx = foregroundCtx;
// Конвертация логических координат в физические
const px = GAME_FIELD_X + this.x * GAME_SCALE;
const py = GAME_FIELD_Y + this.y * GAME_SCALE;
const size = TANK_SIZE * GAME_SCALE;
// Цвет танка в зависимости от типа, пока всего два, потом будут новые типы и новые цвета
// Основной квадрат танка
ctx.fillStyle = this.type === TANK_PLAYER ? COLOR_TANK_PLAYER : COLOR_TANK_ENEMY;
ctx.fillRect(px, py, size, size);
// Индикатор направления (треугольник)
this.renderDirectionIndicator(ctx, px, py, size); // понял, что просто квадрато недостаточно, поэтому добавил "морду"
}
Рендер танка вызывается в методе основного рендера после очистки всего динамического слоя
// Foreground canvas — очищаем и рисуем сущности каждый кадр
clearForeground();
// Рендер танка игрока
if (player) {
player.render();
}
// TODO: Здесь будет рендер врагов, пуль, эффектов
Результат всего этого безобразия
Танк ездит сквозь стены, потому что "физического" движка ещё нет. Проверка коллизий как раз на очереди.
Масленица она же не только про блины, но и про солнышко.
Это солнышко уже погасло, но оставило после себя столько тёплых воспоминаний!
Это Сосиска. В принципе я пекла блины только ради неё. Сама я их не настолько люблю, мужа вполне устроят покупные замороженные, а Сосисочка очень любила, когда я пеку блины. Ещё на стадии замеса теста приходила и начинала ждать. А потом, дождавшись первого, начинала спрашивать - мяу?
На самом деле у нас остальные кошки даже не знают, что можно что-то со стола спросить, потому что они громогласные и наглые, один раз дай - и на шею сядут.
А Сосисочка была деликатная кисонька, спрашивала тихо и скромно. И кто я, чтобы ей отказать? Главное чтобы остальные это не видели.
В те времена печь блины было особо некогда, но каждую масленицу я стралась сделать это хотя бы один раз для этого солнышка 💖
Передаю лисоспасательную эстафету @Rian
Штош. Давайте попробуем в качестве эксперимента отойти от традиции…
Пишите так же 2 числа: страницу и строку книги.
В этой книге 166 страниц, текст начинается с 1-й, а на странице по ~40 строк.
Слова-ответы в комментах я в этот раз писать не буду, я их выкачу сразу в пятницу голосованием. То есть сегодня попробуем в формате быстром - пару дней на написание чисел (поэтому ебанула сегодня, а не в четверг, а то ваще как-то мало времени будет иначе), и потом один день на голосование.
В субботу выкачу слово и с ним тоже попробуем ещё один эксперимент - сразу под словом можно будет начинать писать числа уже для следующего голосования.
И уже в следующий четверг я его запущу. Там уже будет больше времени и для написания чисел, и само голосование будет идти с четверга, т.е. 2 дня. Такой вариант лично мне кажется самым удобным на будущее, если всё-таки что-то будем менять. Но это мне. Я могу и ошибаться))
Поэтому, пишите числа…ну и пишите, как вам такие изменения. Толька чесна!!)) По итогам следующей недели, может быть, тоже проведу опрос касаемо формата выбора слова, чтобы решить - дальше действовать по новой системе или мне лучше вернуть всё как было и не ебать вам мозги)))
Если в итоге вернёмся к старой привычной системе, то можно будет использовать голосования в случаях, когда несколько слов бьются за победу)
И спасибо всем большое за ваши предложения ❤
Тут больше чуваки пугают меня лично:D
Дарона слушаю из бывших SOAD
https://youtu.be/wsmmQ1EqSIc?si=QboESppate6BgfCe