12

我想知道 NES 如何显示其图形肌肉。我已经在网上研究了一些东西并通读了它,但我想知道最后一件事:Nametables。

基本上,根据我的阅读,NES 命名表中的每个 8x8 块都指向模式表中的一个位置,该位置保存图形内存。此外,nametable 也有一个属性表,它为每个 16x16 块设置一个特定的调色板。它们像这样连接在一起:

(假设有 16 个 8x8 块)名称表,ABCD = 指向精灵数据的指针:

ABBB
CDCC
DDDD
DDDD

属性表,其中 1 2 3 = 指向调色板数据的指针,< 左侧引用值,^ 上方,' 左侧和上方:

1<2<
^'^'
3<3<
^'^'

因此,在上面的示例中,块将被着色为

1A 1B 2B 2B

1C 1D 2C 2C

3D 3D 3D 3D

3D 3D 3D 3D

现在,如果我把它放在固定屏幕上——效果很好!因为 NES 分辨率是 256x240 像素。现在,如何调整这些表格以进行滚动?

因为 Nametable 0 可以滚动到 Nametable 1,如果你继续滚动 Nametable 0 将再次环绕。我明白了。但我不明白的是如何滚动属性表。根据我在网上阅读的内容,它为其分配属性的 16x16 块会导致屏幕边缘图块的颜色失真(如在 SMB3 中从左到右滚动时看到的那样,反之亦然)。

我担心的是我了解如何滚动名称表,但是如何滚动属性表?例如,如果我在屏幕左侧有一个绿色块,理论上向右移动屏幕应该会导致右侧的图块也是绿色的,直到它们更多地移动到框架中,它们将恢复到他们的正常颜色。

~~~~编辑:我确实想指出我知道扫描线X和Y。这个想法刚刚在我脑海中闪过。

假设我在 10 的扫描线 Y。这意味着我正在水平读取 10 个值到我的命名表中。这意味着我的第一列不在屏幕上,因为它的像素宽度仅为 8。但是,颜色属性保持不变,因为它的宽度为 16。

假设整个列的颜色属性是绿色,我是否正确假设对用户来说,屏幕左侧的前 6 个像素将被着色为绿色,屏幕上最右边的 10 个像素也应该是绿色的?那么,根据屏幕左侧的假设,我是否正确?

4

5 回答 5

2

这个网站我相信你已经非常非常熟悉了。我会先说我从来没有为 NES 编程,但我对曾经发布的所有 Gameboy 硬件都非常有经验,而且 NES 与 GB/DMG 有很多共同点。我敢打赌,您要么需要做以下几件事之一:

  1. 不要滚动属性表。确保您的关卡在您移动的方向上都有相似的色块。我猜很多第一代游戏都是这样做的。

  2. 继续并允许有限的属性滚动 - 只需确保发生更改的区域是部分颜色共享或足够空间以使更改不会被注意到。

  3. 取出您的旧 skool atari 2600 计时器并在 HBlank 更新结束时写入寄存器 $2006 以完成您需要的颜色交换,等待一些抽动,然后在 HBlank 返回期间恢复,以便下一个的左边缘线路不受影响。我有一种感觉,这是最常用的解决方案,但如果没有一个非常好的模拟器和耐心,这将是一件痛苦的事情。它还会消耗您的整体 CPU 使用率,因为您必须在多条扫描线上的中断中等待才能完成效果。

我希望我能为您提供更具体的答案,但这希望对您有所帮助。谢天谢地,GB/DMG 的滚动系统稍微先进一些。:)

于 2010-06-11T14:46:16.807 回答
1

滚动时,超级马里奥兄弟 3 和柯比大冒险都会在屏幕边缘显示着色伪影。我相信这两款游戏都设置了空白屏幕左侧 8 个像素的位,因此任何一帧都会影响 0-8 个像素。

如果我没记错的话,Kirby's Adventure 总是试图将颜色有问题的列放在屏幕滚动的一侧,以使其不那么引人注目。如果不切换到垂直镜像,我认为这些伪影是不可预防的,这会带来自身的困难。

免责声明:自从我编写任何 NES 代码以来已经有五年了。

于 2010-06-11T21:22:38.233 回答
1

每个命名表都有自己的属性表,因此从一个命名表滚动到另一个命名表时不应出现图形工件。如果您的游戏垂直和水平滚动,您所指的颜色故障类型实际上只是一个问题。您只有两个名称表,因此双向滚动需要您蚕食可见屏幕。这个问题有多种解决方案,可以在这篇 nesdev 帖子中找到一个很好的总结:

http://nesdev.parodius.com/bbs/viewtopic.php?p=58509#58509

于 2010-12-30T17:37:55.067 回答
0

这个网站可能会有所帮助。 http://www.games4nintendo.com/nes/faq.php#4

(搜索“2005/2006 美元怎么了?”并开始阅读该区域。)

它基本上看起来不可能让它像素完美,但是这些将是你可能需要研究的部分。

希望我能提供更多帮助。

于 2010-06-11T07:31:14.747 回答
0

每个名称表都有自己的属性表。如果您将游戏世界限制在两个屏幕上,您只需要编写一次名称表和属性表。当您尝试使世界大于两个屏幕时,困难的部分就来了。《超级马里奥兄弟 1》通过向右滚动、根据需要环绕并在该列出现之前一次渲染一列块(16 像素)来做到这一点。我不知道如何有效地编码(请记住,您只有一毫秒的 vblank 时间)。

于 2012-07-30T03:27:09.910 回答