如何在C64的边框上显示精灵?

时间:2009-09-25 13:59:15

标签: border sprite c64

我看过很酷的C64演示,在屏幕的边框区域显示精灵。这不应该是可能的;我认为他们设法以某种方式欺骗了图形芯片。他们究竟是怎么做到的?

6 个答案:

答案 0 :(得分:28)

是的,你需要汇编程序。这是一个中断时序技巧。 VIC能够在边框中显示精灵,但框架只是隐藏它们,因此精灵可以在它后面滑动。它连接到VIC显示的扫描线。对于下/上边框,这很简单:

  • 编程中断,同步开始某条扫描线,7像素或类似下边界之前的内容。
  • 在VIC中设置寄存器以使边框更小。 (有一个注册表可以做到这一点。)
  • VIC现在认为边界已经开始并且没有开始画它。
  • - >底部没有边框。
  • 在真实边框之后编程另一个中断,将其设置回原始状态。

对于左/右边框中的精灵,它更复杂,因为必须为每个扫描线重复该过程:

  • 编程中断,同步以从某条扫描线开始。
  • 然后做一些NOP,直到你在右边界前7个像素。
  • 在VIC中设置寄存器以使边框更小。
  • - >右侧没有边框。
  • 执行一些NOP,直到您在真实边框之后并将寄存器设置回原始值。
  • 再做一些NOP,直到第2步。

问题在于,所有这些NOP都在忙着等待并偷走你的东西。

我能够从下边框的精灵滚动条中找到一些代码。这是代码。 (它是从一些演示中删除的。)

C198  78        SEI
C199  20 2E C1  JSR C12E     # clear sprite area
C19C  20 48 C1  JSR C148     # init VIC
C19F  A9 BF     LDA #BF      # set up IRQ in C1BF
C1A1  A2 C1     LDX #C1
C1A3  8D 14 03  STA 0314
C1A6  8E 15 03  STX 0315
C1A9  A9 1B     LDA #1B
C1AB  8D 11 D0  STA D011
C1AE  A9 F7     LDA #F7
C1B0  8D 12 D0  STA D012
C1B3  A9 01     LDA #01
C1B5  8D 1A D0  STA D01A
C1B8  A9 7F     LDA #7F
C1BA  8D 0D DC  STA DC0D
C1BD  58        CLI
C1BE  60        RTS

----------------------------------
# init VIC
C148  A2 00     LDX #00
C14A  BD 88 C1  LDA C188,X
C14D  9D 00 D0  STA D000,X   # set first 16 values from table
C150  E8        INX
C151  E0 10     CPX #10
C153  D0 F5     BNE C14A
C155  A9 FF     LDA #FF
C157  8D 15 D0  STA D015
C15A  A9 00     LDA #00
C15C  8D 1C D0  STA D01C
C15F  A9 FF     LDA #FF
C161  8D 17 D0  STA D017
C164  8D 1D D0  STA D01D
C167  A9 C0     LDA #C0
C169  8D 10 D0  STA D010
C16C  A9 F8     LDA #F8
C16E  A2 00     LDX #00
C170  9D F8 07  STA 07F8,X
C173  18        CLC
C174  69 01     ADC #01
C176  E8        INX
C177  E0 08     CPX #08
C179  D0 F5     BNE C170
C17B  A9 0E     LDA #0E
C17D  A2 00     LDX #00
C17F  9D 27 D0  STA D027,X
C182  E8        INX
C183  E0 08     CPX #08
C185  D0 F8     BNE C17F
C187  60        RTS

----------------------------------
# data set into VIC registers
C188  00 F7 30 F7 60 F7 90 F7
C190  C0 F7 F0 F7 20 F7 50 F7

----------------------------------
# main IRQ routine
C1BF  A2 08     LDX #08
C1C1  CA        DEX
C1C2  D0 FD     BNE C1C1
C1C4  A2 28     LDX #28      # 40 or so lines
C1C6  EA        NOP          # "timing"
C1C7  EA        NOP
C1C8  EA        NOP
C1C9  EA        NOP
C1CA  CE 16 D0  DEC D016     # fiddle register
C1CD  EE 16 D0  INC D016
C1D0  AC 12 D0  LDY D012
C1D3  88        DEY
C1D4  EA        NOP
C1D5  98        TYA
C1D6  29 07     AND #07
C1D8  09 18     ORA #18
C1DA  8D 11 D0  STA D011
C1DD  24 EA     BIT   EA
C1DF  EA        NOP
C1E0  EA        NOP
C1E1  CA        DEX
C1E2  10 E4     BPL C1C8     # repeat next line
C1E4  A9 1B     LDA #1B
C1E6  8D 11 D0  STA D011
C1E9  A9 01     LDA #01
C1EB  8D 19 D0  STA D019
C1EE  20 00 C0  JSR C000   # call main code
C1F1  4C 31 EA  JMP EA31   # finish IRQ

答案 1 :(得分:9)

这一切都依赖于时机。 C64有一种方法可以在绘制屏幕时查询电子束的确切垂直位置。 当一个新行开始时,你必须等待几个周期(你可以使用NOP指令计时),然后你必须设置一个负责设置screenmode(和边框宽度)的视频芯片的硬件寄存器。 通过准确计时,再次对每条扫描线进行操作,整个侧边框消失了。

底部边框也出现了类似的伎俩。在垂直边框开始的确切扫描线上,您也必须设置禁用该帧底部边框的视频模式。

事实上,这一切都必须在集会中完成。否则你永远无法完全正确地计时。

作为旁注,我认为侧边伎俩归功于1001 Crew(一个荷兰组)。我不确定是谁取下了第一个底部边界技巧。

答案 2 :(得分:7)

有关在C64上打开边框的主题的精彩教程, 查看Pasi Ojala在C=Hacking Issue 6中的优秀文章。

没有过于技术化,这个技巧使用了VIC的一个功能 芯片让你在25/24行和40/38列文本/图形之间切换,和 涉及在恰当的时刻进行此切换以欺骗VIC 认为事实上它已经切换了边界 没有。查看上面的文章以获得更全面的解释 用代码示例。

答案 3 :(得分:1)

那是很久以前的事了。

我知道有一种解决方案依赖于显示器的频率。

使用CRT,即使当前像素位于正常屏幕之外,也可以知道当前像素。 所以你可以操纵光线。

在我的垃圾堆中某处必须有一些C64书籍。

Offtopic,但使用VIC20(C64的前身)的图形很有趣。无法操纵每个像素,但您可以更改现有字符。因此,您在屏幕上填充了从0到...的所有字符,并更改了字符以将像素设置为屏幕。 ; - 。)

答案 4 :(得分:1)

正如已经说过的,您必须愚弄VIC才认为边界已经开始,但是我写这封信的原因是,最主要的答案有点不准确:我完全找不到要注册的寄存器缩小边框,这样就可以做到(至少在顶部和底部):等到VIC到达第25个字符行,然后启用24行($ D011,位3)。您只需使用38个cols($ D016,位3)就可以对左右边框进行相同的操作,但是这样做需要非常精确的定时,并且还需要通过设置垂直滚动寄存器来消除不良行,因此scanline mod 8永远不会等于滚动值。当然,您不能再使用正常显示了,因为坏行实际上不仅是坏行,它们还用于加载我认为的字符数据,这些内容在非边界区域中每第8行重复一次。当我阅读最佳答案时,我个人有点困惑,希望能有所帮助。 (此外,最主要的答案有一个错误:您不要使边框变小,而是使边框变大)

答案 5 :(得分:0)

时机是关键。当CRT的光束从左向右移动时,通过改变过扫描(边界)颜色在边界中创建图像。生成图像需要两个定时信号 - 垂直刷新和水平刷新。通过检测何时发生水平和垂直刷新,您可以启动一系列汇编程序指令来更改边框颜色以生成图像。您需要计算每个边框像素的CPU时钟滴答数,并使用它来创建在正确的位置更改边框颜色的代码。

在编写游戏方面效果不佳,因为CPU开销太大,无法随时解除用户输入和游戏状态。