純匯編實(shí)現(xiàn)打飛機(jī)小游戲的示例代碼
匯編暑假作業(yè)要求做一個(gè)大項(xiàng)目,題目可以自擬。我思來(lái)想去,還是覺(jué)得做一個(gè)小游戲比較有意思。最后選擇了做打飛機(jī)游戲。
這里采用的是VGA模式320x200 4色。
打飛機(jī)游戲的游戲邏輯比較簡(jiǎn)單。首先,飛機(jī)可以移動(dòng),也可以發(fā)射炮彈;其次,會(huì)有敵人不斷地從前方飛過(guò)來(lái),如果撞上飛機(jī)游戲結(jié)束;最后,飛機(jī)發(fā)射的炮彈可以擊落敵人。
既然是打飛機(jī),我們就必須首先造一臺(tái)飛機(jī),代碼如下:
Comment/***********
function: draw a horizontal line
parameters: horizontal position
vertical position
length of the line
color
return: void
description:draw some points horizontally.
color '0001h' represents drawing a line while
color '0000h' which is black means erase the line.
**********/
drawALine PROC NEAR
PUSH BP
MOV BP, SP
PUSH AX
PUSH CX
PUSH DX
PUSH SI
MOV AH, 0Ch
MOV CX, [BP+4]
MOV DX, [BP+6]
MOV SI, [BP+8]
MOV AL, Byte Ptr [BP+10]
drawALineLoop:
INT 10h
INC CX
DEC SI
JNZ drawALineLoop
POP SI
POP DX
POP CX
POP AX
MOV SP, BP
POP BP
RET
drawALine ENDP
Comment/***********
function: draw a plane or a missile
parameters: horizontal position
vertical position
color
type (plane or missile or enemy)
map length
return: void
description:call "drawALine" function repeatedly.
**********/
drawCraft PROC NEAR
PUSH BP
MOV BP, SP
SUB SP, 8
PUSH AX
PUSH DX
PUSH SI
PUSH DI
MOV DI, 0
MOV AX, [BP+12]
MOV [BP-8],AX
MOV SI, [BP+10]
MOV AX, [BP+8]
MOV [BP-6], AX
MOV AX, [BP+6]
MOV [BP-4], AX
MOV AX, [BP+4]
MOV [BP-2], AX
drawCraftLoop:
PUSH Word Ptr [BP-6]
MOV DX, Word Ptr [SI]
PUSH DX
PUSH Word Ptr [BP-4]
MOV AX, [BP-2]
SHR DX, 1
SUB AX, DX
PUSH AX
CALL drawALine
ADD SP, 8
ADD Word Ptr [BP-4], 1
ADD SI, 2
INC DI
CMP DI, [BP-8]
JB drawCraftLoop
POP DI
POP SI
POP DX
POP AX
MOV SP, BP
POP BP
RET
drawCraft ENDP
PLANEMAP DW 1,1,3,3,3,3,3,3,7,14,16,14,6,2,2,6,6
N1 EQU ($-PLANEMAP)/2
這里之所以做的這么復(fù)雜是出于代碼重用的考慮,相同的代碼只要輸入不同的參數(shù),就能制造出不一樣的東西。這是抽象的思想。
drawCraft 根據(jù)輸入的不同的數(shù)組,可以繪制出不同的東西,比如飛機(jī),導(dǎo)彈,敵人。而不必畫飛機(jī)一個(gè)函數(shù),畫導(dǎo)彈又是另一個(gè)函數(shù)了。
drawCraft主要是一條線一條線地畫,就像3D打印一樣。不過(guò)這里是2D的版本。
光畫了飛機(jī)不行,我們還需要讓它動(dòng)起來(lái)。動(dòng)起來(lái)的方法很簡(jiǎn)單,只需要用黑色覆蓋原圖,然后再在新的位置上建立一個(gè)新的即可:
Comment/*********** function: move a plane parameters: original horizontal position original vertical position direction(left-a up-w right-d bottom-s) return: rectify POS_X, POS_Y description:destory the original and then create a new one **********/ movePlane PROC NEAR PUSH BP MOV BP, SP PUSH AX PUSH BX PUSH CX MOV AX,N1 PUSH AX MOV AX, Offset PLANEMAP PUSH AX MOV AX, 0000h PUSH AX ;black color MOV AX, [BP+6] PUSH AX MOV AX, [BP+4] PUSH AX CALL drawCraft ADD SP, 10 MOV CX, CS:MoveItems MOV AH, Byte Ptr [BP+9] MOV BX, Offset MoveCase movePlaneLoop1: CMP AH, Byte Ptr CS:[BX] JE ToCase ADD BX, 4 LOOP movePlaneLoop1 ToCase: JMP Word Ptr CS: [BX+2] MoveItems DW 4 MoveCase DW 75,Case1,72,Case2,77,Case3,80,Case4, 0, Default Default: JMP EndSwitch Case1: SUB POS_X, 5 JMP EndSwitch Case2: SUB POS_Y, 5 JMP EndSwitch Case3: ADD POS_X, 5 JMP EndSwitch Case4: ADD POS_Y, 5 EndSwitch: ;draw a new plan in new position MOV CX, N1 PUSH CX MOV CX, Offset PLANEMAP PUSH CX MOV CX, 0001h PUSH CX PUSH POS_Y PUSH POS_X CALL drawCraft ADD SP, 10 EndMovePlane: POP CX POP BX POP AX MOV SP, BP POP BP RET movePlane ENDP
有了飛機(jī),還要發(fā)射炮彈啊。我所期望的飛機(jī),應(yīng)該是可以多連發(fā)的,而且是無(wú)限發(fā)!那玩起來(lái)才爽。于是我設(shè)計(jì)了這樣的數(shù)組。
MISSILE DW 512 DUP('$$')
MISSILESNUM DW 0
這是什么意思呢?我們一步一步來(lái)看。首先這是存儲(chǔ)每次發(fā)射炮彈,炮彈所在的位置(橫坐標(biāo)和縱坐標(biāo))。
每當(dāng)玩家按下空格鍵,就向數(shù)組里添加位置信息。這是為了方便后面讓導(dǎo)彈一起上升。
在沒(méi)有鍵盤輸入的時(shí)候。我們想讓導(dǎo)彈自己上升。為了做到這點(diǎn),我們需要遍歷這個(gè)MISSILE數(shù)組,每找到一個(gè)位置信息,就讀出來(lái),刪除它,然后更新數(shù)組位置信息(只需要更新縱坐標(biāo)),然后再在新的位置上畫一個(gè)導(dǎo)彈就行了。
以下是具體實(shí)現(xiàn)代碼
Comment/***********
function:
parameters: horizontal position
vertical position
return: rectify 'MISSILE' and 'MISSILESNUM'
description:When press the space key, this program will put
the position into the 'MISSILE' array.
Then call 'drawMissile' to display it.
**********/
fireMissile PROC NEAR
PUSH BP
MOV BP, SP
PUSH CX
PUSH DX
PUSH SI
PUSH DI
MOV CX, [BP+4]
MOV DX, [BP+6]
SUB DX, 5
MOV SI, Offset MISSILE
fireMissileLoop:
CMP Word Ptr [SI], '$$'
JZ fireMissileIf
ADD SI, 4
JMP fireMissileLoop
fireMissileIf:
MOV [SI], CX
MOV [SI+2], DX
MOV DI, N2
PUSH DI
MOV DI, Offset MISSILEMAP
PUSH DI
MOV DI, 0003h
PUSH DI
PUSH DX
PUSH CX
CALL drawCraft
ADD SP, 10
INC MISSILESNUM
POP DI
POP SI
POP DX
POP CX
MOV SP, BP
POP BP
RET
fireMissile ENDP
Comment/***********
function: rise all the existing missiles
parameters: void
return: rectify MISSILE and MISSILESNUM
description:When there is no input event, this program will
rise all the existing missiles which stored in
the 'MISSILE' array unless there is no missile.
**********/
riseMissile PROC NEAR
PUSH BP
MOV BP, SP
PUSH SI
PUSH CX
PUSH DX
MOV SI, Offset MISSILE
MOV CX, 256
riseMissileLoop:
CMP Word Ptr [SI], '$$'
JZ riseMissileIf
MOV DX, N2
PUSH DX
MOV DX, Offset MISSILEMAP
PUSH DX
MOV DX, 0000h
PUSH DX
MOV DX, Word Ptr [SI+2]
PUSH DX
MOV DX, Word Ptr [SI]
PUSH DX
CALL drawCraft
ADD SP, 10
SUB Word Ptr [SI+2],2
JLE riseMissileIf2
MOV DX, N2
PUSH DX
MOV DX, Offset MISSILEMAP
PUSH DX
MOV DX, 0003h
PUSH DX
MOV DX, Word Ptr [SI+2]
PUSH DX
MOV DX, Word Ptr [SI]
PUSH DX
CALL drawCraft
ADD SP, 10
JMP riseMissileIf
riseMissileIf2:
MOV Word Ptr [SI], '$$'
MOV Word Ptr [SI+2], '$$'
DEC MISSILESNUM
riseMissileIf:
ADD SI, 4
LOOP riseMissileLoop
POP DX
POP CX
POP SI
POP AX
MOV SP, BP
POP BP
RET
riseMissile ENDP
以上做的都是具體的例程。做到這里,回過(guò)頭看一下我們主程序的實(shí)現(xiàn)。
整個(gè)游戲是依靠主程序調(diào)用一個(gè)個(gè)例程來(lái)運(yùn)作的。
Start: MOV AX, _DATA MOV DS, AX CLI MOV AX, _STACK MOV SS, AX MOV SP, Offset TOS STI CALL init MOV AH, 00h MOV AL, 04h INT 10h MOV CX, N1 PUSH CX MOV SI, Offset PLANEMAP PUSH SI MOV CX, 0001h PUSH CX PUSH POS_Y PUSH POS_X CALL drawCraft ADD SP, 10 Again: MOV AH,01h INT 16h Next: JZ Process MOV AH, 00h INT 16h CMP AL, 27 JZ EndMain CMP AL, ' ' JZ Shoot PUSH AX PUSH POS_Y PUSH POS_X CALL movePlane ADD SP, 6 JMP Again Shoot: PUSH POS_Y PUSH POS_X CALL fireMissile ADD SP, 4 JMP Again Process: CALL showScoreByDemical CALL checkCollision INC TIMER MOV DX, DIFFICULTY CMP TIMER, DX JBE Loc1 CALL dropEnemy MOV DX, MAX SUB DX, TIMER MOV TIMER, 0 CMP ENEMYNUM, DX JA Loc1 CALL generateEnemy Loc1: CMP MISSILESNUM, 0 JZ Again CALL riseMissile JMP Again
解釋一下:Again開(kāi)始是主程序。先判斷有沒(méi)有鍵盤輸入,如果有,判斷是不是ESC(退出),然后再判斷是不是空格(攻擊),如果都不是,就執(zhí)行 movePlane,在movePlane中實(shí)現(xiàn)具體的移動(dòng)過(guò)程。
如果沒(méi)有鍵盤輸入,就執(zhí)行Process后面的代碼。這段代碼稍后解釋。
有了飛機(jī),有了導(dǎo)彈,還需要有敵人啊。敵人的制作過(guò)程和導(dǎo)彈類似。也建立一個(gè)ENEMY數(shù)組來(lái)存儲(chǔ)每一個(gè)敵人的位置信息,并在沒(méi)有鍵盤輸入的時(shí)候進(jìn)行更新。只要注意導(dǎo)彈是上升,敵人是下降。
之后是檢測(cè)碰撞,我是用二重循環(huán)遍歷了MISSILE 和 ENEMY兩個(gè)數(shù)組。一開(kāi)始我寫的是嚴(yán)格相等才算碰撞,后來(lái)玩的時(shí)候發(fā)現(xiàn)這條件太苛刻了,于是改成了在一定范圍內(nèi)就行。
Comment/*********** function: check if there is any collision parameters: void return: void description:check vertical pos and horizontal pos, if both are equel, delete one of them. **********/ checkCollision PROC NEAR PUSH BP MOV BP, SP PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI MOV SI, Offset ENEMY MOV DI, Offset MISSILE MOV AX, 0 MOV BX, 0 checkCollisionLoop1: CMP Word Ptr [SI], '$$' JZ checkCollisionIf MOV CX, POS_X SUB CX, Word Ptr[SI] JGE checkCollisionLoc1 NEG CX checkCollisionLoc1: CMP CX, 8 JA checkCollisionLoop2 MOV DX, POS_Y SUB DX, Word Ptr[SI+2] JGE checkCollisionLoc2 NEG DX checkCollisionLoc2: CMP DX, 1 JA checkCollisionLoop2 ;game over PUTS GAMEOVER CALL delay MOV AX, 4C00h INT 21h checkCollisionLoop2: CMP Word Ptr [DI], '$$' JZ checkCollisionIf3 MOV CX, Word Ptr[SI] SUB CX, Word Ptr[DI] JGE checkCollisionLoc3 NEG CX checkCollisionLoc3: CMP CX, 5 JA checkCollisionIf3 MOV DX, Word Ptr[SI+2] SUB DX, Word Ptr[DI+2] JGE checkCollisionLoc4 NEG DX checkCollisionLoc4: CMP DX, 5 JA checkCollisionIf3 JMP deleteEnemy checkCollisionIf3: INC BX ADD DI, 4 CMP BX, 256 JB checkCollisionLoop2 checkCollisionIf: ADD SI, 4 MOV BX, 0 INC AX CMP AX, 256 MOV DI, Offset MISSILE JB checkCollisionLoop1 JMP checkCollisionEnd deleteEnemy: MOV DX, N3 PUSH DX MOV DX, Offset ENEMYMAP PUSH DX MOV DX, 0000h PUSH DX MOV DX, Word Ptr [SI+2] PUSH DX MOV DX, Word Ptr [SI] PUSH DX CALL drawCraft ADD SP, 10 MOV Word Ptr [SI], '$$' MOV Word Ptr [SI+2], '$$' DEC ENEMYNUM ADD SCORE, 2 JMP checkCollisionIf3 checkCollisionEnd: POP DI POP SI POP DX POP CX POP BX POP AX MOV SP, BP POP BP RET checkCollision ENDP
到這里,主要的例程都已經(jīng)結(jié)束了。
再回過(guò)頭看一下主程序的代碼。
Again: MOV AH,01h INT 16h Next: JZ Process MOV AH, 00h INT 16h CMP AL, 27 JZ EndMain CMP AL, ' ' JZ Shoot PUSH AX PUSH POS_Y PUSH POS_X CALL movePlane ADD SP, 6 JMP Again Shoot: PUSH POS_Y PUSH POS_X CALL fireMissile ADD SP, 4 JMP Again Process: CALL showScoreByDemical CALL checkCollision INC TIMER MOV DX, DIFFICULTY CMP TIMER, DX JBE Loc1 CALL dropEnemy MOV DX, MAX SUB DX, TIMER MOV TIMER, 0 CMP ENEMYNUM, DX JA Loc1 CALL generateEnemy Loc1: CMP MISSILESNUM, 0 JZ Again CALL riseMissile JMP Again
從Process開(kāi)始,首先調(diào)用的是顯示分?jǐn)?shù)的例程(比較容易我沒(méi)放上來(lái)),然后先檢測(cè)是否碰撞。這里設(shè)置了一個(gè)DIFFICULTY變量,是適應(yīng)不同難度(DIFFICULTY)。TIMER是用來(lái)定時(shí)的。每次都+1,加到DIFFICLUTY的值才執(zhí)行敵人下降的例程。
難度大的話,敵人移動(dòng)速度快,只需要把DIFFICULTY的值設(shè)小一點(diǎn),就可以更快的使敵人下降;反之亦然。
附上一些效果圖。





附上源碼:https://github.com/zhongyuchen/hitplanegame
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
os_object_release Crash 排查記錄分析
這篇文章主要為大家介紹了os_object_release Crash 排查記錄分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
匯編語(yǔ)言指令集學(xué)習(xí)CMPXCHG比較并交換操作指令詳解
這篇文章主要為大家介紹了匯編語(yǔ)言指令集學(xué)習(xí)CMPXCHG比較并交換操作的指令詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11
X86匯編調(diào)試環(huán)境搭建的過(guò)程
本次使用vscode搭建的,需要的插件有X86 and X86_64 Assembly(也可以使用masm插件),還有一個(gè)hexdump for VSCode。 安裝NASM,并添加到環(huán)境變量,下面看下X86匯編調(diào)試環(huán)境搭建的過(guò)程吧2021-11-11
匯編語(yǔ)言XOR指令:對(duì)兩個(gè)操作數(shù)進(jìn)行邏輯(按位)異或操作(推薦)
匯編語(yǔ)言(assembly language)是一種用于電子計(jì)算機(jī)、微處理器、微控制器或其他可編程器件的低級(jí)語(yǔ)言,亦稱為符號(hào)語(yǔ)言。這篇文章主要介紹了匯編語(yǔ)言XOR指令:對(duì)兩個(gè)操作數(shù)進(jìn)行邏輯(按位)異或操作,需要的朋友可以參考下2020-01-01
用匯編語(yǔ)言實(shí)現(xiàn)從1加到100的方法(1+2+...+100)
這篇文章主要介紹了用匯編語(yǔ)言實(shí)現(xiàn)從1加到100的方法(1+2+...+100),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
匯編語(yǔ)言 and和or邏輯運(yùn)算指令的實(shí)現(xiàn)
這篇文章主要介紹了匯編語(yǔ)言 and,or邏輯運(yùn)算指令的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01

