logo
LIS PUBLICA
☰
  • Новое
  • Горячее
  • Сокровищница
  • Лучшее
  • Сообщества
  • Видео
  • Обсуждаемое

VariusSoft
VariusSoft Серия: Пишем танчики на JavaScript Сообщество: GameDev Опубликовано 6 дней назад
  • [моё]
  • [Сокровищница]
  • GameDev
  • Программирование
  • Battle City
  • Game Engine

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

Пишем свой игровой движок

После прошлого поста я что-то так проникся происходящим, что решил воссоздать ещё одну любовь детства. Но как говорил Маркус Персон: «Если вы не можете написать свой движок, то гавно вы, а не разработчики». Там, скорее всего, было как-о иначе, но суть такая. И да, с этой мыслью я в корне не согласен, но написать свой движок – задача, как минимум, интересная. Я решил, что аркадная игра для этого подходит, как ничто другое. По сути, некий аналог движка уже был реализован в тетрисе, но здесь нужна будет и какая-никакая физическая модель, и интеллект врагов и рендер всего этого безобразия в несколько слоёв и с ФПС побольше, чем 2 :)

Так что, приступим. Что нам нужно:

  • Просчёт физики
  • Работа ИИ агентов
  • Считывание действий игрока
  • Отрисовка результата работы предыдущих пунктов.

Для одного поста такая задачка звучит жирновато, поэтому, видимо, будет серия.

Я решил разделить рисования окружения (статичных объектов), врагов и игроков (динамических объектов) и UI на три разных канваса, которые просто повещены один поверх другого. Там можно будет проще и меньше перерисовывать.

Начинается наш код с проверки, готова ли страница к явлению миру нашего движка.

    if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', init);
} else {
  init();
}

Если готова, то давай же скорее всё проинициализируем

Тут всё просто:

    function init() {
  console.log('Battle City Remake - Initializing...');

  // Инициализация рендерера
  initRenderer();

  // Очищаем все слои
  clearBackground();
  clearForeground();
  clearUI();

  // Рисуем границу игрового поля и отладочную сетку
  renderGameFieldBorder();
  renderDebugGrid();

  console.log('Initialization complete. Starting game loop...');

  // Запускаем game loop
  requestAnimationFrame(gameLoop);
}

Но понятное дело, что кода тут мало, потому что всё вынесено в отдельные методы.

Есть ли среди них хоть что-то интересное?

Ну, renderDebugGrid и renderGameFieldBorder одним названием уже говорят, что там происходит.

Логично, что самое интересное происходит где-то тут requestAnimationFrame(gameLoop);

Но давайте сначала заглянем в инициализацию рендера

    export function initRenderer() {
  // Получаем canvas элементы
  backgroundCanvas = document.getElementById('background-canvas');
  foregroundCanvas = document.getElementById('foreground-canvas');
  uiCanvas = document.getElementById('ui-canvas');

  // Получаем контексты
  backgroundCtx = backgroundCanvas.getContext('2d');
  foregroundCtx = foregroundCanvas.getContext('2d');
  uiCtx = uiCanvas.getContext('2d');

  // Определяем DPR для HiDPI экранов
  dpr = window.devicePixelRatio || 1;

  // Настраиваем все три canvas
  setupCanvas(backgroundCanvas, backgroundCtx);
  setupCanvas(foregroundCanvas, foregroundCtx);
  setupCanvas(uiCanvas, uiCtx);

  console.log(`Renderer initialized (DPR: ${dpr})`);
}

function setupCanvas(canvas, ctx) {
  // Физический размер canvas
  canvas.width = CANVAS_WIDTH * dpr;
  canvas.height = CANVAS_HEIGHT * dpr;

  // Масштабируем контекст для компенсации DPR
  ctx.scale(dpr, dpr);

  // Отключаем сглаживание для пиксельной графики
  ctx.imageSmoothingEnabled = false;

  console.log(`Canvas ${canvas.id} setup: ${canvas.width}×${canvas.height} (logical: ${CANVAS_WIDTH}×${CANVAS_HEIGHT})`);
}

CANVAS_WIDTH и CANVAS_HEIGHT — это константы, они у меня в отдельном файлике лежат, там просто 800 на 600.

В целом, страничка готова к тому, чтоб рисовать всякое

Дёргаем requestAnimationFrame и отдаём её наш gameLoop

    function gameLoop(currentTime) {
  // Вычисляем deltaTime
  const deltaTime = currentTime - lastTime;
  lastTime = currentTime;

  // Накапливаем время
  accumulator += deltaTime;

  // Fixed timestep - обновляем логику с фиксированным шагом
  while (accumulator >= FRAME_TIME) {
    update(FRAME_TIME);
    accumulator -= FRAME_TIME;
  }

  // Рендерим независимо от update
  render();

  // Продолжаем loop
  requestAnimationFrame(gameLoop);
}

Я решил фиксировать ФПС на 30

    export const FPS = 30;                    // Фиксированный FPS
export const FRAME_TIME = 1000 / FPS;     // ~33.33ms на кадр

Метод update содержит (ну, будет содержать) всю нашу игровую логику. Пока он только считает фпс и выводит его на экран для отладки.

    function update(dt) {
  // Пока пусто - здесь будет логика игры

  // Подсчёт FPS для отладки
  frameCount++;
  fpsTimer += dt;

  if (fpsTimer >= 1000) {
    fps = frameCount;
    frameCount = 0;
    fpsTimer = 0;

    // Обновляем FPS на странице
    const fpsElement = document.getElementById('fps');
    if (fpsElement) {
      fpsElement.textContent = fps;
    }
  }
}

Ну и когда всё закончено, отрисовываем

    function render() {
  // Background canvas - перерисовывается только при изменении карты
  // (пока только отладочная сетка, нарисованная в init)

  // Foreground canvas - очищаем и рисуем сущности каждый кадр
  clearForeground();
  // TODO: Здесь будет рендер танков, пуль, эффектов

  // UI canvas - очищаем и рисуем UI каждый кадр
  clearUI();
  renderUI();
}

То есть, по сути, ничего интересного, просто рисую полосочки и квадратики для UI

Результат выглядит вот так

Следующий пост будет посвящён второму этапу

И да, я упоролся и расписал себе полноценный план реализации на 13 этапов. Без ДизДока последнее время вообще не представляю как работать. А раз уж я в команде один, то сам себе и ТЗ пишу... Но лучше так, чем лепить полную отсебятину.

Вопросы замечания предложения в комментариях жду с нетерпением)

А пойду пилить обновление для Лиспублики)


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

Читать дальше...
14
+14 / -0
14
34
ТГ ВК
Pepels
Pepels Опубликовано 6 дней назад

Это ты намекаешь, что скоро появится раздел "игры" на лиспублике?

4
+4 / -0
[ Свернуть ]
AlNiKo
AlNiKo Опубликовано 6 дней назад
Ответ на Комментарий от Pepels

Это ты намекаешь, что скоро появится раздел "игры" на лиспублике?

Дурак на раздевание

sticker
2
+2 / -0
Pepels
Pepels Опубликовано 6 дней назад
Ответ на Комментарий от AlNiKo

Дурак на раздевание

sticker

Идея для следующей лиспубликанской сходки

2
+2 / -0
VariusSoft
VariusSoft Опубликовано 6 дней назад
Ответ на Комментарий от Pepels

Это ты намекаешь, что скоро появится раздел "игры" на лиспублике?

sticker
3
+3 / -0
DELETED_52
DELETED_52 Опубликовано 6 дней назад

Комментарий удалён. Автор удалил свой аккаунт.

1
+1 / -0
[ Свернуть ]
VariusSoft
VariusSoft Опубликовано 6 дней назад
Ответ на Комментарий от DELETED_52

Комментарий удалён. Автор удалил свой аккаунт.

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

Что касается написать движок для своей игры. Тоже не соглашусь. Если ты способен написать движок – ты способен написать движок. И не важной для какой игры. Этот опыт так же универсален, как умение держать в руках молот. При минимальном раскладе ты забьёшь гвоздь, при определённом – станешь кузнецом, а если придут орки, то можно и черепа начать крушить.

Ну а по поводу переделки старых игр, тут и соглашусь и нет. У меня нет цели повторить те самые эмоции. Дать что-то новое? Да, я планирую в самом конце добавить ультимативную киллерфичу, которая, скорее всего, никому нафиг не упрётся, но тем не менее. Я это делаю для развития себя как разработчика игр, для того, чтобы те, кому вопрос интересен, смогли почерпнуть что-то новое или полезное. А если в итоге ещё и получится играбельная версия, то, как будто, это будет ещё и приятным бонусом.

2
+2 / -0
DELETED_52
DELETED_52 Опубликовано 6 дней назад
Ответ на Комментарий от VariusSoft

Обучение на повторении – это единственное верный путь. Учиться сразу на своём – это лишь упорствовать в собственных ошибках и заблуждениях, как слепой котёнок пытаясь найти миску с молоком, при учёте,...

Комментарий удалён. Автор удалил свой аккаунт.

0
+0 / -0
VariusSoft
VariusSoft Опубликовано 6 дней назад
Ответ на Комментарий от DELETED_52

Комментарий удалён. Автор удалил свой аккаунт.

Именно поэтому начинающие художники сразу рисуют свой шедевр, а не пресловутые кружочки и тысячную вазу.

Поэты сразу пишут поэму-эпос.

Пацаны в гараже собирают свой супер-кар, а не изучают, как работает впрыск, и в чём смысл трамблёра.

Повторение существующих игр – это прекрасный способ войти в гейм дев при наличии уже 300 раз выверенного геймплея, концепции и механик. Разработчик может сконцентрироваться непосредственно на воссоздании конкретных аскпеков, а не тратить полгода на написание диздока.

Брать готовый движок нужно в том случае, если ты просто хочешь сделать конкретную игру. Нет смысла разрабатывать свой велосипед, если ты хочешь сделать свою визуальную новеллу. Уже давно есть РенПай, или Юнити на худой конец. Это подход человека, который хочет получить конкретный результат. Он хочет рассказать миру свою историю.

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

2
+2 / -0
DELETED_52
DELETED_52 Опубликовано 6 дней назад
Ответ на Комментарий от VariusSoft

Именно поэтому начинающие художники сразу рисуют свой шедевр, а не пресловутые кружочки и тысячную вазу.

Поэты сразу пишут поэму-эпос.

Пацаны в гараже собирают свой супер-кар, а не изучают, как работает...

Комментарий удалён. Автор удалил свой аккаунт.

0
+0 / -0
VariusSoft
VariusSoft Опубликовано 6 дней назад
Ответ на Комментарий от DELETED_52

Комментарий удалён. Автор удалил свой аккаунт.

Так я и не говорил, что эта серия постов для человека в полным отсутствием фундамента)

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

0
+0 / -0
DELETED_52
DELETED_52 Опубликовано 6 дней назад
Ответ на Комментарий от VariusSoft

Так я и не говорил, что эта серия постов для человека в полным отсутствием фундамента)

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

Комментарий удалён. Автор удалил свой аккаунт.

1
+1 / -0
vervolph
vervolph Опубликовано 6 дней назад

О, я тоже когда-то давным давно танчики писал... на паскале!!!

1
+1 / -0
[ Свернуть ]
VariusSoft
VariusSoft Опубликовано 6 дней назад
Ответ на Комментарий от vervolph

О, я тоже когда-то давным давно танчики писал... на паскале!!!

ту-ду-ду-ду-ду..... *подозрительный взгляд*

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

2
+2 / -0
vervolph
vervolph Опубликовано 6 дней назад
Ответ на Комментарий от VariusSoft

ту-ду-ду-ду-ду..... *подозрительный взгляд*

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

🤣🤣🤣 не, не я ) я вроде максимум на втором на паскале писал. С третьего у нас уже делфи начался

1
+1 / -0
Войти

Вход

Регистрация

Я не помню пароль

Войти через Google
Порог горячего 15
  • Kukabara
    Kukabara

    это всё потому что без Натахи?

    +2
  • capybarystic
    capybarystic

    Спасибо! Сейчас исправлю :)

    +1
  • moortnelis
    moortnelis

    Вот тут ваще будто годов 50-х фото

    +1
Правила сайта
Пользовательское соглашение
О ПД
Принципы самоуправления
Нашёл ошибку?
©2026 Varius Soft