分享

智能营销总部:编程教学 C语言开发打气球小游戏

 新用户76066213 2020-07-29

首先我们写一下项目所需要的头文件

#include<stdio.h>//标准输入输出头文件#include<math.h>//数学库头文件#include<graphics.h>//EasyX图形库头文件#include<mmsystem.h>//多媒体音乐库头文件#pragma comment(lib,"winmm.lib")//导入winmm库#pragma warning(disable : 4996)//4996警告杂注12345

接下来在涵盖几个宏定义进来

#define WIDTH 600//窗口宽度#define WEIGHT 400//窗口高度#define NUM 10//屏幕上所产生气球,子弹的最大数量12

然后我们开始打造一个漂亮的欢迎界面,这里需要二张图片,我把它贴出来。
1.jpg:
1.jpg
2.jpg:
2.jpg
图片有了,上代码,首先先在全局部分定义图片属性

IMAGE img[2];
void Welcome()//实现欢迎界面的函数{
 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())//判断是否有鼠标消息
  {
   MOUSEMSG msg = GetMouseMsg();//获取当前鼠标消息
   if (msg.uMsg == WM_LBUTTONDOWN)//如果鼠标左键按下
   {
    return;//返回主函数
   }
  }
 }}1234567891011121314151617

接下来我们开始准备音乐部分(音乐不方便贴出来,可以自己去网上找合适的)
我们为了不影响程序运行效率,决定使用多线程的方式实现音乐播放
背景音乐:

DWORD WINAPI Music(LPVOID lpParamter){
 mciSendString("open music.mp3 alias BGM", 0, 0, 0);//加载音乐
 mciSendString("play BGM repeat", 0, 0, 0);//播放音乐
 //repeat代表无限循环播放
 while (1);}123456

气球爆炸音效:

DWORD WINAPI MCC(LPVOID lpParamter){
 mciSendString("open fill.mp3 alias BCC", 0, 0, 0);
 mciSendString("play BCC", 0, 0, 0);
 return 0;}12345

做游戏之前,我们先把游戏中的炮台,气球,子弹这3个元素用结构体抽象出来

struct Battery//炮台{//炮管二点的横纵坐标
 int x;
 int y;
 int endx;
 int endy;
 int len;
 //炮管发射出来的子弹的速度
 int speed;
 //炮管倾斜的弧度
 double radian;
 //玩家的游戏得分
 int score;}bat;struct bullet{//子弹的横纵坐标
 int x;
 int y;
 //子弹的半径
 int r;
 //子弹向炮管方向的位移量
 int vx;
 int vy;
 //子弹是否存在的标志
 bool falg;
 //炮管倾斜的弧度
 double radian;
 //子弹的颜色
 DWORD color;}ball[NUM];struct Balloon{//气球的横纵坐标
 int x;
 int y;
 //气球的颜色
 DWORD color;
 //气球是否存在的标志
 bool falg;}boon[NUM];1234567891011121314151617181920212223242526272829303132333435363738394041

下面我们来初始化数据

void GameInit(){
 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 (int i = 0; i < NUM; i++)
 {
  ball[i].falg = false;
 }//因为一开始子弹不存在,子弹需要鼠标点击才生成一个,所以我们先初始化为不存在(false代表不存在)
 for (int i = 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(存在),并且初始化坐标,颜色}1234567891011121314151617181920212223

接下来我们来把数据变得“看的见”

void GameDraw(){
 BeginBatchDraw();//开始双缓冲
 setbkcolor(RGB(114, 191, 207));//设置窗口背景颜色
 cleardevice();//清屏
 for (int i = 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 (int i = 0; i < NUM; i++)//遍历所有子弹(所有包括存在和不存在)
 {
  if (ball[i].falg == true)//如果子弹存在
  {
   setfillcolor(ball[i].color);
   solidcircle(ball[i].x, ball[i].y, ball[i].r);
  }
 }
 char bar[80];//初始化字符串
 sprintf(bar, "分数:%d", bat.score);//往这个字符串里写东西
 setbkmode(0);//去掉文字背景
 settextcolor(YELLOW);//设置文字颜色
 settextstyle(40, 0, "楷体");//设置文字字体大小和字体样式(注:0表示编译器自适应)
 outtextxy(0, 0, bar);//设置文字显示位置,以及所需要显示的字符串
 EndBatchDraw();//结束双缓冲}123456789101112131415161718192021222324252627282930313233343536373839404142434445

我们的炮管现在还是固定的,我们需要让它跟着鼠标动起来,走,现在我们去实现鼠标操作

void MouseEvent(){
 if (MouseHit())//如果有鼠标消息
 {
  MOUSEMSG msg = 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

那么鼠标操作这一步又涉及到子弹的产生,所以我们一起去看看子弹是如何产生的

//生成子弹void CreatBullet(){
 for (int i = 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;
  }
 }}1234567891011121314151617181920212223

子弹生成完了我们也不能让它摆在那里不动,我们得让它飞,所以我们去实现一个函数让子弹移动

void BulletMove(){
 for (int i = 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个子弹后就没有了,这是什么原因呢?走,我们一起去升级一下这个函数

void BulletMove(){
 for (int i = 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

子弹移动了该气球了

//气球移动void BalloonMove(int speed){
 for (int i = 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

然后我们会发现会产生与子弹移动同样的问题,气球一去不复返,所以我们升级一下这个函数

//气球移动void BalloonMove(int speed){
 for (int i = 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();//调用产生气球的函数(气球飞离窗口)
   }
 }}123456789101112131415161718192021222324

好,接下来我们来实现一下产生气球的函数

//产生气球void CreatBall(){
 for (int i = 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

现在一切准备就绪,开始打气球

//开始游戏void PlayGame(){
 for (int i = 0; i < NUM; i++)//遍历所有气球(所有涵盖存在和不存在)
 {
  if (boon[i].falg == false)//如果气球不存在
   continue;//跳过此次循环剩余部分,执行下一次循环判定
   for (int j = 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();//生成气球(气球被打)
    }
   }
 }}123456789101112131415161718192021222324

下面我们把主函数(程序的入口,程序的主干)写出来

int main(){
 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>#pragma comment(lib,"winmm.lib")#pragma warning(disable : 4996)#define WIDTH 600#define WEIGHT 400#define NUM 10struct Battery{
 int x;
 int y;
 int endx;
 int endy;
 int len;
 int speed;
 double radian;
 int score;}bat;struct bullet{
 int x;
 int y;
 int r;
 int vx;
 int vy;
 bool falg;
 double radian;
 DWORD color;}ball[NUM];struct Balloon{
 int x;
 int y;
 DWORD color;
 bool falg;}boon[NUM];IMAGE img[2];DWORD WINAPI MCC(LPVOID lpParamter){
 mciSendString("open fill.mp3 alias BCC", 0, 0, 0);
 mciSendString("play BCC", 0, 0, 0);
 return 0;}DWORD WINAPI Music(LPVOID lpParamter){
 mciSendString("open music.mp3 alias BGM", 0, 0, 0);
 mciSendString("play BGM repeat", 0, 0, 0);
 while (1);}void Welcome(){
 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())
  {
   MOUSEMSG msg = GetMouseMsg();
   if (msg.uMsg == WM_LBUTTONDOWN)
   {
    return;
   }
  }
 }}void GameInit(){
 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 (int i = 0; i < NUM; i++)
 {
  ball[i].falg = false;
 }
 for (int i = 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;
 }}void GameDraw(){
 BeginBatchDraw();
 setbkcolor(RGB(114, 191, 207));
 cleardevice();
 for (int i = 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 (int i = 0; i < NUM; i++)
 {
  if (ball[i].falg == true)
  {
   setfillcolor(ball[i].color);
   solidcircle(ball[i].x, ball[i].y, ball[i].r);
  }
 }
 char bar[80];
 sprintf(bar, "分数:%d", bat.score);
 setbkmode(0);
 settextcolor(YELLOW);
 settextstyle(40, 0, "楷体");
 outtextxy(0, 0, bar);
 EndBatchDraw();}//产生气球void CreatBall(){
 for (int i = 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;
  }
 }}//开始游戏void PlayGame(){
 for (int i = 0; i < NUM; i++)
 {
  if (boon[i].falg == false)
   continue;
   for (int j = 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();
    }
   }
 }}//气球移动void BalloonMove(int speed){
 for (int i = 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();
   }
  }
 }}//生成子弹void CreatBullet(){
 for (int i = 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;
  }
 }}//移动子弹void BulletMove(){
 for (int i = 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;
   }
  }
 }}//鼠标操作void MouseEvent(){
 if (MouseHit())
 {
  MOUSEMSG msg = 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();
  }
 }}int main(){
 initgraph(WIDTH, WEIGHT);
 CreateThread(NULL, 0, Music, NULL, 0, NULL);
 Welcome();
 GameInit();
 while (1)
 {
  MouseEvent();
  GameDraw();
  BulletMove();
  BalloonMove(1);
  Sleep(1);
  PlayGame();
 }
 getchar();}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多