Как я понимаю, ты хочешь сделать на полный экран, 50фпс, как можно больше спрайтов, в основном не пересекающихся на чёрном фоне и без маски. Уровень без скролла, много статичных тайлов, которые и перерисовать не нужно, следовательно бросаемый двойной буфер смысла нет использовать.
Можно попробовать переключаемый двойной буфер(седьмую страницу). Помнить какие знакоместа были со спрайтами подвижных объектов(СПО) два кадра назад, нарисовать новые СПО, запоминая в новой карте знакомест, и забывая знакоместа в старой карте. Потом пробежаться по старой карте знакомест, и затереть недотёртые. Потом переключить экраны. Вычислить продвижения объектов и всё по новой.
Чтобы не использовать седьмую страницу, нужно всё успевать перерисовать в нужном месте в нужное время. Кадровая развёртка у нас бежит сверху вниз. Вот нужно успеть "между струйками".

Чтобы не сортировать СПО по координате Y, можно сделать так: Экран на спектруме как-бы состоит из трёх третей: верхней, средней и нижней. Вот, значит, пишем процедуру, которая обновляет содержимое одной трети. То есть перерисовывает все СПО и прочую индикацию в выбранной трети экрана. А в главном игровом цикле, начинаем вызывать её по порядку для верхней трети, средней, и нижней. Потом синхронизируемся с прерыванием 50гц, двигаем координаты обьектов. И по новой. А для режима пентагона, предусмотреть другой главный игровой цикл: синхронизация, перед обновлением нижней трети. Или средней трети. И ли перед перерасчётом. Всего четыре варианта, можно, думаю, подобрать, для каждого клона методом тыка.
Чтобы не подчищать лохмоты за СПО, зная их динамику, можно нарисовать их таким образом, чтобы они сами себя подчищали. Например танчик, который всегда за кадр может ехать на 1 пиксель вперёд максимум, может сам себя подчищать, имея за кормой один рядок пустых пикселей. В два раза более быстрый танк, должен иметь два рядка пустых пикселей, соответственно. При взрыве танка, последний спрайт анимации взрыва должен затереть всё. И так далее с летящими снарядами и прочим.
А что же делать, если изредка(например, каждый шестнадцатый) кадр будет такой сложный, что чуть-чуть не успеет перерисоваться за 1/50 секунды. Зато соседние кадры с гораздо большим запасиком времени успевают. Так что-же у нас будет дёрганье? Можно ведь это избежать. Но, конечно, синхронизация по HALT, мы отставим, а сделаем цикл ожидания, когда нам IM2_процедура добавит потребность в новом кадре.
Код:
LD HL,NeedFrame
INC (HL)
При старте игры или снятии с паузы (NeedFrame) надо обнулить.
Начать цикл ожидания надо с того, что один кадр отрисован, и мы его отнимаем.
Код:
LD HL,NeedFrame
DEC (HL)
А потом ждём, когда-же NeedFrame станет неотрицательной.
Код:
PHALT:
BIT 7,(HL)
JP NZ,PHALT
Если случайно один сложный кадрик нас(то есть наш Z80) притормозит, то просто INC (HL) выполнится чуть раньше DEC (HL). Ну и ничего страшного, результат-то тот же. JP не сделает переход ни разу, то есть мы сразу выйдем из цикла ожидания и кинемся догонять время. Вместо тупого аппаратного HALT, который нас-бы(ну мы, щас за Z80 думаем), заставил бы стоять до скончания кадра, почти целый кадр.
Всё пишу из головы, код не отлажен, не пытайтесь бездумно копипастить и компилировать.
[свернуть]