汇编网首页登录博客注册
youthangel的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
文章收藏

[2012-11-08 11:12] 手把手教你写汇编版贪吃蛇 第1期 (绝对原创)

贪吃蛇,这个游戏相信大家都玩过了。现在我们要用汇编去实现它(当然是主要功能,界面不一定很漂亮),废话少说,下面进入正题(ps:不说废话,下面还是写了一大堆,耐心读下去!)
这个游戏我们采用的是自下而上,自上而下的设计方式,界面->数据结构->控制(好像是MVC的设计模式),这个分析过程很重要。避免后期胡子眉毛一把抓。忘了,最重要的一点了。开发环境:masmplus.运行环境:winXP或者dos。Win7不可以,因为win7不支持控制台全屏
1、        界面(徒有虚表,核心的在黑屏后面)
从界面上讲,我们要显示的有:①蛇②墙体(障碍物)③食物④计时显示⑤分数显示
好,我们又把任务细化了。先分析前三项①蛇②墙体(障碍物)③食物,我们可以用线代表墙,用N个小矩形代表蛇身,用一个小矩形代表食物。那么我们的问题进一步具体了,怎么画线,画矩形呢?相信有的朋友心里已有答案了,四条线是一个矩形,N个点是一条线。我们只需要画点就可以了
        在介绍画点之前,我们还得对一些硬件的知识有所了解(毕竟汇编是面对的是硬件)。
每个显卡的厂商都会提供自己显卡接口标准,标准有很多,我们不用这种方式,太麻烦。我们采用最原始的方法,直接写显存,就想当初写0b800h那段内存一样。当然,这次我们不能通过写0b800h段显示一个点了。因为,显卡的显示方式分为文本模式、图形模式、视频模式……,我们以前写的0b800h段是文本显示模式,我们先在要让显示器以图形模式显示一个个的像素点。A000h是图形区的读写地址,而且图形模式还要分不同的分辨率。那我们怎么设置分辨率呢?先看课本有没有先关只是?no!那在查查dos、biso中断例程中有没有
通过查看手册,我们看到bios中断中int 10h (ah)=ch时可以修改分辨率,在此我们选择的是320*200  256色的显示方式。好,下面先试验一下!

        ;#mode=dos
.model        small
.code
        start:
              mov       ax,0013h
              int       10h         ;设置图形显示模式320*200 256色VGA

              mov        bx,20
              mov        ax,20;(20,20)
              mov        ch,2;颜色 绿色
              call        pixel
        ;暂停           
              mov       ah,0
              int       16h
        ;返回16色文本模式      
              mov       ax,0003h
              int       10h
        ;退出              
              mov       ax,4c00h
              int       21h
;--------------------------------------------------
;子程序的功能在指定坐标画点
;参数:坐标(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
看到没有,在(20,20)处有个点(O_O)
        下面,解决画线的问题,根据两点一线原理我们只要得到开始和结束坐标就可以画线了。但由于笔者的图形学掌握的不是很好,在此只能画水平和垂直线啦。接下来我们画四条线
;#mode=dos
.model        small
.data
.code
        start:
              mov       ax,0013h
              int       10h         ;设置图形显示模式320*200 256色VGA
        ;左线
              mov        bx,10
              mov        ax,10;(10,10)
              mov        si,10
              mov        di,20;(10,20)
              mov        ch,2
              call        line
         
         ;下线  
              mov        bx,10
              mov        ax,20;(10,20)
              mov        si,20
              mov        di,20;(20,20)
              mov        ch,2
              call        line
          
          ;上线
                mov        bx,10
              mov        ax,10;(10,10)
              mov        si,20
              mov        di,10;(20,10)
              mov        ch,2
              call        line
          ;右线
                  mov        bx,20
              mov        ax,10;(20,10)
              mov        si,20
              mov        di,20;(20,20)
              mov        ch,2
              call        line 
              
        ;暂停           
              mov       ah,0
              int       16h
        ;返回16色文本模式      
              mov       ax,0003h
              int       10h
        ;退出              
              mov       ax,4c00h
              int       21h
    
;----------------画线子程序------------------------
;子程序的功能:
;        在指定坐标画线,只能画水平和垂直的线
;参数:
;        起点坐标(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          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
                                        
看到四条线组成的矩形了吗?距离目标有近了一步
The next,我们进行进一步的封装,把上面那个程序封装成画正方形的子程序,参数:矩形左上角的坐标,大小为5pix
;#mode=dos
.model        small
.data
.code
        start:          
              mov       ax,0013h
              int       10h         ;设置图形显示模式320*200 256色VGA
                    
              mov        ah,15
              mov        al,15;(15,15)              
              mov        ch,2              
              call rec
              mov        ah,20
              mov        al,15;(20,15) 、
              call        rec
              mov        ah,25
              mov        al,15
              call        rec
        ;暂停           
              mov       ah,0
              int       16h
        ;返回16色文本模式      
              mov       ax,0003h
              int       10h
        ;退出              
              mov       ax,4c00h
              int       21h

;----------------画矩形子程序------------------------
;子程序的功能:
;        在指定左上角和右下角坐标画矩形
;参数:
;        左上角坐标(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,0505h;算出右下角的坐标
        ;以左上角为主
                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
看到没有,我们可以画出蛇身了,每次进步一点点!
到这里,我们就可以画出蛇身、墙体和食物了。墙体和食物请读者自行完成(就当是练习了)
至于计分显示和计时显示我们会在下期介绍,另外下期还会介绍我们的数据结构的分配
水平有限,如有不当之处还请指正,不胜感激。
我们下期再见!
评论次数(1)  |  浏览次数(654)  |  类型(冥思苦想) |  收藏此文  | 

[  chinatree   发表于  2012-11-08 12:58  ]

潜力贴留名,沙发。

 
 请输入验证码  (提示:点击验证码输入框,以获取验证码