打飞机小游戏html代码,纯汇编实现打飞机小游戏的示例代码

汇编暑假作业要求做一个大项目,题目可以自拟。我思来想去,还是觉得做一个小游戏比较有意思。最后选择了做打飞机游戏。

这里采用的是VGA模式320x200 4色。

打飞机游戏的游戏逻辑比较简单。首先,飞机可以移动,也可以发射炮弹;其次,会有敌人不断地从前方飞过来,如果撞上飞机游戏结束;最后,飞机发射的炮弹可以击落敌人。

既然是打飞机,我们就必须首先造一台飞机,代码如下:

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

这里之所以做的这么复杂是出于代码重用的考虑,相同的代码只要输入不同的参数,就能制造出不一样的东西。这是抽象的思想。

drawCraft 根据输入的不同的数组,可以绘制出不同的东西,比如飞机,导弹,敌人。而不必画飞机一个函数,画导弹又是另一个函数了。

drawCraft主要是一条线一条线地画,就像3D打印一样。不过这里是2D的版本。

光画了飞机不行,我们还需要让它动起来。动起来的方法很简单,只需要用黑色覆盖原图,然后再在新的位置上建立一个新的即可:

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

有了飞机,还要发射炮弹啊。我所期望的飞机,应该是可以多连发的,而且是无限发!那玩起来才爽。于是我设计了这样的数组。

MISSILE DW 512 DUP('$$')

MISSILESNUM DW 0

这是什么意思呢?我们一步一步来看。首先这是存储每次发射炮弹,炮弹所在的位置(横坐标和纵坐标)。

每当玩家按下空格键,就向数组里添加位置信息。这是为了方便后面让导弹一起上升。

在没有键盘输入的时候。我们想让导弹自己上升。为了做到这点,我们需要遍历这个MISSILE数组,每找到一个位置信息,就读出来,删除它,然后更新数组位置信息(只需要更新纵坐标),然后再在新的位置上画一个导弹就行了。

以下是具体实现代码

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

以上做的都是具体的例程。做到这里,回过头看一下我们主程序的实现。

整个游戏是依靠主程序调用一个个例程来运作的。

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(退出),然后再判断是不是空格(攻击),如果都不是,就执行 movePlane,在movePlane中实现具体的移动过程。

如果没有键盘输入,就执行Process后面的代码。这段代码稍后解释。

有了飞机,有了导弹,还需要有敌人啊。敌人的制作过程和导弹类似。也建立一个ENEMY数组来存储每一个敌人的位置信息,并在没有键盘输入的时候进行更新。只要注意导弹是上升,敌人是下降。

之后是检测碰撞,我是用二重循环遍历了MISSILE 和 ENEMY两个数组。一开始我写的是严格相等才算碰撞,后来玩的时候发现这条件太苛刻了,于是改成了在一定范围内就行。

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

到这里,主要的例程都已经结束了。

再回过头看一下主程序的代码。

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开始,首先调用的是显示分数的例程(比较容易我没放上来),然后先检测是否碰撞。这里设置了一个DIFFICULTY变量,是适应不同难度(DIFFICULTY)。TIMER是用来定时的。每次都+1,加到DIFFICLUTY的值才执行敌人下降的例程。

难度大的话,敌人移动速度快,只需要把DIFFICULTY的值设小一点,就可以更快的使敌人下降;反之亦然。

附上一些效果图。

efcd1f94694789f3e7a538cbdec4be23.png

3653c31be5a89af111e4f3f0af19ac2a.png

46f6d2f50b15d97d4815afc0363e881b.png

18e33412b10d5705f7bc93e7df050f90.png

6a9ba022c58fc339482b828d0fb65084.png

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值