首先我们写一下项目所需要的头文件
#include<stdio.h>//标准输入输出头文件#include<math.h>//数学库头文件#include<graphics.h>//EasyX图形库头文件#include<mmsystem.h>//多媒体音乐库头文件#pragmacomment(lib,"winmm.lib")//导入winmm库#pragmawarning(disable:4996)//4996警告杂注12345
接下来在涵盖几个宏定义进来
#defineWIDTH600//窗口宽度#defineWEIGHT400//窗口高度#defineNUM10//屏幕上所产生气球,子弹的最大数量12
然后我们开始打造一个漂亮的欢迎界面,这里需要二张图片,我把它贴出来。
1.jpg:
2.jpg:
图片有了,上代码,首先先在全局部分定义图片属性
IMAGEimg[2];
voidWelcome()//实现欢迎界面的函数{
loadimage(&img[0],"1.jpg",150,400);//加载图片
loadimage(&img[1],"2.jpg",450,400);//参数含义(图片地址,图片路径,图片宽,图片高)
putimage(0,0,&img[0]);//显示图片
putimage(150,0,&img[1]);//参数含义(显示坐标x,y+图片属性)
while(1)
{
if(MouseHit())//判断是否有鼠标消息
{
MOUSEMSGmsg=GetMouseMsg();//获取当前鼠标消息
if(msg.uMsg==WM_LBUTTONDOWN)//如果鼠标左键按下
{
return;//返回主函数
}
}
}}1234567891011121314151617
接下来我们开始准备音乐部分(音乐不方便贴出来,可以自己去网上找合适的)
我们为了不影响程序运行效率,决定使用多线程的方式实现音乐播放
背景音乐:
DWORDWINAPIMusic(LPVOIDlpParamter){
mciSendString("openmusic.mp3aliasBGM",0,0,0);//加载音乐
mciSendString("playBGMrepeat",0,0,0);//播放音乐
//repeat代表无限循环播放
while(1);}123456
气球爆炸音效:
DWORDWINAPIMCC(LPVOIDlpParamter){
mciSendString("openfill.mp3aliasBCC",0,0,0);
mciSendString("playBCC",0,0,0);
return0;}12345
做游戏之前,我们先把游戏中的炮台,气球,子弹这3个元素用结构体抽象出来
structBattery//炮台{//炮管二点的横纵坐标
intx;
inty;
intendx;
intendy;
intlen;
//炮管发射出来的子弹的速度
intspeed;
//炮管倾斜的弧度
doubleradian;
//玩家的游戏得分
intscore;}bat;structbullet{//子弹的横纵坐标
intx;
inty;
//子弹的半径
intr;
//子弹向炮管方向的位移量
intvx;
intvy;
//子弹是否存在的标志
boolfalg;
//炮管倾斜的弧度
doubleradian;
//子弹的颜色
DWORDcolor;}ball[NUM];structBalloon{//气球的横纵坐标
intx;
inty;
//气球的颜色
DWORDcolor;
//气球是否存在的标志
boolfalg;}boon[NUM];123456789101112131415161718192223242526272829303132333435363738394041
下面我们来初始化数据
voidGameInit(){
srand(GetTickCount());
bat.x=WIDTH/2;
bat.y=WEIGHT-10;
bat.len=50;
bat.endx=bat.x;
bat.endy=bat.y-bat.len;
bat.speed=7;
bat.score=0;
for(inti=0;i<NUM;i++)
{
ball[i].falg=false;
}//因为一开始子弹不存在,子弹需要鼠标点击才生成一个,所以我们先初始化为不存在(false代表不存在)
for(inti=0;i<NUM;i++)
{
//随机坐标
boon[i].x=rand()%(WIDTH-30);
boon[i].y=rand()%(WEIGHT-60);
//随机颜色
boon[i].color=RGB(rand()%256,rand()%256,rand()%256);
boon[i].falg=true;
}//因为气球是游戏一开始就要有的,所以我们把它全部初始化为true(存在),并且初始化坐标,颜色}123456789101112131415161718192223
接下来我们来把数据变得“看的见”
voidGameDraw(){
BeginBatchDraw();//开始双缓冲
setbkcolor(RGB(114,191,207));//设置窗口背景颜色
cleardevice();//清屏
for(inti=0;i<NUM;i++)//遍历所有气球(所有包括存在和不存在)
{
if(boon[i].falg==true)//如果气球存在
{
//画气球
setlinestyle(PS_SOLID,0.1);//设置线条风格PS_SOLID表示实线,0.1表示线条粗细程度
setlinecolor(WHITE);//设置线条颜色
setfillcolor(boon[i].color);//设置填充颜色
fillellipse(boon[i].x,boon[i].y,boon[i].x+40,boon[i].y+50);//画填充椭圆
//画气泡
arc(boon[i].x+5,boon[i].y+5,boon[i].x+35,boon[i].y+45,0,1.4);//画弧
//画绳子
arc(boon[i].x+15,boon[i].y+50,boon[i].x+25,boon[i].y+75,5.2,1.5);
}
}
//画炮台
setlinestyle(PS_SOLID,2);
circle(bat.x,bat.y,40);//画圆
setfillcolor(BLACK);
solidcircle(bat.x,bat.y,5);//画实心圆
//画炮管
setlinecolor(BLACK);
setlinestyle(PS_SOLID,5);
line(bat.x,bat.y,bat.endx,bat.endy);
//绘制子弹
for(inti=0;i<NUM;i++)//遍历所有子弹(所有包括存在和不存在)
{
if(ball[i].falg==true)//如果子弹存在
{
setfillcolor(ball[i].color);
solidcircle(ball[i].x,ball[i].y,ball[i].r);
}
}
charbar[80];//初始化字符串
sprintf(bar,"分数:%d",bat.score);//往这个字符串里写东西
setbkmode(0);//去掉文字背景
settextcolor(YELLOW);//设置文字颜色
settextstyle(40,0,"楷体");//设置文字字体大小和字体样式(注:0表示编译器自适应)
outtextxy(0,0,bar);//设置文字显示位置,以及所需要显示的字符串
EndBatchDraw();//结束双缓冲}12345678910111213141516171819222324252627282930313233343536373839404142434445
我们的炮管现在还是固定的,我们需要让它跟着鼠标动起来,走,现在我们去实现鼠标操作
voidMouseEvent(){
if(MouseHit())//如果有鼠标消息
{
MOUSEMSGmsg=GetMouseMsg();//获取当前鼠标消息
bat.radian=atan2((double)bat.y-msg.y,(double)msg.x-bat.x);//使用数学的正切求出炮台的炮管的倾斜弧度
//同样使用数学知识求出二条直角边的长度
bat.endx=bat.x+cos(bat.radian)*bat.len;//正弦
bat.endy=bat.y-sin(bat.radian)*bat.len;//余弦
if(msg.uMsg==WM_LBUTTONDOWN)//如果鼠标左键按下
{
CreatBullet();//产生子弹
}
}}1234567891011121314
那么鼠标操作这一步又涉及到子弹的产生,所以我们一起去看看子弹是如何产生的
//生成子弹voidCreatBullet(){
for(inti=0;i<NUM;i++)//遍历所有子弹(所有包括存在和不存在)
{
if(ball[i].falg==false)//如果子弹不存在才生成
{
ball[i].color=RGB(rand()%256,rand()%256,rand()%256);//颜色
//设置子弹坐标,让子弹从炮管出来
ball[i].x=bat.endx;
ball[i].y=bat.endy;
ball[i].radian=bat.radian;//让子弹运动方向的水平弧度等于当前炮管的水平弧度
//利用数学的正弦,余弦知识求出子弹的位移量,bat.speed是子弹的速度,一开始已经在炮台的结构体里面定义好了
ball[i].vx=cos(ball[i].radian)*bat.speed;
ball[i].vy=sin(ball[i].radian)*bat.speed;
//设置子弹的大小(圆的半径)
ball[i].r=5;
//最后一定要把子弹改为存在,好让GameDraw函数绘制出来
ball[i].falg=true;
//生成完一个子弹一定要break跳出for循环,否则程序会把所有子弹全部生成完,但我只要一个
break;
}
}}123456789101112131415161718192223
子弹生成完了我们也不能让它摆在那里不动,我们得让它飞,所以我们去实现一个函数让子弹移动
voidBulletMove(){
for(inti=0;i<NUM;i++)
//遍历所有子弹(所有包括存在和不存在)
{
if(ball[i].falg==true)//子弹存在才移动
{
//ball[i].vx,ball[i].vy我们在生成子弹里面就求出来了,这里我们就直接用
ball[i].x+=ball[i].vx;
ball[i].y-=ball[i].vy;
}
}}123456789101112
这时你会发现你打掉(宏定义)NUM个子弹后就没有了,这是什么原因呢?走,我们一起去升级一下这个函数
voidBulletMove(){
for(inti=0;i<NUM;i++)
//遍历所有子弹(所有包括存在和不存在)
{
if(ball[i].falg==true)//子弹存在才移动
{
//ball[i].vx,ball[i].vy我们在生成子弹里面就求出来了,这里我们就直接用
ball[i].x+=ball[i].vx;
ball[i].y-=ball[i].vy;
if(ball[i].x<0||ball[i].x>WIDTH||ball[i].y<0||ball[i].y>WEIGHT)
{
ball[i].falg=false;
}//如果子弹打出窗口了,就把该子弹设置为不存在,这样鼠标点击就可以继续生成子弹了(保证窗口一直可以容纳(宏定义)NUM个子弹)
}
}}12345678910111213141516
子弹移动了该气球了
//气球移动voidBalloonMove(intspeed){
for(inti=0;i<NUM;i++)//遍历所有气球(所有涵盖存在和不存在)
{
if(boon[i].falg==true)//如果气球存在
{
//%50的概率,让气球随风摇摆
if(rand()%2==1)
{
boon[i].x++;
}
else
{
boon[i].x--;
}
//气球上升
boon[i].y-=speed;
}}12345678910111213141516171819
然后我们会发现会产生与子弹移动同样的问题,气球一去不复返,所以我们升级一下这个函数
//气球移动voidBalloonMove(intspeed){
for(inti=0;i<NUM;i++)//遍历所有气球(所有涵盖存在和不存在)
{
if(boon[i].falg==true)//如果气球存在
{
//%50的概率,让气球随风摇摆
if(rand()%2==1)
{
boon[i].x++;
}
else
{
boon[i].x--;
}
//气球上升
boon[i].y-=speed;
if(boon[i].x-40<0||boon[i].x>WIDTH+40||boon[i].y+50<0||boon[i].y>WEIGHT)//如果气球升到了窗口之外
{
boon[i].falg=false;//把气球设置为不存在
CreatBall();//调用产生气球的函数(气球飞离窗口)
}
}}12345678910111213141516171819222324
好,接下来我们来实现一下产生气球的函数
//产生气球voidCreatBall(){
for(inti=0;i<NUM;i++)//遍历所有气球(所有涵盖存在与不存在)
{
if(boon[i].falg==false)//如果气球不存在
{
//随机气球坐标
boon[i].x=rand()%(WIDTH-30);
boon[i].y=(rand()%100)+WEIGHT;
//随机气球颜色
boon[i].color=RGB(rand()%256,rand()%256,rand()%256);
//生成完成把气球设置为存在
boon[i].falg=true;
break;//同理,只需要一个,break
}
}}1234567891011121314151617
现在一切准备就绪,开始打气球
//开始游戏voidPlayGame(){
for(inti=0;i<NUM;i++)//遍历所有气球(所有涵盖存在和不存在)
{
if(boon[i].falg==false)//如果气球不存在
continue;//跳过此次循环剩余部分,执行下一次循环判定
for(intj=0;j<NUM;j++)
//遍历所有子弹(所有涵盖存在和不存在)
{
if(ball[j].falg==false)//如果子弹不存在
continue;//跳过此次循环剩余部分,执行下一次循环判定
if(ball[j].x>boon[i].x&&ball[j].x<boon[i].x+40&&
ball[j].y>boon[i].y&&ball[j].y<boon[i].y+50)
//如果子弹与气球重叠(打到了气球)
{
CreateThread(NULL,0,MCC,NULL,0,NULL);//执行多线程,播放气球爆炸音效
ball[j].falg=false;//子弹设置为不存在
boon[i].falg=false;//气球设置为不存在
bat.score++;//玩家分数加1
CreatBall();//生成气球(气球被打)
}
}
}}12345678910111213141516171819222324
下面我们把主函数(程序的入口,程序的主干)写出来
intmain(){
initgraph(WIDTH,WEIGHT);//创建窗口
CreateThread(NULL,0,Music,NULL,0,NULL);//调用多线程,循环播放背景音乐
Welcome();//欢迎界面
GameInit();//数据初始化
while(1)//死循环
{
MouseEvent();//鼠标操作
GameDraw();//绘制(让游戏可视化)
BulletMove();//子弹移动
BalloonMove(1);//气球移动
Sleep(1);//适当延时
PlayGame();//开始打气球
}
getchar();//防止闪屏}12345678910111213141516
最后,博主送你源代码,感谢你认真的观看(因为我自己写代码很少注释,所以源代码注释少)但上面的详解可是注释慢慢,为了方便大家理解。
#include<stdio.h>#include<math.h>#include<graphics.h>#include<mmsystem.h>#pragmacomment(lib,"winmm.lib")#pragmawarning(disable:4996)#defineWIDTH600#defineWEIGHT400#defineNUM10structBattery{
intx;
inty;
intendx;
intendy;
intlen;
intspeed;
doubleradian;
intscore;}bat;structbullet{
intx;
inty;
intr;
intvx;
intvy;
boolfalg;
doubleradian;
DWORDcolor;}ball[NUM];structBalloon{
intx;
inty;
DWORDcolor;
boolfalg;}boon[NUM];IMAGEimg[2];DWORDWINAPIMCC(LPVOIDlpParamter){
mciSendString("openfill.mp3aliasBCC",0,0,0);
mciSendString("playBCC",0,0,0);
return0;}DWORDWINAPIMusic(LPVOIDlpParamter){
mciSendString("openmusic.mp3aliasBGM",0,0,0);
mciSendString("playBGMrepeat",0,0,0);
while(1);}voidWelcome(){
loadimage(&img[0],"1.jpg",150,400);
loadimage(&img[1],"2.jpg",450,400);
putimage(0,0,&img[0]);
putimage(150,0,&img[1]);
while(1)
{
if(MouseHit())
{
MOUSEMSGmsg=GetMouseMsg();
if(msg.uMsg==WM_LBUTTONDOWN)
{
return;
}
}
}}voidGameInit(){
srand(GetTickCount());
bat.x=WIDTH/2;
bat.y=WEIGHT-10;
bat.len=50;
bat.endx=bat.x;
bat.endy=bat.y-bat.len;
bat.speed=7;
bat.score=0;
for(inti=0;i<NUM;i++)
{
ball[i].falg=false;
}
for(inti=0;i<NUM;i++)
{
boon[i].x=rand()%(WIDTH-30);
boon[i].y=rand()%(WEIGHT-60);
boon[i].color=RGB(rand()%256,rand()%256,rand()%256);
boon[i].falg=true;
}}voidGameDraw(){
BeginBatchDraw();
setbkcolor(RGB(114,191,207));
cleardevice();
for(inti=0;i<NUM;i++)
{
if(boon[i].falg==true)
{
//画气球
setlinestyle(PS_SOLID,0.1);
setlinecolor(WHITE);
setfillcolor(boon[i].color);
fillellipse(boon[i].x,boon[i].y,boon[i].x+40,boon[i].y+50);
//画气泡
arc(boon[i].x+5,boon[i].y+5,boon[i].x+35,boon[i].y+45,0,1.4);
//画绳子
arc(boon[i].x+15,boon[i].y+50,boon[i].x+25,boon[i].y+75,5.2,1.5);
}
}
//画炮台
setlinestyle(PS_SOLID,2);
circle(bat.x,bat.y,40);
setfillcolor(BLACK);
solidcircle(bat.x,bat.y,5);
//画炮管
setlinecolor(BLACK);
setlinestyle(PS_SOLID,5);
line(bat.x,bat.y,bat.endx,bat.endy);
//绘制子弹
for(inti=0;i<NUM;i++)
{
if(ball[i].falg==true)
{
setfillcolor(ball[i].color);
solidcircle(ball[i].x,ball[i].y,ball[i].r);
}
}
charbar[80];
sprintf(bar,"分数:%d",bat.score);
setbkmode(0);
settextcolor(YELLOW);
settextstyle(40,0,"楷体");
outtextxy(0,0,bar);
EndBatchDraw();}//产生气球voidCreatBall(){
for(inti=0;i<NUM;i++)
{
if(boon[i].falg==false)
{
boon[i].x=rand()%(WIDTH-30);
boon[i].y=(rand()%100)+WEIGHT;
boon[i].color=RGB(rand()%256,rand()%256,rand()%256);
boon[i].falg=true;
break;
}
}}//开始游戏voidPlayGame(){
for(inti=0;i<NUM;i++)
{
if(boon[i].falg==false)
continue;
for(intj=0;j<NUM;j++)
{
if(ball[j].falg==false)
continue;
if(ball[j].x>boon[i].x&&ball[j].x<boon[i].x+40&&
ball[j].y>boon[i].y&&ball[j].y<boon[i].y+50)
{
CreateThread(NULL,0,MCC,NULL,0,NULL);
ball[j].falg=false;
boon[i].falg=false;
bat.score++;
CreatBall();
}
}
}}//气球移动voidBalloonMove(intspeed){
for(inti=0;i<NUM;i++)
{
if(boon[i].falg==true)
{
if(rand()%2==1)
{
boon[i].x++;
}
else
{
boon[i].x--;
}
boon[i].y-=speed;
if(boon[i].x-40<0||boon[i].x>WIDTH+40||boon[i].y+50<0||boon[i].y>WEIGHT)
{
boon[i].falg=false;
CreatBall();
}
}
}}//生成子弹voidCreatBullet(){
for(inti=0;i<NUM;i++)
{
if(ball[i].falg==false)
{
ball[i].color=RGB(rand()%256,rand()%256,rand()%256);
ball[i].x=bat.endx;
ball[i].y=bat.endy;
ball[i].radian=bat.radian;
ball[i].vx=cos(ball[i].radian)*bat.speed;
ball[i].vy=sin(ball[i].radian)*bat.speed;
ball[i].r=5;
ball[i].falg=true;
break;
}
}}//移动子弹voidBulletMove(){
for(inti=0;i<NUM;i++)
{
if(ball[i].falg==true)
{
ball[i].x+=ball[i].vx;
ball[i].y-=ball[i].vy;
if(ball[i].x<0||ball[i].x>WIDTH||ball[i].y<0||ball[i].y>WEIGHT)
{
ball[i].falg=false;
}
}
}}//鼠标操作voidMouseEvent(){
if(MouseHit())
{
MOUSEMSGmsg=GetMouseMsg();
bat.radian=atan2((double)bat.y-msg.y,(double)msg.x-bat.x);
bat.endx=bat.x+cos(bat.radian)*bat.len;
bat.endy=bat.y-sin(bat.radian)*bat.len;
if(msg.uMsg==WM_LBUTTONDOWN)
{
CreatBullet();
}
}}intmain(){
initgraph(WIDTH,WEIGHT);
CreateThread(NULL,0,Music,NULL,0,NULL);
Welcome();
GameInit();
while(1)
{
MouseEvent();
GameDraw();
BulletMove();
BalloonMove(1);
Sleep(1);
PlayGame();
}
getchar();}12345678910111213141516171819222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119111221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992000220320420520620720820921021121221321421521621721821921222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265