编辑: 被控制998 | 2013-10-19 |
static int shape_height = 10;
移动图形: 让图形能在屏幕上移动我们需要擦除现在位置的图形并在新位置重画.这可以通过保存运动前后X、Y坐标的轨迹坐标来实现: static int old_x = 0;
static int old_y = 0;
static int shape_x = 0;
static int shape_y = 0;
接下来绘图变的简单了,我们只需通过调用'
draw_shape'
函数和old_x、old_y坐标将其变为背景色来擦除它,再调用一次用新 '
x'
、'
y'
坐标来绘制新位置的图形: draw_shape(old_x, old_y, VRAM_A, RGB15(0, 0, 0));
draw_shape(shape_x, shape_y, VRAM_A, RGB15(31, 0, 0));
注意在'
draw_shape'
函数中的 帧缓冲 参数位置是'
VRAM_A'
,这是我们之前映射到主屏的 帧缓冲 . 并不太正确: 一个简单的画图和计算位置的 '
main'
函数可以是这样: int main(void) { powerON(POWER_ALL);
videoSetMode(MODE_FB0);
vramSetBankA(VRAM_A_LCD);
while(1) { ? old_x = shape_x;
? old_y = shape_y;
? shape_x++;
? if(shape_x + shape_width >
= SCREEN_WIDTH) { ? ? shape_x = 0;
? ? shape_y += shape_height;
? ? if(shape_y + shape_height >
= SCREEN_HEIGHT) { ? ? shape_y = 0;
? ? } ? } ? ? ? draw_shape(old_x, old_y, VRAM_A, RGB15(0, 0, 0));
? draw_shape(shape_x, shape_y, VRAM_A, RGB15(31, 0, 0));
} 如果你运行的话你会看见一个 倾斜 的图形在屏幕上运动.(不是矩形). 垂直扫描中断 (Vertical Blank Interrupt): 出现一个倾斜矩形的原因是屏幕显示的工作方法.硬件设备刷新屏幕的频率是1/60秒.它通过访问每一个象素来实现,一行接一行,复制 帧缓冲 的内容到显示屏. 同时,在main函数中,我们在改变帧缓冲中的内容.所以如果硬件在我们擦除之前绘制图形,它不会被马上擦除.如果我们在硬件绘制之前改变数据,它会绘制一部分新数据和一部分旧数据. 幸好硬件有一种方法告诉我们它绘制完成.这就叫 垂直扫描中断 ('
Vertical Blank Interrupt'
)我们可以注册一个函数让它在这种情况发生时被调用. 中断是一个硬件机制,它中断我们当前正在做的事并调用一些函数做一些其他的事.当中断函数返回时,之前的活动就像没有中断一样继续. 为了防止我们之前看到的画图问题,我们希望在向帧缓冲写入数据时硬件不要刷新屏幕.做这的最好时候就是在垂直扫描中断时. 设置中断: 首先我们要告诉NDS在中断时我们要调用什麽函数: void InitInterruptHandler() { REG_IME = 0;
IRQ_HANDLER = on_irq;
REG_IE = IRQ_VBLANK;
REG_IF = ~0;
DISP_SR = DISP_VBLANK_IRQ;
REG_IME = 1;
} 在这个代码片中我们只是让垂直扫描中断发生并在发生的同时调用'
on_irq'
函数. '
on_irq'
函数会像我们之前在 '
main'
函数中做的一样向帧缓冲中写入数据: 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, RGB15(31, 0, 0));
? // 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;
} } 这个函数主要是向缓冲中写入数据,其余部分是做一些中断操作. 我们也需要告诉NDS我们处理了垂直扫描中断.这是我们以后要调用的 '
swiWaitForVBlank'
需要的,我会在那时解释.代码是这样的: // Tell the DS we handled the VBLANK interrupt ? VBLANK_INTR_WAIT_FLAGS |= IRQ_VBLANK;