设置一个好的时钟中断,将能使1个CPU发挥2个CPU的功效,大大方便和简化程序的编制,提高系统的运行效率和可操作性。我们可以把一些例行的或者需要定时执行的时钟中断中,还可以利用时钟中断完成定时、延时等操作。
对于一般的C语言爱好者而言,就如何在C中使用中断例程这一问题应该已经非常熟悉,例如,我们可以通过INT86()函数调用13H号中断直接对磁盘物理扇区进行操作,也可以通过INT86()函数调用33H号中断在屏幕上显示鼠标光标等。其实,13H号也好,33H号也好,它们只不过就是一些函数,这些函数的参数通过CPU的寄存器传递。中断号也只不过是间接地指向函数体的起始内存单元,说它是间接的,也就是说,函数的起始段地址和偏移量是由中断号通过一种方法算得的(具体如何操作,下面会作解释)。如此一来,程序员不必要用太多的时间去写操作硬件的程序了,只要在自己的程序中设置好参数,再调用BIOS或DOS提供的中断服务程序就可以了,大大减小了程序开发难度,缩短了程序开发周期。那么中断既然是函数,就可以由用户任意的调用、由用户任意地编写。
计算机内存的前1024个字节(偏移量00000H到003FFH)保存着256个中断向量,每个中断向量占4个字节,前两个字节保存着中断服务程序的入口地址偏移量,后两个字节保存着中断程序的入口段地址,使用时,只要将它们分别调入寄存器IP及CS中,就可以转入中断服务程序实现中断调用。每当中断发生时,CPU将中断号乘以4,在中断向量表中得到该中断向量地址,进而获得IP及CS值,从而转到中断服务程序的入口地址,调用中断。这就是中断服务程序通过中断号调用的基本过程。在计算机启动的时候,BIOS将基本的中断填入中断向量表,当DOS得到系统控制权后,它又要将一些中断向量填入表中,还要修改一部分BIOS的中断向量。有一部分中断向量是系统为用户保留的,如60H到67H号中断,用户可以将自己的中断服务程序写入这些中断向量中。不仅如此,用户还可以自己更改和完善系统已有的中断向量。
一、键盘中断的设计
例程如下:
/*键盘中断的设计*/
#include<stdio.h>
#include<dos.h>
#include<conio.h>
#include<math.h>
#include<bios.h>
#include<graphics.h>
#include<stdlib.h>
#include<string.h>
/*定义按键*/
#define ENTER 7181
#define UP 18432
#define DOWN 20480
#define LEFT 19200
#define RIGHT 19712
#define LOWERV 12150
/*定义delay()函数的间隔,根据电脑的不同请调节数字*/
#define TIME 1500
#define TIME2 1500
/*myi,myj是自己的坐标,number记录豆子数,seed,seed2是种子参数,为产生随机数*/
int myi,myj,number=0,seed=0,seed2=100;
int a[25][19]; /*a[][]记录每个方格的信息,1墙,6豆子*/
int d[4]={2,3,22,22},e[4]={5,16,3,16}; /*记录4个敌人的坐标,d记录横坐标,e纵坐标*/
int i,j,k;
/*指针记录自己坐标,以便于函数中的操作,具体请看moveright等函数*/
int* p1=&myi;
int* p2=&myj;
int q=0,z=0;
char num[4];
/*存储画面用*/
int size2,size3,size4,size5,size6;
void *buffer2;
void *buffer3;
void *buffer4;
void *buffer5;
void *buffer6;
/*主函数*/
int main(){
int graphdriver=VGA;
int graphmode=VGAHI;
int* moveup(int*,int*); /*该函数,自己向上移动一格,后三个类似*/
int* movedown(int*,int*);
int* moveleft(int*,int*);
int* moveright(int*,int*);
int dmove(int,int); /*怪的移动:和自己拉近距离*/
int dmove2(int,int); /*怪的移动:为了不让怪逼得太紧,该函数产生随机坐标,怪向那个坐标靠近一步*/
int zhadan1(int,int); /*炸弹*/
for(i=0;i<25;i++) /*数组a清零*/
for(j=0;j<19;j++)
a[i][j]=0;
for(i=0;i<25;i++) /*最边上一圈设为7,(只为了填充颜色表示界限)之后会参数改1,表示墙体*/
a[i][0]=7,a[i][18]=7;
for(j=0;j<19;j++)
a[0][j]=7,a[24][j]=7;
/*以下是墙体*/
a[6][1]=1;
a[13][1]=1;
a[2][2]=1;
a[20][2]=1;
a[4][3]=1;
a[8][3]=1;
a[22][3]=1;
a[2][4]=1;
a[6][4]=1;
a[13][4]=1;
a[18][4]=1;
a[15][5]=1;
a[4][6]=1;
a[7][7]=1;
a[10][7]=1;
a[20][7]=1;
a[3][8]=1;
a[5][8]=1;
a[16][8]=1;
a[12][9]=1;
a[2][10]=1;
a[19][10]=1;
a[22][10]=0;
a[5][11]=0;
a[10][11]=1;
a[17][12]=1;
a[14][13]=1;
a[22][13]=1;
a[3][14]=1;
a[7][14]=1;
a[5][15]=1;
a[10][15]=1;
a[2][16]=1;
a[14][16]=1;
a[19][16]=1;
a[6][17]=1;
a[16][17]=1;
a[9][1]=1;
a[11][2]=1;
a[16][2]=1;
a[9][5]=1;
a[11][5]=1;
a[22][5]=1;
a[1][7]=1;
a[17][6]=1;
a[22][5]=1;
a[13][7]=1;
a[23][7]=1;
a[18][8]=1;
a[8][9]=1;
a[15][10]=1;
a[13][11]=1;
a[3][12]=1;
a[8][12]=1;
a[20][12]=1;
a[1][13]=1;
a[12][14]=1;
a[16][14]=1;
a[19][14]=1;
a[11][17]=1;
/*以下是豆子*/
a[15][1]=6;
a[18][1]=6;
a[3][2]=6;
a[18][2]=6;
a[22][2]=6;
a[7][3]=6;
a[9][3]=6;
a[11][3]=6;
a[13][3]=6;
a[1][4]=6;
a[15][4]=6;
a[20][4]=6;
a[5][5]=6;
a[13][5]=6;
a[16][6]=6;
a[19][6]=6;
a[2][7]=6;
a[15][7]=6;
a[1][8]=6;
a[9][8]=6;
a[10][8]=6;
a[11][8]=6;
a[15][8]=6;
a[6][9]=6;
a[9][9]=6;
a[17][9]=6;
a[21][9]=6;
a[3][10]=6;
a[9][10]=6;
a[10][10]=6;
a[11][10]=6;
a[16][10]=6;
a[1][11]=6;
a[8][11]=6;
a[6][12]=6;
a[9][12]=6;
a[12][12]=6;
a[16][12]=6;
a[4][13]=6;
a[9][14]=6;
a[21][14]=6;
a[17][15]=6;
a[3][16]=6;
a[7][16]=6;
a[13][16]=6;
a[9][17]=6;
clrscr();
initgraph(&graphdriver,&graphmode,"");
/*墙体上色,参数1的为淡灰色,参数7的为棕色*/
for(i=0;i<25;i++)
for(j=0;j<19;j++)
{
if(a[i][j]==1)
{
setfillstyle(1,7);
bar(i*25+1,j*25+1,25*i+25,25*j+25);
}
if(a[i][j]==7)
{
setfillstyle(1,6);
bar(i*25+1,j*25+1,25*i+25,25*j+25);
}
}
/*参数7改1,表示墙体,以便于后边统一操作*/
for(i=0;i<25;i++)
a[i][0]=1,a[i][18]=1;
for(j=0;j<19;j++)
a[0][j]=1,a[24][j]=1;
/*画自己,一个扇形*/
setfillstyle(1,4);
pieslice(288,238,15,345,11);
myi=11,myj=9;
/*画敌人*/
setfillstyle(8,2);
for(i=0;i<4;i++)
{
bar(d[i]*25+3,e[i]*25+3,d[i]*25+24,e[i]*25+24);
}
/*画豆子*/
for(j=1;j<18;j++)
for(i=1;i<24;i++)
{
if(a[i][j]==6)
{
setfillstyle(1,14);
pieslice(i*25+13,j*25+13,0,360,9);
}
}
/*游戏的循环体开始了*/
/*游戏的循环体开始了*/
do{
int flag=0; /*flag记录游戏状态,1输,2豆子未吃完,继续游戏,0游戏胜利*/
int x,y,s=0;
int key;
/*判断一段时间内是否有按键按下,按下去执行按键判断部分,否则去执行敌人移动部分,用参数S来控制*/
for(i=0;i<50;i++)
{
delay(1);
if(bioskey(1)!=0)
{
s=1;
break;
}
}
if(s==1)
{
key=bioskey(0);
switch(key)
{ /*按键判断:前四个方向,最后一个炸弹*/
case UP:moveup(&myi,&myj);break;
case DOWN:movedown(&myi,&myj);break;
case RIGHT:moveright(&myi,&myj);break;
case LEFT:moveleft(&myi,&myj);break;
case LOWERV:zhadan1(myi,myj);break;
}
}
/*判游戏是否输了*/
for(i=0;i<4;i++)
{
if(myi==d[i]&&myj==e[i])
flag=1;
}
if(flag==1)
{
printf(" you lose! ");
getchar();
break;
}
/*根据敌人的移动,来设置敌人坐标的变化*/
for(z=0;z<4;z++)
if (q++%3==0)
{ /*每三次里面有一次为向自己移动,另两次随机动,可以把三改掉来修改游戏难度*/
x=dmove(d[z],e[z]);
if(x==1)
d[z]-- ;
else if(x==2)
d[z]++ ;
else if(x==3)
e[z]++ ;
else if(x==4)
e[z]-- ;
}
else
{
y=dmove2(d[z],e[z]);
if(y==1)
d[z]-- ;
else if(y==2)
d[z]++ ;
else if(y==3)
e[z]++ ;
else if(y==4)
e[z]-- ;
}
/*左上角显示拥有的豆子数*/
setfillstyle(1,8);
bar(1,1,150,22);
k=number;
itoa(k,num,10);
settextstyle(1,0,1);
outtextxy(1,1," your peas: ");
outtextxy(120,1,num);
/*敌人移动过了,所以再次判断是否输了*/
for(i=0;i<4;i++)
{
if(myi==d[i]&&myj==e[i])
flag=1;
}
if(flag==1)
{
printf(" you lose! ");
getchar();
break;
}
/*判断是否胜利*/
for(j=1;j<18;j++)
for(i=1;i<24;i++)
{
if(a[i][j]==6)
flag=2;
}
if(flag==0)
{
printf(" you win! ");
getchar();
break;
}
}while(1);
}
/*自己向右移动的函数:传地址进来,以便直接在函数中改坐标,而不用像怪移动那样在主函数里改坐标*/
int* moveright(int *p1 ,int *p2) {
if(a[*p1+1][*p2]!=1) /*右边不是墙体才可以动*/
{
/*这四行画自己,嘴巴向右*/
setfillstyle(1,0);
bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
setfillstyle(1,4);
pieslice(*p1*25+13,*p2*25+13,15,345,11);
/*保存自己的图像,以便于动画*/
size2=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
buffer2=malloc(size2);
getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer2);
/*向右移动时的动画*/
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(*p1*25+i+1,*p2*25+1,*p1*25+i+2,*p2*25+25); /*每次把最左边一条竖线擦掉*/
putimage(*p1*25+i+2,*p2*25+1,buffer2,0); /*每次图像显示向右一个像素*/
delay(TIME2);
}
(*p1)++; /*自己的横坐标加1*/
if(a[*p1][*p2]==6) /*移动后有豆子就吃掉,同时参数6被改掉*/
a[*p1][*p2]=4,number++;
free(buffer2); /*释放存储图像的指针,不然移动多次后内存不够用,会去侵占number变量的 内存,导致number变0,这个问题自己调试了好久*/
}
}
/*自己向右移动的函数,由于pieslice()函数无法一笔画(反正我自己不会),所以画图像要解释下*/
int* moveleft(int *p1,int *p2)
{
if(a[*p1-1][*p2]!=1)
{
setfillstyle(1,0); /*先把当前一格变成背景黑色 */
bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
setfillstyle(1,4); /*画个红色的圆,默认白色边界*/
fillellipse(*p1*25+13,*p2*25+13,11,11);
setfillstyle(1,0); /*画个黑色扇形,这个可以一笔画,但是边界是白色,相当于嘴巴被白色封了*/
pieslice(*p1*25+13,*p2*25+13,162,202,11); /*至于为什么是162°到202°,因为160-200显示的时 候多个角,不知道为什么*/
setcolor(0); /*设置 黑色*/
arc(*p1*25+13,*p2*25+13,157,200,11); /*用黑色的线画一条弧,用来覆盖原来的白色*/
setcolor(15); /*把前景色还原为白色,不然以后画出来的都要黑色了*/
/*这些跟上面函数一样,不罗嗦了,之后的两个函数也一样*/
size3=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
buffer3=malloc(size3);
getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer3);
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(*p1*25+24-i,*p2*25+1,*p1*25+25-i,*p2*25+25);
putimage(*p1*25-i,*p2*25+1,buffer3,0);
delay(TIME2);
}
(*p1)--;
if(a[*p1][*p2]==6)
a[*p1][*p2]=4,number++;
free(buffer3);
}
}
int* moveup(int* p1,int* p2)
{
if(a[myi][myj-1]!=1)
{
setfillstyle(1,0);
bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
setfillstyle(1,4);
fillellipse(*p1*25+13,*p2*25+13,11,11);
setfillstyle(1,0);
pieslice(*p1*25+13,*p2*25+13,70,110,11);
setcolor(0);
arc(*p1*25+13,*p2*25+13,70,110,11);
setcolor(15);
size4=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
buffer4=malloc(size4);
getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer4);
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(*p1*25+1,*p2*25+24-i,*p1*25+25,*p2*25+25-i);
putimage(*p1*25+1,*p2*25-i,buffer4,0);
delay(TIME2);
}
(*p2)--;
if(a[*p1][*p2]==6)
number++,a[*p1][*p2]=4;
free(buffer4);
}
}
int* movedown(int *p1,int *p2)
{
if(a[myi][myj+1]!=1)
{
setfillstyle(1,0);
bar(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
setfillstyle(1,4);
fillellipse(*p1*25+13,*p2*25+13,11,11);
setfillstyle(1,0);
pieslice(*p1*25+13,*p2*25+13,250,290,11);
setcolor(0);
arc(*p1*25+13,*p2*25+13,247,288,11);
setcolor(15);
size5=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
buffer5=malloc(size5);
getimage(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25,buffer5);
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(*p1*25+1,*p2*25+1+i,*p1*25+25,*p2*25+i+1);
putimage(*p1*25+1,*p2*25+2+i,buffer5,0);
delay(TIME2);
}
(*p2)++;
if(a[*p1][*p2]==6)
number++,a[*p1][*p2]=4;
free(buffer5);
}
}
/*怪的移动:向自己靠近*/
int dmove(d,e)
{
if(d-myi>0&&a[d][e]==6&&a[d-1][e]!=1)
{
/*怪在自己的右方&&怪现在的坐标有豆子&&左边一格不 是墙*/
/* 怪移动的动画*/
for(i=0;i<25;i++)
{
setfillstyle(1,0); /*每次用背景黑色擦掉最右边一竖线*/
bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);
setfillstyle(8,2); /*每次在左边画一条线,怪设计成正方形方便(不用图像存储),偷个懒*/
bar(d*25-i,e*25+1,d*25+1-i,e*25+25);
delay(TIME);
}
/*因为有豆子,所以添上豆子*/
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 1; /*1传回去表示让怪的横坐标要减一*/
}
else if(d-myi>0&&a[d-1][e]!=1&&a[d][e]!=6)
{
/*没豆子的情况:本来可以和上面合并,不改了*/
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);
setfillstyle(8,2);
bar(d*25-i,e*25+1,d*25+1-i,e*25+25);
delay(TIME);
}
return 1;
}
if(d-myi<0&&a[d][e]==6&&a[d+1][e]!=1)
{
/*怪在自己的左方,有豆子,其他都同上上面那个*/
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);
setfillstyle(8,2);
bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);
delay(TIME);
}
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 2;
}
else if(d-myi<0&&a[d+1][e]!=1&&a[d][e]!=6)
{ /*怪在自己左方,没豆子*/
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);
setfillstyle(8,2);
bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);
delay(TIME);
}
return 2;
}
/*如果横坐标和自己同或者左右移动时碰到墙了,就要动纵坐标了,和上面几乎一样*/
if(d==myi||(d-myi<0&&a[d+1][e]==1)||(d-myi>0&&a[d-1][e]==1))
{
if(e-myj<0&&a[d][e]==6&&a[d][e+1]!=1)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);
setfillstyle(8,2);
bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i);
delay(TIME);
}
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 3;
}
else if(e-myj<0&&a[d][e+1]!=1&&a[d][e]!=6)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);
setfillstyle(8,2);
bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i);
delay(TIME);
}
return 3;
}
if(e-myj>0&&a[d][e]==6&&a[d][e-1]!=1)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);
setfillstyle(8,2);
bar(d*25+1,e*25-i,d*25+25,e*25+1-i) ;
delay(TIME);
}
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 4;
}
else if(e-myj>0&&a[d][e-1]!=1&&a[d][e]!=6)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);
setfillstyle(8,2);
bar(d*25+1,e*25-i,d*25+25,e*25+1-i);
delay(TIME);
}
return 4;
}
}
}
/*怪随机动,其实和前面那个一样,就是和自己坐标myi,myj比较变成了和随机产生的坐标(a1,b)比较,既然一样,就不多说,产生随机数解释下*/
int dmove2(d,e)
{
int a1,b;
srand(seed++); /*种子每次要变,不然产生的随机数会相同*/
a1=rand()%24; /*取余数才能使坐标落在我游戏画面内*/
b=rand()%18;
if(d-a1>0&&a[d][e]==6&&a[d-1][e]!=1)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);
setfillstyle(8,2);
bar(d*25-i,e*25+1,d*25+1-i,e*25+25);
delay(TIME);
}
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 1;
}
else if(d-a1>0&&a[d-1][e]!=1&&a[d][e]!=6){
for(i=0;i<25;i++){
setfillstyle(1,0);
bar(d*25+25-i,e*25+1,d*25+26-i,e*25+25);
setfillstyle(8,2);
bar(d*25-i,e*25+1,d*25+1-i,e*25+25);
delay(TIME);
}
return 1;
}
if(d-a1<0&&a[d][e]==6&&a[d+1][e]!=1)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);
setfillstyle(8,2);
bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);
delay(TIME);
}
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 2;
}
else if(d-a1<0&&a[d+1][e]!=1&&a[d][e]!=6)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1+i,e*25+1,d*25+2+i,e*25+25);
setfillstyle(8,2);
bar(d*25+25+i,e*25+1,d*25+26+i,e*25+25);
delay(TIME);
}
return 2;
}
if(d==a1||(d-a1<0&&a[d+1][e]==1)||(d-a1>0&&a[d-1][e]==1))
{
if(e-b<0&&a[d][e]==6&&a[d][e+1]!=1)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);
setfillstyle(8,2);
bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i) ;
delay(TIME);
}
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 3;
}
else if(e-b<0&&a[d][e+1]!=1&&a[d][e]!=6)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+1+i,d*25+25,e*25+2+i);
setfillstyle(8,2);
bar(d*25+1,e*25+25+i,d*25+25,e*25+26+i) ;
delay(TIME);
}
return 3;
}
if(e-b>0&&a[d][e]==6&&a[d][e-1]!=1)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);
setfillstyle(8,2);
bar(d*25+1,e*25-i,d*25+25,e*25+1-i);
delay(TIME);
}
setfillstyle(1,14);
pieslice(d*25+13,e*25+13,0,360,9);
return 4;
}
else if(e-b>0&&a[d][e-1]!=1&&a[d][e]!=6)
{
for(i=0;i<25;i++)
{
setfillstyle(1,0);
bar(d*25+1,e*25+24-i,d*25+25,e*25+25-i);
setfillstyle(8,2);
bar(d*25+1,e*25-i,d*25+25,e*25+1-i) ;
delay(TIME);
}
return 4;
}
}
}
/*炸弹的函数*/
int zhadan1(myi,myj)
{
if(number<3) /*豆子数比三大才能炸*/
return 0;
else
{
number=number-3; /*炸一次消耗三个豆子*/
/*保存自己的图像*/
size6=imagesize(*p1*25+1,*p2*25+1,*p1*25+25,*p2*25+25);
buffer6=malloc(size6);
getimage(myi*25+1,myj*25+1,myi*25+25,myj*25+25,buffer6);
/*判断怪是否在炸弹的威力范围里面,若在,怪的坐标变掉,用随机数产生,但是不能产生在墙里,也不能靠自己太近*/
for(i=0;i<4;i++)
{
if(myi-1==d[i]&&myj==e[i])
{
do{
srand(seed2++);
d[i]=rand()%24;
e[i]=rand()%18;
}while(a[d[i]][e[i]]==1||(d[i]-myi)*(d[i]-myi)+(e[i]-myj)*(e[i]-myj)<5);
setfillstyle(1,7);
bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);
}
else if(myi+1==d[i]&&myj==e[i])
{
do{
srand(seed2++);
d[i]=rand()%24;
e[i]=rand()%18;
}while(a[d[i]][e[i]]==1||d[i]==myi&&e[i]==myj);
setfillstyle(1,7);
bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);
}
else if(myi==d[i]&&myj-1==e[i])
{
do{
srand(seed2++);
d[i]=rand()%24;
e[i]=rand()%18;
}while(a[d[i]][e[i]]==1||d[i]==myi&&e[i]==myj) ;
setfillstyle(1,7);
bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);
}
else if(myi==d[i]&&myj+1==e[i])
{
do{
srand(seed2++);
d[i]=rand()%24;
e[i]=rand()%18;
}while(a[d[i]][e[i]]==1||d[i]==myi&&e[i]==myj);
setfillstyle(1,7);
bar(d[i]*25+1,e[i]*25+1,d[i]*25+25,e[i]*25+25);
}
else
seed2++;
}
/*画一个方格的炸弹作为动画的开始*/
setfillstyle(7,13);
bar(myi*25+1,myj*25+1,myi*25+25,myj*25+25);
/*炸弹的动画,每次在上一步的基础上,上下左右各添一条线*/
for(i=0;i<24;i++)
{
setfillstyle(7,13);
bar(myi*25-1-i,myj*25+1,myi*25-i,myj*25+25);
bar(myi*25+26+i,myj*25+1,myi*25+27+i,myj*25+25);
bar(myi*25+1,myj*25-1-i,myi*25+25,myj*25+25);
bar(myi*25+1,myj*25+26+i,myi*25+25,myj*25+27+i);
delay(2000);
}
delay(10000);
/*炸弹动画结束以后把炸弹炸到的区域清成背景黑色*/
setfillstyle(1,0);
bar(myi*25-24,myj*25+1,myi*25+50,myj*25+25);
bar(myi*25+1,myj*25-24,myi*25+25,myj*25+50);
/*如果该范围里面有墙体,要重新补上*/
for(i=myi-1;i<=myi+1;i++)
for(j=myj-1;j<=myj+1;j++)
{
if(a[i][j]==1)
{
if(i==0||i==24||j==0||j==18)
setfillstyle(1,6),bar(i*25+1,j*25+1,25*i+25,25*j+25);
else
setfillstyle(1,7),bar(i*25+1,j*25+1,25*i+25,25*j+25);
}
}
/*炸弹范围内的豆子被炸掉,所以参数6要被改掉,索性非墙的方格参数全设为5*/
for(i=myi-1;i<=myi+1;i++)
{
if(a[i][myj]!=1)
a[i][myj]=5;
}
for(i=myj-1;i<=myj+1;i++)
{
if(a[myi][i]!=1)
a[myi][i]=5;
}
/*最后把自己的图像补上*/
putimage(myi*25+1,myj*25+1,buffer6,0);
free(buffer6);
}
}
二、鼠标中断的设计
例程如下:
头文件例程
/*鼠标中断设计*/
#ifndef __KEY_MOU_H__
#define __KEY_MOU_H__
#include<stdio.h>
#include<graphics.h>
#include<dos.h>
#include<stdlib.h>
union REGS regs;
void shubiao(int x,int y);
int init(int xmin,int xmax,int ymin,int ymax);
void read();
void cursor(int x,int y);
void newxy();
void mouse_scan1(int * x,int * y,int * buttons,int * done1,int * help);
void mouse_scan2(int * x,int * y,int * buttons,int * done2,int *done);
#define KB_S_N_DOWN 80 //定义各功能键的扫描码
#define KB_S_N_UP 72
#define KB_S_N_HOME 71
#define KB_S_N_END 79
#define KB_S_N_ENTER 28
#define KB_S_N_F1 59
#define KB_S_N_D 32
#define KB_S_N_H 35
#define KB_S_N_O 24
#define KB_S_N_Q 16
#define KB_S_N_X 45
#define KB_S_N_B 0x3062
int getkey();
void key_scan1(int it_num,int * done1,int * hp,void * buffer);
void key_scan2(int it_num,int * done2,int * done,void *buffer);
int row=0;
extern int a;
int help();
void quit(void * buffer);
#endif
函数体例程
/*鼠标中断设计*/
#include"key_mou.h"
/*************鼠标函数*********************/
void shubiao(int x,int y)
{
int xmin=2;
int xmax=638;
int ymin=2;
int ymax=478;
setwritemode(XOR_PUT);
if(init(xmin,xmax,ymin,ymax)==0)
{
printf("Mouse or Mouse Driver Absent,Please Install!");
delay(5000);
exit(1);
}
cursor(x,y);
delay(5);
}
int init(int xmin,int xmax,int ymin,int ymax)
{
int retcode;
regs.x.ax=0; //鼠标复位及取状态
int86(51,®s,®s);
retcode=regs.x.ax;
if(retcode==0)
{
return 0; //返回0表示鼠标或鼠标驱动程序未安装
}
regs.x.ax=7; //设置水平位置最大值
regs.x.cx=xmin;
regs.x.dx=xmax;
int86(51,®s,®s);
regs.x.ax=8; //设置垂直位置最大值
regs.x.cx=ymin;
regs.x.dx=ymax;
int86(51,®s,®s); //表示鼠标器和安装程序已安装
return retcode;
}
void read(int *px,int *py,int *mbutt) //读鼠标的按键位置和按键状态
{
regs.x.ax=3; //取按钮状态和鼠标位置
int86(51,®s,®s);
* px=regs.x.cx;
* py=regs.x.dx;
* mbutt=regs.x.bx;
delay(100);
}
void cursor(int x,int y) //画十字光标函数
{
setwritemode(1);
setcolor(BLUE);
setlinestyle(0,0,1);
line(x,y,x,y+11);
line(x+1,y+1,x+1,y+10);
line(x+2,y+2,x+2,y+9);
line(x+3,y+3,x+8,y+8);
line(x+3,y+4,x+7,y+8);
line(x+3,y+5,x+6,y+8);
line(x+3,y+6,x+5,y+8);
line(x+3,y+7,x+4,y+8);
line(x+3,y+8,x+3,y+8);
setwritemode(0);
}
void newxy(int * x,int * y,int * mbutt)
{
int xx0=* x,yy0=* y;
int mx,my;
read(&mx,&my,mbutt);
cursor(xx0,yy0);
cursor(mx,my);
delay(5);
* x=mx;
* y=my;
}
/***************菜单一中扫描鼠标**********************/
void mouse_scan1(int * x,int * y,int * buttons,int * done1,int * hp)
{
int k=0;
/*读鼠标*/
newxy(x,y,buttons);
if(* x>=210&&* x<=435&&* y>=215&&* y<=260&&* buttons==1)
{
* done1=1;
}
else if(* x>=210&&* x<=435&&* y>=260&&* y<=305&&* buttons==1)
{
k=help();
if(k==1)
{
cleardevice();
* done1=1;
* hp=1;
}
}
else if(* x>=210&&* x<=435&&* y>=305&&* y<=350&&* buttons==1)
{
cleardevice();
closegraph();
exit(0); //回到系统
}
}
/*****************菜单二中扫描鼠标*************************/
void mouse_scan2(int * x,int * y,int * buttons,int * done2,int *done)
{
/*读鼠标*/
newxy(x,y,buttons);
if(*x>=400&&* x<=530&&*y>=160&&* y<=200&&* buttons==1)
{
a=1; //进入单人游戏
* done2=1;
* done=1;
}
else if(* x>=400&&* x<=530&&* y>=220&&* y<=260&&* buttons==1)
{
a=2; //进入双人游戏
* done2=1;
* done=1;
}
else if(* x>=400&&* x<=530&&* y>=220&&* y<=320&&* buttons==1)
{
cleardevice();
* done2=1;
}
}
/*******************键盘函数*************************/
int getkey()
{
union REGS rg;
rg.h.ah=0;
int86(0x16,&rg,&rg);
return rg.h.ah;
}
/*****菜单一中扫描键盘*******/
void key_scan1(int it_num,int * done1,int * hp,void * buffer)
{
int key=0;
int k=0;
key=getkey();
switch(key)
{
case KB_S_N_UP:
putimage(180,220+row*45,buffer,XOR_PUT); //消除原来的光标
row-=1;
if(row==-1)
{
row=it_num-1;
}
putimage(180,220+row*45,buffer,XOR_PUT); //光标上移并显示
break;
case KB_S_N_DOWN:
putimage(180,220+row*45,buffer,XOR_PUT); //消除原来的光标
row+=1;
if(row==3)
{
row=0;
}
putimage(180,220+row*45,buffer,XOR_PUT); //光标下移并显示
break;
case KB_S_N_F1:
k=help();
if(k==1)
{
cleardevice();
* done1=1;
* hp=1;
}
break;
case KB_S_N_X:
quit(buffer);
break;
case KB_S_N_ENTER:
switch(row)
{
case 0: * done1=1;
break;
case 1: k=help();
if(k==1)
{
cleardevice();
* done1=1;
* hp=1;
}
break;
case 2: quit(buffer);
break;
}
break;
case 0:
break;
}
}
/*******菜单二中键盘扫描键盘*********/
void key_scan2(int it_num,int * done2,int * done,void *buffer)
{
int key=0;
key=getkey();
switch(key)
{
case KB_S_N_UP:
putimage(375,170+row*60,buffer,XOR_PUT); //消除原来的光标
row-=1;
if(row==-1)
{
row=it_num-1;
}
putimage(375,170+row*60,buffer,XOR_PUT); //光标上移并显示
break;
case KB_S_N_DOWN:
putimage(375,170+row*60,buffer,XOR_PUT); //消除原来的光标
row+=1;
if(row==3)
{
row=0;
}
putimage(375,170+row*60,buffer,XOR_PUT); //光标下移并显示
break;
case KB_S_N_ENTER:
switch(row)
{
case 0: a=1; //进入单人模式
* done2=1;
* done=1;
break;
case 1: a=2; //进入双人模式
* done2=1;
* done=1;
break;
case 2: cleardevice();
setbkcolor(BLACK);
* done2=1;
break;
}
break;
case 0:
break;
}
}
三、禁用鼠标中断或键盘中断的设计
例程如下:
/*禁用键盘中断或鼠标中断的设计*/
#define _WIN32_WINNT 0x0400
#include <windows.h>
HHOOK mouseHook = NULL;
HHOOK keyboardHook = NULL;
HINSTANCE hInst = NULL;
int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
break;
case DLL_PROCESS_DETACH:
if (keyboardHook)
{
UnhookWindowsHookEx(keyboardHook);
}
if (mouseHook)
{
UnhookWindowsHookEx(mouseHook);
}
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return 1;
}
long CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
return 1;
}
long CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam)
{
return 1;
}
BOOL CALLBACK LockKeyboard(BOOL bDisable)
{
if (bDisable)
{
if (keyboardHook == NULL)
{
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, hInst, NULL);
}
if (mouseHook == NULL)
{
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseProc, hInst, NULL);
}
return keyboardHook != NULL && mouseHook != NULL;
}
else
{
if (keyboardHook && UnhookWindowsHookEx(keyboardHook))
{
keyboardHook = NULL;
}
return keyboardHook == NULL && mouseHook == NULL;
}
}
//调用事例
C/C++ code
#include <windows.h>
#define DLLFILENAME TEXT("locklib.dll")
typedef BOOL (__stdcall *LockKeyboard)(BOOL);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("AutoUpgrade") ;
MSG msg ;
HWND hwnd ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (hInstance, szAppName) ;
wndclass.hCursor = NULL
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
return 0 ;
}
hwnd = CreateWindow (szAppName,
TEXT ("AutoUpgrade"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
ShowCursor(FALSE);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInstance;
static LockKeyboard lockKeyboard;
switch (message)
{
case WM_CREATE:
hInstance = LoadLibrary(DLLFILENAME);
if (hInstance)
{
lockKeyboard = (LockKeyboard)GetProcAddress(hInstance, TEXT("LockKeyboard"));
if (lockKeyboard != NULL)
{
(lockKeyboard)(TRUE);
}
}
break;
case WM_DESTROY :
if (lockKeyboard)
{
(lockKeyboard)(FALSE);
}
if (hInstance)
{
FreeLibrary(hInstance);
}
PostQuitMessage (0);
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}