NDS自制软件教程3



掌叔
2008-06-15 09:30:35

摘自:ndsbbs
作者:nashi1987

这一节,我们介绍如何处理用户的按键操作。

REG_KEYINPUT 寄存器:

NDS有一个硬件寄存器,当按键被按下时,寄存器的值会改变。寄存器REG_KEYINPUT 位于内存地址的0x4000130处。它是只读寄存器。当按键时,值会改变:

KEYS Bit Key 'ndslib' define Down if Up if
0 A KEY_A Cleared Set
1 B KEY_B Cleared Set
2 Select KEY_SELECT Cleared Set
3 Start KEY_START Cleared Set
4 Directional Right KEY_RIGHT Cleared Set
5 Directional Left KEY_LEFT Cleared Set
6 Directional Up KEY_UP Cleared Set
7 Directional Down KEY_DOWN Cleared Set
8 Right Alternate Button KEY_R Cleared Set
9 Left Alternate Button KEY_L Cleared Set

REG_KEYXY 寄存器:
你会注意到这里漏掉了两个键, 'X' 和 'Y'。
这两个键是从不同的寄存器读取的,REG_KEYXY寄存器,在内存地址0x04000136处。不幸的是这个寄存器只能被ARM7读取。

为了让它能被ARM9读取,在LIBNDS的ARM7样板代码中,ARM7在垂直间隔中断时读取寄存器值并储存在IPC数据结构中,IPC可被ARM9读取。这是相关代码片:

void InterruptHandler(void) {
[...]

but = REG_KEYXY;

[...]

IPC->heartbeat = heartbeat;
IPC->buttons = but;
IPC->touchX = x;

[...]
}

REG_KEYXY 寄存器不仅包含X、Y键状态位,它还包括触控笔和NDS屏幕和上或打开的状态位:

XKEYS Bit Key 'ndslib' define Down if... Up if ...
0 X (1 << 0) Cleared Set
1 Y (1 << 1) Cleared Set
2 Pen Down (1 << 6) Cleared Set
3 Hinge (1 << 7) Set Cleared


读键:

使读取 REG_KEYINPUT 寄存器变的简单一点,我取它值的补码。这允许使用'&' 操作符来判断键是否被按下。我们可以这样写代码:

uint16 keysPressed = ~(REG_KEYINPUT);
if(keys_pressed & KEY_UP)
--shape_y;
来取代这个不直观的
if(!(REG_KEYINPUT & KEY_UP))
--shape_y;

同样的事ARM7可以这样做:
uint16 specialKeysPressed = ~IPC->buttons;

// Y Key
if(specialKeysPressed & (1 << 1))
shape_color = RGB15(7, 7, 7);

// X Key
if(specialKeysPressed & (1 << 0))
shape_color = RGB15(0, 15, 15);

// Pen Down
if(specialKeysPressed & (1 << 6))
shape_color = RGB15(0, 31, 31);

// Hinge closed
if(!(specialKeysPressed & (1 << 7)))
shape_color = RGB15(0, 0, 0);


通过键来控制图形移动:
我们对上一篇教程中的示例做一下轻微改动,以通过键来控制。

我们用方向键控制来代替图形的自动移动。其他的键控制图形的颜色。合上屏幕会使它消失,打开再按一个键又会让它重现。

我们使用一个公共变量来储存颜色值:

static uint16 shape_color = RGB15(31, 0, 0);

绘图代码也须改变:
void on_irq()
{
if(REG_IF & IRQ_VBLANK) {
draw_shape(old_x, old_y, VRAM_A, RGB15(0, 0, 0));
draw_shape(shape_x, shape_y, VRAM_A, shape_color);

// Tell the DS we handled the VBLANK interrupt
VBLANK_INTR_WAIT_FLAGS |= IRQ_VBLANK;
REG_IF |= IRQ_VBLANK;
}
else {
// Ignore all other interrupts
REG_IF = REG_IF;
}
}

图形通过方向键移动:

uint16 keysPressed = ~(REG_KEYINPUT);

// Based on the key pressed, move the shape.
if(keysPressed & KEY_UP)
--shape_y;
if(keysPressed & KEY_DOWN)
++shape_y;
if(keysPressed & KEY_LEFT)
--shape_x;
if(keysPressed & KEY_RIGHT)
++shape_x;

颜色通过测试IPC->buttons的值来改变,但首先取它的补码使其更加直观:

uint16 specialKeysPressed = ~IPC->buttons;

// Change the color of the shape if the relevant key was pressed.
if(keysPressed & KEY_A)
shape_color = RGB15(31, 0, 0);

if(keysPressed & KEY_B)
shape_color = RGB15(0, 31, 0);

if(keysPressed & KEY_SELECT)
shape_color = RGB15(0, 0, 31);

if(keysPressed & KEY_START)
shape_color = RGB15(31, 31, 31);

if(keysPressed & KEY_R)
shape_color = RGB15(15, 0, 15);

if(keysPressed & KEY_L)
shape_color = RGB15(7, 15, 7);

// Y Key
if(specialKeysPressed & (1 << 1))
shape_color = RGB15(7, 7, 7);

// X Key
if(specialKeysPressed & (1 << 0))
shape_color = RGB15(0, 15, 15);

// Pen Down
if(specialKeysPressed & (1 << 6))
shape_color = RGB15(0, 31, 31);

// Hinge closed
if(!(specialKeysPressed & (1 << 7)))
shape_color = RGB15(0, 0, 0);


小猫
2011-09-18 12:53:58

good