8088汇编蛇游戏碰撞检测实现及代码优化技术问询
8088汇编蛇游戏:蛇身碰撞检测实现与代码优化建议
原代码片段
org 0x100 jmp start checkBorder: push bp mov bp,sp push ax push bx push cx push dx mov ax,[bp+6] mov bx,[bp+4] cmp ax,17 jz over cmp ax,54 jz over cmp bx,2 jz over cmp bx,23 jz over jmp nover over: mov ax,0xb800 mov es,ax mov di,1974 mov si,gover mov cx,[glen] mov ah,0x70 cld next: lodsb stosw loop next mov ah, 0 ; service 0 – get keystroke int 0x16 ; call BIOS keyboard service nover: pop dx pop cx pop bx pop ax pop bp ret 4 start: call clrscr mov bx,20 mov dx,10 mov [direction],0 mov word[snake_location], l3: mov ax,0 push ax call printScore mov ax,3 push ax call printLives call printRec mov ax, bx push ax ; push x position mov ax, dx push ax ; push y position push word [length] ; push message length push word[direction] call printSnake ; call the printstr subroutine call delay call delay call delay call clrscr ; clear the screen push bx push dx call checkBorder mov ah,0x01 int 0x16 jz skip mov ah, 0 int 0x16 cmp al,0x77 jz u cmp al,0x73 jz d cmp al,0x61 jz l cmp al,0x64 jz r cmp al,0x1B jz ex skip: cmp al,0x71 jnz l3 u: sub dx,1 mov [direction],2 mov [snake_location] jmp l3 d: add dx,1 mov [direction],3 jmp l3 l: sub bx,1 mov [direction],1 jmp l3 r: add bx,1 mov [direction],0 jmp l3 ex: mov ax, 0x4c00 int 0x21 length: dw 4 score: db 'Score: ' live: db 'Lives: ' slen: dw 7 gover: db 'Game Over!' glen: dw 10 direction: db 0 snake_location:dw 0
需求说明
我需要给这个8088汇编编写的蛇游戏实现碰撞检测功能:蛇默认长度为4,形态为****0(其中0是蛇头),碰撞检测仅针对蛇头。之前尝试硬编码实现,不仅效率低下,还因蛇头位置计算错误导致检测结果异常,现寻求高效的蛇碰撞检测实现方法及代码优化建议。
高效蛇身碰撞检测实现方案
1. 重构蛇身坐标存储
原代码中snake_location仅存储单个值,无法记录完整蛇身位置。需改为坐标数组,每个元素存储蛇身一节的(X,Y)坐标(用16位字存储:高8位存Y,低8位存X,节省内存且便于对比)。
修改数据段定义:
; 蛇身坐标数组,每个元素为 (Y << 8) | X,初始长度4 snake_positions dw 4 dup(0) length: dw 4 ; 当前蛇长度
初始化时填充初始蛇身坐标(蛇头在(20,10),身体依次向左延伸):
start: call clrscr mov bx,20 ; 蛇头X mov dx,10 ; 蛇头Y mov [direction],0 ; 初始化蛇身数组 mov ax, dx shl ax, 8 or ax, bx mov [snake_positions], ax ; 蛇头 mov ax, dx shl ax, 8 or ax, bx-1 mov [snake_positions+2], ax ; 第一节身体 mov ax, dx shl ax, 8 or ax, bx-2 mov [snake_positions+4], ax ; 第二节身体 mov ax, dx shl ax, 8 or ax, bx-3 mov [snake_positions+6], ax ; 第三节身体
2. 实现蛇身碰撞检测子程序
编写checkSelfCollision子程序,传入蛇头坐标(X,Y)和蛇长度,遍历蛇身数组(跳过蛇头自身)对比坐标,若存在匹配则触发碰撞。
; 子程序:检测蛇头是否碰撞蛇身 ; 参数:[bp+6] = 蛇头X, [bp+4] = 蛇头Y ; 返回:若碰撞则跳转到over(与边界检测共用处理逻辑) checkSelfCollision: push bp mov bp, sp push ax push bx push cx push si ; 把蛇头坐标打包成16位字:(Y <<8) | X mov ax, [bp+4] shl ax, 8 or ax, [bp+6] mov bx, ax ; bx = 蛇头打包坐标 mov cx, [length] dec cx ; 遍历次数:蛇长度-1(跳过蛇头) mov si, 2 ; 从第一节身体开始(数组偏移2字节) check_loop: cmp ax, [snake_positions+si] jz over ; 坐标匹配,触发碰撞 add si, 2 ; 下一节身体 loop check_loop jmp no_self_collision over: ; 复用边界检测的Game Over逻辑 mov ax,0xb800 mov es,ax mov di,1974 mov si,gover mov cx,[glen] mov ah,0x70 cld next_gover: lodsb stosw loop next_gover mov ah, 0 int 0x16 no_self_collision: pop si pop cx pop bx pop ax pop bp ret 4
3. 主循环中调用碰撞检测
在边界检测后调用自碰撞检测:
l3: ; ... 原有打印、延迟逻辑 ... call clrscr push bx push dx call checkBorder ; 先检测边界碰撞 push bx push dx call checkSelfCollision ; 再检测蛇身碰撞 ; ... 键盘输入逻辑 ...
代码优化建议
1. 修复蛇头位置更新逻辑
原代码中mov word[snake_location],未完成,需改为移动时更新蛇身数组:每次蛇移动,将数组中所有元素向前移位(覆盖最旧的身体节),最后将新蛇头坐标存入数组末尾。
示例代码(以向右移动为例):
r: add bx,1 mov [direction],0 ; 更新蛇身数组:向前移位 mov si, 0 mov cx, [length] dec cx shift_loop: mov ax, [snake_positions+si+2] mov [snake_positions+si], ax add si,2 loop shift_loop ; 存入新蛇头坐标 mov ax, dx shl ax,8 or ax,bx mov [snake_positions+2*([length]-1)], ax jmp l3
2. 减少全屏清屏操作
原代码每次循环调用clrscr清全屏,效率极低。改为仅清除蛇身旧位置:遍历蛇身数组,将对应显存位置设为空格+属性。
; 子程序:清除蛇身旧位置 clearSnake: push bp mov bp, sp push ax push bx push cx push di push si mov ax, 0xb800 mov es, ax mov cx, [length] mov si, 0 clear_loop: mov ax, [snake_positions+si] mov bl, al ; bl = X shr ax, 8 ; al = Y ; 计算显存偏移:Y*160 + X*2 mov di, ax shl di, 6 ; Y*64 shl ax, 4 ; Y*16 add di, ax ; Y*80 shl di, 1 ; Y*160 shl bl, 1 ; X*2 add di, bx mov word [es:di], 0x0720 ; 空格+灰色属性 add si,2 loop clear_loop pop si pop di pop cx pop bx pop ax pop bp ret
3. 优化键盘输入处理
原代码键盘检测逻辑冗余,合并为一次按键读取:
mov ah,0x01 int 0x16 jz skip mov ah,0 int 0x16 ; 直接处理按键,无需额外判断 cmp al,0x77 jz u cmp al,0x73 jz d cmp al,0x61 jz l cmp al,0x64 jz r cmp al,0x1B jz ex cmp al,0x71 jz l3 ; 处理Q键直接回到循环 skip: jmp l3
4. 合并碰撞检测子程序
将边界检测和自碰撞检测合并为一个子程序,减少栈操作开销:
; 合并后的碰撞检测子程序 checkCollision: push bp mov bp, sp push ax push bx push cx push dx push si mov ax, [bp+6] ; X mov bx, [bp+4] ; Y ; 边界检测 cmp ax,17 jz collision_trigger cmp ax,54 jz collision_trigger cmp bx,2 jz collision_trigger cmp bx,23 jz collision_trigger ; 自碰撞检测 mov dx, bx shl dx,8 or dx, ax ; dx = 蛇头打包坐标 mov cx, [length] dec cx mov si,2 self_check_loop: cmp dx, [snake_positions+si] jz collision_trigger add si,2 loop self_check_loop jmp no_collision collision_trigger: ; Game Over逻辑 mov ax,0xb800 mov es,ax mov di,1974 mov si,gover mov cx,[glen] mov ah,0x70 cld next_gover: lodsb stosw loop next_gover mov ah,0 int 0x16 no_collision: pop si pop dx pop cx pop bx pop ax pop bp ret 4
内容的提问来源于stack exchange,提问作者Adeel Umar
相关产品推荐
相关产品推荐

