人气 132

[游戏程序] [游戏入门基础]电脑游戏编程入门 (DOS) [复制链接]

九艺网 2017-3-4 00:52:27

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
[table][tr][td]这里以电脑VGA  13H视频模式为例,系统介绍制作电脑游戏的基本方法。VGA   INT 13H模式是一种工作在图形方式下的模式,它具有320X200的屏幕分辩率,同屏上可以显示256种颜色(超级任天堂和世嘉5代游戏机也只有256种颜色),早期的许多游戏都是在这一图形方式下开发的(如大家非常熟悉的仙剑奇侠传、红色警戒、DOOM等),在这种模式下开发游戏具有编程简单、运行速度快、颜色丰富等特点。虽然以今天的标准来说320X200的分辩率已经不算什么,但是它仍然是一个学习电脑游戏编程的很好的入门环境,我们可以通过开发VGA 13H模式下的游戏,逐步地由简单到复杂地学习游戏设计的基本方法,只要掌握了游戏设计的基本方法和理论,再利用其它软件工具(象WATCOM    C、DJGPP、VC、DIRECT  X等32位的C编译器等)来设计游戏将变得非常容易。函数用TURBO C 2.0编译,也可以稍作修改用其它的C编译器来编译运行。我们先来了解一下电脑显示器的工作原理和显示卡的结构。一.显示器的工作原理

       目前在个人计算机上广泛使用的是采用阴极射线管(CRT)的光栅扫描显示器,我们在屏幕上所看到的颜色是由电子枪发出的电子束打在CRT屏幕背面的荧光层上的点形成的,通过控制点的亮度可以产生不同的颜色。电子束不断地从左到右、从上到下扫描整个屏幕,使屏幕显示出图案,电子束以大约每秒70次的速率在屏幕上重画这一图案,这个过程称为显示刷新或屏幕刷新,具体的扫描频率依赖于所用的显示适配器(又称为显示卡)。电子束从屏幕的左上角开始向右扫描,到达屏幕的右边缘后,电子束被关闭(水平断开),接着它又迅速地返回到屏幕的左边缘(水平回扫)开始进行下一行水平方向的扫描,在完成全部的水平方向的扫描后,电子束在屏幕的右下角结束,此时电子束被关闭(垂直断开),接着又迅速地返回到屏幕的左上角(垂直回扫),开始下一屏扫描。电子束就是这样周而复始地扫描整个屏幕。显示器在两种方式下工作:文本方式和图形方式,电脑游戏一般在图形方式下进行。
二.显示器的坐标系统

       计算机屏幕上的坐标与我们通常使用的直角坐标系不同,坐标原点(0,0)在屏幕的左上角,向右是水平方向的坐标,向下是垂直方向的坐标,且坐标没有负值。
三.显示卡的结构

       显示器上的显示卡负责将图形显示在屏幕上。显示存储器中存放着在屏幕上显示的图像数据,显示卡硬件不停地将显存中的内容显示在屏幕上。显示存储器实际上是安装在显示卡上的一块或几块大规模集成电路,其容量有1M、2M、4M、8M等,在DOS下我们可以访问的内存只有1MB空间(这就是DOS的局限性所在),地址从00000H到FFFFFH,这段内存根据用途又分为不同的块,系统分配给图形缓冲区(显示存储器)的地址在A0000H到BFFFFH之间,大小为128KB,其中,VGA占用了A0000H到AFFFFH段,共64KB,这段地址是内存映射地址,供我们访问显示存储器用。在VGA 13H图形模式下,显示内存使用A0000H到AF9FFH的一段线性内存空间,每个字节表示一个点,对应屏幕上的一个像点,320*200的屏幕分辨率共需要64000个字节,刚好64KB,因为一个字节可以表示的最大整数值为256,所以每个像点就可以表示256种颜色。
四.设置视频模式

       画图以前必须使屏幕工作在图形方式,这就要设置屏幕的视频模式。设置视频模式有许多种方法,其中调用视频BIOS功能是最简单的一种,通过调用BIOS中断0x10的服务程序,可以很方便地设置屏幕模式。调用方法是将值0放入ah寄存器,显示模式放入al寄存器中,然后调用int86()函数。

设置视频模式的函数:

void SetVideoMode(int mode)
{
    union REGS r;
    r.h.ah=0;
    r.h.al=mode;
    int86(0x10,&r,&r);
}

其中mode是视频模式。
五.在屏幕上画点

       由于显示存储器是线性排列的,每个像点用一个字节来表示,所以对像点寻址非常容易,像点在显示内存中的偏移地址可由这个公式确定:y*320+x,其中,y是像点在垂直方向的坐标,x是水平方向的坐标,320是屏幕的宽度。有了像点的偏移地址,然后加上显示内存的首地址即可得到像点在显示内存中的绝对地址。只要将表示点的颜色值放到这个地址处,就可以在屏幕上画点了。首先建立一个指针VideoBufferPtr,使它指向显示内存的首地址:
  char far *VideoBufferPtr=( char far *)0xa0000000;
将这个指针加上像点的偏移地址,像点的最终地址就确定了,它等于:
    VideoBufferPtr+y*320+x;
把颜色值color写到这个地址:
*(VideoBufferPtr+y*320+x)=color;
画点的函数:
void DrawPoint(int x,int y,unsigned char color)
{
    *(VideoBufferPtr+y*320+x)=color;
}

六.显示字符

       游戏经常在屏幕上打印出显示游戏状态的文本,使游戏者了解当前游戏的状态,这是游戏与游戏者进行交互的必不可少的。然而在图形模式下显示文本与在文本模式下有很大区别,在图形模式下文本必须使用基于画位图的方法来显示。这里介绍一种简便的方法:利用计算机只读存储器中的ASCII字体数据。在计算机只读存储器(ROM)中固化有ASCII字体数据,这可在基址F000:FA6E上找到。我们只需了解数据是如何存储的,然后再得出存取该数据的算法,就可以用任意颜色在屏幕上用画位图的方法把字符画出来。在ROM中,字符按照ASCII字符编码的顺序放置,由于每个字符为8*8的点阵,所以每个字符占据8个字节的存储空间,要找出某个字符,我们只需将这个字符的ASCII码与8相乘,然后将结果加到基址F000:FA6E上。由于字符用画位图的方法来显示,因此我们可以随意给它们指定颜色(前景或背景颜色)。在图形模式下,我们只需要两个函数就能够打印文本:一个用于显示单个字符,另一个用来显示字符串。
定义一个远指针指向ROM字符集的开始位置:
  char far *RomCharPtr=(char far *)0xf000fa6e;
下面是在屏幕上打印字符和字符串的函数:
1.打印字符的函数。
void PrintChar(int cx,int cy,char c,unsigned char Fcolor,unsigned char Bcolor,int flag)
{
    int offset,x,y;
    char far *TempPtr;
    unsigned char bit_mask;
    TempPtr=RomCharPtr+(cheight=h;
    image->buffer=(char far *)farmalloc(size);
    if(image->buffer==NULL)  return 0;
    return 1;
}

4.从外部文件读入数据的函数:
int LoadPCX(char *filename,PCXPicturePtr image,int flag)
{
    FILE *fp;
    unsigned num_bytes,count,size;
    int index;
    unsigned char data;
    PCXHeader PcxHeader;
    size=image->width*image->height;
    if((fp=fopen(filename,"rb"))==NULL)
        return 0;
    fread(&PcxHeader,sizeof(PCXHeader),1,fp);
    count=0;
    while(count=192&&data0)
            {
                *(image->buffer+count)=data;
                ++count;
            }
        }
        else
        {
            *(image->buffer+count)=data;
            ++count;
        }
    }
    fseek(fp,-768L,SEEK_END);
    for(index=0;indexpalette[index].red=((fgetc(fp))>>2);
        image->palette[index].green=((fgetc(fp))>>2);
        image->palette[index].blue=((fgetc(fp))>>2);
    }
    fclose(fp);
    if(flag==1)
        for(index=0;indexpalette[index]);
    return 1;
}

其中参数flag用来指明调入文件的同时是否设置颜色寄存器(flag=1设置)。
5.画位图的函数:
void DrawImage(int x,int y,int width,int height,char far *image)
{
    int i,j;
    for(i=0;i8)&0x00ff)
int far *clk=(int far *)0x0000046c;


1.改变时间定时器值的函数:
void ChangTime(unsigned cnt)
{
    outportb(0x43,0x3c);
    outportb(0x40,LOW_BYTE(cnt));
    outportb(0x40,HI_BYTE(cnt));
}

2.延时函数:
<p><font face="Fixedsys" size="2">void Delay(int d)
{
    int tm=*clk;
    while(*clk-tm
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2024-5-10 14:29 , Processed in 0.075527 second(s), 23 queries .

Powered by Discuz! X3.4  © 2001-2017 Discuz Team.