如何使用mov ah,0 int 16h实现汇编蛇游戏的连续移动
汇编语言蛇游戏:实现无需按键的持续移动
当前你用汇编写的蛇游戏只能在按键时移动,要改成蛇持续移动、仅检测键盘缓冲区是否有指令的话,核心是把阻塞式的按键读取换成非阻塞检测,再配合主循环自动执行移动逻辑。具体改法如下:
关键修改点
- 改用
int 16h的ah=1h功能:这个功能会检测键盘缓冲区是否有按键,有按键就设置ZF=0并返回按键码,没有则ZF=1,不会阻塞程序运行。 - 重构主循环:每次循环先检测按键(处理方向切换),然后根据当前
dir变量执行对应移动,调用延迟函数后再进入下一轮循环。 - 修复代码笔误:原代码中
a:标签里的mov [byte ptr di], 3应该是mov [byte ptr dir], 3,之前写错了操作对象。
修改后的核心循环代码
main_loop: ; 非阻塞检测键盘 mov ah, 1h int 16h jz no_key_press ; 没按键就直接执行移动 ; 有按键就读取并处理 mov ah, 0h int 16h mov [byte ptr saveal], al cmp [byte ptr saveal], 'w' jz set_dir_up cmp [byte ptr saveal], 'a' jz set_dir_left cmp [byte ptr saveal], 's' jz set_dir_down cmp [byte ptr saveal], 'd' jz set_dir_right cmp [byte ptr saveal], 'q' jmp exit set_dir_up: mov [byte ptr dir], 1 jmp move_snake set_dir_down: mov [byte ptr dir], 2 jmp move_snake set_dir_left: mov [byte ptr dir], 3 jmp move_snake set_dir_right: mov [byte ptr dir], 4 jmp move_snake no_key_press: ; 没有按键时,按当前方向移动 move_snake: cmp [byte ptr dir], 1 jz do_up cmp [byte ptr dir], 2 jz do_down cmp [byte ptr dir], 3 jz do_left cmp [byte ptr dir], 4 jz do_right jmp main_loop ; 初始方向没设置时,循环等待按键 do_up: call up jmp delay_and_loop do_down: call down jmp delay_and_loop do_left: call left jmp delay_and_loop do_right: call right jmp delay_and_loop delay_and_loop: call delay jmp main_loop
完整修改后的代码
MODEL small STACK 100h DATASEG ; -------------------------- ; 变量定义 ; -------------------------- saveal db ' ' dir db 0 ; 方向变量:1=上,2=下,3=左,4=右 app dw 0 ; 苹果位置 st_am dw 3 stars dw 0, 0, 0 ; 蛇身各段位置 CODESEG proc black body: mov [es:si], ax add si, 2 cmp si, 25*80*2 jnz body ret endp black proc up mov di, 80*2 cmp si, di jb not_move_up cmp si, [app] jnz move_up call apple move_up: call delete call replace_stars sub si, 80*2 mov ah, 156 mov al, '*' mov [es:si], ax mov [stars], si not_move_up: ret endp up proc down mov di, (24*80*2)-1 cmp si, di jg not_move_down cmp si, [app] jnz move_down call apple move_down: call delete call replace_stars add si, 80*2 mov ah, 156 mov al, '*' mov [es:si], ax mov [stars], si not_move_down: ret endp down proc left mov dx, 0 mov bx, si mov ax, si mov si, 80*2 div si mov si, bx cmp dx,0 jz not_move_left cmp si, [app] jnz move_left call apple move_left: call delete call replace_stars sub si, 2 mov ah, 156 mov al, '*' mov [es:si], ax mov [stars], si not_move_left: ret endp left proc right mov dx, 0 mov bx, si mov ax, si mov si, 80*2 div si mov si, bx cmp dx,158 jz not_move_right cmp si, [app] jnz move_right call apple move_right: call delete call replace_stars add si, 2 mov ah, 156 mov al, '*' mov [es:si], ax mov [stars], si not_move_right: ret endp right proc apple mov ax, 40h mov es, ax mov ax, [es:6ch] and ax, 0000001111111110b mov di,ax mov [app], di mov ax, 0b800h mov es, ax mov al, '@' mov ah, 154 mov [es:di], ax ret endp apple proc delete mov bx, offset stars mov di, [st_am] dec di shl di, 1 mov di, [bx+di] mov ax, 0b800h mov es, ax mov al, ' ' mov ah, 0 mov [es:di], ax ret endp delete proc replace_stars mov bx, [st_am] ; 蛇身长度(初始3) dec bx shl bx, 1 ; 计算最后一段的偏移 replace: mov ax, [stars+bx-2] mov [stars+bx], ax sub bx, 2 jnz replace ret endp replace_stars proc first_3_dots mov bx, offset stars mov si, ((12*80+40)*2)-2 mov al, '*' mov ah, 156 mov [es:si], ax mov [bx], si mov si, (12*80+40)*2 mov al, '*' mov ah, 156 mov [es:si], ax mov [bx+2], si mov si, ((12*80+40)*2)+2 mov al, '*' mov ah, 156 mov [es:si], ax mov [bx+4], si ret endp first_3_dots proc delay mov cx, 0FFFFh delay1: mov ax, 300 delay2: dec ax jnz delay2 loop delay1 ret endp delay proc incS ret endp incS start: mov ax, @data mov ds, ax ; -------------------------- ; 初始化代码 ; -------------------------- mov ax, 0b800h mov es, ax mov si,0 mov al, ' ' mov ah, 0 call black call first_3_dots mov si, ((12*80+40)*2)-2 call apple ; -------------------------- ; 主循环 ; -------------------------- main_loop: ; 非阻塞检测键盘 mov ah, 1h int 16h jz no_key_press ; 无按键则直接移动 ; 有按键就读取并处理 mov ah, 0h int 16h mov [byte ptr saveal], al cmp [byte ptr saveal], 'w' jz set_dir_up cmp [byte ptr saveal], 'a' jz set_dir_left cmp [byte ptr saveal], 's' jz set_dir_down cmp [byte ptr saveal], 'd' jz set_dir_right cmp [byte ptr saveal], 'q' jmp exit set_dir_up: mov [byte ptr dir], 1 jmp move_snake set_dir_down: mov [byte ptr dir], 2 jmp move_snake set_dir_left: mov [byte ptr dir], 3 jmp move_snake set_dir_right: mov [byte ptr dir], 4 jmp move_snake no_key_press: ; 无按键时按当前方向移动 move_snake: cmp [byte ptr dir], 1 jz do_up cmp [byte ptr dir], 2 jz do_down cmp [byte ptr dir], 3 jz do_left cmp [byte ptr dir], 4 jz do_right jmp main_loop ; 初始方向未设置时,循环等待按键 do_up: call up jmp delay_and_loop do_down: call down jmp delay_and_loop do_left: call left jmp delay_and_loop do_right: call right jmp delay_and_loop delay_and_loop: call delay jmp main_loop exit: mov ax, 4c00h int 21h END start
内容的提问来源于stack exchange,提问作者yarden
相关产品推荐
相关产品推荐

