純匯編實(shí)現(xiàn)打飛機(jī)小游戲的示例代碼
匯編暑假作業(yè)要求做一個大項(xiàng)目,題目可以自擬。我思來想去,還是覺得做一個小游戲比較有意思。最后選擇了做打飛機(jī)游戲。
這里采用的是VGA模式320x200 4色。
打飛機(jī)游戲的游戲邏輯比較簡單。首先,飛機(jī)可以移動,也可以發(fā)射炮彈;其次,會有敵人不斷地從前方飛過來,如果撞上飛機(jī)游戲結(jié)束;最后,飛機(jī)發(fā)射的炮彈可以擊落敵人。
既然是打飛機(jī),我們就必須首先造一臺飛機(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ī)一個函數(shù),畫導(dǎo)彈又是另一個函數(shù)了。
drawCraft主要是一條線一條線地畫,就像3D打印一樣。不過這里是2D的版本。
光畫了飛機(jī)不行,我們還需要讓它動起來。動起來的方法很簡單,只需要用黑色覆蓋原圖,然后再在新的位置上建立一個新的即可:
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ā)的,而且是無限發(fā)!那玩起來才爽。于是我設(shè)計了這樣的數(shù)組。
MISSILE DW 512 DUP('$$') MISSILESNUM DW 0
這是什么意思呢?我們一步一步來看。首先這是存儲每次發(fā)射炮彈,炮彈所在的位置(橫坐標(biāo)和縱坐標(biāo))。
每當(dāng)玩家按下空格鍵,就向數(shù)組里添加位置信息。這是為了方便后面讓導(dǎo)彈一起上升。
在沒有鍵盤輸入的時候。我們想讓導(dǎo)彈自己上升。為了做到這點(diǎn),我們需要遍歷這個MISSILE數(shù)組,每找到一個位置信息,就讀出來,刪除它,然后更新數(shù)組位置信息(只需要更新縱坐標(biāo)),然后再在新的位置上畫一個導(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
以上做的都是具體的例程。做到這里,回過頭看一下我們主程序的實(shí)現(xiàn)。
整個游戲是依靠主程序調(diào)用一個個例程來運(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開始是主程序。先判斷有沒有鍵盤輸入,如果有,判斷是不是ESC(退出),然后再判斷是不是空格(攻擊),如果都不是,就執(zhí)行 movePlane,在movePlane中實(shí)現(xiàn)具體的移動過程。
如果沒有鍵盤輸入,就執(zhí)行Process后面的代碼。這段代碼稍后解釋。
有了飛機(jī),有了導(dǎo)彈,還需要有敵人啊。敵人的制作過程和導(dǎo)彈類似。也建立一個ENEMY數(shù)組來存儲每一個敵人的位置信息,并在沒有鍵盤輸入的時候進(jìn)行更新。只要注意導(dǎo)彈是上升,敵人是下降。
之后是檢測碰撞,我是用二重循環(huán)遍歷了MISSILE 和 ENEMY兩個數(shù)組。一開始我寫的是嚴(yán)格相等才算碰撞,后來玩的時候發(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é)束了。
再回過頭看一下主程序的代碼。
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開始,首先調(diào)用的是顯示分?jǐn)?shù)的例程(比較容易我沒放上來),然后先檢測是否碰撞。這里設(shè)置了一個DIFFICULTY變量,是適應(yīng)不同難度(DIFFICULTY)。TIMER是用來定時的。每次都+1,加到DIFFICLUTY的值才執(zhí)行敵人下降的例程。
難度大的話,敵人移動速度快,只需要把DIFFICULTY的值設(shè)小一點(diǎn),就可以更快的使敵人下降;反之亦然。
附上一些效果圖。
附上源碼:https://github.com/zhongyuchen/hitplanegame
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
os_object_release Crash 排查記錄分析
這篇文章主要為大家介紹了os_object_release Crash 排查記錄分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11匯編語言指令集學(xué)習(xí)CMPXCHG比較并交換操作指令詳解
這篇文章主要為大家介紹了匯編語言指令集學(xué)習(xí)CMPXCHG比較并交換操作的指令詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11匯編語言XOR指令:對兩個操作數(shù)進(jìn)行邏輯(按位)異或操作(推薦)
匯編語言(assembly language)是一種用于電子計算機(jī)、微處理器、微控制器或其他可編程器件的低級語言,亦稱為符號語言。這篇文章主要介紹了匯編語言XOR指令:對兩個操作數(shù)進(jìn)行邏輯(按位)異或操作,需要的朋友可以參考下2020-01-01用匯編語言實(shí)現(xiàn)從1加到100的方法(1+2+...+100)
這篇文章主要介紹了用匯編語言實(shí)現(xiàn)從1加到100的方法(1+2+...+100),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01匯編語言 and和or邏輯運(yùn)算指令的實(shí)現(xiàn)
這篇文章主要介紹了匯編語言 and,or邏輯運(yùn)算指令的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01