在 Commodore 64 上动态更新磁贴数据的更好方法

Better way to dynamically update tile data on Commodore 64

我打算在我的新 C64 项目中使用多色字符模式的软件精灵。我的想法是使用 superimpose 'bullet' sprite data to tile data.

我想我可以在地址 'TILESET' 处获取 tileset 数据,在地址 'SPRITE' 处获取精灵数据。我可以将这两者结合起来准备一个具有动态计算背景的子弹字符并存储在地址 'SUPERIMPOSED'

我写了下面的代码和循环计数来验证是否可行。我认为不是。该循环消耗了 219 个周期。近四根光栅线。并且我没有包括此循环之前所需的其他必要计算。就像计算目标地址一样。

当我想在屏幕上显示 16 个子弹时,需要 64 个光栅或 8 个字符行。所以我开始怀疑了。这是正确的方法吗?或者还有其他更优化的方法来完成同样的工作吗?

                         cycles
                        ---------
    ldy #             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

我正在考虑在背景中使用重复模式。这样我就可以使用相同的子弹瓦片而无需重新计算。

正如 Jester 所建议的,作为第一个优化,只需重复 ldaandstadey 八次。消除 cpybne。这将立即节省 103 个周期。即使您想保留正式循环,请注意 dey 设置零标志,因此您不需要 cpy.

作为第二个优化,考虑编译精灵。您不必从 sprite, x 执行读取,而是将这些值直接编码到您的例程中,为每个精灵创建一个不同的例程。那会再减少 16 个周期。

话虽这么说,您的 lda 将是对齐的 table 中的 4 个周期,而不是 3 个。所以还有 8 个您没有考虑。这意味着 unrolled plus specialized to your sprite = 102 cycles(省略了最后的 dey)。

在不知道 C64 架构的情况下 and/or 你的代码的其余部分做了什么,如果任何人摄取 SUPERIMPOSED 可以从堆栈页面这样做,考虑将输出写入堆栈而不是通过索引寻址.只需使用适当的种子值加载 s 并通过 pha 存储新结果。这将以 12 个额外的设置和恢复周期为代价为每个商店节省两个周期。

根据这个想法,如果您可以自由决定这些 table 的外观,那么请考虑切换它们的格式 — 而不是一个包含 TILESET 的所有八个字节的 table ,使用八个table,每个都持有它的一个字节。那将消除在循环中调整 y 的需要;只需在每次展开的迭代中使用不同的目标 table。

假设 TILESETSUPERIMPOSED 都可以是八个 table,那么您可以得出:

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 ...

因此,您仍然需要具有不同 table 基地址的该例程的八个副本才能命中 256 个输出块。假设您有 20 个 sprite,那么您的 sprite 绘图例程总共有 20*8 = 160 个副本,每个副本可能大约为 100 个字节,因此您花费了大约 16kb。

如果您的游戏在一种精灵上比在其他精灵上重得多——例如通常是两三艘宇宙飞船相互发射数千发子弹——显然你可以非常有选择性地进行优化并降低总占地面积。