;说明:运行环境XP或者DOSBOX,Win7不可以
; 编译环境masm 6.11以上版本
;能用的区域是,255*200,因为画不上去,把计分和计时放在右
;70pix大的位置
;移动过程,
;游戏结束标志
;没有解决的bug,食物坐标的产生
;需要改进的地方,字符串的显示
comment ;
控制函数:
1、获取键盘并修改方向标志位
2、按标志位移动每个节点
3、检测蛇的死亡
4、获取蛇头将来位置的颜色值
5、把食物放在5的倍数的位置上
6、修改、显示计分计时
活动范围:5-250,5-195
;
;补充知识
;1 、MOV AH,0 ;读时钟计数器值
;INT 1AH
;2、随机数 out 43h, al
;in al, 40h
;#mode=dos
.model small
data segment
snack: db 150,150,'$' ;以行列的方式存,方便调用
dw 160 dup(0) ;此处需空出足够的空间,否则会修改方向标志
drect: db 4dh ;
life: db 1;生命值 1代表活着 0代表死亡
food: db 8 dup(0)
times: db "time",'$'
time: db "90",'$' ;上限90s
temp: db 0;临时记录秒
marks: db "mark",'$'
mark: db "00",'$' ;一节一分,60分过关
data ends
.code
start:
call init ;初始化
goon:
call delay;延时
;call ctime;改变时间
mov ch,0
call show_snack;擦除影子
call move;移动
;判断是否还活着
mov ax,data
mov ds,ax
mov bx,life
mov al,[bx]
cmp al,0
je home;如果蛇死亡退出
mov ch,2
call show_snack;显示
mov ah,0bh
int 21h
cmp al,0 ;检测是否有输入
je goon ;没有的话继续
call get_key ;有的话进行处理
jmp goon
home:
;返回16色文本模式
mov ax,0001h
int 10h
mov ax,cs
mov ds,ax
mov dx,offset mes
mov ah,9
int 21h
jmp back2
mes: db "Game over",'$'
back2:
;暂停
mov ah,0
int 16h
;退出
mov ax,4c00h
int 21h
;------------------------------------------
;子程序的功能:
; 改变时间
;------------------------------------------
ctime:
;获取时间
push ax
push bx
push dx
push ds
mov ah,0
int 1ah;秒在dh中
mov ax,data
mov ds,ax
mov bx,offset temp
mov dl,[bx]
sub dl,dh
jz retc;相同的话退出
mov bx,offset time
mov ax,[bx]
sub ax,3030h
xchg al,ah
sub ax,1
xchg al,ah
add ax,3030h
mov [bx],ax
call stime
retc:
pop ds
pop dx
pop bx
pop ax
ret
;------------------------------------------
;子程序的功能:
; 移动每个节点
;--------------------------------------------------
move:
push ax
push bx
push cx
push ds
push dx
mov ax,data ;指向数据段
mov ds,ax
;取得方向标志,修改所有节点的坐标
mov bx,drect
mov ah,[bx]
mov bx,snack ;取出蛇头准备移动
mov dx,[bx] ;保存蛇头
;进行比较
cmp ah,48h
je up ;上
cmp ah,50h
je down ;下
cmp ah,4bh
je left ;左
cmp ah,4dh
je right ;右
up:
mov ax,[bx] ;取出来
sub al,5 ;修改
cmp al,4
jna dead
push ax
push bx
push dx
mov bh,0;页号
mov dx,0
sub al,3;保证关键点在中部
mov dl,al;行
mov cx,0
mov cl,ah;列
mov ah,0dh;功能号
int 10h;颜色在al中
pop dx
pop bx
pop cx;用cx保存取颜色前的ax
cmp al,2;蛇的颜色是2
je dead
cmp al,3;食物颜色是3
je eat
mov [bx],cx ;写回去,cx中是当前蛇头的位置
jmp show_next
down:
mov ax,[bx] ;取出来
add al,5 ;修改
cmp al,195
jnb dead;死亡
push ax
push bx
push dx
mov bh,0;页号
mov dx,0
add al,3;保证关键点在中部
mov dl,al;行
mov cx,0
mov cl,ah;列
mov ah,0dh;功能号
int 10h;颜色在al中
pop dx
pop bx
pop cx;用cx保存取颜色前的ax
cmp al,2;蛇的颜色是2
je dead
cmp al,3;食物颜色是3
je eat
mov [bx],cx ;写回去
jmp show_next
left:
mov ax,[bx] ;取出来
sub ah,5 ;修改
cmp ah,4
jna dead
push ax
push bx
push dx
mov bh,0;页号
mov dx,0
sub ah,3;保证关键点在中部
mov dl,al;行
mov cx,0
mov cl,ah;列
mov ah,0dh;功能号
int 10h;颜色在al中
pop dx
pop bx
pop cx;用cx保存取颜色前的ax
cmp al,2;蛇的颜色是2
je dead
cmp al,3;食物颜色是3
je eat
mov [bx],cx ;写回去
jmp show_next
right:
mov ax,[bx] ;取出来
add ah,5 ;修改
cmp ah,250
jnb dead
push ax
push bx
push dx
mov bh,0;页号
mov dx,0
add ah,3;保证关键点在中部
mov dl,al;行
mov cx,0
mov cl,ah;列
mov ah,0dh;功能号
int 10h;颜色在al中
pop dx
pop bx
pop cx;用cx保存取颜色前的ax
cmp al,2;蛇的颜色是2
je dead
cmp al,3;食物颜色是3
je eat
mov [bx],cx ;写回去
jmp show_next
dead:
mov bx,life
mov al,[bx]
mov al,0
mov [bx],al;修改为死亡
jmp retnext
;移动每个节点,第一个节点已经移动
show_next:
add bx,2
mov ax,[bx] ;取出下一个节点坐标
cmp al,'$'
je retnext
xchg dx,ax ;跟上一个节点坐标交换
mov [bx],ax ;在写回去
jmp show_next
retnext:
pop dx
pop ds
pop cx
pop bx
pop ax
ret
eat:
;把当前蛇头位置放回去
;保存蛇头ax
;取出下一个节点
mov [bx],cx
next:
add bx,2
mov ax,[bx]
xchg dx,ax;交换节点,保存在dx中
mov [bx],ax
cmp dl,'$'
je return;
jmp next
return:
add bx,2
mov [bx],dx;把最后一个节点放回去
call show_food;吃完以后产生一个食物
call chgmark;修改分数
jmp retnext
;-------------获取按键子程序----------------------
;子程序的功能:
; 根据键盘值的上下左右修改方向标志
;--------------------------------------------------
chgmark:
push ax
push ds
push bx
mov ax,data
mov ds,ax
mov bx,offset mark
mov ax,[bx]
xchg al,ah;高低位互换
inc ax
xchg al,ah
mov [bx],ax
call smark
pop bx
pop ds
pop ax
ret
;-------------获取按键子程序----------------------
;子程序的功能:
; 根据键盘值的上下左右修改方向标志
;--------------------------------------------------
get_key:
push ax
push bx
push ds
mov ax,data
mov ds,ax
mov bx,drect
mov ah,0
int 16h
cmp ah,50h
je down1 ;下
cmp ah,4dh
je right1 ;右
cmp ah,48h
je up1 ;上
cmp ah,4bh
je left1 ;左
retsw:
pop ds
pop bx
pop ax
ret
;如果键盘方向和当前方向相反,退出
up1:
mov al,[bx] ;取出来
cmp al,50h
je retsw
mov al,48h ;修改
mov [bx],al ;写回去
jmp retsw
down1:
mov al,[bx] ;取出来
cmp al,48h
je retsw
mov al,50h ;修改
mov [bx],al ;写回去
jmp retsw
right1:
mov al,[bx] ;取出来
cmp al,4bh
je retsw
mov al,4dh ;修改
mov [bx],al ;写回去
jmp retsw
left1:
mov al,[bx] ;取出来
cmp al,4dh
je retsw
mov al,4bh ;修改
mov [bx],al ;写回去
jmp retsw
;--------------------------------------------------
;子程序的功能延时0.5s
;--------------------------------------------------
delay:
push ax
push bx
push cx
mov bx,4
;执行完33144次是0.5s
again: mov cx,33144
waitf:
in al,61h ;跟61h端口的pb4有关
and al,10h
cmp al,ah
je waitf
mov ah,al
loop waitf
dec bx
jnz again
pop cx
pop bx
pop ax
ret
;----------------------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------------------
; 以下为各种显示子函数
; init、bound、show_snack、show_food、rec、line、pixel
;----------------------------------------------------------------------------------------------------------------
;----------------------------------------------------------------------------------------------------------------
;----------------初始化子程序------------------------
;子程序的功能:
; 修改显示模式、显示蛇、墙体、食物、计时、分数
;参数:无
;--------------------------------------------------
init:
;显示time
push ax
push cx
push ds
push bx
mov ax,0013h
int 10h ;设置图形显示模式320*200 256色VGA
call stime
call smark
mov ch,2
call show_snack
call show_food
call bound
;mov ah,0
;int 1ah;秒在dh中
;mov ax,data
;mov ds,ax
;mov bx,offset temp
;mov [bx],dh
pop bx
pop ds
pop cx
pop ax
ret
;----------------显示时间子程序------------------------
;子程序的功能:
; 修改计时
;参数:无
;--------------------------------------------------
stime:
push ax
push bx
push dx
push ds
mov ah,2
mov bh,0
mov dh,2 ;行
mov dl,34 ;列
int 10h
mov ax,data
mov ds,ax
mov dx,times
mov ah,9
int 21h
mov ah,2
mov bh,0
mov dh,7 ;行
mov dl,34 ;列
int 10h
mov dx,time ;时间值
mov ah,9
int 21h
pop ds
pop dx
pop bx
pop ax
ret
;----------------显示分数程序----------------------
;子程序的功能:
; 修改分数
;参数:无
;--------------------------------------------------
smark:
;显示mark
push ax
push bx
push dx
push ds
mov ah,2
mov bh,0
mov dh,90 ;行
mov dl,50 ;列
int 10h
mov ax,data
mov ds,ax
mov dx,marks
mov ah,9
int 21h
mov ah,2
mov bh,0
mov dh,96 ;行
mov dl,50 ;列
int 10h
mov dx,mark ;分值
mov ah,9
int 21h
pop ds
pop dx
pop bx
pop ax
ret
;----------------显示边界线程序------------------------
;子程序的功能:
; 画出可用屏幕的边界线,蓝色为蛇的活动范围
;-----------------------------------------------------
bound:
push ax
push bx
push si
push di
push cx
;下
mov bx,0
mov ax,199 ;(0,199)
mov si,255
mov di,199 ;(255,199)
mov ch,5
call line
mov bx,4
mov ax,196 ;(4,196)
mov si,251
mov di,196 ;(251,196)
call line
;左
mov bx,0
mov ax,0 ;(0,0)
mov si,0
mov di,199 ;(0,199)
call line
mov bx,4
mov ax,4 ;(4,4)
mov si,4
mov di,196 ;(4,196)
call line
;上
mov bx,0
mov ax,0 ;(0,0)
mov si,255
mov di,0 ;(255,0)
call line
mov bx,4
mov ax,4 ;(4,4)
mov si,251
mov di,4 ;(251,4)
call line
;右
mov bx,255
mov ax,0 ;(255,0)
mov si,255
mov di,199 ;(255,199)
call line
mov bx,251
mov ax,4 ;(251,4)
mov si,251
mov di,196 ;(251,196)
call line
;多出来的65pix
;右
mov bx,319
mov ax,0 ;(319,0)
mov si,319
mov di,199 ;(319,199)
mov ch,4
call line
;左
mov bx,256
mov ax,0 ;(255,0)
mov si,256
mov di,199 ;(256,199)
call line
;上
mov bx,256
mov ax,0 ;(256,0)
mov si,319
mov di,0 ;(319,0)
call line
;下
mov bx,256
mov ax,199 ;(256,119)
mov si,319
mov di,199 ;(319,199)
call line
pop cx
pop di
pop si
pop bx
pop ax
ret
;----------------显示蛇身子程序------------------------
;子程序的功能:
; 在屏幕上显示蛇身
;参数:
; snack地址标号的坐标数据遇,'$'结束
; 蛇身颜色,ch
;-----------------------------------------------------
show_snack:
push ax ;保护现场
push ds
push bx
push cx
mov ax,data
mov ds,ax
mov bx,0
show_again:
mov ax,snack
add bx,ax
mov ax,[bx]
cmp al,'$'
je retsnack
call rec
add bx,2
jmp show_again
retsnack:
pop cx
pop bx
pop ds ;恢复现场
pop ax
ret
;----------------显示食物子程序------------------------
;子程序的功能:
; 在屏幕上随机显示一个食物(不能和蛇身重合)
;参数:无
;算法:
; 利用40端口产生随机数,并把这个坐标记录放在food的结构体中
;-----------------------------------------------------
show_food:
push ax
push bx ;保护现场
push ds
push cx
xor al, al
out 43h, al
in ax,40h
mov bl,190 ;再大就要超出屏幕了
div bl ;得到不大于190的余数
mov al,ah
mov ah,0
mov bl,5
div bl;用得到的不大于5的余数除以5在乘以5(我同学想到的)
mov ah,0
mul bl;乘以5
mov bh,al;保存得到的横坐标
xor al, al
out 43h, al
in ax,40h
mov bl,245 ;再大就要超出边界了
div bl ;用得到的不大于5的余数除以5在乘以5(我同学想到的)
mov al,ah
mov ah,0
mov bl,5
div bl
mul bl;得到纵坐标在al中
mov ah,bh ;行列坐标放在bx中,接下来是查找是否是蛇身的某个节点
mov bx,data
mov ds,bx
mov bx,food
add ax,0505h;保证食物不在墙体上出现
mov [bx],ax ;保存食物的位置,也可以不保存
mov ch,3
call rec
pop cx
pop ds
pop bx
pop ax ;恢复现场
ret
;----------------画矩形子程序------------------------
;子程序的功能:
; 在指定左上角和右下角坐标画矩形
;参数:
; 左上角坐标(ah,al)列行 < 右下角坐标(bl,bh)颜色值ch
; (bx,ax)列行 (si,di)
;--------------------------------------------------
rec:
push ax
push bx
push cx ;保护现场
push dx
push si
push di
mov bl,ah
mov bh,al
add bx,0404h ;算出右下角的坐标
;以左上角为主
push ax
push bx
;左线(ah,al) (ah,bh)
mov dx,bx ;保存bx
mov bx,0
mov bl,ah
mov ah,0 ;开始坐标准备完毕
mov si,bx
push dx
mov cl,dh
mov dx,0
mov dl,cl
mov di,dx
pop dx ;结束坐标准备完毕
push ax
push bx ;下面要用ax,bx
call line
pop bx
pop ax
;上线
mov di,ax
mov dh,0
mov si,dx
call line
pop bx
pop ax ;ax,bx恢复为刚进入子程序时的状态
;以右下角为主
;右线
mov dx,ax
mov ax,0
mov al,bh
mov bh,0
mov si,bx
mov di,ax ;结束坐标完毕
mov bx,si
mov al,dl
push di
push si
call line
pop si
pop di
;下线
mov bl,dh
mov ax,di
call line
pop di ;恢复现场
pop si
pop dx
pop cx
pop bx
pop ax
ret
;----------------画线子程序------------------------
;子程序的功能:
; 在指定坐标画线,只能画水平和垂直的线
;参数:
; 起点坐标(bx,ax)列行,终点坐标(si,di)颜色值ch
;--------------------------------------------------
line:
push ax
push bx
push si
push di
push cx ;保护现场
push dx
cmp di,ax
je level ;水平画线
cmp si,bx ;求差
je perp ;垂直画线
level: ;水平线
sub si,bx ;si代表要画的的总列数,bx代表但前要画的列(行在ax中),颜色在ch中
inc si ;相减会少一
putl:
call pixel ;调用子程序,显示一个点
inc bx ;指向下一列
dec si ;列数减一
jnz putl ;重复调用画点,连成线
back:
pop dx ;恢复现场
pop cx
pop di
pop si
pop bx
pop ax
ret
perp: ;垂直线
sub di,ax ;di代表要画的的总列数,bx代表但前要画的列(行在ax中),颜色在ch中
inc di ;相减会少一
putp:
call pixel ;调用子程序,显示一个点
inc ax ;指向下一列
dec di ;列数减一
jnz putp ;重复调用画点,连成线
jmp short back
;----------------画点子程序------------------------
;画点子程序的功能:
; 在指定坐标画点
;参数:
; 坐标(bx,ax)列行,颜色值ch
;--------------------------------------------------
pixel:
push ax
push bx
push dx
push di
push es ;保护现场,ax,bx本来不用的,为了方便以后的调用就保护了
mov dx,0a000h ;图形的开始内存,相当于文本模式的0b800h
mov es,dx
mov dx,320
mul dx ;算出第n行的内存地址dx:ax
add ax,bx ;算出n行中的m列
mov di,ax
mov es:[di],ch ;给这个单元赋颜色值
pop es ;恢复现场
pop di
pop dx
pop bx
pop ax
ret
end start
- [cutebe] 相当牛,这个苦思冥想也值了。^_^ 11/30 00:00
- [parse] 如果忽略消息循环,那么操作系统加载的程序很快就执行完了,就像DOS程序一闪而过,所以CPU会空闲下来 06/30 09:04
- [游客] 楼主好厉害,挺一下! 01/19 08:43
- [游客] 很不错。 01/04 18:36
- [chinatree] 潜力贴留名,沙发。 11/08 12:58
- [youthangel] 恩,这次对了 10/30 18:56
- [fpamc] mov bx,18 在这条指令的上边是不是要加一条sub dx,dx? 10/30 10:03
- [fpamc] 对的 10/27 11:19
- [fpamc] 对的 10/27 09:00
- [fpamc] 哦,对不起,看错了。实验13也有一个7ch中断 10/27 08:52
- [游客] 现在急需一个汇编大作业。。。。。。可以么。。。。。如果今天之内看见留言 就加 1765496715 12/28 16:52
- [youthangel] 这算是对我学习的鼓励吗?谢谢!咱们这样交流就可以了 10/11 15:48
- [fpamc] 多日观察,你的学习积极性挺高的。可以来我们群了。群号:75916434 10/11 10:58
[ 游客 发表于 2013-01-04 18:36 ]
很不错。
[ 游客 发表于 2013-01-19 08:43 ]
楼主好厉害,挺一下!