易码技术论坛

 找回密码
 加入易码
搜索
查看: 133186|回复: 5

前辈们留下的珍贵资料

[复制链接]
发表于 2005-4-30 12:09:00 | 显示全部楼层
支持,立刻下载~~
发表于 2005-4-30 12:10:00 | 显示全部楼层
顶先
发表于 2005-4-30 12:22:00 | 显示全部楼层
那个Dos游戏编程有点古老了,不过有一些概念还是比较不错的^_^
RPG制作讲的是一种比较经典的RPG模式。也很不错~~^_^
发表于 2005-4-30 17:07:00 | 显示全部楼层
8错8错,好东东哦~
发表于 2005-4-30 18:44:00 | 显示全部楼层
好东西 直接贴出来8
quote:
这里以VGA  13H视频模式为例,介绍电脑游戏的制作方法,VGA 13H是一种工作在图形方式下的模式,320*200的屏幕分辩率,同屏可以显示256种颜色,具有编程简单、运行速度快、颜色丰富等特点,早期的许多游戏,象大家非常熟悉的仙剑奇侠传、红色警戒、DOOM等就使用了这一模式,虽然以今天的标准来说320*200的分辩率已经不算什么,但本室觉得它仍然是一个很好的游戏编程入门环境,在这一模式下,逐步地由简单到复杂学习游戏设计的基本方法。下面将要介绍的函数使用TURBO C 2.0,也可以作些修改用其它的C编译器来编译,这里介绍的函数在VGA13H游戏库中有更多的描述。

一.显示器的工作原理

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

二.显示器的坐标系统
  计算机屏幕上的坐标与我们通常使用的直角坐标系不同,坐标原点(0,0)在屏幕的左上角,向右是水平方向的坐标,向下是垂直方向的坐标,且坐标没有负值,与直角坐标系刚好相反,在设计屏幕时我们必须注意到这个差别。

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

将屏幕设置成13H模式这样调用函数:SetVideoMode(0x13);

将屏幕还原为字符模式:SetVideoMode(0x03);

五.如何在屏幕上画点?
  画点是所有图形编程工作中最基本的操作,在前面的介绍中我们知道,显示存储器中每个字节对应屏幕上的一个像素点,如果我们改变显存中某个字节的内容,相应地就会改变屏幕上某个点的颜色,所以在屏幕上画点实际上就是要找到点在显示内存中的位置,并改变它的值。从前面的介绍我们知道VGA 13H模式使用一段64KB大小的线性内存空间,所以要找到像点的位置非常容易,这个位置可由y*320+x来确定,其中,y是像点在垂直方向的坐标,x是水平方向的坐标,320是屏幕的宽度,知道了像点的位置,再把这个位置加上显示内存的首地址就可得到像点在显示内存中的绝对地址,然后将点的颜色值放到这个地址上就可在屏幕上画出一个点了。
我们建立一个指针,使它指向显示内存的首地址:

  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;
}

六.设置颜色寄存器

  VGA显示卡具有显示256种颜色的能力,每种颜色用一个0-255之间的数值来表示,那么这些数值与我们在屏幕上实际见到的颜色之间又有什么关系呢?
实际上这些数值只是VGA显示卡上的颜色寄存器的索引值,并不是我们在屏幕上实际看到的颜色,在颜色寄存器里才保存了颜色的真实值。VGA显示卡上有一个包含256个单元的颜色寄存器(我们称为调色板),每个单元由三个部份组成,这三部份分别代表颜色中的红、绿、蓝三种成份,用三个字节表示,显示器就是用红、绿、蓝三种成份来组成任何我们看到的颜色。
颜色寄存器一共有768个字节(3*256=768),当我们要在屏幕上显示某种颜色时,显示卡硬件根据颜色的索引值在颜色寄存器中查找相应的单元,找到后从中取出颜色值显示在屏幕上,这个过程与画家使用调色板很相似,颜色寄存器相当于调色板,颜色寄存器中的单元相当于调色板上的色格,在色格中装有预先调好的颜色,当画家需要用某种颜色作画时,从装有那种颜色的色格中把颜色取出来。比如我们要显示颜色索引值为30的颜色,显示卡硬件就去查找颜色寄存器的第30单元,30单元位于距颜色寄存器首址3*30=90处(因为每个单元有三个字节),找到后取出90处记录有红、绿、蓝三种成份的三个字节作为在屏幕上显示的色彩信号,实际上每个字节只用了六位来表示颜色,其它两位没用,这六位表示的数的值域为0-63,所以每种颜色(红、绿、蓝)成份具有64种亮度的表现能力,三种颜色组合共可以产生64*64*64=262,144种颜色,显示卡从这262,144种颜色中取出256种在同一屏幕上显示。
显示图形之前我们必须事先设置好颜色寄存器,否则屏幕上显示的图形就不是原来的颜色,而是一些乱七八糟的颜色。
  设置颜色寄存器也可以用调用BIOS功能的方法,但是这种方法速度比较慢,不适合在游戏中使用,游戏设计中更多的是采用直接访问VGA显示卡的I/O端口的方法来快速设置颜色寄存器,我们只需访问四个I/O端口就可以完成设置颜色寄存器的工作,这四个端口分别是:0x3c6、0x3c7、0x3c8和0x3c9。
  端口0x3c6称为调色板屏蔽寄存器,用来屏蔽所要求的调色板寄存器的位,如果你在这个寄存器中放入0xff,你就可以通过调色板索引寄存器0x3c7和0x3c8(一个用于读,一个用于写)访问任何你希望访问的颜色寄存器,端口0x3c9称为调色板数据寄存器,红、绿、蓝三种成份就是通过它进行读写(颜色值要读或写三次)。我们定义一个颜色结构以方便处理颜色寄存器:

typedef struct RGB_COLOR
{
unsigned char red;
unsigned char green;
unsigned char blue;
}RGBColor,*RGBColorPtr;

结构中的red、green和blue变量用来保存颜色的红、绿、蓝三种成份。

设置颜色寄存器值的函数:

void SetPaletteRegister(int index,RGBColorPtr color)
{
outportb(0x3c6,0xff);
outportb(0x3c8,index);
outportb(0x3c9,color->red);
outportb(0x3c9,color->green);
outportb(0x3c9,color->blue);
}

获取颜色寄存器值的函数:

void GetPaletteRegister(int index,RGBColorPtr color)
{
outportb(0x3c6,0xff);
outportb(0x3c7,index);
color->red=inportb(0x3c9);
color->green=inportb(0x3c9);
color->blue=inportb(0x3c9);
}

七.画位图
  计算机绘制图像通常采用一种称为位映射图(BITMAP)的图形处理方法进行,位映射图是一个矩形的点阵结构(二维矩阵),显示在屏幕上时,对应屏幕上一个矩形区域,组成位图的数据储存在内存中一段连续的区间。我们比较常见的位图文件有:BMP、PCX、GIF、JPG等。位图通常存储在外部文件中,使用以前将其从磁盘文件调入内存,然后显示在屏幕上。
下面介绍将256色PCX图形文件读入内存的方法:

1.PCX文件头结构:

typedef struct PCX_HEADER
{
char menufactrue; /* 厂家标识编号 0x0a */
char version; /* 文件版本编号 */
char packing_type; /* 压缩模式 */
char bits_per_pixel; /* 每点占用的位数 */
int minx; /* 最小X坐标值 */
int miny; /* 最小Y坐标值 */
int maxx; /* 最大X坐标值 */
int maxy; /* 最大Y坐标值 */
int hres; /* 水平分辨率 */
int vres; /* 垂直分辨率 */
char palette[48]; /* 颜色调色板 */
char unused; /* 未使用 */
char bit_plance; /* 位平面个数 */
int bytes; /* 单一水平线占用的字节数 */
int palette_type; /* 调色板类型 */
char unused2[58]; /* 未使用 */
}PCXHeader,*PCXHeaderPtr;

2.定义用来存放PCX图像数据的结构:

typedef struct PCX_PICTURE
{
int width;
int height;
char far *buffer;
RGBColor palette[256];
}PCXPicture,*PCXPicturePtr;

3.初始化图像数据的函数:

int InitPCX(PCXPicturePtr image,int w,int h)
{
unsigned size=w*h;
image->width=w;
image->height=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<=size)
{
data=fgetc(fp);
if(data>=192&&data<=255)
{
num_bytes=data-192;
data=fgetc(fp);
while(num_bytes-->0)
{
*(image->buffer+count)=data;
++count;
}
}
else
{
*(image->buffer+count)=data;
++count;
}
}
fseek(fp,-768L,SEEK_END);
for(index=0;index<256;index++)
{
image->palette[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;index<256;index++)
SetPaletteRegister(index,(RGBColorPtr)&image->palette[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;i<height;i++)
for(j=0;j<width;j++)
{
if(*image!=0&&(x+j)>=0&&(x+j)<320&&(y+i)>=0&&(y+i)<200)
DrawPoint(x+j,y+i,*image);
image++;
}
}

x,y是图像在屏幕上的左上角坐标,width,height是图像的宽度和高度,image是指向内存中图像的指针。

我们对if(*image!=0&&(x+j)>=0&&(x+j)<320&&(y+i)>=0&&(y+i)<200)语句进行一下分析:

  *image!=0用来检查所画的颜色值是否是透明色,如果是,则不画出来,这样我们就可以画出有透明效果的图象,即透过图象可以看到背景,透明色通常取值0,也可以用其他的颜色值表示。
  (x+j)>=0&&(x+j)<320&&(y+i)>=0&&(y+i)<200语句用来判断所画点的坐标是否超出屏幕显示的范围,这样可以画出具有裁剪效果的图象,如图象的一部份在屏幕外。

八.打印字符

  游戏经常在屏幕上打印出显示游戏状态的文本,使游戏者了解当前游戏的状态,这是游戏与游戏者进行交互必不可少的过程。在图形模式下显示文本与在文本模式下有很大区别,在图形方式下文本必须使用基于画位图的方法来显示。
这里介绍一种简便的方法:利用计算机只读存储器中的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+(c<<3);
offset=(cy<<8)+(cy<<6)+cx;
for(y=0;y<8;y++)
{
bit_mask=0x80;
for(x=0;x<8;x++)
{
if((*TempPtr&bit_mask))
*(VideoBufferPtr+offset+x)=Fcolor;
else if(flag==1)
*(VideoBufferPtr+offset+x)=Bcolor;
bit_mask=(bit_mask>>1);
}
offset+=320;
TempPtr++;
}
}

cx,cy 是字符在屏幕上的坐标,c 字符的ASCII码,Fcolor,Bcolor 分别是字符的前景和背景颜色,flag 打印标志,当flag=1时显示字符的背景色,否则打印的字符具有透明效果。

2.打印字符串的函数。

void PrintString(int x,int y,char *string,unsigned char Fcolor,unsigned char Bcolor,int flag)
{
int index;
for(index=0;string[index]!=0;index++)
PrintChar(x+(index<<3),y,string[index],Fcolor,Bcolor,flag);
}

*string 字符串指针。

九.控制游戏的速度
  初学游戏编程的人常常会遇到这样的问题,设计出来的游戏在一台机子上速度运行正常,当把游戏在另一台运算速度比较快的机子上运行时,游戏速度也变得很快。问题就在于游戏中没有一个时间基准值在控制它。
  那么如何控制游戏的速度?方法是用电脑时钟计数来控制。
PC机采用一块8253定时器芯片计算系统时钟的脉冲,若干个系统时钟周期转换成一个脉冲,这些脉冲序列可以用以计时,也可以送入计算机的扬声器产生特定频率的声音。8253定时器芯片独立于CPU运行,它可以象实时时钟那样,CPU的工作状态对它没有任何影响。8253芯片有三个独立的通道,每个通道的
 楼主| 发表于 2005-4-30 08:52:45 | 显示全部楼层 |阅读模式


两篇技术文贴(dos游戏编程    RPG制作)

想做点东西的朋友不妨牺牲点点时间看看~~~

这都是我精心收藏的~对本人启发很大的
[em05][em05][em05]
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-4-20 21:37 , Processed in 0.009820 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表