Лучший способ динамически обновлять данные плитки на Commodore 64
Я планирую использовать программные спрайты в режиме многоцветного символа для моего нового проекта C64. Моя идея состоит в том, чтобы наложить данные спрайтов "маркеры".
Я думаю, что у меня могут быть данные набора тайлов по адресу 'TILESET', данные спрайта по адресу 'SPRITE'. И я могу объединить эти два, чтобы подготовить маркер пули с динамически рассчитанным фоном и сохранить по адресу "SUPERIMPOSED"
Я написал следующий код и количество циклов, чтобы проверить, возможно ли это. И я думаю, что это не так. Цикл съедает 219 циклов. Почти четыре растровые линии. И я не включил другие необходимые вычисления, необходимые перед этим циклом. Нравится расчет целевых адресов.
Когда я хочу иметь 16 пуль на экране, это займет 64 растра или 8 строк символов. Так что я стал подозрительным. Это правильный путь? Или есть другой, более оптимизированный способ сделать ту же работу?
cycles
---------
ldy #$07 4 x1 = 4
- LDA TILESET,x 3 x8 = 24
AND SPRITE,x 4 x8 = 32
STA SUPERIMPOSED,x 5 x8 = 40
dey 2 x8 = 16
cpy 4 x8 = 32
bne - 3 x8-1 = 71
----------
219 Cycle
Я рассматриваю повторяющийся узор в фоновом режиме. Так что я могу использовать ту же плитку пули без перерасчета.
1 ответ
Как говорит Шут, в качестве первой оптимизации просто повторите lda
, and
, sta
а также dey
восемь раз Устранить cpy
а также bne
, Это сразу спасет 103 цикла. Даже если вы хотите сохранить формальный цикл, обратите внимание, что dey
устанавливает нулевой флаг, так что вам не нужно cpy
,
В качестве второй оптимизации рассмотрим скомпилированный спрайт. Вместо выполнения чтения из sprite, x
эти значения должны быть закодированы непосредственно в вашей программе, создавая отдельную процедуру для каждого спрайта. Это сократило бы еще 16 циклов.
Как говорится, ваш lda
будет 4 цикла в выровненной таблице, а не 3. Таким образом, есть 8, которые вы не учли. Это означает, что развернутый плюс специализированный для вашего спрайта = 102 цикла (пропустив последний dey
).
Не зная архитектуры C64 и / или того, что делает остальная часть вашего кода, если кто-то глотает SUPERIMPOSED
можно сделать это со страницы стека, рассмотрите возможность записи выходных данных в стек, а не посредством индексированной адресации. Просто загрузить s
с соответствующим начальным значением и сохраните новые результаты через pha
, Это сэкономит два цикла на магазин за счет 12 дополнительных циклов настройки и восстановления.
Исходя из этой мысли, если у вас была свобода в том, как выглядят эти таблицы, рассмотрите возможность переключения их формата - вместо одной таблицы, которая содержит все восемь байтов TILESET
, используйте восемь таблиц, каждая из которых содержит один байт. Это избавило бы от необходимости корректировать y
в петле; просто используйте разные целевые таблицы в каждой развернутой итерации.
Предположим, что оба TILESET
а также SUPERIMPOSED
может быть восемь таблиц, которые сводят вас к:
LDA TILESET1, x
AND #<value>
STA SUPERIMPOSED1, x ; * 8
[... LDA TILESET2, x ...]
... что в общей сложности 88 циклов. Если SUPERIMPOSED
является линейным, но на странице стека:
TSX
TXA
LDX #newdest
TXS
TAX ; adds 10
LDA TILESET1, y
AND #<value>
PHA ; * 8
[... LDA TILESET2, y ...]
TXS ; adds 2
... что составляет 84 цикла.
Позднее добавление:
Если вы хотите предварительно умножить индекс в x
на 8, эффективно уменьшая ваш индексируемый диапазон до 32 плиток, затем вы можете приступить к заполнению линейного выходного массива, не корректируя y, согласно:
LDA TILESET, x
AND #<value1>
STA SUPERIMPOSED, x
LDA TILESET+1, x
AND #<value2>
STA SUPERIMPOSED+1, x
... etc ...
Таким образом, вам потребуется восемь копий этой подпрограммы с разными базовыми адресами таблиц, чтобы иметь возможность получить 256 выходных фрагментов. Предположим, у вас есть 20 спрайтов, что составляет в общей сложности 20*8 = 160 копий вашей процедуры построения спрайтов, каждый из которых, вероятно, будет порядка 100 байт, поэтому вы тратите около 16 КБ.
Если ваша игра на одном типе спрайта намного тяжелее, чем на других - например, обычно два или три космических корабля стреляют тысячами пуль друг в друга - тогда очевидно, что вы можете оптимизировать очень выборочно и уменьшить общий объем.