Как игнорировать множественные нажатия клавиш? - PullRequest
1 голос
/ 30 марта 2019

Я создал 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 Ответ

1 голос
/ 30 марта 2019

Ваша проблема возникает из-за нажатий клавиш Пробел , которые остаются в буфере клавиатуры, когда вы этого не хотите, что приводит к их последующей обработке.Одним из решений является очистка буфера клавиатуры непосредственно перед ожиданием нажатия Пробел , например:

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

Это, однако, не лучший способ сделать это.Согласно ответу Стивена Китта о ретрокомпьютере :

Если вы используете функции BIOS для чтения с клавиатуры в своей игре, самый быстрый способ очистить буфер - это сделать егоtail равен его голове: прочитайте значение в 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 указывает на буферhead и 0x0041C в хвосте. Если оба указателя равны, буфер пуст.)

Если вам интересно, прочитайте оригинального ответа .

...