首页 > 代码库 > NESASM教程——第十天——主角DMA

NESASM教程——第十天——主角DMA

【主角DMA?】

是的,主角DMA。你还记得我们怎么利用$2003和$2004寄存器写入SPR-RAM(OAM)的吗?实际上真实系统中这种做法是不可靠的。我们应该利用内存作为OAM,然后向一个寄存器写入值,所有内容都自动拷贝到真实OAM。如果你不懂,那我们做一遍就懂了。

【什么内存?】

就像我上面说的,我们需要使用“变量”内存来复制一份OAM。本教程使用$0300用于复制的OAM。注意NES上只有64个主角(占用64*4B=256B,0x100)。所以基本上你自己定义的变量尽可能放在$0000-$0200内。从$0300-$0400的布局应该同OAM完全一致。

另外记住,$300是一个内存地址,而不像内存变量。我们必须在每次读写后将地址加一,而不是持续读写同一个地址的内容。

我们用偶数在百位用于我们OAM拷贝。我会告诉你为什么的。


好了,希望你理解了上述理论,下面看汇编代码。


;;--- 代码开始 ---;;
	.inesmap 0  ;
	.inesprg 1  ; 
	.ineschr 1  ; 
	.inesmir 1  ; 

	.bank 1
	.org $FFFA
	.dw 0
	.dw Start
	.dw 0

	.bank 0  ; 代码段
	.org $0000 ; 

	; 普通变量在这里定义

	.org $0300 ; OAM镜像从这里开始

Sprite1_Y:     .db  0   ; 1号主角的纵坐标
Sprite1_T:     .db  0   ; 1号主角的瓷砖编号
Sprite1_S:     .db  0   ; 1号主角的特殊待遇
Sprite1_X:     .db  0   ; 1号主角的横坐标
Sprite2_Y:     .db  0   ; 2号主角的纵坐标
Sprite2_T:     .db  0   ; 不用说了吧?
Sprite2_S:     .db  0   ; 
Sprite2_X:     .db  0   ; 
; 依此类推去吧。。。

	.org $8000 ; 代码开始

Start: 
	; 
	; 先卖个关子
	; 后面会给出详细代码

infin:
	jmp infin  ; 死循环
;;--- 代码结束 ---;;

如果你不懂,email我告诉我你到底哪不懂。

【DMA寄存器】

DMA寄存器地址是$4014,我们需要写3进去。为什么是3?因为我们内存OAM在$300处。你向$4014写入n,那么就从$0n00处拷贝内容到真正OAM。也就是说,如果从$0400开始那就写4,如果从$0500开始那就写5,明白?

下面看怎么搬运我们的OAM到真实OAM中:

	lda #$3  ; 也可以写成 #3, 因为显然3的十进制和十六进制表示是相同的
	sta $4014 ; 一旦写入, 拷贝就开始

就是这样,比我们老办法可靠多了,而且更简单!

【怎样按照上述方法修改第九天的代码?】

我们需要做几件事。

首先,拷贝 .org $0300和后面那堆东西到我们旧的变量区。我们再也不用那些变量了,因为我们的主角X,Y都使用OAM拷贝。

其次,使用查找替换功能吧所有X_Pos和Y_Pos改为Sprite1_X和Sprite1_Y。

再次,找到写$2003的代码块,替换为:

	lda #$3  ; 
	sta $4014 ;

就是它了!我们用这种方法也节省了几个字节代码空间。

【今日回顾】

希望你喜欢主角DMA,我已经将它尽可能口语化了。我们今天学到了更好的写OAM数据的方法,明天还要看下更好的方法来捕获VBlank。接下来是。。。。。中断!

希望你的代码没有bug。

NESASM教程——第十天——主角DMA