8086彙編初學之貪吃蛇
阿新 • • 發佈:2019-02-16
前言
一直沒想過要去學習彙編,覺得需要用匯編的場合無非三種:
1. 與硬體結合很緊密高階語言做不到
2. 時空效率要求甚高演算法層面已不能優化到
3. 逆向破解等只能用某些途徑看其彙編指令
其餘情況下,用匯編無異於有炮不用偏用鳥槍。
本來準備等自己需求以上場合時再去學,但因為學校舉辦的彙編比賽,計算機學院都要參加,也算是一個由頭,於是開始了我的第一個彙編程式。
執行效果
程式碼只有400行,功能很簡略,實現了最基本的遊戲流程,看執行效果
概述
本質上用匯編去寫一個貪吃蛇和用其他語言去實現沒什麼區別,不過是換一種方式表達,當然,是一種更加麻煩的方式。
以前用c++實現過 C++貪吃蛇和C++俄羅斯方塊。所以對於這類小遊戲,該怎麼切是知道了,剩下的事就是找傢伙了。
要實現這類簡易的小遊戲,需要二點:
1. 定時器
2. 非阻塞接收按鍵
有上面兩者便可以搞定一切。
但在彙編下,為這兩點,耽擱了不少時間。不對,是三點,還有生成隨機數(原本很容易的事都變得麻煩了起來)。
定時器
事實上,查了很多資料,但還是不知道怎樣去實現定時器,所以這個需求只能變通的解決。
用空迴圈來控制時間。
非阻塞接受按鍵
getInput:
mov al, 0
mov ah, 1
int 16h;檢視鍵盤緩衝區是否有資料
cmp ah, 1;ah為0表示有,否則沒有
je getInputEnd
mov al, 0
mov ah, 0
int 16h;從緩衝區讀取資料
;此時值已經在ax裡了,做你想做的
getInputEnd:
ret
隨機數
mov ax, 0h;間隔定時器
out 43h, al;通過埠43h
in al, 40h;
in al, 40h;
in al, 40h;訪問3次,保證隨機性
;如果對範圍並不需要精確,可以直接與運算來獲得,
;否則,用div取餘
mov bl, 18
div bl
mov al, ah
mov ah, 0;此時ax的值就是0~18的
程式碼
assume cs:code,ds:data,ss:stack
data segment
sfood dw 0
sdct dw 0
sbody dw 400 dup(0)
data ends
stack segment
dw 20 dup(0)
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, 20
mov ax, 0b800h
mov es, ax
mov si, 4 ;儲存資料段偏移量
mov cx, 4;初始蛇長度
mov ax, 0A04h
s:;初始化蛇
mov ds:[si], ax
add si, 2
inc al
loop s
mov ax, 4d00h;向右
mov ds:[2], ax;初始化方向
call clearBg;清屏
call outBg;輸出地圖邊框
call outBody;輸出蛇
call creatFood;輸出食物
mov cx, 30
Game:
push cx
call updateBody
mov cx, 0Fh
aaaa1:
push cx
mov cx, 0FFFh
bbbb:
push cx
call getInput
pop cx
loop bbbb
pop cx
loop aaaa1
;jmp GameEnd
jmp Game
GameEnd: ;退出
;call outBody
mov ax, 4c00h
int 21h
updateBody:
mov ax, ds:[2]
mov di, si
sub di, 2
cmp ax, 4800h
je shang
mov ax, ds:[2]
cmp ax, 5000h
je xia
mov ax, ds:[2]
cmp ax, 4b00h
je zuo
mov ax, ds:[2]
cmp ax, 4d00h
je you
shang:
mov ax, ds:[di]
sub ah, 1
jmp checkBody
xia:
mov ax, ds:[di]
add ah, 1
jmp checkBody
zuo:
mov ax, ds:[di]
sub al, 1
jmp checkBody
you:
mov ax, ds:[di]
add al, 1
;mov ds:[di], ax
jmp checkBody
checkBody:
push ax
;判斷蛇頭是否碰到地圖邊界
cmp ah, 0
je GameEnd
cmp ah, 20
je GameEnd
cmp al, 0
je GameEnd
cmp al, 20
je GameEnd
;判斷蛇頭是否碰到蛇身
mov cx, si
sub cx, 6
mov di, 4
s0:
mov bx, ds:[di]
cmp bx, ax
je GameEnd
add di, 2
sub cx, 1
loop s0
pop ax
;判斷蛇頭是否吃到食物
mov bx, ds:[0]
cmp ax, bx
je addBody
jmp updateStart
updateStart:
mov cx, si
sub cx, 6
mov di, 4
push ax
mov dl, ' ';字元
mov dh, 0;顏色
mov bx, ds:[di]
call outStr
s5:
mov dx, ds:[di+2]
mov ds:[di], dx
add di, 2
sub cx, 1
loop s5
mov dl, ' ';字元
mov dh, 71h;顏色
mov bx, ds:[di]
call outStr
pop ax
mov ds:[di], ax
mov dl, ' ';字元
mov dh, 44h;顏色
mov bx, ds:[di]
call outStr
updateEnd:
ret
addBody:
mov dl, ' ';字元
mov dh, 71h;顏色
mov bx, ds:[di]
call outStr
mov ax, ds:[0]
mov ds:[si], ax
mov dl, ' ';字元
mov dh, 44h;顏色
mov bx, ds:[si]
call outStr
add si, 2
call creatFood
jmp updateEnd
getInput:;獲取鍵盤輸入
mov al, 0
mov ah, 1
int 16h;接收鍵盤
cmp ah, 1
je getInputEnd
mov al, 0
mov ah, 0
int 16h;
mov cx, ax;鍵盤值在ax
;判斷輸入
cmp cx, 4800h
je gshang
cmp cx, 5000h
je gxia
cmp cx, 4b00h
je gzuo
cmp cx, 4d00h
je gyou
jmp getInputEnd
gshang:
mov ax, ds:[2]
cmp ax, 5000h
je getInputEnd
jmp fx
gxia:
mov ax, ds:[2]
cmp ax, 4800h
je getInputEnd
jmp fx
gzuo:
mov ax, ds:[2]
cmp ax, 4d00h
je getInputEnd
jmp fx
gyou:
mov ax, ds:[2]
cmp ax, 4b00h
je getInputEnd
jmp fx
fx:;更改方向標誌
mov ds:[2], cx
getInputEnd:
ret;結束
outBody:
mov cx, si
sub cx, 6
mov di, 4
s1:
mov ax, ds:[di]
mov dl, ' ';字元
mov dh, 71h;顏色
mov bl, al;列
mov bh, ah;行
call outStr
add di, 2
sub cx, 1
loop s1
mov dl, ' '
mov dh, 44h
mov ax, ds:[di]
mov bl, al
mov bh, ah
call outStr
ret
outBg:
mov dl, ' ';字元
mov dh, 71h;顏色
mov bl, 0;列
mov bh, 0;行
mov cx, 20
row:
push cx
push bx
call outStr;上邊界
pop bx
push bx
add bh, 20
call outStr;下邊界
pop bx
inc bl;列加1
pop cx
loop row
mov bl, 0;
mov bh, 0;
mov cx, 21
col:
push cx
push bx
call outStr;左邊界
pop bx
push bx
add bl, 20
call outStr;右邊界
pop bx
inc bh;行加1
pop cx
loop col
ret
outStr: ;在指定位置輸出字元
mov al, 80
mul bh;行乘以80
mov bh, 0
add bl, bl;
add ax, bx;加上列即為偏移量
push si
mov si, ax
add si, si
mov es:[si], dl
mov es:[si+1], dh
mov es:[si+2], dl
mov es:[si+3], dh
pop si
ret
creatFood:;生成食物
call getFoodPosition
mov dl, ' '
mov dh, 071h
mov bx, ds:[0]
call outStr
ret
getFoodPosition:;獲取食物位置
f1:
call getRand
mov ds:[0], al
call getRand
mov ds:[1], al
mov cx, si
sub cx, 4
mov di, 4
s11:
mov ax, ds:[di]
cmp ax, ds:[0]
je f1
add di, 2
sub cx, 1
loop s11
ret
getRand:;獲取隨機數 範圍1~19
mov ax, 0h;間隔定時器
out 43h, al;通過埠43h
in al, 40h;
in al, 40h;
in al, 40h;訪問3次,保證隨機性
mov bl, 18
div bl
mov al, ah
mov ah, 0
inc al
ret
clearBg: ;清屏
mov ax, 3h
int 10h
ret
code ends
end start