I made a DOS program in assembly that makes a square jump when you press space.
If you hold space while the square is jumping, it continues to jump even after you stop pressing space. How can I make it only pay attention to space being pressed while the square is on the ground?
Code (compiled with 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
Your problem comes from the Space keypresses remaining in the keyboard buffer when you don't want them to, causing them to be handled later. One solution is to clear the keyboard buffer just before you wait for Space to be pressed, like so:
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
Then simply amend your loop like so:
loopSquareJump:
Call ClearKeyboardBuffer
Call WaitForSpace
Call PlayerJump
jmp loopSquareJump
This is, however, not a great way to do it. According to Stephen Kitt's answer on Retrocomputing:
If you’re using BIOS functions to read from the keyboard in your game, the quickest way to clear the buffer is to make its tail equal to its head: read the value at 0x0041A and write it to 0x0041C (with interrupts disabled):
proc clearkeyboardbuffer ; AX is clobbered push ds mov ax, 0040h mov ds, ax mov ax, [001Ah] mov [001Ch], ax pop ds ret endp clearkeyboardbuffer
(The BIOS keyboard buffer is a circular list starting at 0x0041E, and 0x0041A points at the buffer’s head, and 0x0041C at its tail. If both pointers are equal, the buffer is empty.)
Read more on the original answer, if you're interested.