Алексей@Swamp_Dok
Программист, радиолюбитель.
Information
- Rating
- 4,728-th
- Location
- Воронеж, Воронежская обл., Россия
- Date of birth
- Registered
- Activity
Specialization
Разработчик игр, Инженер встраиваемых систем
From 50,000 ₽
C++
C
Программирование микроконтроллеров
Python
Разработка игр
Разработка электроники
Можно сделать рамку вокруг полигонов и использовать разные цвета для соседних полигонов.
Про разработку игр для денди можно у меня в профиле почитать) Сейчас, правда, отвлёкся на разработку 3D- движка для неё же.
Я, видимо, неправильно сформулировал про 16х16. У меня не одна клетка 16х16, а я вся карта 16х16 (один блок карты 1х1). Поэтому обычное определение расстояния через корни особо ничего не даст. И отсюда и прыжки персонажа, а шаг камеры сейчас 256 значений на 90 градусов.
Еще я использую рабочую сцену 32х16 тайла (быстрее можно вывести и удобный размер для хранения и вывода). Можно сделать 32х24, столько байт я тоже должен успеть вывести за один кадр.
Но увеличение вертикального разрешения на треть увеличит и время формирования кадра перед его выводом (каждый тайл сцены нужно отредактировать в буфере).
Пока буду продолжать экспериментировать с картой 16х16, возможно как-то получится в таком режиме выводить более-симпатичную картинку. если сделать разрешение всей карты 256х256, то я точно не успею посчитать все лучи, даже с идеальной оптимизацией.
Еще я рассчитываю на уменьшение угла обзора до 60 градусов, это на треть увеличит горизонтальное разрешение сцены (сейчас 90 градусов).
Еще можно будет все-таки попробовать считать расстояние через корни (при текущем разрешении не сложно сделать таблицу). Но думаю, что это ничего не даст.
"Быстрая" память есть у 6502 , но там 1-2 такта разница у команд относительно других разделов памяти, но там всего 256 байт. Я их и так использую в алгоритмах. Проект я собираю с помощью батника, который запускает компилятор сс65.
Даже текущий алгоритм явно съедает несколько кадров (точные расчеты я пока не делал), при том, что каждый луч проходит максимум 8 шагов. Т.е. расстояние до стен у меня от 1 до 8. Увеличение дальности тут тоже ничего не даст, только увеличение разрешения карты. Но не хочется переходить к 16-битным индексам, это сразу замедлит любые обращения к карте раза в 3. А у нас и так с ФПС проблемы.
Поэтому пока буду дожимать текущий подход, если совсем плохо будет с визуалом, то буду увеличивать разрешение, но это минимум 256х256 делать придется, тут таблицы уже нормально не прилепишь, но варианты все равно есть на крайний случай.
Добавил затемнение стен при удалении и простую карту (правда она не помещается по высоте полностью). Потом еще добавлю стрелку направления вместо собаки на карте.
Вот чуть улучшенный вариант. Я ещё придумал как сделать градиентное затемнение при удалении от игрока, но пока не реализовал.
Корней у меня вообще нет в коде. Расстояние я нахожу через количество итераций Брезенхема. Двух зайцев одним брезенхемом. Спасибо деду за алгоритм.
И в ходе экспериментов проявились проблемы с разрешением карты 16х16. Шаги игрока будут прыжками и всего по 8-ми направлениям.
И из-за малого разрешения карты диапазон высот стен очень маленький. Расстояние от 1 до 8 блоков. Итого стены от 2 до 16 тайлов.
Из-за малого диапазона высот непонятно какие стены на нас смотрят под углом, а на какие мы смотрим прямо. Не знаю как лучше отобразить отличия прямых и сужающихся стен (они часто могут не успеть сменить высоту за 2-3 луча). Надо экспериментировать с визуально.
Ещё возможно поможет уменьшение угла обзора до 60 градусов. Так будет больше горизонтальное разрешение. Сейчас 90.
Признаки жизни код подает, камера с мерцанием уже крутится. Но считывается окружение плохо сейчас. Но пустой лабиринт скорее всего выжму в 60 фпс, про остальное буду думать потом.
Переписывание всего на ассемблере может дать ускорение в 5-10 раз. Но пока все отлаживаю на си.
Привет. Немного продвинул свой 2.5D-движок. Для трассировки и вычисления расстояния использую свой старый брезенхем (взял код из своей прошлой статьи). Он вроде бы подходит.
За один кадр пока я не успеваю все посчитать (Примерно 25к тактов на кадр доступно, но я вижу, что можно оптимизировать). Думаю, трассировку успею посчитать. Но ведь потом еще и логику считать, спрайты и музыку. Но если хотя бы пустой лабиринт заработает, уже будет успех.
Вот что удалось получить. Первый корректный рассчет столбцов (было много проблем из-за оптимизации и восьмибитности):
Про мышь я думал. Я планирую делать программный UART, чтоб денди подключить к интернету, а UART почти как PS/2 протокол работает. Если получится UART, можно попробовать и UART. Но процессорного времени оно есть будет очень много, так как таймеров нет и придется задержки делать NOP-ми.
Оптимальный вариант делать адаптер на МК, который будет постоянно держать на выходе состояние мыши, которое можно будет быстро считать раз в кадр без NOP-ов. Но это не особо спортивно. К денди подключалась мышь, но там скорее всего какой-то свой протолок был. Я даже думал купить денди клаву с мышей и бейсик картриджем, чтоб поэкспериментировать.
Аппаратное отзеркаливание тайлов работает только со спрайтами, фоны аппаратно зеркалить нельзя.
Выглядит отлично, рубленные края вообще не мешают взгляду. Но на денди даже поинтереснее можно попробовать делать графику, какие-никакие текстуры там можно сделать. Еще можно подумать про пол и потолок. Но даже в таком виде, если получится плавная камера, это будет разрыв.
И код без оптимизации самое то, чтоб проще было повторить концепцию. Надеюсь в ближайшее время добью демку. Самому уже интересно посмотреть, что получится. Даже не верится, что можно на денди сделать плавную камеру без доп микросхем.
В ASCII почти тоже самое концептуально получается. В коде новом позже подробнее покопаюсь.
И про шестеренку отличная аналогия :) Сколько по твоему шагов на круг нормально будет? 256 шагов на 360 градусов без проблем могу добавить, переменные останутся однобайтными.
Я на всякий случай решил уточнить про конечную точку, просто думал может что-то не так понял. С помощью приращений луч строится в букварях, которые я читал.
Тут у нас небольшие противоречия получаются, так как я стараюсь ограничиться 8-битными переменными и не использовать дроби. Поэтому у меня пока локация 16х16 блоков (условно 1х1 метр один блок). И координаты у меня пока меняются с шагом в один блок для простоты. (16х16 поле положений игрока)
Конечные точки лучей мне нужны, так как я не хочу считать приращения, ибо приращения дробные будут. А с конечными точками я могу запустить целочисленного Брезнхема без умножений. Она сразу будет определять и пересечения с блоками и в конце даст расстояние (количество закрашенных пикселей луча).
Итого с умножениями находим только конечную точку. А рыбий глаз можно компенсировать коэффициентами табличными для каждого луча (всего лишь одна дополнительная сумма получается).
Еще я понял, что раз я научился за один кадр загружать 1 килобайт+, значит я могу честную 3D-сцену тоже выводить за один кадр. Это тоже все сильно упрощает, не нужно думать как красиво закрашивать сцену за один кадр. Но за один кадр много полигонов не посчитать, хотя и открывается мотивация для максимальной оптимизации расчета полигонов. Возможно помогут таблицы умножений. Надо много думать и экспериментировать.
Такой вопрос пока. Как ты получаешь конечную точку для Брезенхема (точка к которой мы шагаем)? Просто рассчитываешь ее через синусы-косинусы и дальность обзора для текущего угла обзора?
Я думаю заранее посчитать коэффициенты для получения конечной точки для всех возможных углов (их всего 128 штук получается при обзоре в 90 градусов, минимальный поворот камеры будет 2.8 градуса).
Тут еще вопрос как будет выглядеть поворот камеры, учитывая, что минимальное смещение камеры 1 тайл (8 пикселей).
Осталось написать рейтресинг и можно будет попробовать собрать демку. Интересно как оно будет выглядеть.
Еще нужно определиться с оптимальной геометрией локации. Угол обзора, площадь одного блока карты, дальность обзора, высота стен.
Пока буду ориентироваться на 16 тайлов как максимальную высоту стены. Угол обзора думаю взять 90 градусов, так будет детальнее сцена. При 32-х лучах на 90 градусов получаем 2.8 градуса на луч.
Еще можно сделать масштабирование текстур. Нарисовать 3-4 варианта и подставлять нужную в зависимости от расстояния до стены. Но это потом.
Если использовать Брезенхема для определения коллизий, то заодно можно получить и расстояние до пересечения. Не нужно будет считать корни и квадраты. Но с таблицами не уверен, что быстрее будет работать. Может Брезенхем тут и не пригодится.
10000 операций должно хватить на расчёт 32-х лучей по-любому. Думаю останется время и на остальные вещи.
Попробовал позднее зажигание сцены, это работает. Есть небольшие артефакты, но можно вывести за кадр 700-800 байт за счёт выбрасывания 4х верхних строк невидимых.
700 байт хватает на вывод 20 строк тайлов за один кадр. Размер окна 20х32 думаю вполне норм. Остальные 8 строк можно использовать под интерфейс.
Скролинг задаёт положение камеры между двумя таблицами имён (это по сути две фоновые картинки, которые имеют смешные края). А скрол водит камеру с одной картинки на другую.
Лучше выводить фон за 1 кадр, так как редактирование фона в несколько кадров будет заметно или нужно будет формировать кадр в невидимой таблице имён и после дорисовки нового кадра переводить на неё камеру, но это тоже может быть заметно. Поэтому лучше стараться за один кадр все сделать. Тем более 60 фпс это приятно.
Но все текстуры придётся использовать готовые для краёв стен, дверей, окон и тд. По месту подставлять нужные тайлы, попиксельное рисование слишком медленное (нужно грузить 16 байт вместо одного).
Попробовал сейчас сколько можно максимально записать байт в видео память в NTSC и PAL. В итоге получается, что в NTSC за время возврата луча можно загрузить 209 байт, в PAL - целых 265. Десяток +- байт еще можно накрутить, если упростить обработчик прерывания и убрать вызов функции.
Это значит, что в PAL уже можно вывести 2.5D сцену 16х16 тайлов за один кадр. Или 60 фпс, если успею посчитать 16 лучей за время кадра
В NTSC тоже скорее всего получится, если использовать позднее включение экрана. Там верхние 4 ряда тайлов все равно не используется, а это довольно много времени (около двух миллисекунд или 4000 тактов). Загрузка одно байта занимает 8 тактов, а это целых 500 байт (в идеале)!
Очень неожиданно, спасибо за наработки и идеи)
Пока только бегло ознакомился, тут мне надо целенаправленно вникать, ибо тема серьёзная. Про оптимизацию рейтрейсинга я пока даже не думал :)
И пока не могу ничего по срокам говорить, и так щас в активной разработке несколько больших денди проектов. 2.5D только в списке планов. Но может и набросаю наивную демку за пару вечеров в рубрике 6 кадров )
А идея с полигональными врагами и 2.5D фонами хорошая, я больше думал про статичные фоны а-ля резиденты. Полигональные модели ещё и масштабировать можно.
Совмещение 2.5d и 3d вполне бьётся, так как модели я вывожу спрайтами. Для фонов места достаточно в видеопамяти.
Ещё есть вопрос плавной смены кадров. Тут я думаю можно использовать скролинг. Один кадр рисуем в первую таблицу имён, второй во вторую. Так можно будет разом вывести весь кадр, если он формировался несколько аппаратных кадров.
А в тему синусов и умножений. Тут только таблицы. Места должно хватить.
И ещё раз спасибо за статью, очень полезно и интересно.
Я бы начал с клавиатуры)
Давно хочу свою ОС написать полноценную, но сначала для ардуины, а то там только иммитации. Полноценной рабочей станции не нашёл на гитхабе. Там интересно будет написать виртуальную машину или интерпретатор.
Потом её можно будет портировать на денди, если код правильно организовать.
А можно ссылку на описание реализации? Там ведь маппер простой, нет прерываний по счётчику строк, видимо просто такты посчитали.
Спасибо за наводку, я примерно представляю как это можно реализовать в моем случае.
Спасибо за рекомендации игр, надо ознакомиться с референсами.
А 2.5D окружение без доп видео надстройки действительно невозможно, особенно на весь экран.
Но если сделать стены без заливки, то может и получится сделать плавную камеру в нормальном разрешении. Надо считать тайлы и такты. И я прикидывал, что смогу заменить умножение таблицами, памяти хватает. Как-нибудь попробую.
В каком-то виде 2.5D движок обязательно буду реализовывать, без плавной камеры точно получится. Да и были такие игры на NES.
Видеокарту будем изобретать в одном из будущих проектов :) (есть очень необычная идея). Для денди пока попробую ограничиться базовыми возможностям и простым маппером.
И хорошо бы ещё заняться написанием хорошего кода реализации ММС3 маппера под дешёвые ПЛИС 5 вольтовые. Можно было бы делать дешёвые картриджи и с минимумом микросхем. Но с ПЛИС у меня маловато опыта.
Да, сс65 слабенький. Приходится очень аккуратно с ним работать.