Super Mario Bros. COVID-19 Edition

Всем привет!

Сделал для вас игру на актуальную нынче тему :)

Скачать тут:
zxart.ee/rus/soft/game/arcade/platform/super-mario-bros-covid-19-edition/







Движок, который я показывал на CAFe 2019, продолжает развиваться.
За последние пару месяцев в комплекте к нему появился UI-редактор миров.
Именно в нём и сделаны уровни для игры.

Играйте, наслаждайтесь. :)
Баг-репорты присылайте в личку в телеграм.

9 комментариев

avatar
Очень интересно было бы почитать (я где то слышал что на профильных форумах обсуждение было) как движок работает.
Я в эмуляторе немного анализировал что в экранной области происходит — как понял основная идея, что пустые области попиксельно никак не обрабатываются, а скроллится только активное содержимое. Но всё равно интересно какие структуры и т.п.
Ибо действительно fps и отзывчивость фантастические для спектрума.
avatar
Движок — это конвеер, который в каждом кадре делает одну и ту же работу.

Сначала идёт обработчик прерывания, на нём висит музыка, звуковые эффекты, и глобальные счётчики фреймов.
Затем идёт блок рендера. На время вызова графических процедур, прерывания запрещаются.

Рендер состоит из следующих шагов:
— очищаются все динамические объекты на экране (герой, враги, призы, файлболлы, — всё, что движется);
— выводятся неподвижные блоки, причём очищать их не нужно, т.к. «с хвоста» блоки чистят сами себя;
— поверх блоков выводятся все динамические объекты, с занесением в стек информации для очистки в следующем фрейме;

Далее опрашивается user input (клавиатура или джойстик). На основе этого для главного героя выбирается спрайт, и придаётся ускорение по осям (разбег, прыжок, торможение, итд).

Затем запускается конвеер обработки всей логики. Она полностью одинакова для всех движущихся объектов в сцене. Каждый объект прогоняется по этому конвееру: — изменяется состояние, координаты, детектируются коллизии, срабатывают события и происходит обработка реакции на события (если они заданы).
Весь алгоритм линейный, т.е. обработка всех физических свойств, всех коллизий и событий для одного объекта всегда занимает примерно одинаковое время, независимо от игровой ситуации.

После прогонки всех объектов по конвееру, последним в очереди идёт проверка общеигровых событий, таких как: достижение конца уровня, переключение режимов ГГ (immunity, starman, итп), проверка возможности захода в «трубы», и т.п.

Затем просто ждём следующего прерывания, меняем экраны местами, и поехали с начала.

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

В целом, у движка есть три режима работы:
— обычный геймплей, когда работают и рендер и логика;
— анимация («взятие приза», «заход в трубу», «скатывание по флагу») — работает только рендер, а логика управляется специально написанным скриптом;
— распаковка данных в память, тут 100% CPU отдаётся на распаковку, а на экране в это время показываются попеременно два статичных кадра, и просто играет музыка.

Если интересно, могу более подробно расписать по любому пункту.
avatar
Надеюсь, это не прозвучит обидно, но мне прочесть этот текст было интереснее, чем поиграть в саму игру!
avatar
И сразу вопрос — «с занесением в стек информации для очистки в следующем фрейме» — что именно тут подразумевается? Т.е. вопрос вот в чём, что лежит под спрайтом вроде легче выяснить при выводе статических объектов. Но у тебя это разнесено. Т.е. ты либо должен восстанавливать, что у тебя под спрайтом ещё раз, либо сохранять экранные данные, либо?
avatar
В памяти в RAM 2 по статичным адресам находятся четыре стека (по два стека на два экрана):
— 204 байта отведено под сохранение 2х-байтных адресов из области атрибутов, которые были «покрашены» в текущем фрейме, и которые нужно почистить позже;
— +2 байта на указатель стека;
— 48 байт отведено под хранение 16 «троек», где первые два байта — это адрес в экранной области, куда был выведен спрайт в текущем фрейме, и еще 1 байт кодирует размер выведенного спрайта;
— +2 байта на указатель стека.

Когда приходит время почистить экран и атрибуты:
— выгребаем по-порядку адреса из атрибутного стека, и вливаем по ним цвет фона;
— затем выгребаем «тройки» из второго стека и выводим на экран пустые прямоугольники: адрес в экране знаем, размер спрайта знаем.

Такие размеры стеков были выбраны исходя из того, что на экране не может быть более 16 динамических объектов одновременно (и то — это с большим запасом; в 3.5 Мгц столько не влезет). Средний размер одного спрайта 3x2 = 6 знакомест. Бывают также спрайты размерами по 2 (оружие), 4 (враг, приз) или 8 знакомест.

Помнить, что было под спрайтом, не нужно. Каждый раз всё заново перерисовывается.
avatar
зачем прерывания запрещать на графике, если не успеть может только логика?
avatar
Графика рисуется через стек, и оставлять прерывания небезопасно.
Я, конечно, закладываю некое свободное время во фрейм. Но оно тоже может не успеть, на какой-нибудь супер-медленной машине.

Рендеринг всей графики в игре должен занимать не более ~80% фрейма. Это как бы теоретический максимум.
Но вполне может быть, что если сцена окажется перенасыщенной, и тогда и вывод графики вылезет за фрейм.
Этого нужно избегать еще на этапе дизайна уровня — использовать автоматические метрики, которые подскажут опасность «выхода за фрейм».
avatar
а сейчас разве не просчитан дизайн заранее?

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

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

А такого, чтобы спрайт игрока перекрашивал собой фоновые блоки — я не видел.
(Хотя есть одно исключение: взять «звезду» и подойти вплотную к белому блоку, у которого цвет идентичен цвету фона)
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.