在Commodore 64上绘制屏幕边框

60

我对此有25年的好奇心,我很想了解这个技巧。

在Commodore 64中,6569 VIC无法寻址边框。你只能在光标移动的中央区域绘制像素。边框始终是统一的颜色,尽管你可以使用poke 53280,color命令更改其颜色(如果我没记错的话)。

尽管如此,我清楚地记得,游戏介绍中的边框具有图形特性,就像它完全可寻址一样。我试图理解它是如何工作的,但从未到达过那个点。传说这是对精灵的巧妙运用,在某些情况下,可以在边框上绘制,但我不知道它是否是一个城市传说。

编辑:刚刚从提供的链接之一中读到了以下内容:

精灵跨越垂直光栅线复用(超过8个精灵,有时高达120个精灵)。直到Group Crest于2007年5月发布Krestage 3之前,人们普遍认为每个光栅线最多只能出现8个精灵,但重新分配新的Y坐标后,它会在屏幕更低的位置重新出现。

这太邪恶了......你要在光栅到达之前打败它并重新定位精灵...


如果我没记错的话,精灵就是你实现这个功能的方式。稍微搜索一下,可能会找到至少一个网站上有详细信息。 - Jerry Coffin
3
可惜没有一面代表“棒极了”的旗帜。 - Paul Nathan
14
为什么我费尽力气想要用依赖注入来替换这段记忆,却仍然能够记得在C64上,使用 POKE 53280 和 POKE 53281 可以改变背景和边框颜色这个毫无用处的事实? - JohnFx
基本上这里是同样的问题: https://dev59.com/k3M_5IYBdhLWcg3wNgOZ - paprika
1
是的... 这是一个重复问题,但是这里也有很好的答案,删除它会很可惜。 - Stefano Borini
显示剩余5条评论
9个回答

46

首先,只有精灵可以显示在边框区域或者是一个重复的8位模式(宽度为8像素),这个模式是从视频存储器的最后一个字节读取的,通常为$3fff。 请注意,只有当您欺骗VIC芯片“不显示”边框时,您才能看到这些精灵或8位模式。详见下文。

边框对于精灵具有更高的优先级,因此通常情况下,在边框区域绘制精灵时,边框会覆盖精灵。通过一些VIC芯片的技巧,您可以关闭边框。

您可以相当容易地关闭顶部和底部的边框(我将在下面解释),并使用非常关键的时序关闭侧边框。

首先,让我们简要介绍一下c64上VIC芯片的工作原理。

VIC芯片从左上角开始绘制屏幕,然后向下一行,再从左到右绘制,直到整个屏幕被绘制完毕。它每秒执行50次重新绘制操作(对于PAL设备)或60次(对于NTSC设备)。

有一个8位的VIC寄存器,其中包含任何给定时间点的光栅垂直位置。 $d012.实际上,有超过255个可能的位置,因此第9位存储在寄存器$d011的第7位(最高位)中。因此,在任何时刻,您都可以读取这些寄存器,并找到光栅的垂直位置。没有可用的寄存器来读取光栅的X位置。

关闭顶部和底部边框的技巧是:

1)将屏幕设置为25行模式

2)等待光栅到达$f2和$fa之间的垂直位置(24行模式和25行模式中边框开始的8个像素之间)。

3)将屏幕设置为24行模式......将边框的垂直起点移动到当前光栅位置以上

4)等待垂直光栅位置($fa)之后

5)每个帧都要重复

步骤3欺骗VIC芯片认为已经开始绘制边框,因此它永远不会开始绘制。是的,打开了顶部和底部的边框。

关于侧边框,您可以使用不同的寄存器执行相同的操作,但由于水平移动比垂直移动快得多,因此定时需要更紧。还有另一个问题要考虑,称为抖动。 <- 我在这里不解释。搜索“稳定的光栅C64”以深入了解该问题。


3
是的,我知道24行模式,但我从未想到它可以用这种方式……唯一我不明白的是:基本上这让你清除了底部。在24边框模式下,底部边框会增加8个像素,但当你清除底部边框时,光栅将返回第0行,并通过复位开始绘制边框。 - Stefano Borini
2
你错误地认为边框标志在屏幕刷新开始时被重置。停止绘制边框的标志出现在第48或56行左右,具体取决于24或25行模式。开始绘制边框的标志只会在$f2和$fa行出现,同样取决于24或25个字符行模式。因此,当边框的“开始绘制”标志在$fa左右的行未设置时,它不会再尝试,直到下一个$f2-$fa区域。 - JohnD
2
哇...这是我在SO上见过的最好的答案之一。干得好!:D - moobaa
1
Atari使用了一种不同的技巧。您可以在任意时间改变边框颜色。因此,通过将颜色变化与电子束的移动时间配合,您可以创建图形。 - SF.

9
请注意,Krestage 3所做的(如问题中所述)是不同的。
其中一个技巧是在“纸张”(工作区矩形,边框内的东西)底部刚被绘制时混淆边框。这样可以让你在上下边框中有精灵。
更高级别的技巧是在纸张的右侧边缘,在每个光栅线上进行干扰,所有这些都如JohnD的答案中所解释的那样。这样可以让你在左右边框中有精灵。
所有这些都不能让你在一行中拥有超过8个精灵。这只是Krest的魔法。
到目前为止,我所知道的关于VIC芯片最好的资源是Christian Bauer的"The MOS 6567/6569 video controller (VIC-II) and its application in the Commodore 64",而一个有用的补充是Marko Mäkelä的"The memory accesses of the MOS 6569 VIC-II and MOS 8566 VIC-IIe Video Interface Controller"
读者注意:这些内容有点技术性,如果你自己编程过一些VIC效果,可能会更容易理解。

如果链接失效了,只需通过标题在Google上搜索文章,它们会被无限复制。


6

您可以使用简单的BASIC程序打开上下边框:

    1 poke56334,0:poke53266,212:poke53265,27:poke16383,0
    2 h=53265:i=53273:h1=19:h2=27:i1=1
    3 pokei,i1:waiti,i1:pokeh,h1:pokeh,h2:goto3

(注:此代码用于控制 Commodore 64 计算机的边框显示,不适用于其他设备)

4
我要在这里冒个险(我自己没有做过)。我在维基百科上找到了这个。 c64demo section部分解释说:
不可能实现的效果在演示中被实现,主要是由于与 MOS Technology VIC-II 芯片 相关的未记录的副作用。一些 VIC 技巧的例子:
提到的其中一个黑客技巧是:
精灵滚动条放置在边框中。通过欺骗硬件不要在屏幕周围绘制边框,可以将精灵移动到该区域并显示。
当然,问题的有趣部分是如何完成它。我建议在一些包含源代码的 演示数据库 中寻找使用该黑客技巧的演示。

4
微软飞行模拟器在边框上进行了绘制。首先,我们可以通过在正确的时间更改边框颜色来实现边框绘制效果。例如,LOGO为海龟图形设计了分屏模式,其中屏幕在上方切换为HiRes图形,在下方显示少量文本。该框架的颜色也不同。因此,很容易实现地平线效果,绿色草地在下方,蓝色天空在上方(如飞行模拟器),这种效果延伸到框架。
当您运行野生帧闪烁程序时,就像
   C000 LDX #00
        STX D020
        INX
        STX D020
        DEX
        BEQ C002

然后,你可以在每10-20个像素左右改变颜色。我认为这是最快的变化方式。因此,你可以在边框上画一条水平线。fastest change of border color 你可以使用VIC中相同的垂直线寄存器$D012和$D011的第7位来计时。你可以从该寄存器读取当前扫描线。但是,如果你向其中写入数据,并启用$D01A寄存器中的低位,则当扫描线到达该行时,VIC将发出IRQ信号。这就是分屏效果的实现方式。
这里有一个例子。首先,我设置了我的中断程序:
   C000 SEI        ; disable interrupt
        LDA #1F    ; set interrupt routine to C01F
        STA 0314   ; set low byte
        LDA #C0    ; high byte
        STA 0315   ; set
        LDA #C0    ; raster position for horizon
        STA D012   ; set to raster position interrupt
        LDA D011   ; and for the high bit of the raster position
        AND #7F    ; clear the high bit
        STA D011   ; and set the cleared high bit
        LDA #F1    ; enable the raster interrupt
        STA D01A   ; in the appropriate register
        CLI        ; allow interrupt
        RTS        ; return from subroutine

这是我的实际中断例程:

   C01F LDA D019   ; load VIC interrupt register
        STA D019   ; and clear it
        BMI C02E   ; if highest bit is set, go to our routine
        LDA DC0D   ; else disable CIA interrupt
        CLI        ; enable interrupt
        JMP EA31   ; continue with normal system interrupt routine

   C02E LDA D012   ; load current vertical scan line
        CMP #01    ; is it just about the first line?
        BCS C042   ; if not jump to bottom part
        LDA #03    ; cyan
        STA D020   ; set border color (sky)
        LDA #C0    ; horizon level 
        STA D012   ; set vertical scan interrupt to occur at horizon
        JMP EA81   ; continue with normal interrupt minus cursor blink

   C042 LDA #00    ; black to draw a piece of horizontal line on the horizon
        STA D020   ; set border color
        LDX #08    ; a short busy loop
   C049 DEX
        BNE C049
        LDA #01    ; white to draw on the right side horizon
        STA D020   ; set border color
        LDX #02    ; very short busy loop
   C053 DEX
        BNE C053
        LDA #05    ; finally green as the grass
        STA D020   ; set border color
        LDA #00    ; next scan line interrupt at top of screen
        STA DO12   ; set scan line interrupt
        JMP EA81   ; continue normal interrupt sans cursor blink 

以下是光荣的结果: 在地平线上画有两条线段的分屏


1
源代码中有错别字(C64屏幕截图上是正确的):应该写成 “LDX#02”,而不是“LDC#02;非常短的忙碌循环”。 - Iain

2

打印 "兄弟,它是53280。"


是的 - 53281 是内部值。 - Wim

2
据我所知,这只适用于精灵图。
精灵可以在边框区域内,而且边框会覆盖精灵。通过一些诡计,可以去掉边框。

1

边框中的图形:可以是精灵或使用$3FFF效果(实际上根本不是精灵)。要详细了解需要比我在此处可用的更多空间和时间。


1
你可以在基本语言中让精灵边框化:BASIC Sprites in Border 如果我没记错的话,还有一种方法可以混淆视频芯片,使其绘制文本的第26行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接