如何忽略多次按键?

时间:2019-03-30 11:29:46

标签: assembly dos x86-16 tasm

我在汇编中制作了一个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

1 个答案:

答案 0 :(得分: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

但是,这不是一个好方法。根据{{​​3}}:

  

如果您要使用BIOS功能从游戏的键盘中进行读取,   清除缓冲区的最快方法是使其尾部等于   头:读取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指向缓冲区的尾部。如果两者   指针相等,缓冲区为空。)

如果有兴趣,请阅读更多Stephen Kitt's answer on Retrocomputing