【问题标题】:How do I ignore multiple keypresses?如何忽略多个按键?
【发布时间】:2019-03-30 11:29:46
【问题描述】:

我在汇编中制作了一个 DOS 程序,当你按下空格键时会进行方形跳转。

如果您在方块跳跃时按住空格键,即使您停止按空格键,它也会继续跳跃。我怎样才能让它只关注广场在地上时被按下的空间?

代码(用 TASM 编译):

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




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 WaitForSpace
    EnterSpace:  ;Wait until user presses Space
    mov ah,0
    int 16h
    cmp al,32
    jne EnterSpace
    ret
    endp WaitForSpace


    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 Sqaure
    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

    
    loopSquareJump:
    Call WaitForSpace
    Call PlayerJump
    jmp loopSquareJump

    

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

【问题讨论】:

标签: assembly dos x86-16 tasm


【解决方案1】:

您的问题来自键盘缓冲区中剩余的 Space 按键,当您不希望它们时,导致它们稍后被处理。一种解决方案是在等待按下 Space 之前清除键盘缓冲区,如下所示:

proc ClearKeyboardBuffer
ClearKeyboardBuffer_loop:
mov ah,01h
int 16h                     ; is there a key pressed
jz ClearKeyboardBuffer_ret  ; if not, return
mov ah,00h
int 16h                     ; "handle" the key
jmp ClearKeyboardBuffer_loop

ClearKeyboardBuffer_ret:
ret
endp ClearKeyboardBuffer

然后像这样简单地修改你的循环:

loopSquareJump:
Call ClearKeyboardBuffer
Call WaitForSpace
Call PlayerJump
jmp loopSquareJump

但是,这不是一个很好的方法。根据Stephen Kitt's answer on Retrocomputing

如果您在游戏中使用 BIOS 功能从键盘读取数据, 清除缓冲区的最快方法是使其尾部等于其 head:读取 0x0041A 处的值并将其写入 0x0041C(使用 中断禁用):

proc clearkeyboardbuffer
; AX is clobbered
    push ds
    mov ax, 0040h
    mov ds, ax
    mov ax, [001Ah]
    mov [001Ch], ax
    pop ds
    ret
endp clearkeyboardbuffer

(BIOS 键盘缓冲区是一个从 0x0041E 开始的循环列表,并且 0x0041A 指向缓冲区的头部,0x0041C 指向缓冲区的尾部。如果两者 指针相等,缓冲区为空。)

如果您有兴趣,请阅读更多on the original answer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多