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



我计划在我的新C64项目中使用多色字符模式的软件精灵。我的想法是使用叠加"子弹头"精灵数据来平铺数据。

我想我可以在地址"tileset"有tileset数据,在地址"sprite"有sprite数据。我可以将这两者结合起来,准备一个具有动态计算背景的子弹头字符,并存储在地址"叠加"中

我写了下面的代码和循环计数来检查它是否可行。我认为事实并非如此。循环消耗了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

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

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

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

也就是说,您的lda将是一个对齐表中的4个循环,而不是3个。所以有8个你没有考虑。这意味着展开的加号专门用于你的精灵=102个循环(省略了最后的dey(。

在不了解C64体系结构和/或代码其余部分的功能的情况下,如果从堆栈页面获取SUPERIMPOSED的人可以这样做,请考虑将输出写入堆栈,而不是通过索引寻址。只需加载具有适当种子值的s,并通过pha存储新结果。这将为每个商店节省两个周期,而另外需要12个设置和恢复周期。

根据这个想法,如果你对这些表的外观有自由度,那么可以考虑切换它们的格式——不要用一个表来容纳TILESET的全部八个字节,而是用八个表,每个表都容纳一个字节。这样就不需要在循环中调整y;只需在每个展开的迭代中使用不同的目标表。

假设TILESETSUPERIMPOSED都可以是八个表,则可以归结为:

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字节的数量级,所以你需要花费大约16kb。

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