我正在尝试用汇编语言制作炸弹人风格的游戏。在这个游戏中,我有一个由“*”、空格和“b”组成的固定地图。为了移动玩家,我创建了两个字节类型变量,称为player1和player2,它们存储玩家的当前位置(最多250个)。当您输入有效输入时,相应的移动功能将激活并在寄存器 b 中加载所述玩家的位置,根据移动减少它或减少它,并在当前位置留下痕迹(对于 p1 为“.”和 p2 的 ','),由于同样的问题,它也不起作用。
然后调用验证移动,x中我有地图第一位数字的方向,b中是玩家的位置,那么为什么lda b,x不能正常工作呢?这些位置工作得很好,但该语句有时会返回甚至不在文本中的字符的 ascii 代码。最好的部分是,当我手动执行指令(将 b 寄存器添加到 x 方向)并使用调试器检查该内存时,它会显示正确的字符。为什么会发生这种情况? 这是整个代码,相关子程序是“validate_pos”
.area PROG (ABS)
keyboard .equ 0xFF02
screen .equ 0xFF00
b1: .byte 57
b2: .byte 70
b3: .byte 141
b4: .byte 155
b5: .byte 216
m: .byte 19
player1: .byte 96
player2: .byte 80
statep1: .byte 1 ;0-exploted, 1-playing, 2-goal
statep2: .byte 1
turn: .byte 0 ;0-P1, 1-P2
statemap: .byte 0 ;0-no_bombs, 1-w_bombs
.org 0x100
.globl begin
menu: .ascii "\n\n\n\n\n----------------------------------------------"
.ascii "\n- Bomberman -"
.ascii "\n----------------------------------------------"
.ascii "\nModo de juego: player 1- W,A,S,D "
.ascii "\n player 2- I,K,J,L "
.ascii "\n "
.ascii "\To exit the program press 'p' at any"
.ascii "\nmoment. "
.ascii "\nTo show the hidden bombs press 'b' at "
.ascii "\any moment. "
.ascii "\n----------------------------------------------"
.asciz "\n to begin press 'b':"
goal1: .asciz "\n\33[31mplayer 1\33[37m: goal!"
goal2: .asciz "\n\33[34mplayer 2\33[37m: goal!"
playing1: .asciz "\n\33[31mplayer 1\33[37m: playing..."
playing2: .asciz "\n\33[34mplayer 2\33[37m: playing..."
exploted1: .asciz "\n\33[31mplayer 1\33[37m: exploted"
exploted2: .asciz "\n\33[34mplayer 2\33[37m: exploted!"
t1: .asciz "\nturn \33[31mplayer 1\33[37m: (W,A,S,D...b...p): "
t2: .asciz "\nturn \33[34mplayer 2\33[37m: (I,J,K,L...b...p): "
map : .ascii "\n******************M*****"
.ascii "\n* *"
.ascii "\n* b b *"
.ascii "\n* *"
.ascii "\n* *"
.ascii "\n* b *"
.ascii "\n* b *"
.ascii "\n* *"
.ascii "\n* b *"
.asciz "\n************************"
wins1: .asciz "\nwins PLAYER 1!"
wins2: .asciz "\nwins PLAYER 2!"
begin:
ldu 0xf000
lbsr read_menu
program:
clra
clrb
lbsr siguiente_turn
lbsr validate_input
lbsr pmap
finish: clra
sta 0xFF01
read_menu:
ldx #menu
lbsr loop
lda keyboard
cmpa #'b
lbeq begin_program
cmpa #'p
lbeq finish1
bra begin
begin_program:
clra
lda #'0
sta statemap
lbsr pmap
clra
rts
finish1:
clra
sta 0xFF01
exit1:
clra
bra program
pmap:
clra
clrb
ldx #map
lda statemap
cmpa #'0
beq no_bombs
cmpa #'1
beq w_bombs
w_bombs:
lda ,x+
beq exit1
cmpb player1
beq is_1
cmpb player2
beq is_2
sta screen
incb
bra w_bombs
no_bombs:
lda ,x+
beq exit1
cmpb player1
beq is_1
cmpb player2
beq is_2
cmpa #'b
beq is_b
sta screen
incb
bra no_bombs
is_1:
lda #'1
sta screen
incb
clra
lda statemap
cmpa #'0
beq no_bombs
cmpa #'1
beq w_bombs
is_2:
lda #'2
sta screen
incb
clra
lda statemap
cmpa #'0
beq no_bombs
cmpa #'1
beq w_bombs
is_b:
lda #'
sta screen
incb
bra no_bombs
siguiente_turn:
clra
lda turn
cmpa #'0
lbeq p1
cmpa #'1
lbeq p2
p1:
lbsr imprimir_state
ldx #t1
lbsr loop
rts
p2:
lbsr imprimir_state
ldx #t2
lbsr loop
rts
imprimir_state:
lbsr pstate1
lbsr pstate2
rts
pstate1:
clrb
ldb statep1
cmpb #0
lbeq e1
cmpb #1
lbeq j1
cmpb #2
lbeq m1
clrb
pstate2:
ldb statep2
cmpb #0
lbeq e2
cmpb #1
lbeq j2
cmpb #2
lbeq m2
clrb
e1: ldx #exploted1
lbsr loop
rts
e2: ldx #exploted2
lbsr loop
rts
j1: ldx #playing1
lbsr loop
rts
j2: ldx #playing2
lbsr loop
rts
m1: ldx #goal1
lbsr loop
rts
m2: ldx #goal2
lbsr loop
rts
validate_input:
lda keyboard
ldb turn
ldx #map
cmpb #'0
lbeq validate_input_p1
cmpb #'1
lbeq validate_input_p2
clrb
validate_input_p1:
cmpa #'w
lbeq move_up_p1
cmpa #'a
lbeq move_left_p1
cmpa #'s
lbeq move_down_p1
cmpa #'d
lbeq move_right_p1
cmpa #'b
lbeq changeb
cmpa #'p
lbeq finish2
lbsr program
rts
validate_input_p2:
cmpa #'i
lbeq move_up_p2
cmpa #'j
lbeq move_left_p2
cmpa #'k
lbeq move_down_p2
cmpa #'l
lbeq move_right_p2
cmpa #'b
lbeq changeb
cmpa #'p
lbeq finish2
lbsr program
rts
changeb:
clra
lda statemap
cmpa #'0
lbeq change1
cmpa #'1
lbeq change0
change1:
clra
ldb #'1
stb statemap
lbsr pmap
clrb
rts
change0:
clra
ldb #'0
stb statemap
lbsr pmap
clrb
rts
exit_validate1:
clra
lda #'1
sta turn
clra
rts
exit_validate2:
clra
lda #'0
sta turn
clra
rts
finish2:
clra
sta 0xFF01
move_up_p1:
ldb player1
lda #'.
sta b,x
ldb player1
subb #25
lbsr validate_pos
stb player1
lbsr exit_validate1
rts
move_left_p1:
lda #'.
sta b,x
ldb player1
decb
lbsr validate_pos
stb player1
lbsr exit_validate1
rts
move_right_p1:
lda #'.
sta b,x
ldb player1
incb
lbsr validate_pos
stb player1
jsr exit_validate1
rts
move_down_p1:
lda #'.
sta b,x
ldb player1
addb #25
lbsr validate_pos
stb player1
lbsr exit_validate1
rts
move_right_p2:
lda #',
sta b,x
ldb player2
incb
lbsr validate_pos
stb player2
lbsr exit_validate2
rts
move_left_p2:
lda #',
sta b,x
ldb player2
decb
lbsr validate_pos
stb player2
lbsr exit_validate2
rts
move_up_p2:
lda #',
sta b,x
ldb player2
subb #25
lbsr validate_pos
stb player2
lbsr exit_validate2
rts
move_down_p2:
lda #',
sta b,x
ldb player2
addb #25
lbsr validate_pos
stb player2
lbsr exit_validate2
rts
validate_pos:
lda b,x
cmpb #225
lbhs program
cmpb #25
lbls program
cmpa #'*
lbeq program
cmpa #'1
lbeq program
cmpa #'2
lbeq program
cmpa #'M
lbeq state_goal
cmpa #'b
lbeq state_exploted
rts
state_exploted:
ldb #0
lda turn
cmpa #1
lbeq goal_2
stb statep1
lbra exit_validate1
exploted_2:
sta statep2
lbra exit_validate2
state_goal:
ldb #2
lda turn
cmpa #1
lbeq goal_2
stb statep1
lbra exit_validate1
goal_2:
sta statep2
lbra exit_validate2
loop:
lda ,x+
lbeq exit
sta screen
bra loop
exit:
rts
.org 0xFFFE ;RESET
.word begin
显然,当与 8 位累加器(例如
A,Y
或 B,X
)一起使用时,称为“累加器从寄存器的偏移量”的寻址模式将 8 位累加器视为带符号的。 (遗憾的是,这并没有立即出现在我找到的文档中。)
但是,如果您的索引无论如何都在
B
中,只需清除 A
即可使 D
成为 B
中值的无符号 16 位扩展,因此通过清除 A
,您可以使用 D,X
寻址而不是 B,X
。
从
leay D,Y
开始,然后是 lda ,Y
是有意义的,以确保它正在计算正确的地址,然后在确定后应该能够返回到 lda D,Y
。
对于未来的读者,当您遇到任何类型的复杂寻址模式(包括 x86 和其他处理器中的许多问题)时,请尝试计算 地址写入寄存器,然后使用简单的间接从该地址加载/存储。这可以说明复杂寻址模式与您的期望有何不同/哪里不同。在某些处理器上,有一个
lea
指令,它将采用相同的寻址模式,但将计算出的地址生成到寄存器中,这可以使调试更简单,因为您可以直接观察计算出的地址。 (对于其他一些,您必须替换添加和移位,如果这些有效,那么您对复杂的寻址模式有一些误解,如果这些不起作用,那么您可能会得到一些错误的输入作为索引或基指针。)
事实上,这种分而治之的方法也可以用于调试汇编或 C、C#、Java 等中的其他事物:将复杂的事物/语句/操作分解为通过变量或寄存器连接的多个更简单的语句,以阐明调试器中的中间计算。