Графика в текущем проекте (Dave) выводится с помощью AZBK, а точнее с помощью одной из графических фич AZBK — блиттера. Суть «азбучного» блиттера состоит в том, что ему можно давать пакет команд, который он читает себе в буфер и потом выполняет уже самостоятельно, не отнимая процессорного времени.
Наконец-то я победил эти «хвосты» при скроллинге! Можно делать игру дальше!
При больших сдвигах рулона среднего экранного слоя (где бродят Зомби) промелькивали объекты, которые должны были уже быть стерты. И борьба с ними заняла у меня три дня…
Пока я использовал блиттер в атоматическом режиме (он при этом сам стартует при каждом прерывании по вектору 100) — все было почти хорошо. Точнее, в эмуляторе было вооще все хорошо, а вот на реальном железе при глобальном скроллинге экрана иногда наблюдалось какое-то дергание экрана. Этим, конечно же, было поручено заняться Тэду из будущего. При этом возникал вопросы о скоростном построении экрана из множества тайлов — ведь количество команд, которые можно скормить блиттеру за раз, ограничено. А это значит, что лабиринт будет заполняться порциями, каждыя из которых будет выводиться при очередном прерывании по вектору 100 («кадровое»). С появлением в AZBK режима ручного запуска блиттера, эта проблема ушла — выдаем блиттеру пакет за пакетом и запускаем все это сами, не ожидая милостей от вектора 100. Заодно появилась возможность сбрасывать блиттеру фоновые задачи, типа «удали старые спрайты со скрытого экрана, а мы в это время посчитаем куда какому монстру сделать шаг». И вывод на экран стало возможно делать тогда, когда хочется, а не ожидая очередного «кадрового» прерывания. Вот тут и был подвох.
Как только я добавил Зомби, шагающих туда-сюда, потребовалось их еще и скроллить вместе с фоном, когда Дейв инициирует движение окна. При этом, когда скроллинг (вертикальный или горизонтальный) докручивался до максимума и надо было уже переключать окно, вдруг могли промелькнуть какие-то дополнительные фигуры Зомби, там, где их никак быть не могло. Я предположил, что это спрайты, которые не успели стереться, а это место экранной страницы было вытащено скроллингом на видимую область экрана. Стало ясно, что эти вещи надо тоже теперь синхронизировать вручную — сдвиг рулонов и переключение видимой области экрана. Но когда пакет команд блиттеру ушел, то о том, что блиттер его обработал, можно судить только по биту 15 в регистре 177270. Т.е. надо ждать, когда этот бит сбросится в 0 и потом можно переключать рулоны.
А рулоны двигаются совсем в другом месте — в подпрограмме перемещения слоев в зависимости от деятельности Дейва. Блиттер работает сам по себе где-то в фоне, а вот регистры скроллинга изменяют изображение сразу. Значит, нам в этой подпрограмме нельзя изменять сами регистры, нужно просто вычислять новые значения, чтобы применить их потом, сразу кучей, после того, как блиттер закончит стирать/выводить спрайты и все будет готово к отображению нового кадра. Причем желательно это сделать как раз в момент обратного хода луча, чтобы было незаметно.
В итоге, я завел несколько переменных, содержащих копии регистров управления слоями экрана и движок теперь изменяет не сами регистры, а эти переменные. А перенос значений из этих переменных в сами регистры происходит в тот момент, когда все готово и блиттер завершил обработку команд.
Вот тогда призраки и были изгнаны и «дрожь земли» пропала!
Да, еще я напоролся на небольшие грабли: если пакет команд маленький, то блиттер так шустро его выполняет, что бит 15 (признак работы блиттера) и установиться не успевает. И это приводило к бесконечным ожиданиям «когда ты там начнешь команды обрабатывать??» и зависаниям.
В цикле вывода на экран стоял wait и сам вывод начинался после возникновения прерывания по вектору 100 («кадровое прерывание» на БК). Это необходимо, чтобы спрайты не мигали на экране, ведь их приходится стирать и выводить снова, и момент, когда спрайта нет на экране не должен быть виден игроку. Но это самое ожидание обратного хода луча может все и тормозить, если программе есть чем заняться 🙂 Альтернативой является использование двух экранных страниц — одну страницу скрываем, стираем на ней спрайты (все равно она не отображается сейчас), выводим заново на новых местах, а в это время демонстрируем вторую. Таким образом момент, когда спрайты стерты, не виден.
На БК0011М экранных страниц две. А сколько их на AZBK? Да сколько хочешь, ведь вся память AZBK может быть отображена с любой страницы. И включать эти страницы можно в любые слои экрана. Вот я и завел себе две экранных страницы для верхнего экранного слоя и вывожу туда бегущего Дейва, попеременно включая то одну, то вторую. В итоге ожидания обратного хода луча нет и мигания спрайтов тоже нет.
Завтра заведу две экранных страницы и для среднего слоя, где Зомби гуляют.
Переделал движок анимации монстров. В анимации Зомби каждая фаза движения стоит на экране 8 кадров, напрашивалось решение выводить на экран только один из этих спрайтов, первый. А потом 7 кадров пусть он себе стоит, не надо выводить его заново. Что и было реализовано. Получен, конечно, большой выигрыш в скорости обработки монстров. Но можно еще ускорить, если сдвинуть начальные фазы монстров так, чтобы они обновляли свои ключевые спрайты не одновременно.
Не обошлось без подводных камней: пакет команд в блиттер уходит сразу после получения «кадрового» прерывания, а вот изменения начального адреса отображения слоя видеопамяти — в процессе обработки скроллинга движком. В итоге иногда на экране мелькают призраки Зомби, которые не успели стереться. Идеи борьбы с этими «хвостами» у меня есть, завтра попробую реализовать.
Монстров на одном уровне в Дейве прямо толпы — количество их достигает 60 штук. Конечно, не все они видны и в реальной игре Дейва быстро сожрут при большом столпотворении, но все равно есть что оптимизировать…
исправил спрайты со смещенным контуром (один был при стрельбе влево вверх, второй — при заряжании)
добавил анимацию перезарядки и расход патронов (собственно, добавил еще вчера, но из-за кривых спрайтов выглядело это не очень)
оптимизировал обнаружение препятствий летящей пулей — процедура ускорилась в 17 раз 🙂
добавил команду «повтор спрайта» для движка движений — таблицы движений сократились даже не знаю во сколько раз
добавил задание индивидуального шага в анимацию объектов обстановки, теперь они работают как положено, с разными скоростями — дым летит быстро, алмазы мигают медленно, очки плывут вверх средне
допилил стрельбу — после выстрела не происходит возврат в базу, пока не отпустят кнопку выстрела
добавил проверку попыток стрелять при пустом магазине и соответствующие движения
Как-то мне попалось мини-интервью Джона Ромеро, его там спросили под каким углом стреляет Дейв. Ответ был — 45 градусов. Я тогда удивился, почему вообще возник такой вопрос у народа. Поизучал траектории полета пули в оригинале и тоже удивился: что-то там не похоже на 45 градусов никак:
Пришлось немного повысчитывать, но все получилось, теперь Дейв стреляет:
И вот появилось ощущение той самой игры! Теперь надо или подумать над звуками в игре, или заняться монстрами, разлетающимися кусками от них и т.д.
P.S. Совсем забыл — надо же перезарядку дробовика еще сделать 🙂
Свежие комментарии