c语言键盘操作

更新时间:2023-09-30 22:41:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

第一章 编程技术实现

如果你是在dos下编程,情况要复杂一些。你需要编写一个键盘中断扫描程序,然后用这个程序

(函数)替换系统的中断程序(通过中断向量表)。

如果你是在windows下编程,就比较简单了。用

SHORT GetAsyncKeyState(int vKey);

函数就可以了,具体使用方法可以查msdn。

如果你想做一个比较正规一些的windows游戏,可以研究一下DirectInput。

本章内容简介:本章主要介绍如何实现键盘和鼠标的输入,图形图像技术,动画技术,发声技术,汉字显示技术,精确的时间控制技术。是编写大型程序的基本功。虽然每个技术所涉及的内容很少,所提及的函数也很少,但是当它们组合在一起的时候,就可以编写大型程序。 一、键盘:

首先有必要介绍一下计算机是如何来处理键盘输入的数据的键盘里面有一个微处理器,用来扫描和检测每个键的按下或者抬起的状态,然后向主机传送一个字节的键盘扫描码,键盘扫描码翻译成对应的ASCⅡ码。

作为编程来说,只要知道每个按键都有对应的ASCⅡ码。由于ASCⅡ码不能将键盘上所有的按键全部包括,因此有些控制键如Ctrl、Alt、End、Home和Del等用扩充的ASCⅡ码表示。至于每个按键所对应的ASCⅡ码到底是什么,这里介绍一个函数可以实现该功能:

int bioskey(int n)

该函数声明在bios.h头文件中,所以调用之前需要在程序开始的位置写

上 #include,(以后如果第一次碰到的函数可以在TC根目录下的include文件夹中的头文件中查找,可以用记事本打开。) 参数n用来确定该函数的三个功能,具体如下表所示 表1-1

参数n的具体数值 0 实现的功能 bioskey(0) 返回按键的键值——两个字节的整型数据。若没有键按下,该函数一直等待,直到有键按下(这种情况有时会影响效率,在之后的例2中会看到有一种方法可以实现:在一定时间内没有按键就去执行下面的代码)。 当按下时,返回该键所对应的ASCⅡ码或其扩展的ASCⅡ码。具体请看例1; 1 2 bioskey(1) 查询是否有键按下。 若没有键按下,返回0;若有键按下,返回非零值 bioskey(2) 将返回一些控制键是否被按过,按过的状态由该函数返回的值来表示,具体请看表2

如选参数n为2时,当某位为1时,表示相应的键已按,或相应的控制功能已有效,若key值为0x09, 那么从表1-2中可以得知右Shift键和Alt键被按下,因为只有0x01和0x08相加和为0x09。 若该函数还是无法理解也不影响最后编小游戏,故此处不做详细介绍。 表1-2

字节位 对应的16进制数 含义 0 1 2 3 例1-1: #include int main ( ) {

int key; key=bioskey(0); printf(“%x”,key);

0x01 0x02 0x04 0x08 字节位 对应的16进制数 含义 0x10 0x20 0x40 0x80 Scroll Lock已打开 Num Lock已打开 Caps Lock已打开 Inset 已打开 右Shift键被按下 4 左Shift键被按下 5 Ctrl键被按下 Alt键被按下 6 7 }

/* 该例子中,若按下键盘上的UP (↑)键,屏幕会显示4800(16进制),用 16进制是一种习惯, 在上表2中也体现了这种习惯的合理性。*/ 例1-2:

#include #include int main(){ int i , s;

for(i=0;i<5000;i++){

delay(1); /*delay()函数用于延时,即使同样的参数会根据不同的实际情况的 不同而延时不同的时间,精确的时间控制请参阅《精确的时间控制》(超链接)一章*/ if(bioskey(1)!=0){ s=1; break; } }

printf(“hello”); } }

/* 该例中用了一个5000次的循环,每次延时1,每次去判断是否有按键被按下,如果有,则跳出循环,马上去执行printf(“hello”);若5000次循环里面都没有按键按下,在循环结束后,执行printf(“hello”); 这种方法对于最后编小游戏非常有用,在最后的吃豆子放炸弹(超链接)例子中会再次提到 */

最后再介绍一个函数: int kbhit(void);

该函数声明在conio.h头文件中,所以调用之前需要在程序开始的位置写上 #include

若按了键盘,该函数返回1,否则返回0;

C语言也可以实现鼠标的操作,但由于这种方法效率低,现在的面向对象的编程都不是用C语言的鼠标操作手段。并且,本课程的一些例子中,也可以不用鼠标的操作,一般只用键盘就可以实现所需要的功能,因此,这里就不做介绍。

第二章 文本与图像的显示

第一节 硬件基础

由于本课程的重点在于让大家体会C语言的进一步用法,所以对于硬件部分的知识(有兴趣的话可以到硬件概论学习硬件知识),本人会在非讲不可的情况下给大家做一介绍,就本人经历而言,没有掌握硬件知识也不影响C语言的应用,但为了知识的完整性,本人就文字图像显示所涉及的硬件知识做一介绍。

对于TC而言,如果想利用C的库函数在屏幕上显示图像,它所支持的显卡类型如下表2-1所示: 表2-1

分辨率 320×200 320×200 640×200 320×200 640×200 640×350 640×350 640×480 640×480 颜色数 4 2 2 16 16 2 16 2 16 显卡类型 CGA CGA CGA EGA EGA EGA EGA VGA VGA

表格说明:表中所出现的显卡类型有:

CGA(彩色图形适配器) EGA(增强型图形适配器) VGA(视频图形阵列适配器)

之后将介绍TC所支持的模式

第二节 文本显示方式

这里所涉及的函数有:文本窗口大小的设定,窗口颜色的设置,窗口文本的清除和输入输出等函数,在之后会对这些函数做详细介绍。这些函数包含在 conio.h 头文件中。

1. void textmode (int newmode) 函数 该函数用来定义文本方式,具体如下表所示: 表3-2

显示方式 行×列 颜色 40×25 黑白 40×25 彩色 80×25 黑白 80×25 彩色 80×25 单色 上一次的显示方式

2.void window (int left, int top, int right, int bottom);

该函数定义屏幕上一个矩形的区域作为窗口。(left,top)是窗口的左上角坐标,(right,bottom)是窗口右下角坐标,这样一个矩形就唯一确定了。对于屏幕上的坐标需要解释一下,如下图3-1:如果屏幕是640×480分辨率,则坐上角为坐标(0,0),右下角是(640,480) 图3-1:

0 1 2 3 7 -1 BW40 C40 BW80 C80 数值 符号常量 表格解释:该函数设置之后才能用上面所提到

的一些文本显示方式下的函数。当然如果不用该函数,TC会认为是缺省定义,也就是说,它会默认一种模式:80×25。

在调用函数时,参数用数值或者用符号常量是

MONO 一样的,比如 textmode(0);和textmode(BW40); LASTMODE 等效。

注意:该函数中的坐标如果超过了屏幕坐标,TC不会编译报错,但是该函数无效了。 窗口定义之后,用有关的窗口输入输出函数就可以只在此窗口内进行操作而不超出窗口界限。

3 . void textbackground(int color) 和 void textcolor(int color) 函数

前者用来设置背景颜色,后者用来设置字符函数。具体应用会在之后的例子给出 有关颜色参数color的取值具体如下表3-3所示: 表3-3:

适用于前景色或颜色 数背景色 值 前景色,背景色 前景色,背景色 前景色,背景色 前景色,背景色 前景色,背景色 前景色,背景色 黑 蓝 绿 青 红 棕 0 1 2 3 4 6 符号常量 BLACK BLUE GREEN GYAN RED BROWN

前景色,背景色 洋红 前景色,背景色 淡灰 前景色 前景色 前景色 前景色 前景色 前景色 深灰 淡蓝 淡绿 淡青 淡红 淡洋红 5 MAGENTA 7 LIGHTGRAY 8 9 10 11 12 DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTGYAN LIGHTRED 13 LIGHTMAGENTA

前景色 前景色 前景色 黄 白 闪烁 14 15 128 YELLOW WHITE BLINK 另外有函数 void textattr(int attr) 可以同时设置文本的字符和背景颜色。

如要求黄底蓝字:textattr(BLUE+(YELLOW<<4)); << 表示移位运算,在C课程中有介绍(超链接)再如:要求蓝底黄字并且要闪烁:

textattr(128+YELLOW+(BLUE<<4));使用时只要根据这两个的框架并结合表2-3就可以自己定义。

最后说明下:textbackground( ) 和 textcolor( ) 函数设置了之后,要用 clrscr( )函数清除窗口,这样才能显示出所设置的颜色。clrscr( )函数会在下一文章具体解释(超链接)。

4. 窗口内文本输入输出函数 4.1文本输入函数

窗口定义好之后,文本输入可以采用getch( ) 或 getche( ) 函数。这两个函数定义在 stdio.h头文件中。函数原型分别是:

int getch(void) int getche(void) (void表示没有参数) 它们的区别是:

getch( ):读入一个字符,当你用键盘输入的时候,屏幕不显示你所输入的字符。

getche( ) :读入一个字符,键盘输入的时候,屏幕显示所输入的字符。遇到窗口最右端会自动换行。

4.2 文本的输出函数:

int cprintf(char *format,表达式表);

括号中内容的格式跟 printf()函数相同(pirnf()在C语言中将诶少超链接),比如 cprintf("%d",a) 。 int cputs(char *str);

该函数类似于puts()函数(puts()在C语言中介绍超链接),输出一个字符串到窗口。 int putch(int ch); 输出一个字符到窗口。

这里要解释下,TC虽然可以在屏幕上画多个窗口,但是每次只能处理一个窗口,所以这些函数在都是在当前窗口进行操作,而要对别的窗口操作,需要将定义那个窗口的函数重新调用一次,则那个窗口就成了当前窗口。

以上三个函数都定义在conio.h头文件中。conio.h是一个C标准库中的头文件。conio是Console Input/Output(控制台输入输出)的简写,其中定义了通过控制台进行数据输入和数据输出的函数,主要是一些用户通过按键盘产生的对应操作。

5 有关窗口或文本整体的操作 void clrscr(void);

该函数清除窗口中的文本,并将光标移到当前窗口的左上角。 void clreol(void);

该函数清除当前光标到光标所在行的结尾的所有字符,不改变 标位置。

void delline(void);

该函数删除光标所在行的一行字符。 void gotoxy(int x,int y);

光标定位到坐标(x,y)处,若坐标超出窗口就不起作用了。 int movetext(int x1, int y1,int x2, int y2, int x3, int y3)

该函数把左上角(x1, y1),右下角(x2, y2)的矩形整体拷贝到左上角为(x3, y3)的一个新矩形内。原窗口仍保留。

int gettext(int x1,int y1,int x2,int y2, void *buffer) ;

该函数把左上角(x1, y1)到右下角(x2, y2)的窗口内的文本全部存到buffer指针(指针的内容在C语言课程中介绍,超链接)。 其中的坐标是指屏幕的绝对坐标。

int puttext(int x1,int y1,int x2,int y2,void*buffer)

相对应于上面这个函数,该函数把指针buffer中的内容拷贝到左上角(x1, y1)到右下角(x2, y2)的窗口内。其中的坐标是指屏幕的绝对坐标。

下面一个例子是对以上的几个函数的运用。该例子实现了绘制左右两个窗口,用Tap键切换光标。可以在光标所在窗口输入文本,ESC键退出。

例子3-1:

#include #include #include

char leftbuf[40*25*2]; /*切换时保存左窗口文本*/

char rightbuf[40*25*2]; /*切换时保存右窗口文本*/

int leftx, lefty; /*切换时保存左窗口当前坐标*/

int rightx, righty; /*切换时保存右窗口当前坐标*/

void draw_left_win();/*重绘左边窗口*/

void draw_right_win();/*重绘右边窗口*/ int main() { int key; int turn;

textmode(C80); /*采用之前提及的 80×25 彩色显示模式*/

textbackground(0); textcolor(WHITE);

clrscr(); /*清屏,也使得以上三个函数起作用 */

/*以下4句话定义右边窗口为绿色背景,红色前景*/ window(41,2,79,24); textbackground(2); textcolor(4);

clrscr(); /*清屏,也使得以上三个函数起作用,单步调试可以发现,未执行该函数,屏幕不会出现右窗口 */

gettext(41,2,79,24, rightbuf); /*用rightbuf指针存放右窗口文本 */

window(2,2,40,24); /*左边窗口为蓝色背景,白色前景*/ textbackground(1); textcolor(15); clrscr();

gettext(2,2,40,24, leftbuf);

turn = 0; /*初始激活左窗口*/ for(;;) {

key=bioskey(0);

if(key == 0x11b) /*ox11b是ESC键的ASCII码,如果按下ESC键,退出*/ exit(0);

/*获取窗口输入的文本的ASCII码值*/

if(key == 0xf09) /*ox11b是tap键的ASCII码,如果按下tap键,切换窗口*/ {

if(turn == 0) /*切换到左窗口*/ {

gettext(2,2,40,24, leftbuf); leftx = wherex(); lefty = wherey(); draw_right_win();

turn = 1; }

else if(turn == 1) /*切换到右窗口*/ {

gettext(41,2,79,24, rightbuf); rightx = wherex(); righty = wherey(); draw_left_win(); turn = 0; } } else

putch(key); /*当前光标处显示新输入的文本字符*/ } }

/*重绘右边窗口*/ void draw_right_win() {

window(41,2,79,24); textbackground(2); textcolor(4); clrscr();

puttext(41,2,79,24, rightbuf);

gotoxy(rightx, righty); }

/*重绘左边窗口*/ void draw_left_win() {

window(2,2,40,24); textbackground(1); textcolor(15); clrscr();

puttext(2,2,40,24, leftbuf); gotoxy(leftx, lefty); }

第三节 图形显示方式

TC有一个图形库文件(graphic.lib),提供了许多有用的图形函数,这些函数均包含在graphics.h头文件中。

TC所支持的图形模式如下表所示(和文本显示类似,表格就不具体介绍了): 表4-1: 适配器 CGA 模式 0 1 2 3 4 EGA VGA 0 1 0 1 分辨率 320×200 320×200 320×200 320×200 640×200 640×200 640×350 640×200 640×350 颜色数 4 4 4 4 2 16 16 16 16 符号常量 CGAC0 CGAC1 CGAC2 CGAC3 CGAHI EGALO EGAHI VGALO VGAMED 2 640×480 16 VGAHI TC支持的都是早期的模式,自己编小游戏时也只能在差的里面挑最高的了——VGAHI

1. void far initgraph(int far *pdriver, int far *pmode, char far *path)

该函数用来设置图形方式,也就是选择上表中一种模式。按照习惯,该函数使用时一般

先定义两个变量graphdiver, graphmode 。下面以表中最后一种模式为例,说明该函数具体的使用方法。

int graphdiver=VGA; int graphmode =VGAHI;

initgraph(&graphdiver, & graphmode,"");

最后一个参数写作 "" 是表示驱动程序路径就在程序文件当前所在目录,所以方便起见,一般把TC目录下的BGI文件中的所有文件(驱动程序都在里面了)都拷贝到程序文件所在目录,那么例子中的程序才可以正常运行,否则要写路径, 比如"d:\\\\tc\\\\BGI" 此外,若设置 int graphdiver=DETECT; 那么TC会自动检测最高的显示模式,graphdiver参数不用赋值。

(如果出现 BGI Error: Graphics not initialized(use 'initgraph')错误,可能是上述路径的问题,也有可能是机子的问题,请参照附录)

一旦调用了该函数,显示器就变成了图形显示模式,而要回到上一节所说的文本显示模式,需要调用函数 closegraph( ) ; 2. void far setcolor(int color); void far setbkcolor(int color);

这两个函数分别用来设置前景色(画图函数所画出的图形的颜色)和背景色。

下面表4-2介绍了VGAHI模式下color参数的16种情况。这也同样适用于EGAHI模式,其他模式的不作介绍了。

表中的所代表的颜色和第三讲文本显示模式下的表3-3相同,看英文就可以知道颜色。 表4-2: 数值 0 符号常量 EGA_BLACK 1 2 3 4 5 6 7 EGA_BLUE EGA_GREEN EGA_GYAN EGA_RED EGA_MAGENTA EGA_BROWN EGA_LIGHTGRAY

数值 8 9 符号常量 EGA_DARKGRAY EGA_LIGHTBLUE 3. void far setviewport(int x1, int y1, int x2, int y2, clipflag );

10 EGA_LIGHTGREEN 11 EGA_LIGHTGYAN 12 EGA_LIGHTRED 13 EGA_LIGHTMAGENTA 14 EGA_YELLOW 15 EGA_WHITE 和文本显示方式类似,在图形方式下,也可以利用该函数设置一个左上角(x1, y1)到右下角(x2, y2)的窗口。clipflag参数为0时,所画图形即使超出了该窗口,仍将显示超出部分;clipflag参数非0时(比如写作1),所画图形超出该窗口的部分将不显示。设置窗口之后,就可以用相对坐标来定位了,也就是说图形的左上角(x1, y1)成了坐标(0, 0)。 用该函数可以在屏幕上设置多个函数,甚至可以重叠,但是和文本显示方式下的设置窗口函数一样,只能对当前窗口操作,若要操作别的窗口,需要重新调用该函数。

用setcolor设置前景色时,只对当前窗口内所画图形起作用,并且该窗口在第二次被调用时如果没有使用setcolor设置前景色,TC也能记住之前所设置的颜色。 用setbkcolor设置背景色时,对整个屏幕背景都起作用。 4. 清屏函数 cleardevice( ); 和 clear ( );

这两个函数分别作用在整个屏幕和当前窗口。画图前调用该函数。 5. 文本输出

void far outtext(char far *textstring);

该函数将字符串指针textstring所指向的内容输出到当前位置。

void far outtextxy(int x, int y, char far *textstring);

该函数在(x,y)处输出字符串指针textstring所指向的内容。

此外介绍一下sprintf()函数。

原型为int sprintf(char *string,char *format,arg_list)

函数sprintf()后两个参数的用法和printf()函数一样,只是sprintf()函数给出第一个参数string(一般为字符数组)。一般在图形方式下输出数字比较麻烦。此时可调用sprintf()函数将所要输出的格式送到第一个参数,然后显示输出。再用前两个函数输出。

举例来说,cprintf(str, \就将数字10转为文本放入了字符串str中。然后就可以调用前两个函数输出了。

void far settextjustify(int horiz, int vert); 该函数用来设置输出方式。具体如下表所示 表4-3: 参数horiz 符号名 LEFT_TEXT RIGHT_TEXT

void far settextstyle(int font, int direction, int char size);

该函数用来设置文本输出的字型,方向和大小。具体如下表所示 表4-4: 参数font 符号值 DEFAULT_FONT TRIPLEX_FONT SMALL_FONT GOTHIC_FONT 值 0 1 2 4 含义 8×8字符点阵 三倍笔画体字 小字笔画体字 无衬线笔画体字 黑体笔画体字 值 含义 0 2 输出左对齐 输出右对齐 参数vert 符号名 值 含义 底部对齐 中心对齐 顶部对齐 BOTTOM_TEXT 0 TOP_TEXT 2 CENTER_TEXT 1 输出以字串中心对齐 CENTER_TEXT 1 SANS_SERIF_FONT 3 参数direction 参数size HORIZ_DIR VERT_DIR 无 0 1 1 2 3 4 5 6 7 8 9 10 水平输出 垂直输出 8×8点阵 16×16点阵 24×24点阵 32×32点阵 40×40点阵 48×48点阵 56×56点阵 64×64点阵 72×72点阵 80×80点阵

下面举个例子对以上几个函数的实际应用: 例4-1:

#include main() {

int i,graphdriver,graphmode,size,page; char s[30];

graphdriver=DETECT;

initgraph(&graphdriver,&graphmode,\ /*自动设置最高模式,运行时请将BGI中文

件拷到程序文件所在目录,否则请输入路径*/

cleardevice(); /*清屏*/

/*以下代码应该不用解释了,可以单步调试去了解,单步调试方法参见附录2*/ settextstyle(DEFAULT_FONT,HORIZ_DIR,2); settextjustify(LEFT_TEXT,0);

outtextxy(220,20,\

settextstyle(TRIPLEX_FONT,HORIZ_DIR, 2); settextjustify(LEFT_TEXT,0); outtextxy(220,50,\

settextstyle(SMALL_FONT,HORIZ_DIR, 2); settextjustify(LEFT_TEXT,0); outtextxy(220,80,\

settextstyle(SANS_SERIF_FONT,HORIZ_DIR,2); settextjustify(LEFT_TEXT,0); outtextxy(220,110,\

settextstyle(GOTHIC_FONT,HORIZ_DIR, 2); settextjustify(LEFT_TEXT,0); outtextxy(220,140,\ getch(); closegraph(); }

最终效果如下图所示:当然您也可以单步调试看每小段所显示的字型。

第四节 绘制图形

这一节所介绍的绘图函数,都是在图形显示方式下的。所以要先用上一节提到的initgraph( )设置图形显示方式。所用函数包含在头文件中。

首先介绍几个画图定位有关的函数 1. void far moveto(int x ,int y);

该函数使画图起始坐标定位到(x,y)处。如果假想有一只画笔,那么画图起始坐标就是画笔的笔尖所在坐标。

2. void far moverel(int dx ,int dy);

该函数使画图起始坐标从原坐标(a,b)移动到(a+dx, b+dy) 3. int far getx(void); 和 int far gety(void);

这两个函数用来得到画图起始坐标所在位置。前者得到X坐标,后者得到Y坐标。(void表示没有参数,使用时:getx(); 就可以得到X坐标) 画点

1. void far putpixel(int x, int y, int color);

该函数在(x,y)坐标上画一点,颜色参数color如第三讲表3-3所示。 画线

1. 首先介绍一下线类型的设置,

void far setlinestyle(int linestyle, unsigned upattern, int thickness); (unsigned表示无符号类型)

这个函数比较复杂,下面仔细介绍一下:

thickness参数只有两个选择,1或者3,分别表示1个像素宽的线和三个像素宽的线,想要更宽,可以多次在不同位置调用,也可以用后面会讲到的画矩形函数来实现。 linestyle参数的选择有如下表所示5种情况: 表5-1: 符号常量 SOLID_LINE DOTTED_LINE CENTER_LINE DASHED_LINE USERBIT_LINE 值 含义 0 1 2 3 4 实线 点线 中心线 点画线 用户自定义线 表格说明:如果linestyle参数选择0、1、2或3,upattern 参数取0;如果linestyle参数选择4。那么就表示需要用户自定义,具体说明如下:

自定义的情况下,upattern参数有16个位,每个位代表一个像素,若该位是1,则用设置好的前景色显示该点像素;若该位是0,则用背景色显示,其效果就是不显示。比如:想画间隔的点线 ………………… 用二进制表示1010101010101010 (16位),参数upattern参数通常习惯用16进制表示,此时该二进制数就是0xAAAA, 所以调用函数

setlinestyle(4, 0xAAAA, 1); 之后再用画线函数所画图形就是1个像素宽的点线,当然随便改二进制数中每一位的0、1值就可以改变线的类型。

另外一点需要注意的是,setlinestyle函数也会作用到接下来所要讲的画图函数(比如画圆、矩形等)的边线,所以若在之前调用了该函数,要想画出边线为实线的圆,要重新调用该函数,并设置为实线。

设置好了线类型并且调用了前一节所提到的setcolor( )函数设置线的颜色之后,就可以用以下三个函数来画线了,具体请看例4-1。 2. void far line(int x0, int y0, int x1, int y1);

{

putimage(70+i,170,buffer,COPY_PUT); /*左边球向右运动*/ putimage(500-i,170,buffer,COPY_PUT); /*右边球向左运动*/ }/*两球相撞后循环停止*/ for(i=0;i<185;i++) {

putimage(255-i,170,buffer,COPY_PUT); /*左边球向左运动*/ putimage(315+i,170,buffer,COPY_PUT); /*右边球向右运动*/ }

}while (!kbhit());/*当不按键时重复上述过程*/ getch(); closegraph(); }

4. 利用页交替的方法

这种方法形象的讲,就相当于帷幕的效果,帷幕前是当前展示的场景,帷幕后做各种准备工作,等灯光一黑,前台退场,到后台去准备下一次出场,而之前的后台走到帷幕前展示出来,如此循环。

这里主要新用到的是两个函数: void far setvisualpage(int pagenum);

该函数用来设置显示页,设置之后,之后写的代码都在屏幕上显示出来。 void far setactivepage(int pagenum);

该函数设置激活页,该函数之后的代码都是在都在该页上编辑,但是在没有使用显示函函数之前它是不会显示了。不过setbkcolor()设置背景色的效果会马上显示出来。

具体请看下面一个例子: 例11-1:

#include #include main() {

int i,graphdriver,graphmode,size,page; graphdriver=DETECT;

initgraph(&graphdriver,&graphmode,\ cleardevice();

setactivepage(1); /* 设置l页为编辑页 */ setbkcolor(BLUE); setcolor(RED); setfillstyle(1,10);

circle(130,270,30); /* 画圆 */ floodfill(130,270,4); /* 用淡绿色填充圆 */ setactivepage(0); /* 设置0页为编辑页 */ cleardevice(); /* 清0页 */ setfillstyle(1,5);

bar(100,210,160,270); /* 画方块并填充洋红色

setvisualpage(0); /* 设置0页为可视页 */ page=1;

*/ do{

setvisualpage(page); /* 显示设定页的图像 */

delay(8000); /* 延迟,这行请自行调整,现在的机子都应该套上个循环 才有如下图的效果,否则动画非常快*/ page=page-1; if(page<0) page=1; } while(!kbhit()); getch(); closegraph(); }

第六节 精确的时间控制手段

由于delay()函数的不精确性,动画代码在移植到别的计算机运行时会有很大差别,所以,本节就为了实现其可移植性而这种方法。

通过读取屏幕的垂直回扫中断来控制时间。其接口地址是0x3da ,通过

(inportb(0x3da)&0x08) 这句代码来获得该中断返回值的第四位的值,该位的特点就是垂直回扫过程中,它的值是1;垂直回扫结束后它的值是0。回扫频率是60赫兹,所以在一秒钟内,该值在0和1之间循环变化60次。这个速度不会改变。(以上讲到了部分硬件知识,中断的概念本来应该在本课程讲解的,但不用了解只要知道具体的用法即可,每次 使用只要套例子中的格式,有兴趣的话可以上网查找有关中断的知识)。

下面是套用的格式:在1秒钟内,动画代码执行60次

do { /* (游戏)循环 */

/* 利用屏幕的垂直回扫周期来控制游戏节奏 (60Hz) */

if ((inportb(0x3da)&0x08)!=0 && action_flag==0) /* 垂直回扫过程中 */ {

/* 动画代码写在这里 */ action_flag=1; }

else if ((inportb(0x3da)&0x08)==0 && action_flag==1) /* 垂直回扫过程结束后 */ {

action_flag=0; } } while (1);

下面,将例10-2改编,同样是两球相撞。(可能由于硬件问题无法实现) 例12-1

#include #include main() {

int i,graphdriver,graphmode,size,action_flag, sign; void *buffer;

graphdriver=DETECT;

initgraph(&graphdriver,&graphmode,\ setbkcolor(BLUE); cleardevice(); setcolor(YELLOW); setlinestyle(0,0,1); setfillstyle(1,5); circle(100,200,30);

floodfill(100,200,YELLOW); /* 填充圆 */ size=imagesize(69,169,131,231); /* 指定图像占字节数 */ buffer=malloc(size); /* 分配缓冲区(按字节数) */ getimage(69,169,131,231,buffer); /* 存图像 */

putimage(500,169,buffer,COPY_PUT); /* 重新复制 */ i=0; sign=0; do{

if ((inportb(0x3da)&0x08)!=0 && action_flag==0) /* 垂直回扫过程中 */ {

if(sign==0){

putimage(70+i,170,buffer,COPY_PUT); /*左边球向右运动*/ putimage(500-i,170,buffer,COPY_PUT); /*右边球向左运动*/ i++;

本文来源:https://www.bwwdw.com/article/jm2d.html

Top