#include "graphics.h" /*图形系统头文件*/
#include <stdlib.h>
#define SCREEN_W 640
#define SCREEN_H 480
#define LEFT 0x4b00 /*光标左键值*/
#define RIGHT 0x4d00 /*光标右键值*/
#define DOWN 0x5000 /*光标下键值*/
#define UP 0x4800 /*光标上键值*/
#define ESC 0x011b /* ESC键值*/
#define ENTER 0x1c0d /* 回车键值*/
#define SPACE 0x3920 /*空格键*/
int SPEED= 50; /*调速度,下面的是调最多出现的炸弹数*/
int NUM=5; /*记录炸弹总数(屏幕中有炸弹的最大数字)*/
int score=100 ; /*记录分数的变量*/
int boom_num=0; /*记录炸弹实际数目*/
struct PLANE /*飞机的结构体,包含它的位置和生命*/
{ int x;
int y;
int life;
} plane={320,400,5};
struct BOOM
{
int x; /*子弹的出生位置的整数形式*/
int y;
double xd; /*子弹的出生位置的浮点数,即实际值*/
double yd;
double xp; /*炸弹移动的时候在正交方向的偏移量,用来描述矢量*/
double yp;
int display; /*描述出现的变量,0为出现*/
int color; /*描述分值的,用颜色表示,不同颜色表示不同分值。本游戏没有细化什么颜色代表什么分值,仅仅是娱乐*/
}boom[16];
struct SHOOT
{ int x; /*射出的子弹的起始位置*/
int y;
int display;/*描述该子弹是否发射*/
int hit;/*描述是否打中目标,0表示打中*/
}shoot[64];
int GameOver(void) /*游戏结束*/
{
cleardevice();
setcolor(RED);
settextstyle(0,0,4);
outtextxy(180,200,"GAME OVER");
getch();
}
int PrScore() /*画得分的函数,我为了能分清各个模块所以分开写的,可以和draw()函数合并*/
{
char str_score[10];
char str_life[10];
setfillstyle(SOLID_FILL,BLACK); /*为了能够每次轨迹移动后把前面的画面画黑,有刷新的效果*/
bar(50,6,400,12);
setcolor(6);
settextstyle(0,0,1);
sprintf(str_score,"SCORE:%d",score); /*拼接字符串*/
outtextxy(30,6,str_score); /*输出改字符串*/
sprintf(str_life,"LIFE:%d",plane.life);
outtextxy(130,6,str_life);
}
void draw_boom(struct BOOM boom ,int color) /*用指定颜色画一个炸弹*/
{
if(!boom.display)
{
setfillstyle(SOLID_FILL,color);
fillellipse(boom.x,boom.y,10,10); /*炸弹就是一个球模型*/
}
}
void draw_shoot(struct SHOOT shoot,int color) /*用指定的颜色画一个子弹*/
{
if(!shoot.display)
{
setfillstyle(SOLID_FILL,BLACK);
fillellipse(shoot.x,shoot.y-1,3,5); /*盖住前面一个的残留*/
setfillstyle(SOLID_FILL,color);
fillellipse(shoot.x,shoot.y,3,5); /*炸弹就是一个球模型*/
}
}
void draw_plane(int x,int y,int color) /*这个函数用来在指定位置画一个指定颜色的飞机*/
{
int array[6];
array[0]=x;
array[1]=y;
array[2]=x+60;
array[3]=y+30;
array[4]=x-60;
array[5]=y+30;
setcolor(BLACK);
setfillstyle(SOLID_FILL,color);
fillellipse(x,y,10,50);
fillpoly(3,array); /*此函数和一个至少有2n元素的一维数组配合,画一个有n个顶点的多边形*/
fillellipse(x,y+45,10,3);
fillellipse(x-30,y+15,3,20) ;
fillellipse(x+30,y+15,3,20) ;
}
int play(void) /*游戏主函数*/
{
int i=0; /*记录子弹数目用的变量*/
int j=0;
int p,q; /*计数变量,无实际意义*/
int key; /*接收按键值临时储存变量*/
int b;/*记录随机产生数,记录炸弹的*/
char str_speed[10]; /*这两个数组用来记录在设置界面的速度和炸弹数的提示字符串*/
char str_booms[10];
int SELECT = 0; /*用来记录在设置界面,选中的是哪个设置项*/
START: /*游戏界面*/
/*
PrScore() ; /*刷新一下得分*/
draw_plane(plane.x,plane.y,25) ; /*按键后,要画一个新的飞机*/
*/
while(!kbhit())
{
if (SPEED<300)SPEED=50+score/500*50;
PrScore() ;
draw_plane(plane.x,plane.y,25) ; /*按键后,要画一个新的飞机*/
/*扫描绘制子弹的部分*/
for(j=0;j<64;j++)
{
if(shoot[j].display==0)
{
draw_shoot(shoot[j],15);
shoot[j].y -=1; /*子弹移动起来,动画效果*/
if(shoot[j].y<10) /*如果子弹接近边界,则将子弹的显示标记去掉,并且用黑色抹去最后一个轨迹*/
{
draw_shoot(shoot[j],BLACK);
shoot[j].display=1;
}
}
}
/*以下是随机生成炸弹*/
boom_num=0;
for(j=0;j<16;j++){ if(boom[j].display==0)boom_num+=1;} /*检查屏幕中炸弹数目*/
b=random(16); /*生成随机(颜色)炸弹*/
if (boom[b].display!=0 && boom_num < NUM) /**屏幕中炸弹数目不够多,并且随机随到的炸弹不是已经显示了的*/
{
boom[b].display=0;
boom[b].xd=10.0001+random(630); /*初始化炸弹坐标*/
boom[b].yd=10.0001+random(300);
boom[b].xp=0.03+random(5)*SPEED/500.0; /*初始化移动速度*/
boom[b].yp=0.03+random(5)*SPEED/500.0;
if( boom[b].xd>320.0 )boom[b].xp*=-1; /*这两行的作用是,如果随机位置靠角落了,就往相反方向走*/
if( boom[b].yd>240.0 )boom[b].yp*=-1; /*作用是防止炸弹刚出来就离开屏幕了*/
}
/*扫描绘制炸弹部分*/
for(j=0;j<16;j++)
{
if(boom[j].display==0)
{
boom[j].yd+=boom[j].yp;
boom[j].xd+=boom[j].xp;
draw_boom(boom[j],BLACK); /*用黑色盖住前面一个,动画效果*/
boom[j].x=(int)boom[j].xd; /*炸弹移动起来*/
boom[j].y=(int)boom[j].yd;
draw_boom(boom[j],boom[j].color); /*画上新的*/
if(boom[j].y<20||boom[j].y>460||boom[j].x<20||boom[j].x>620)
{
draw_boom(boom[j],BLACK);
boom[j].display=1; /*当炸弹离开屏幕,那么炸弹显示位标记非0,炸弹总数减1,用黑色抹去离开时候最后一个炸弹样子*/
score-=10; /*没打中的炸弹离开了屏幕扣10分*/
if (score<0)return (GameOver());
}
}
}
/*扫描打中的部分*/
for(p=0;p<64;p++)
{
for(q=0;q<16;q++)
{
if(boom[q].display==0&&0==shoot[p].display) /*限定判断的子弹和炸弹都必须是在屏幕上的*/
{
if(abs(boom[q].x-shoot[p].x)<10 && abs(boom[q].y-shoot[p].y)<10)
{ /*如果距离过近说明打中*/
setfillstyle(SOLID_FILL,BLACK);
fillellipse(boom[q].x,boom[q].y,20,20); /*打中后相关的一片都抹去*/
boom[q].display=1; /*都不再显示了*/
shoot[p].display=1;
score+=20; /*打中了加分,暂时每个不同的分用颜色表示*/
}
}
}
}
/*炸弹碰到飞机的部分*/
for(q=0;q<16;q++)
{
if(boom[q].display==0&&plane.life>0)
{
if(abs(boom[q].x-plane.x)<30 && abs(boom[q].y-plane.y)<50)
{ /*如果距离过进说明打中*/
setfillstyle(SOLID_FILL,BLACK);
fillellipse(boom[q].x,boom[q].y,20,20); /*打中后相关的一片都抹去*/
boom[q].display=1;
plane.life-=1;
if (0==plane.life)return (GameOver()); /*结束游戏,函数出口2*/
}
}
}
} /*while()结束,下面是处理按键的循环*/
if (i==64)i=0; /*循环利用子弹,一般一个屏幕最多不会有这么多子弹吧*/
key=bioskey(0);/*接收按键*/
if (ESC==key)return 0;/*程序中断,游戏出口*/
if(ENTER==key) /*进入设置界面,先画背景,再在循环中重绘数字*/
{
setfillstyle(SOLID_FILL,26);
bar(SCREEN_W/2-160,SCREEN_H/2-100,SCREEN_W/2+160,SCREEN_H/2+100); /*漆一个矩形框*/
setcolor(BLACK);
settextstyle(0,0,3);/*设置显示字体的大小*/
outtextxy(SCREEN_W/2-130,SCREEN_H/2-80,"SPEED:"); /*下面几行是用来画在设置界面的提示文字*/
outtextxy(SCREEN_W/2-130,SCREEN_H/2-30,"BOOMS:");
setcolor(BLACK);
settextstyle(0,0,1);
outtextxy(SCREEN_W/2-140,SCREEN_H/2+30,"press UP or DOWN to select");
outtextxy(SCREEN_W/2-140,SCREEN_H/2+50,"press LE