跳至内容

超级任天堂编程/手柄输入

来自维基教科书,开放世界开放书籍

手柄是 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,因为读取过程需要一些时间才能完成。

华夏公益教科书