此代碼用于蛇游戲。proc detect _ direction 呼叫 mov_snake proc,它可以做很多事情,并以呼叫 detect_direction 結束。當我在 DosBox(最新版本)中運行代碼時,蛇的位置被更新了兩次并且代碼停止運行(不是通過 endgame proc,c:tasm/bin/ 行再次出現)
如果您有任何想法,請發表評論。
ideal
model small
stack 100h
dataseg
message db 'game over, to play again press y$'
object_location dw 2
clock equ es:6ch
longer db 0
snake dw 2000 dup (0)
codeseg
proc cleanscreen ; cleans the screen
push cx
push bx
mov cx,4000d
mov bx,0
clean: mov [byte ptr es:bx],0
inc bx
loop clean
pop bx
pop cx
ret
endp cleanscreen
proc startgame
mov ax, 0b800h
mov es, ax
call cleanscreen
mov dl, '*'
mov dh,200
mov di,2000d;snake head first position
mov [es:di], dx
mov [es:di-2], dx
mov [es:di-4], dx
mov [word ptr snake],1996d
mov [word ptr snake 2], 1998d
mov [word ptr snake 4], 2000d
mov cx, 3
call random
mov ah,0
int 16h
call detect_direction
ret
endp startgame
proc delay
push cx
push bx
mov cx, 0ffffh ;delay loop
lopa:
mov bx, 20d
lopb:
dec bx
cmp bx, 0
jnz lopb
loop lopa
pop bx
pop cx
ret
endp delay
proc buffer
mov ah,1
int 16h
jz nothingchanged
mov ah,0
int 16h
nothingchanged:
ret
endp buffer
proc detect_direction
cmp al, 'w'
je up
cmp al, 'a'
je left
cmp al, 'd'
je right
cmp al, 's'
je down
cmp al, 'q'
je gameover
up: sub di,160
jmp move_on
down: add di,160d
jmp move_on
right: add di,2
jmp move_on
left: sub di,2
jmp move_on
gameover:call endgame
move_on:
call move_func
ret
endp detect_direction
proc updatesnake
push bx
push si
mov bx, offset snake
cmp [longer],1 ;if longer is one , increase snake length
je increa
mov si, [bx]
mov [word ptr es:si], 0 ; delete tail
sub bx,2
increa:
mov [es:di], dx
add bx,2 ; prevent tail value from being deleted when being increased
updateloop:
mov si, [bx 2]
mov [bx], si
inc bx
loop updateloop
mov [bx], di
cmp [longer],1
jne reg
inc cx ; this prevent inseting a junk value when increasing snake's length
reg:
pop si
pop bx
ret
endp updatesnake
proc move_func
call updatesnake
call delay
call boundries
call check_if_eaten
call buffer
call detect_direction
ret
endp move_func
proc boundries
push ax
push dx
cmp di,160d
ja keep_playing
cmp di,3840d
jb keep_playing
mov ax,di
mov dl,160d
div dl
cmp ah,0
jne keep_playing
mov ax,di
inc ax
div dl
cmp ah,0
jne keep_playing
call endgame
keep_playing:
pop dx
pop ax
ret
endp boundries
proc random
push ax
push bx
push cx
push si
push dx
mov ax, [clock] ; read timer counter
mov cx, [word cs:bx] ; read one byte from memory
xor si, cx ; xor memory and counter
and si, 2000d ; leaves value between 0-2000
sal si,1 ; mult value
mov [object_location], si ; save in memory for future checking
mov dl,'@'
mov dh, 150
mov [es:si],dx
pop dx
pop si
pop cx
pop bx
pop ax
ret
endp random
proc check_if_eaten
mov [longer],0
cmp di, [object_location]
jne skip_increase
call random
mov [longer], 1
skip_increase:
ret
endp check_if_eaten
proc endgame
push dx
call cleanscreen
mov dx, offset message
mov ah,9h
int 21h
mov ah,0
int 16
cmp al, 'y'
jne line
call startgame
line:
pop dx
ret
endp endgame
start:
mov ax, @data
mov ds, ax
call startgame
exit:
mov ax, 4c00h
int 21h
end start
uj5u.com熱心網友回復:
與您之前的問題相比,您的代碼有了很大改進,但由于仍然存在許多錯誤,我懷疑是否有人能完全回答您的“為什么???”
我將專注于您的程式之一,邊界,如果蛇與頂行或底行或左列或右列相撞,您希望在哪里結束游戲
第一個測驗 ,cmp di,160 ja keep_playing意味著只要蛇沒有碰到螢屏的頂行,你就可以繼續玩。其他邊界甚至都沒有經過驗證!
如果像 in 那樣反轉條件跳轉,您需要什么cmp di, 160 jb stop_playing。
在第四個測驗中(對于右側邊框),您將奇數(因為inc ax)除以 160。這將始終產生非零余數。所以,不是一個有用的測驗。要測驗左右邊界,您可以只進行一次劃分并將余數解釋兩次:0 是左側碰撞,158 是右側碰撞。
proc boundries
push ax
push dx
cmp di, 160 ; Top row
jb stop_playing
cmp di, 3840 ; Bottom row
ja stop_playing
mov ax, di
mov dl, 160
div dl
cmp ah, 0 ; Left column
je stop_playing
cmp ah, 158 ; Right column
jne keep_playing ; All 4 tests passed!
stop_playing:
call endgame
keep_playing:
pop dx
pop ax
ret
endp boundries
作為獎勵的隨機程序,在那里你讀時鐘的AX暫存器,但突然你不使用AX,并開始使用SI,而不是!
如果您臨時將段暫存器設定為 BIOS 資料頁的 0040h,則該
mov ax, [clock] ; read timer counter指令將讀取由您的等式定義的真實時鐘:clock equ es:6chESpush es mov ax, 0040h mov es, ax mov ax, [clock] ; read timer counter pop esAND像這樣的指令and si, 2000 ; leaves value between 0-2000不會以您期望的方式限制值!限制在該特定范圍內需要除以 2001 并使用余數。
這是我的新隨機程式的版本:
proc random
push ax ; \
push bx ; | (i)
push dx ; /
push ds ; (ii)
xor dx, dx ; The word-sized `DIV` division requires this
mov ds, dx
mov ax, [046Ch] ; (iii) read timer counter
pop ds
xor ax, [cs:bx] ; XOR counter and a (randomly chosen?) WORD from memory
mov bx, 2000 ; (iiii)
div bx ; DX:AX / BX -> Remainder in DX is [0,1999]
shl dx, 1 ; Convert into text video offset
mov bx, dx ; Move to an address register
mov [object_location], bx
mov word [es:bx], 9640h ; Character @ with attribute 96h (150)
pop dx
pop bx
pop ax
ret
endp random
(i) 使用的暫存器更少 == 需要保留的暫存器更少!
(ii) UsingDS給出更短的代碼。
(iii) 停止使用具有段覆寫的“令人困惑”的時鐘設備es:。
(iii) 為了留在螢屏上,object_location應該限制??為 {0, 2, 4, 6, ... , 3998]。
我最近發布了 Q/A The quintessential Snake Game。如何追蹤蛇?. 也許你可以從中得到一兩個想法......
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/365369.html
