0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C/C++实现球球大作战(高仿版),全源码分享带你轻松完成!

C语言编程学习基地 来源:C语言编程学习基地 2023-02-02 09:40 次阅读

每天一个C语言小项目,提升你的编程能力!

《球球大作战》虽然在玩法上类似于大球吃小球的模式看起来很单薄。但是在游戏过程中会出现无数种意外情况,这就需要玩家运用一系列策略来达到不被吃和吃掉别人球的目的,大大增加了游戏的耐玩性。

一个人的话想要实现复刻球球太困难了,所以这是仿照成熟版球球大作战写的简易版小游戏,有食物、敌人,甚至像和平精英一样加了一层外面的毒圈。

游戏操作起来很简单,用 A S D W 四个键控制球的移动方向。

地图大小是屏幕的16倍,吃完所有敌人就胜利。记住不要被敌人吃掉哦!

效果图展示:

a783d09a-a241-11ed-bfe3-dac502259ad0.png

a79b990a-a241-11ed-bfe3-dac502259ad0.png

完整的游戏源代码如下:

#include 
#include 
#include 
#include 
#include 


#define WIDTH    1024      // 屏幕宽
#define HEIGHT    576        // 屏幕高
#define MAPW    (WIDTH * 4)    // 地图宽
#define MAPH    (HEIGHT * 4)  // 地图高
#define AINUM       100        // AI 数量
#define FNUM        2000      // FOOD 数量
#define PTIME       180        // 毒圈刷新时间
#define DISTANCE(x1, y1, x2, y2)  (sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)))


struct FOOD
{
  bool    eat;
  COLORREF  color;    // 颜色
  int      x, y;    // 坐标
  char    type;
};


struct BALL          // 定义小球结构
{
  bool    life;    // 生命
  COLORREF  color;    // 颜色
  int      x, y;    // 坐标
  float    r;      // 半径
};


FOOD food[FNUM];                // 食物
BALL mover = { 1, RGB(0, 0, 0), 0, 0, 0 };  // 玩家
BALL ai[AINUM] = { 1, RGB(0, 0, 0), 0, 0, 0 };  // 机器大军


void move(BALL* ball);        // 玩家移动
void draw();            // 绘图
void start();            // 游戏开始
void setall();            // 初始化数据
void AI();              // AI
void Food();            // 食物
void delay(DWORD ms);        // 绝对延时


DWORD* pBuffer;            // 显示缓冲区指针
int eaten = 0;            // 吃 AI 的数量
int ai_eaten = 0;          // AI 吃 AI的数量
int lx = -20, ly = MAPH + 20, rx = MAPW + 20, ry = -20;    // 毒的位置
int relx = -20, rely = MAPH + 20, rerx = MAPW + 20, rery = -20;    // 毒的位置
float asp = 1;            // 缩放因子
float Time = 0;            // 时间


int main()
{
  initgraph(WIDTH, HEIGHT);
  start();
  setall();        // 游戏初始化


  BeginBatchDraw();
  while (true)
  {
    move(&mover);    // 玩家移动
    AI();
    Food();
    draw();        // 绘图
    FlushBatchDraw();  // 显示缓存的绘制内容
    delay(20);      // 绝对延迟
  }
}


void move(BALL* ball)
{
  if (ball->r <= 0)  ball->life = false;


  if (ball->life == false)      // 判定游戏是否接束
  {
    HWND hwnd = GetHWnd();
    MessageBox(hwnd, _T("你被吃了"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION);  // 结束
    closegraph();
    exit(0);
  }


  if (eaten + ai_eaten == AINUM)  // 是否吃掉所以 AI
  {
    HWND hwnd = GetHWnd();
    MessageBox(hwnd, _T("恭喜过关"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION);  // 结束
    closegraph();
    exit(0);
  }


  if (ball->x > (MAPW - ball->r) || ball->x - ball->r < 0 || ball->y - ball->r < 0 || ball->y >(MAPH - ball->r))
    ball->r -= 0.1f;


  for (int i = 0; i < AINUM; i++)  // 玩家吃 AI 判定
  {
    if (ball->r >= ai[i].r)
    {
      if (ai[i].life == 0) continue;


      if (DISTANCE(ball->x, ball->y, ai[i].x, ai[i].y) < (4 / 5.0 * (ball->r + ai[i].r)))
      {
        ai[i].life = 0;    // 吃掉
        ball->r += (ai[i].r * ai[i].r / 2) / ball->r;  // 推理过程: pai * ball->r*ball->r += pai*ai[i].r*ai[i].r;   πr*r=πr*r+πai[i].r*ai[i].r
        eaten++;
      }
    }
  }


  for (int n = 0; n < FNUM; n++)      // 玩家吃食物
  {
    if (food[n].eat == 0) continue;


    if (DISTANCE(ball->x, ball->y, food[n].x, food[n].y) < ball->r)
    {
      ball->r += 4 / ball->r;      // 增加面积
      food[n].eat = 0;        // 食物被吃
    }
  }


  static int mx = 0, my = 0;      // 记录偏移量
  if (GetAsyncKeyState(65) & 0x8000) { ball->x -= 2;  mx += 2; }  //左边
  if (GetAsyncKeyState(87) & 0x8000) { ball->y -= 2;  my += 2; }  //上面
  if (GetAsyncKeyState(83) & 0x8000) { ball->y += 2;  my -= 2; }  //下面
  if (GetAsyncKeyState(68) & 0x8000) { ball->x += 2;  mx -= 2; }  //右边
  setorigin(mx, my);          // 坐标修正
}


void AI()
{
  for (int i = 0; i < AINUM; i++)
  {
    if (ai[i].r > mover.r)      // AI 吃玩家
    {
      if (DISTANCE(mover.x, mover.y, ai[i].x, ai[i].y) < 2 / 3.0 * ai[i].r + mover.r)
      {
        ai[i].r += (mover.r * mover.r) / ai[i].r;
        mover.life = 0;
        mover.r = 0;
      }
    }


    for (int j = 0; j < AINUM; j++)  // AI 吃 AI
    {
      if (ai[i].r > ai[j].r)
      {
        if (ai[j].life == 0) continue;


        if (DISTANCE(ai[i].x, ai[i].y, ai[j].x, ai[j].y) < 4 / 5.0 * ai[i].r + ai[j].r)
        {
          ai[i].r += (ai[j].r * ai[j].r) / ai[i].r;    // 面积增加
          ai[j].life = 0;
          ai[j].r = 0;
          ai_eaten++;
        }
      }
    }


    double min_DISTANCE = 100000;
    int min = -1;
    for (int k = 0; k < AINUM; k++)    // AI 靠近 AI
    {
      if (ai[i].r > ai[k].r && ai[k].life == 1)
      {
        if (DISTANCE(ai[i].x, ai[k].x, ai[i].y, ai[k].y) < min_DISTANCE)
        {
          min_DISTANCE = DISTANCE(ai[i].x, ai[k].x, ai[i].y, ai[k].y);
          min = k;
        }
      }
    }


    if ((min != -1) && (rand() % 2 == 1))
    {
      if (rand() % 2)
      {
        if (ai[i].x < ai[min].x) ai[i].x++;
        else ai[i].x--;
      }
      else
      {
        if (ai[i].y < ai[min].y) ai[i].y++;
        else ai[i].y--;
      }
    }


    for (int n = 0; n < FNUM; n++)    // AI 吃食物
    {
      if (food[n].eat == 0) continue;


      if (DISTANCE(ai[i].x, ai[i].y, food[n].x, food[n].y) < ai[i].r)
      {
        ai[i].r += 4 / ai[i].r;
        food[n].eat = 0;
      }
    }
  }
}


void Food()
{
  for (int i = 0; i < FNUM; i++)      // 食物重新生成
  {
    if (food[i].eat == 0)
    {
      food[i].eat = 1;
      food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
      food[i].x = rand() % MAPW;
      food[i].y = rand() % MAPH;
      food[i].type = rand() % 10 + 1;
    }
  }
}


void draw()
{
  clearcliprgn();
  setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 20);  // 改笔的颜色、状态
  setlinecolor(RGB(0, 100, 0));
  line(relx, rely, relx, rery);  // 左竖
  line(relx, rely, rerx, rely);  // 上横
  line(relx, rery, rerx, rery);  // 下横
  line(rerx, rery, rerx, rely);  // 右竖
  setfillcolor(GREEN);


  if (mover.x - 0.5 * WIDTH / asp < relx)    floodfill(relx - 11, mover.y, RGB(0, 100, 0));
  if (mover.x + 0.5 * WIDTH / asp > rerx)    floodfill(rerx + 11, mover.y, RGB(0, 100, 0));
  if (mover.y - 0.5 * HEIGHT / asp < rery)    floodfill(mover.x, rery - 11, RGB(0, 100, 0));
  if (mover.y + 0.5 * HEIGHT / asp > rely)    floodfill(mover.x, rely + 11, RGB(0, 100, 0));


  setlinecolor(WHITE);      // 改笔颜色   状态
  setlinestyle(PS_NULL);


  for (int i = 0; i < FNUM; i++)  // 画出食物
  {
    if (food[i].eat == 0) continue;
    setfillcolor(food[i].color);
    switch (food[i].type)    // 形状
    {
    case 1:    solidellipse(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4);        break;
    case 2:    solidellipse(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2);        break;
    case 3:    solidrectangle(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2);        break;
    case 4:    solidrectangle(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4);        break;
    case 5:    solidroundrect(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4, 2, 2);    break;
    case 6:    solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 2);    break;
    case 7:    solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 4, 2);    break;
    case 8:    solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 4);    break;
    case 9:    solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 1, 1);    break;
    case 10:  fillcircle(food[i].x, food[i].y, 4);                    break;
    }
  }


  for (int i = 0; i < AINUM; i++)  // 画 AI
  {
    if (ai[i].life == 0) continue;
    setfillcolor(ai[i].color);
    fillcircle(ai[i].x, ai[i].y, int(ai[i].r + 0.5));
  }


  setfillcolor(mover.color);    // 画玩家
  fillcircle(mover.x, mover.y, int(mover.r + 0.5));


  IMAGE map(150, 100);      // 小地图
  SetWorkingImage(&map);
  setbkcolor(RGB(120, 165, 209));  // 浅灰色背景
  cleardevice();


  for (int i = 0; i < AINUM; i++)  // 画 AI
  {
    if (ai[i].life == 0) continue;
    setfillcolor(ai[i].color);
    fillcircle(ai[i].x * 150 / WIDTH / 4, ai[i].y * 100 / HEIGHT / 4, int(ai[i].r / 28 + 0.5));
  }


  setfillcolor(mover.color);    // 画玩家
  fillcircle(mover.x * 150 / WIDTH / 4, mover.y * 100 / HEIGHT / 4, int(mover.r / 28 + 0.5));
  setlinecolor(RGB(0, 100, 0));


  if (lx != rx && ly != rx)
  {
    line(lx * 150 / WIDTH, ly * 100 / HEIGHT, lx * 150 / WIDTH, ry * 100 / HEIGHT);  // 左竖
    line(lx * 150 / WIDTH, ly * 100 / HEIGHT, rx * 150 / WIDTH, ly * 100 / HEIGHT);  // 上横
    line(lx * 150 / WIDTH, ry * 100 / HEIGHT, rx * 150 / WIDTH, ry * 100 / HEIGHT);  // 下横
    line(rx * 150 / WIDTH, ry * 100 / HEIGHT, rx * 150 / WIDTH, ly * 100 / HEIGHT);  // 右竖
  }


  setfillcolor(GREEN);
  floodfill(lx - 11, ly - 11, RGB(0, 100, 0));


  SetWorkingImage();      // 恢复绘图背景
  putimage(mover.x + int(0.5 * WIDTH) - 150, mover.y - int(0.5 * HEIGHT), 150, 100, &map, 0, 0);            // 画出小地图
  setlinecolor(LIGHTBLUE);  // 改笔颜色   状态
  setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 4);
  line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT), mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99);  // 地图边框线
  line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99, mover.x + int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT) + 99);  // 地图边框线


  setlinestyle(PS_NULL);    // 恢复笔
  wchar_t str[32];
  swprintf_s(str, L"质量:%.1f  击杀:%d", mover.r, eaten);
  settextcolor(BLUE);      // 改字体
  outtextxy(mover.x - int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT), str);
  settextcolor(BLUE);      // 改字体
  outtextxy(mover.x - 36, mover.y - 8, _T("作者:无言"));
}


void setall()
{
  srand((unsigned)time(NULL));    // 随机数
  mover.color = RGB(rand() % 256, rand() % 256, rand() % 256);  // 随机颜色
  mover.life = 1;          // 统统赋初值
  mover.x = int(WIDTH * 0.5);
  mover.y = int(HEIGHT * 0.5);
  mover.r = 20;


  for (int i = 0; i < AINUM; i++)    // AI 的
  {
    ai[i].life = 1;
    ai[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
    ai[i].r = float(rand() % 10 + 10);
    ai[i].x = rand() % (MAPW - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);
    ai[i].y = rand() % (MAPH - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);
  }


  for (int i = 0; i < FNUM; i++)    // 食物的
  {
    food[i].eat = 1;
    food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
    food[i].x = rand() % MAPW;
    food[i].y = rand() % MAPH;
    food[i].type = rand() % 10 + 1;
  }


  pBuffer = GetImageBuffer(NULL);  // 获取显示缓冲区指针
  setbkcolor(WHITE);        // 白色背景
  cleardevice();          // 初始化背景
  settextcolor(LIGHTRED);      // 改字体
  setbkmode(TRANSPARENT);
  settextstyle(16, 0, _T("宋体"));
}


void delay(DWORD ms)        // 绝对延时
{
  static DWORD oldtime = GetTickCount();


  while (GetTickCount() - oldtime < ms)
    Sleep(1);


  oldtime = GetTickCount();
}


void start()
{
  setbkcolor(WHITE);    // 白色背景
  cleardevice();      // 初始化背景
  settextcolor(RED);    // 改字体
  setbkmode(TRANSPARENT);
  settextstyle(128, 0, _T("宋体"));
  outtextxy(40, 20, _T("仿制球球大作战"));
  settextstyle(32, 0, _T("宋体"));
  outtextxy(740, 135, _T("Ver 1.6"));
  settextcolor(BLUE);    // 改字体
  outtextxy(304, 240, _T("W上移 S下移 A左移 D右移"));
  outtextxy(112, 340, _T("躲避大球   追补小球   贪吃食物   增强实力"));
  settextcolor(BLACK);  //改字体
  settextstyle(32, 0, _T("宋体"));
  outtextxy(384, 500, _T("按任意键开始游戏"));
  settextstyle(20, 0, _T("宋体"));
  outtextxy(810, 10, _T("作者粉丝群: 734106058"));
  _getch();
}

大家赶紧去动手试试吧!

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 游戏
    +关注

    关注

    2

    文章

    696

    浏览量

    26039
  • C语言
    +关注

    关注

    180

    文章

    7529

    浏览量

    128469
  • 源码
    +关注

    关注

    8

    文章

    573

    浏览量

    28584
  • C++
    C++
    +关注

    关注

    21

    文章

    2066

    浏览量

    72899
  • 源代码
    +关注

    关注

    94

    文章

    2927

    浏览量

    66062

原文标题:C/C++实现球球大作战(高仿版),全源码分享带你轻松完成!

文章出处:【微信号:cyuyanxuexi,微信公众号:C语言编程学习基地】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    26 C语言手写大作战

    C语言编程语言
    车同轨,书同文,行同伦
    发布于 :2022年08月11日 03:32:57

    -碰撞实验

    -碰撞实验两运动物体相互接触时,运动状态发生迅速变化现象缺点:操作容易有危险性优点:有设计、研究性竞赛性、有趣设备简单。
    发表于 12-05 15:57

    直径对钎焊质量影响

    【摘要】:焊是BGA及μBGA等高密度封装技术中凸点制作关键材料。焊直径是影响焊度及表面质量的关键因素。采用切丝重熔法制作焊,研
    发表于 04-24 10:09

    MSP430之裸奔框架C++程序源码(菜农C++裸奔大法系列之一) 转载

    /*------------------------------------------------------------------------MSP430之裸奔框架C++程序源码(菜农C++裸奔大法)本程序主要表现了
    发表于 02-01 11:06

    开学大作战!元气加满不做卢瑟!!

    自己要改的缺点向好友公开,总不会厚脸皮不行动吧!只需要登录人人网找到“惠普电脑”即可啦!努力了才会成为下一个乔布斯!才能成为下一个盖茨巴菲特!才会成为下一个林书豪!更何况,这样才会有姑娘喜欢!想要在新学期脱卝光的,想要在考卝试时轻卝松过的,想要在年轻时不做卢瑟的!新学期大作战,赶紧走起来!
    发表于 02-24 16:12

    电子发烧友网电子杂志11月刊新鲜出炉:嵌入式厂商大作战

    `电子发烧友网电子杂志11月刊新鲜出炉:嵌入式厂商大作战!——内容精彩纷呈,绝对不容错过!`
    发表于 01-08 16:47

    C++大作业课程设计报告--简单个人电话号码查询系统设计.zip

    C++大作业课程设计报告--简单个人电话号码查询系统设计
    发表于 01-21 20:51

    未来2018年最新电子产品——Linkcn是什么?

    音乐,1 ,专业支持国服:王者荣耀/倩女幽魂/大作战/梦幻西游/御剑诛仙/最强NBA/穿越火线/幻想西游/节奏大师/DNF等2 视频类:爱奇艺/优酷/腾讯视频/PPTV/土豆/乐视TV/华数TV
    发表于 11-03 14:25

    基于Dragon Board 410c开发板实现输入驱动:按键和轨迹驱动

    MSM具有按键和轨迹的功能,对应的驱动程序在文件arch/arm/mach-msm/board-mahimahi-keypad.c中,接下来开始介绍此文件的实现流程。(1)文件
    发表于 09-25 15:49

    怎样用C语言(及少量C++实现火柴人打羽毛

    分享20级同学大一上学期用C语言(及少量C++实现的火柴人打羽毛。由于同学们刚学了三个月的编程,实现还不够完善,工程代码、图片音乐素材可
    发表于 07-20 07:54

    从0开始,181页知识带你轻松搞定C++语言

    擅长面向对象程序设计的同时,还可以进行基于过程的程序设计,因而C++就适应的问题规模而论,大小由之。 C++不仅拥有计算机高效运行的实用性特征,同时还致力于提高大规模程序的编程质量与程序设计语言的问题描述能力。 这个资料带你从最
    发表于 07-24 13:10

    C++大作

    大学C++课程,期末大作实现功能:简单密码加密、解密系统
    发表于 04-26 14:49 1次下载

    移动电竞开发探索的新生期:《球球大作战》的移动电竞探索

    两年前《球球大作战》悄无声息地出现在苹果商店,也许连制作团队自己也没有想到,这款看上去与世无争的“球吃球”游戏会有在上海梅赛德斯-奔驰文化中心举办大型比赛的一天。从简单的“球吃球”模式到台上台下数千名现场观众为选手们绷紧神经,它只用了不到一年的时间。
    的头像 发表于 02-17 18:27 2073次阅读
    移动电竞开发探索的新生期:《球球<b class='flag-5'>大作战</b>》的移动电竞探索

    如何用C语言实现球球大作战项目

      这篇文章主要为大家详细介绍了 C语言实现——《球球大作战项目》 ,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下! 在室友面前秀一下岂不是美滋滋!   游戏介绍
    的头像 发表于 11-21 16:36 1732次阅读

    智慧家庭系列文章 | 控制权大作战:谁才是智能家居系统的控制中心?

    智慧家庭系列文章 | 控制权大作战:谁才是智能家居系统的控制中心?
    发表于 10-31 08:23 0次下载
    智慧家庭系列文章 | 控制权<b class='flag-5'>大作战</b>:谁才是智能家居系统的控制中心?