超级任天堂编程/手柄输入
手柄是 SNES 从用户处获取输入的方式。最多可以连接四个手柄到系统,并且还支持特殊控制器(鼠标,超级瞄准镜 等)。
注意:本教程正在进行中。我对 SNES 还比较陌生,所以请随时纠正本文档中的任何错误。
首先,我们将列出我们将要使用的寄存器
大小 | 地址 | 官方名称 | 描述 |
字节 | $4200 | NMITIMEN | 计数器使能 |
字节 | $4212 | HVBJOY | 状态寄存器 |
字 | $4218 | CNTRL1L & -H | 手柄 #1 状态 |
字 | $421a | CNTRL2L & -H | 手柄 #2 状态 |
字 | $421c | CNTRL3L & -H | 手柄 #3 状态 |
字 | $421e | CNTRL4L & -H | 手柄 #4 状态 |
字节 | $4016 | 手柄 #1 旧式状态 | |
字节 | $4017 | 手柄 #2 旧式状态 |
现在,让我们更深入地了解一下它们
$4200 - NMITIMEN - 计数器使能 n-vh---j
这个寄存器你可能很熟悉。如果你之前做过任何 SNES 编码,你会发现你可能已经使用过这个寄存器来启用 VSync 中断。对于手柄输入,我们必须确保位 0 ("j") 设置。这告诉 SNES 我们将轮询其他手柄寄存器。
作为参考,构成我们将在寄存器 $4200 中加载的字节其余部分的 n-vh---j 位如下
位名称 | 位置 | 描述 |
n | 7 | 启用/禁用 NMI |
v | 5 | 启用/禁用垂直触发时的 IRQ |
h | 4 | 启用/禁用水平触发时的 IRQ |
j | 0 | 手柄轮询位 |
$4212 - HVBJOY - SNES 状态寄存器 vh-----j
此寄存器用于查看某些数据是否已准备好从 SNES 中轮询。在这种情况下,我们只关心位 0 ("j")。如果我们轮询 $4212 并且位 0 设置,那么我们知道其他 SNES 手柄寄存器将包含相关数据。但是,如果省略此步骤,通常不会太糟糕。在我将在后面展示的算法中,跳过了此检查,但此解释仍然存在以完整性。
$4218/9 到 $421e/f - 手柄状态寄存器 hi:bystudlr lo:axlriiii
这些是 16 位寄存器,它们返回连接到 SNES 的每个手柄的按钮和/或类型状态。$4218 和 $4219 包含手柄 1 的数据,手柄 2、3 和 4 紧随其后。位按如下方式排列
位(s) | 描述 |
$4219/b/d/f | (hi) |
b | B 按钮 |
y | Y 按钮 |
s | 选择按钮 |
t | 开始按钮 |
u | 向上方向键按钮 |
d | 向下方向键按钮 |
l | 向左方向键按钮 |
r | 向右方向键按钮 |
$4218/a/c/e | (lo) |
a | A 按钮 |
x | X 按钮 |
l | L 按钮 |
r | R 按钮 |
iiii | 控制器类型 ID |
大多数这些都是不言自明的。如果对应按钮的位设置,则该按钮被按下。唯一有点令人困惑的是神秘的 "iiii" 位 - 它们确定连接到端口的控制器类型。基本上,如果它们读取 0000,则它是一个标准的 SNES 控制器。否则,它是自定义控制器类型或损坏数据。
$4016 和 $4017 - 手柄 1 和 2 旧式状态
对于这些,你会注意到我省略了每个寄存器的特定位。基本上,这些工作方式与从 NES 读取状态的方式完全相同。因此,我认为在此处包含这些信息是多余的,除了 $4200 的位 0 必须清除才能以这种方式使用它们。但是,这些寄存器仍然很有用。如果你将 0 写入 $4016,那么这两个寄存器可以用来检查手柄 1 和 2 是否已连接。在写入 0 之后(你只需要写入 $4016,而不是两个),如果未连接,则从寄存器读取将返回 0,如果已连接,则返回其他内容。
当你初始化时
.ENUM $80
Joy1A db ;B, Y, Select, Start, Up, Down, Left, Right
Joy1B db ;A, X, L, R, iiii-ID
.ENDE
lda #%10000001 ; Enable NMI and Auto Joypad read
sta NMITIMEN ; Interrupt Enable Flags
在你的主游戏循环中(或在合适的地方)无需检查
lda CNTRL1L ; $4218
sta Joy1A
lda CNTRL1H ; $4219
sta Joy1B
但是,在从自动手柄读取寄存器读取之前,应测试 HVBJOY 的最低位是否为 0,因为读取过程需要一些时间才能完成。