I'm making the snake game and ran into a problem.
For now, I used int 21h, so it only moved when I pressed a key. Now I want it to move continuously so it isn't waiting for me to press a key but just checks if there's something in the buffer. To do that I'm using ah 0h and int 16h however, I don't know how to do that it'll always move. I think I need to add a loop somewhere that checks what is in dir and based on that it goes to where it's supposed to go but I just don't know what the loop is supposed to look like (I also think I should use delay if I'm not wrong).
I think the relevant parts are:
mov ah, 0h
int 16h
mov [byte ptr saveal], al
cmp [byte ptr saveal], 'w'
jz w
cmp [byte ptr saveal], 'a'
jz a
cmp [byte ptr saveal], 's'
jz s
cmp [byte ptr saveal], 'd'
jz d
cmp [byte ptr saveal], 'q'
jmp exit
w:
mov [byte ptr dir], 1
call up
jmp wasd
s:
mov [byte ptr dir], 2
call down
jmp wasd
a:
mov [byte ptr di], 3
call left
jmp wasd
d:
mov [byte ptr dir], 4
call right
jmp wasd
The whole code is:
MODEL small
STACK 100h
DATASEG
; --------------------------
; Your variables here
; --------------------------
saveal db ' '
dir db 0 ;not used
app dw 0 ;place of the apple
st_am dw 3
stars dw 0, 0, 0 ;places of the *
CODESEG
proc black
body:
mov [es:si], ax
add si, 2
cmp si, 25*80*2
jnz body
ret
endp black
proc up
mov di, 80*2
cmp si, di
jb not_move_up
cmp si, [app]
jnz move_up
call apple
move_up:
call delete
call replace_stars
sub si, 80*2
mov ah, 156
mov al, '*'
mov [es:si], ax
mov [stars], si
not_move_up:
ret
endp up
proc down
mov di, (24*80*2)-1
cmp si, di
jg not_move_down
cmp si, [app]
jnz move_down
call apple
move_down:
call delete
call replace_stars
add si, 80*2
mov ah, 156
mov al, '*'
mov [es:si], ax
mov [stars], si
not_move_down:
ret
endp down
proc left
mov dx, 0
mov bx, si
mov ax, si
mov si, 80*2
div si
mov si, bx
cmp dx,0
jz not_move_left
cmp si, [app]
jnz move_left
call apple
move_left:
call delete
call replace_stars
sub si, 2
mov ah, 156
mov al, '*'
mov [es:si], ax
mov [stars], si
not_move_left:
ret
endp left
proc right
mov dx, 0
mov bx, si
mov ax, si
mov si, 80*2
div si
mov si, bx
cmp dx,158
jz not_move_right
cmp si, [app]
jnz move_right
call apple
move_right:
call delete
call replace_stars
add si, 2
mov ah, 156
mov al, '*'
mov [es:si], ax
mov [stars], si
not_move_right:
ret
endp right
proc apple
mov ax, 40h
mov es, ax
mov ax, [es:6ch]
and ax, 0000001111111110b
mov di,ax
mov [app], di
mov ax, 0b800h
mov es, ax
mov al, '@'
mov ah, 154
mov [es:di], ax
ret
endp apple
proc delete
mov bx, offset stars
mov di, [st_am]
dec di
shl di, 1
mov di, [bx+di]
mov ax, 0b800h
mov es, ax
mov al, ' '
mov ah, 0
mov [es:di], ax
ret
endp delete
proc replace_stars
mov bx, [st_am] ; The amount of stars (3 or more)
dec bx
shl bx, 1 ; Offset to the last star
replace:
mov ax, [stars+bx-2]
mov [stars+bx], ax
sub bx, 2
jnz replace
ret
endp replace_stars
proc first_3_dots
mov bx, offset stars
mov si, ((12*80+40)*2)-2
mov al, '*'
mov ah, 156
mov [es:si], ax
mov [bx], si
mov si, (12*80+40)*2
mov al, '*'
mov ah, 156
mov [es:si], ax
mov [bx+2], si
mov si, ((12*80+40)*2)+2
mov al, '*'
mov ah, 156
mov [es:si], ax
mov [bx+4], si
ret
endp first_3_dots
proc delay
mov cx, 0FFFFh
delay1:
mov ax, 300
delay2:
dec ax
jnz delay2
loop delay1
ret
endp delay
proc incS
ret
endp incS
start:
mov ax, @data
mov ds, ax
; --------------------------
; Your code here
; --------------------------
mov ax, 0b800h
mov es, ax
mov si,0
mov al, ' '
mov ah, 0
call black
call first_3_dots
mov si, ((12*80+40)*2)-2
call apple
wasd:
mov ah, 0h
int 16h
mov [byte ptr saveal], al
cmp [byte ptr saveal], 'w'
jz w
cmp [byte ptr saveal], 'a'
jz a
cmp [byte ptr saveal], 's'
jz s
cmp [byte ptr saveal], 'd'
jz d
cmp [byte ptr saveal], 'q'
jmp exit
w:
mov [byte ptr dir], 1
call up
jmp wasd
s:
mov [byte ptr dir], 2
call down
jmp wasd
a:
mov [byte ptr di], 3
call left
jmp wasd
d:
mov [byte ptr dir], 4
call right
jmp wasd
exit:
mov ax, 4c00h
int 21h
END start
You don't need an additional loop. The wasd main loop is fine. But instead of waiting (blocking) for the user to press a key, simply check (non-blocking) if the user has already pressed a key. If a key is indeed available then store its info in the dir variable and use it normally. And if no key is available right now, then use whatever is in the dir variable as if it had been pressed right now.
Instead of using values {1,2,3,4}, I would use the ASCII codes themselves, so {'w','a','s','d'}.
Seeing how you have initialized the snake, I also suggest you initialize the dir variable to point to the left (
dir db 'a').Correct. With the above changes everything will become much too fast. You need to add a suitable delay to the main loop. Waiting for one tick on the BIOS timer is already a good solution:
If it still doesn't work, then try next code that is similar to your very own apple procedure:
And in case TASM is a really stupid assembler, then also change:
[EDIT]
Your recent comment contains a typo that could explain why it still takes a long time to respond. The first time that you wrote
mov ah, 0hint 16h, it needs to bemov ah, 01hint 16h.As I was curious whether it would actually work, I have translated your complete program for the FASM assembler. I believe FASM is superior to TASM, so if you're not forced to use TASM, you could consider becoming a FASM user. FASM is a modern assembler that is being actively maintainded by its author, supported by a community, and that comes with an easy to use IDE with no need for any external linker.
I'm happy to report that it all works! One change that I needed to make though, is slowing the program down even more, by turning the simple delay loop into a pair of nested loops that wait for about 3/18 sec. For your convenience, I have refrained from most other changes...