You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 00:54:58