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

DOS汇编程序优化:如何让方块仅在地面时响应空格跳跃

解决方法:仅在方块处于地面时响应空格键

要解决这个问题,我们需要跟踪方块的状态(是否在地面),并避免在跳跃过程中响应按键输入。原代码的问题在于使用了阻塞式的按键等待,且没有检查方块位置就触发跳跃,导致缓冲区的按键会被重复处理。以下是具体修改步骤:

1. 添加地面状态变量

首先在数据段定义一个变量来标记方块是否处于地面:

DATASEG
X dw 0
Y dw 0
SquareX dw 20
SquareY dw 193
SquareSize dw 0
color db 1 ; default color is blue
FloorY dw 194
FloorX dw 0
IsOnGround db 1 ; 1 = 在地面,0 = 在空中

2. 替换阻塞式按键等待为非阻塞检查

原代码的WaitForSpace过程会阻塞程序直到按下空格,这会导致跳跃过程中按住空格时,缓冲区积累多个按键事件。我们需要在主循环中使用非阻塞的按键检查(int 16h的1号功能),只在方块在地面时响应空格。

3. 修改主循环逻辑

移除原来的loopSquareJump阻塞循环,替换为非阻塞的主循环,加入状态判断:

start:
mov ax, @data
mov ds, ax
Call GraphicsScreen
Call PaintFloor
Call PaintPlayerSquare
mov [IsOnGround], 1 ; 初始状态:方块在地面

loopMain:
; 非阻塞检查是否有按键输入
mov ah, 1
int 16h
jz SkipKeyCheck ; 没有按键,跳过处理

; 读取按键
mov ah, 0
int 16h
cmp al, 32
jne SkipKeyCheck ; 不是空格键,跳过

; 检查是否在地面
cmp [IsOnGround], 1
jne SkipKeyCheck ; 不在地面,忽略按键

; 触发跳跃:标记为空中,执行跳跃过程
mov [IsOnGround], 0
Call PlayerJump
mov [IsOnGround], 1 ; 跳跃结束,回到地面

SkipKeyCheck:
; 加入短延迟避免循环过快(可根据需要调整时长)
push cx
push dx
push ax
MOV CX, 0H
MOV DX, 1000H ; 更短的延迟,比如1ms左右
MOV AH, 86H
INT 15H
pop ax
pop dx
pop cx

jmp loopMain

4. 移除无用的WaitForSpace过程

因为我们不再使用阻塞式等待,所以可以删除WaitForSpace过程,减少冗余代码。

修改后的完整代码

IDEAL
MODEL small
STACK 100h
DATASEG
X dw 0
Y dw 0
SquareX dw 20
SquareY dw 193
SquareSize dw 0
color db 1 ; default color is blue
FloorY dw 194
FloorX dw 0
IsOnGround db 1 ; 1 = 在地面,0 = 在空中
CODESEG
proc HalfSecondDelay
push cx ;Backup
push dx
push ax
MOV CX, 1H
MOV DX, 3H
MOV AH, 86H
INT 15H
pop ax ;Backup
pop dx
pop cx
ret
endp HalfSecondDelay

proc PlayerJump ;Makes The Square Jump
push cx
mov cx, 10
MoveUp:
Call HalfSecondDelay
call RemovePlayerSquare
sub [SquareY],4 ; Move Up
call PaintPlayerSquare
loop MoveUp
mov cx, 10
MoveDown:
Call HalfSecondDelay
call RemovePlayerSquare
add [SquareY], 4 ; Move Down
Call PaintPlayerSquare
loop MoveDown
pop cx
ret
endp PlayerJump

proc PaintFloorLine
push bp
mov bp,sp
push cx
mov cx, 320
LoopPaintFloorLine:
call PaintPixel
inc [X]
loop LoopPaintFloorLine
pop cx
pop bp
ret
endp PaintFloorLine

proc PaintFloor ;Paints The Floor
push bp
mov bp,sp
push cx
mov [x], 0
mov [y], 194
mov [color], 0Ah
mov cx, 7
loopPaintFloor:
call PaintFloorLine
inc [Y]
mov [x], 0
loop loopPaintFloor
pop cx
pop bp
ret
endp PaintFloor

proc PaintPixel
push bp
mov bp,sp
push ax
push bx
push cx
push dx
mov cx,[X]
mov dx,[Y]
mov al,[color]
mov ah,0ch
int 10h
pop dx
pop cx
pop bx
pop ax
pop bp
ret
endp PaintPixel

proc PaintLine
push bp
mov bp,sp
push cx
mov cx, [SquareSize]
loopPaintLine:
call PaintPixel
inc [X]
loop loopPaintLine
mov cx, [SquareSize] ; Return The X
sub [X], cx
pop cx
pop bp
ret
endp PaintLine

proc PaintSquare ;Paints A Square
push bp
mov bp,sp
push cx
mov cx, [SquareSize]
loopPrinSquare:
call PaintLine
dec [Y]
loop loopPrinSquare
mov cx, [SquareSize] ; Return The Y
add [Y], cx
pop cx
pop bp
ret
endp PaintSquare

proc PaintPlayerSquare ; Paints The Player Square
push bp
mov bp,sp
mov ax, [SquareX]
mov [x], ax
mov ax, [SquareY]
mov [Y], ax
mov [SquareSize], 25
mov [color], 1 ; blue color
call PaintSquare ;
pop bp
ret
endp PaintPlayerSquare

proc RemovePlayerSquare ;Removes The Player Square
push bp
mov bp,sp
push ax
push bx
push cx
push dx
mov ax, [SquareX]
mov [x], ax
mov ax, [SquareY]
mov [Y], ax
mov [color], 0 ; black color
call PaintSquare ;
pop dx
pop cx
pop bx
pop ax
pop bp
ret
endp RemovePlayerSquare

proc GraphicsScreen
mov al, 13h
mov ah, 0
int 10h
ret
endp GraphicsScreen

start:
mov ax, @data
mov ds, ax
Call GraphicsScreen
Call PaintFloor
Call PaintPlayerSquare
mov [IsOnGround], 1 ; 初始状态标记为在地面

loopMain:
; 非阻塞检查按键缓冲区
mov ah, 1
int 16h
jz SkipKeyCheck

; 读取按键
mov ah, 0
int 16h
cmp al, 32
jne SkipKeyCheck

; 验证是否在地面
cmp [IsOnGround], 1
jne SkipKeyCheck

; 执行跳跃
mov [IsOnGround], 0
Call PlayerJump
mov [IsOnGround], 1

SkipKeyCheck:
; 短延迟,防止循环占用过多CPU
push cx
push dx
push ax
MOV CX, 0H
MOV DX, 500H
MOV AH, 86H
INT 15H
pop ax
pop dx
pop cx

jmp loopMain

exit:
mov ax, 4c00h
int 21h
END start

关键说明

  • 状态跟踪:IsOnGround变量确保只有当方块回到地面后,才会响应下一次空格键按压。
  • 非阻塞按键检查:使用int 16h的1号功能(ah=1)检查按键,不会阻塞主循环,程序可以同时处理跳跃动画和输入。
  • 清空按键缓冲区:当读取按键(ah=0)时,会移除缓冲区中的按键事件,避免跳跃过程中积累的空格被重复处理。

内容的提问来源于stack exchange,提问作者yoav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:51:19