Важная информация

User Tag List

Страница 2 из 2 ПерваяПервая 12
Показано с 11 по 13 из 13

Тема: Legends & Myths (dev log)

  1. #11

    Регистрация
    18.01.2021
    Адрес
    г. Санкт-Петербург
    Сообщений
    366
    Спасибо Благодарностей отдано 
    56
    Спасибо Благодарностей получено 
    459
    Поблагодарили
    135 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

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

    Вжух


    P.S. Вывод временно осуществляется в одном экране, без буферизации, поэтому видны мерцания (в эмуляторе NoFlick попытался это сгладить)
    Последний раз редактировалось Deadly; 08.01.2026 в 13:20.

    Эти 5 пользователя(ей) поблагодарили Deadly за это полезное сообщение:

    Andrew771(08.01.2026), Beaver(08.01.2026), Dart Alver(08.01.2026), Lethargeek(08.01.2026), Vatr(10.01.2026)

  2. #12

    Регистрация
    18.01.2021
    Адрес
    г. Санкт-Петербург
    Сообщений
    366
    Спасибо Благодарностей отдано 
    56
    Спасибо Благодарностей получено 
    459
    Поблагодарили
    135 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию



    Display List для гекс-рендера

    Хочу описать одну архитектурную идею, к которой я пришёл при оптимизации рендера гексагональной карты.

    Текущая реализация:
    В рендере карты есть несколько проходов:
    - отрисовка гексов;
    - туман войны;
    - эффекты;
    - обновление экрана.

    При этом все они проходят по одним и тем же гексам и тем же маршрутами, но каждый раз:

    - заново считают экранные координаты;
    - заново обходят карту;
    - держат много временных значений в регистрах.

    Это работает, но не быстро и не очень эффективно.

    Идея
    Разделить процесс на два этапа:

    Генерация списка — выполняется редко (например, при скролле или других событиях).
    Исполнение списка — выполняется каждый кадр.

    Вместо того чтобы каждый проход сам обходил карту, я один раз формирую линейный список того, что нужно отрисовать.
    По сути — простой software display list.

    Как выглядит список
    Список — это массив (или стек) записей, по одной на каждый видимый гекс.

    В каждой записи хранится:
    - индекс обрабатываемого гексагона в рендер-буфере (0–39);
    - номер строки начала рисования (0–191);
    - количество рисуемых колонок гексагона (0–5).

    Такой список даёт несколько преимуществ:
    - порядок элементов уже правильный (сверху вниз);
    - в будущем можно добавить сортировку по оси Y для спрайтов;
    - длина списка фиксирована;
    - внутри прохода нет ветвлений (не обновляемые гексагоны просто не попадают в список).

    Генерация списка

    Этот этап выполняется:
    - при изменении положения видимой области карты;
    - при анимации гексагона;
    - при игровых событиях, влияющих на состояние гексагона.

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

    Использование списка

    Каждый проход рендера просто:
    - берёт готовый список;
    - линейно по нему проходит;
    - делает своё грязное дело.

    Например:
    один проход рисует гексы;
    другой — эффекты;
    третий — туман войны.

    Никаких повторных расчётов — только чтение уже подготовленных данных.

    Задел на будущее

    Пока список содержит только гексы, но формат легко расширяется:
    - можно добавить тип записи (гекс, спрайт, эффект);
    - смешивать разные элементы в одном списке;
    - рисовать всё одним проходом сверху вниз.

    Даже если до этого не дойдёт, текущая реализация уже даёт ощутимый выигрыш.

    Итог:
    Исключается многократный обхода карты в пользу одного подготовленного списка.
    Это упростило код, сделало его более читабельным, снизило нагрузку и сделало рендер более контролируемым.
    По сути — простой display list без лишней магии, который хорошо ложится на ограниченное железо.



    Прошло время.... )



    Здесь постарался исправить почти все проблемы с обновлением гексов. Самое главное — когда экран не скроллится, даже с анимациями FPS не проседает. Далее нужно корректно обновлять гексагоны выше и ниже (если это необходимо) текущего анимированного гексагона. Это хорошо видно на горах (высоких тайлах): гора не обновилась после того, как выше изменился гексагон. Но это уже другая задача — расширение текущего рендера.

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

    P.S. Да, это может показаться регрессом, но всё же работает на 3,5 МГц.
    Тут можно скачать билд, описание во вложении...
    Последний раз редактировалось Deadly; 15.01.2026 в 16:04.

    Эти 3 пользователя(ей) поблагодарили Deadly за это полезное сообщение:

    Beaver(15.01.2026), Black Cat / Era CG(15.01.2026), jerri(15.01.2026)

  3. #13

    Регистрация
    18.01.2021
    Адрес
    г. Санкт-Петербург
    Сообщений
    366
    Спасибо Благодарностей отдано 
    56
    Спасибо Благодарностей получено 
    459
    Поблагодарили
    135 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

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

    Но я пошёл чуть дальше. С подобным сталкивался ещё в TornMetal, когда обновлялась только та часть экрана, которая изменилась. Там это было проще — всегда были доступны два окна. В текущей реализации такой возможности нет, так как спрайты значительно больше, и копирование из страниц в буферы перед отрисовкой слишком затратно. Поэтому приходится рисовать в основном экране (который выступает в роли теневого), а затем обновлять теневой экран.

    Логику обновления описал следующим образом:
    ; -----------------------------------------
    ; ⚠️ холодный запуск:
    ; 1. принудительно выставить адрес левого верхнего угла отображаемой карты
    ; данные о центрировании карты могут браться из метаданных карты и/или иным способом
    ; 2. принудительное копирование в Tilemap-буфер из тайловой карты на странице 1
    ; 3. принудительное выставление флагов в Render-буфере
    ; формируется для каждого тайла
    ;
    ; ⚠️ горячий запуск:
    ; не должен самовозбуждать флаги обновления в Render-буфере,
    ; дабы снизить нагрузку на обновление экрана
    ;
    ; ℹ️ цикл обновления экрана:
    ; 1. в выставленные тайминги скролла проверить вектор движения карты,
    ; обновить адрес левого верхнего угла отображаемой карты
    ; 2. принудительное обновление Tilemap- и Render-буферов по необходимости,
    ; если адрес левого верхнего угла отображения карты изменился
    ; * Tilemap-буфер копируется из тайловой карты на странице 1
    ; * Render-буфер формируется для каждого тайла, где:
    ; - выставляется флаг HU (принудительного обновления гексагона)
    ; - копируется флаг FG (тумана, 0 — гексагон закрашен туманом целиком)
    ; из буфера метаданных карты
    ; - номер анимации гексагона устанавливается в ноль,
    ; в последующих шагах он будет модифицирован
    ; * Render-буфер для каждого столбца гексагона выставляется флаг CU
    ; необходимости обновить столбец гексагона (0 - обновление столбца не требуется)
    ; 3. применение внешних событий изменения/обновления гексагонов
    ; * основной список гексагон-объектов,
    ; которые обязаны менять анимацию каждый тик гексагонов
    ; каждый такой объект имеет информацию о количестве анимаций в цикле
    ; * дополнительный список гексагон-объектов,
    ; которые рандомно выбираются из доступных на экране
    ; каждый такой объект после проигрывания одного цикла анимации
    ; удаляется из списка
    ; 4. отображение гексагонов
    ; 5. отображение объектов на карте
    ; * список динамических объектов влияет на флаг HU (принудительного обновления гексагона)
    ; спрайты героя, VFX заклинаний и т.п.
    ; 6. отображение тумана на видимых гексагонах
    ; 7. копирование узора рамки на игровой части экрана
    ; 8. анализ флагов HU (принудительного обновления гексагона) и высот гексагонов,
    ; позволяет определить, какие экранные блоки требуется копировать в теневой экран
    ; * выставленный флаг HU говорит о том, что гексагон изменился
    ; используя высоты гексагона, можно определить,
    ; какие соседние экранные блоки были задеты,
    ; и на их основе формируются флаги обновления грязных экранных блоков
    ; * экранные блоки копируются в теневой экран
    ;
    ; ℹ️ цикл обновления курсора:
    ; 1. если не требуется копирование из основного экрана в теневой:
    ; ⚠️ важно: обязательно в начале прерывания (избежать сечения луча)
    ; * восстанавливаем фон под курсором (в теневом экране), если он имеется
    ; * отображаем курсор в новой позиции (в теневом экране)
    ; ℹ️ ToDo: можно избежать этого пункта,
    ; если предыдущая анимация и положение не изменились
    ; * любая логика прерывания
    ; 2. буферный экран (основной) готов копироваться в теневой экран
    ; * включить в адресном пространстве #C000–#FFFF страницу 7
    ; (с теневым экраном)
    ; * отображаем курсор в новой позиции (в основном экране)
    ; * переключаемся на отображение основного экрана
    ; (теневой экран перестаёт быть видимым)
    ; * на странице 7 расположен код копирования экранных блоков,
    ; буфер под курсор и другие необходимые массивы
    ; (гексагон-объектов и т.п.)
    ; копируются блоки экрана в теневой
    ; (ℹ️ сечение луча не страшен)
    ; * отображаем курсор в новой позиции (в теневом экране)
    ; * переключаемся на отображение теневого экрана
    ; (основной экран перестаёт быть видимым)
    ; * восстановить фон в основном экране под курсором
    ; * сброс флагов готовности экрана
    ; -----------------------------------------

    Но вот насчёт копирования из основного в теневой экран решил разбить на блоки:


    Разбиение игрового окна на блоки копирования позволяет оптимизировать вывод и не обновлять весь экран одновременно в статическом виде. С анимациями есть исключение — требуется полное обновление игровой области:
    При скролле обновляются все буферы, и игровое окно необходимо перерисовать полностью.
    Игровое окно размечено на блоки 6×6 знакомест, так как это подходит для стековой переброски POP/PUSH. Также присутствуют области 4×6, 6×4 и 4×4.

    ℹ️ Во время отображения каждая новая строка начинается на 4 знакоместа ниже. При выводе в буфер рендера (RenderBuffer) записывается информация о высоте каждого знакоместа: если знакоместо высокое — бит хранит 1, иначе — 0.

    Эти данные необходимы для:
    наложения сглаживающего тумана,
    определения высоты структуры столбца гексагона.

    Структура столбца гексагона:
    бит 7 — самое нижнее знакоместо,
    бит 0 — самое высокое.

    При сканировании битов с 7 по 0 (LSB → MSB) ищем первый встречающийся включённый бит — номер бита обозначает высоту данной колонки гексагона.

    - - - Добавлено - - -





    Небольшой экскурс в происходящее.
    Если какой-то тайл гексагона обновляется (в данном случае это туман — простой способ отработать поведение обновления гексогональных тайлов корректно), то для корректного восприятия top-down гексагонной карты должны перерисовываться и соседние тайлы.

    Добавил возможность перерисовывать ровно половину гексагонного тайла — его верхнюю часть. Напомню, тайл имеет размер 6×8 знакомест, и именно эта половина соответствует нахлёсту нижнего тайла. После смены флага обновления анимированного тайла окружающие его тайлы тоже должны обновляться, но не полностью.

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

    Верхние тайлы обновляются полностью (в будущем можно оптимизировать и обновлять только нижнюю половину), а для нижних тайлов необходимо обновлять лишь их верхнюю половину. Иначе стокнёмся с проблемой зацикленности и придётся обновлять ещё и тайл ниже нижнего, и так далее, пока не закончится экран.

    P.S. собственно можно взглянуть под капотом как оно работает.

Страница 2 из 2 ПерваяПервая 12

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 2 (пользователей: 1 , гостей: 1)

  1. Deadly

Похожие темы

  1. Death Drive Destruction (dev log)
    от Deadly в разделе Игры
    Ответов: 137
    Последнее: 25.12.2025, 20:16
  2. Log Cabin Dizzy (ZX Spectrum Edition)
    от Verm-V в разделе Игры
    Ответов: 15
    Последнее: 07.02.2021, 16:50
  3. Ответов: 42
    Последнее: 23.01.2021, 23:21
  4. Legends of Bytes #6
    от cherkasy в разделе Пресса
    Ответов: 39
    Последнее: 27.11.2019, 02:40
  5. Legends of Bytes #3
    от cherkasy в разделе Пресса
    Ответов: 11
    Последнее: 24.02.2012, 18:46

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •