C/C++编程笔记:C语言开发球球大作战(源码分享),你想试试吗?
游戏背景
《球球大作战》是Superpop一款自主研du发的免费手机网络游戏。 以玩家间的实时互动PK产生游戏乐趣为设计宗旨,通过简单的规则将玩家操作直接转化为游戏策略,体验智谋碰撞的战斗乐趣。
游戏的基本操作包括键盘按下(上下左右四个方向,还有作弊测试按键空格键和A键),玩家可以在地图上随意移动,不过不能超出边界。不管是玩家还是AI都可以吃比自己小的球,反之也可以被吃,吃掉之后直径会增大,增大算法是被吃掉的半径的1/4。如果玩家被吃掉,会在任意地方重新开始。
那么今天,我们就用C语言,来写出我们的球球大作战,一起来看看吧!
效果展示

游戏步骤
球球大作战游戏分为几个步骤:
①使用自定义空白图片表示地图;②绘制玩家,食物;③处理玩家移动,以及吃食物判断;④绘制一个AI并实现其移动;
话不多说,接下来我们之间来看我们的代码吧!需要素材以及相关资料源码可以关注微信公众号输入关键词领取,那先来看看代码吧!
源码分享
#include<graphics.h> //包含easyx图形库文件
#include<time.h> //C语言时间头文件
#include<mmsystem.h>//win32多媒体设备接口文件
#pragma comment(lib,"winmm.lib")//win32多媒体设备接口库
#define WIN_WIDTH 1024 //屏幕的宽
#define WIN_HEIGHT 640//576 //屏幕高
#define MAP_WIDTH (WIN_WIDTH*3) //地图宽度
#define MAP_HEIGHT (WIN_HEIGHT*3)//地图高度
#define FOOD_NUM 500 //食物数量
#define AI_NUM 200 //ai数量
IMAGE map(MAP_WIDTH, MAP_HEIGHT);
POINT g_CameraPos; // 摄像机(屏幕左上角)在地图上的位置
struct Ball
{
bool flag; // 是否被吃 活 1,死 0
COLORREF color; // 颜色
float r; //
float x; // 坐标
float y;
int type; //食物独有属性,决定是什么类型的食物(圆?矩形?多边形?)
};
struct Ball mover; //玩家
struct Ball food[FOOD_NUM]; //食物数组
struct Ball ai[AI_NUM]; //AI数量
void ChaseAlgorithom(Ball *chase, Ball *run);
float DisTance(Ball b1, Ball b2);
void Gameinit()
{
//设置随机数种子
srand((unsigned)time(NULL));
//播放背景音乐
mciSendString("open BallGame.mp3 alias bk", , , );
mciSendString("play bk repeat", , , );
//初始化食物
for (int i = ; i < FOOD_NUM; i++)
{
food[i].x = (float)(rand() % MAP_WIDTH);
food[i].y = (float)(rand() % MAP_HEIGHT);
food[i].r = (float)(rand() % + );
food[i].color = RGB(rand() % , rand() % , rand() % ); // 随机颜色
food[i].flag = ;
food[i].type = rand() % ;
}
//初始化AI
for (int i = ; i < AI_NUM; i++)
{
ai[i].color = RGB(rand() % , rand() % , rand() % ); //rand()%256 随机取值 0-255
ai[i].flag = ;
ai[i].x = rand() % (MAP_WIDTH - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5); //AI产生的位置不会出现一个越界
ai[i].y = rand() % (MAP_HEIGHT - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);
ai[i].r = float(rand() % + );
}
{//初始化玩家数据
mover.color = BLUE;
mover.r = ;
//玩家在窗口的位置
mover.x = rand() % WIN_WIDTH;
mover.y = rand() % WIN_HEIGHT;
mover.flag = ;
}
}
//游戏地图开始绘制位置判断
void computeCameraPos()
{
// 以人物位置为中心计算摄像机的理论位置
g_CameraPos.x = mover.x - WIN_WIDTH / ;
g_CameraPos.y = mover.y - WIN_HEIGHT / ; // 防止摄像机越界
if (g_CameraPos.x < ) g_CameraPos.x = ;
if (g_CameraPos.y < ) g_CameraPos.y = ;
if (g_CameraPos.x > MAP_WIDTH - WIN_WIDTH) g_CameraPos.x = MAP_WIDTH - WIN_WIDTH;
if (g_CameraPos.y > MAP_HEIGHT - WIN_HEIGHT) g_CameraPos.y = MAP_HEIGHT - WIN_HEIGHT;
}
//游戏绘制
void Gamedraw()
{
SetWorkingImage(&map);
setbkcolor(WHITE); // 白色背景
cleardevice();
//画食物
for (int i = ; i < FOOD_NUM; i++)
{
if (food[i].flag == )
{
setfillcolor(food[i].color);
if (food[i].type == )
{
solidellipse((int)food[i].x, (int)food[i].y, (int)(food[i].x + food[i].r), (int)(food[i].y + food[i].r));
}
else if (food[i].type == )
{
solidpie((int)food[i].x, (int)food[i].y, (int)(food[i].x + food[i].r), (int)(food[i].y + food[i].r), 0.0, 1.5);
}
else
{
solidcircle(int(food[i].x), int(food[i].y), int(food[i].r));
}
}
else
{
food[i].x = (float)(rand() % MAP_WIDTH);
food[i].y = (float)(rand() % MAP_HEIGHT);
food[i].r = (float)(rand() % + );
food[i].color = RGB(rand() % , rand() % , rand() % ); // 随机颜色
food[i].flag = ;
food[i].type = rand() % ;
}
}
//画AI
for (int i = ; i < AI_NUM; i++)
{
if (ai[i].flag == )
{
setfillcolor(ai[i].color);
solidcircle(ai[i].x, ai[i].y, ai[i].r);
}
else
{
ai[i].color = RGB(rand() % , rand() % , rand() % ); //rand()%256 随机取值 0-255
ai[i].flag = ;
ai[i].x = rand() % (MAP_WIDTH - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5); //AI产生的位置不会出现一个越界
ai[i].y = rand() % (MAP_HEIGHT - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);
ai[i].r = float(rand() % + );
}
}
//绘制玩家
setfillcolor(RED);
fillcircle(mover.x, mover.y, mover.r);
//绘制玩家名称
settextcolor(BLACK);
setbkmode(TRANSPARENT);
settextstyle(, , "楷体");
char pname[] = "微信公众号:C语言编程学习基地";
int twidth = textwidth(pname) / ;//计算文字宽度为了居中显示在玩家中央
outtextxy(mover.x - twidth, mover.y, pname);
//恢复默认工作区,即窗口
SetWorkingImage();
//更新摄像机位置
computeCameraPos();
//把地图显示到窗口上
putimage(, , WIN_WIDTH, WIN_HEIGHT, &map, g_CameraPos.x, g_CameraPos.y);
}
//玩家移动,参数为玩家移动的速度(单位像素)
void Gamemove(int speed)
{
//获取键盘按键
if (GetAsyncKeyState(VK_UP) & 0x8000)
{
if (mover.y - mover.r > )
{
mover.y -= speed;
}
}
if (GetAsyncKeyState(VK_DOWN) & 0x8000)
{
if (mover.y + mover.r < MAP_HEIGHT)
{
mover.y += speed;
}
}
if (GetAsyncKeyState(VK_LEFT) & 0x8000)
{
if (mover.x - mover.r > )
{
mover.x -= speed;
}
}
if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
{
if (mover.x + mover.r < MAP_WIDTH)
{
mover.x += speed;
}
}
//作弊测试,按空格不断增大,A缩小
if (GetAsyncKeyState(VK_SPACE) & 0x8000)
{
mover.r += ;
}
if (GetAsyncKeyState('A') & 0x8000)
{
if (mover.r > )
mover.r -= ;
}
}
//玩家吃食物
void EatFood()
{
for (int i = ; i < FOOD_NUM; i++)
{
if (food[i].flag == && DisTance(food[i], mover) < mover.r)
{
food[i].flag = ;
mover.r += food[i].r / ;
}
}
}
//玩家吃Ai,Ai吃玩家
void EatAi()
{
for (int i = ; i < AI_NUM; i++)
{
if (ai[i].flag == )
continue;
//玩家吃Ai
if (DisTance(ai[i], mover) < mover.r - ai[i].r / )
{
ai[i].flag = ;
mover.r += ai[i].r / ;
break;//吃到一个就退出
}
//ai吃玩家
else if (DisTance(ai[i], mover) < ai[i].r - mover.r / )
{
mover.x = rand() % MAP_WIDTH;
mover.y = rand() % MAP_HEIGHT;
ai[i].r += mover.r / ;
mover.r = ;
break;
}
}
}
//AI吃食物,AI吃Ai
void AiEatFood()
{
for (int i = ; i < AI_NUM; i++)
{
if (ai[i].flag == )
continue;
//ai吃食物
for (int j = ; j < FOOD_NUM; j++)
{
if (food[j].flag == && DisTance(ai[i], food[j]) < ai[i].r)
{
food[j].flag = ;
ai[i].r += food[i].r / ;
}
}
//Ai吃Ai
for (int k = i + ; k < AI_NUM; k++)
{
if (ai[k].flag == )
{
if (DisTance(ai[i], ai[k]) < ai[k].r - ai[i].r / )
{
ai[i].flag = ;
ai[k].r += ai[i].r / ;
}
else if (DisTance(ai[i], ai[k]) < ai[i].r - ai[k].r / )
{
ai[k].flag = ;
ai[i].r += ai[k].r / ;
}
} }
}
}
//Ai移动算法,追逐比自己半径小的球
void AiMove()
{
for (int i = ; i < AI_NUM; i++)
{
double min_DISTANCE = MAP_WIDTH;//最大搜索距离
int min = -;//用来保存找到目标小球的下标
if (ai[i].flag == )
{
//AI靠近AI
for (int k = i + ; k < AI_NUM; k++)
{
if (ai[i].r > ai[k].r&&ai[k].flag == )
{//如果能吃,且距离达到要求则更新距离,并保存下标
if (DisTance(ai[i], ai[k]) < min_DISTANCE)
{
min_DISTANCE = DisTance(ai[i], ai[k]);
min = k;
}
}
}
}
//如果找到目标,则去追逐
if ((min != -))
{
ChaseAlgorithom(&ai[i], &ai[min]);
} }
}
void JudeEat()
{
EatFood();
EatAi();
AiEatFood();
AiMove();
}
int main()
{
initgraph(WIN_WIDTH, WIN_HEIGHT, );
Gameinit();
DWORD t1, t2;
t1 = t2 = GetTickCount();
while ()
{
Gamedraw();
Gamemove();
if (t2 - t1 > )
{
JudeEat();
t1 = t2;
}
t2 = GetTickCount();
} getchar();
closegraph();
return ;
} //追逐算法
void ChaseAlgorithom(Ball *chase, Ball *run)
{
if (rand() % == )
{
if (chase->x < run->x)
{
chase->x += ;
}
else
{
chase->x -= ;
}
}
else
{
if (chase->y < run->y)
{
chase->y += ;
}
else
{
chase->y -= ;
}
}
}
//求两点之间的距离
float DisTance(Ball b1, Ball b2)
{
return sqrt((b1.x - b2.x)*(b1.x - b2.x) + (b1.y - b2.y)*(b1.y - b2.y));
}
以上就是本篇文章的全部分享,希望对大家有帮助!
自学C/C++编程难度很大,不妨和一些志同道合的小伙伴一起学习成长!
C语言C++编程学习交流圈子,【点击进入】微信公众号:C语言编程学习基地
有一些源码和资料分享,欢迎转行也学习编程的伙伴,和大家一起交流成长会比自己琢磨更快哦!

C/C++编程笔记:C语言开发球球大作战(源码分享),你想试试吗?的更多相关文章
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...
- C/C++编程笔记:C语言成绩管理系统!链式结构的管理系统源码分享
最近很多同学因为学校的要求,需要完成自己的那个C语言课程设计,于是就有很多人私信或者加我私聊我,问的最多的还是<学生成绩管理系统>,其实当你项目写多了你就会发现:其实各类的管理系统都离不开 ...
- C/C++编程笔记:C语言实现连连看游戏,小白练手项目(源码分享)
本篇文章分享看题目就知道是写给初学者的,学的比较好的小伙伴也可以将自动算法等一些知识给加进去,希望对大家有帮助! 好了,当我们所有的准备工作做好之后,我们就可以来编写我们的C语言连连看游戏了! 其实这 ...
- GO语言slice详解(结合源码)
一.GO语言中slice的定义 slice 是一种结构体类型,在源码中的定义为: src/runtime/slice.go type slice struct { array unsafe.Point ...
- hadoop2.5.2学习及实践笔记(二)—— 编译源代码及导入源码至eclipse
生产环境中hadoop一般会选择64位版本,官方下载的hadoop安装包中的native库是32位的,因此运行64位版本时,需要自己编译64位的native库,并替换掉自带native库. 源码包下的 ...
- 基于python语言的tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)
基于python语言的tensorflow的‘端到端’的字符型验证码识别 1 Abstract 验证码(CAPTCHA)的诞生本身是为了自动区分 自然人 和 机器人 的一套公开方法, 但是近几年的 ...
- Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍
最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...
- 用GO语言开发editplus编辑器插件(附源码)
我要开发的插件功能极为简单,就是对用户选中的内容进行base64编码或解密工作. 其中所涉及的技术部分主要是GO语言程序开发和editplus插件配置的部分,首先我们来看一下GO语言代码的写法,如下: ...
- C语言学生管理系统源码分享
大家好 我就是如假包换的...陈玲 自从运营了C语言程序设计微信公众号 很多粉丝都给我备注 ...奇葩 实在是不敢当 也被人开始叫玲玲姐 我知道 很多人都想看我出境 我本人也有 年多的舞台演讲训练 实 ...
随机推荐
- 01 . SaltStack部署配置及简单应用
SaltStack简介 SaltStack saltstack是一个新的基础平台管理工具,只需要花费数分钟即可运行起来,可以支撑管理上万台服务器的规模,数秒钟即可完成数据传递. saltstack是使 ...
- 从0开始,手把手教你用Vue开发一个答题App01之项目创建及答题设置页面开发
项目演示 项目演示 项目源码 项目源码 教程说明 本教程适合对Vue基础知识有一点了解,但不懂得综合运用,还未曾使用Vue从头开发过一个小型App的读者.本教程不对所有的Vue知识点进行讲解,而是手把 ...
- IDEA怎么设置类的注释模板和方法注释模板
文件头注释模板 File | Settings | Editor | File and Code Templates /** * @Author your name * @DateTime ${YEA ...
- 07 Vue常见插件
项目功能插件 1.vue-router { path: '/', name: 'home', // 路由的重定向 redirect: '/home' } { // 一级路由, 在根组件中被渲染, 替换 ...
- javascript基础(五): jQuery
jQuery javaScript和jQuery的关系? jQuery库,里面存在大量的JavaScript函数 获取jQuery 公式:$(selector).action() <!DOCT ...
- 你有认真了解过自己的“Java对象”吗? 渣男
对象在 JVM 中是怎么存储的 对象头里有什么? 文章收录在 GitHub JavaKeeper ,N线互联网开发必备技能兵器谱,有你想要的. 作为一名 Javaer,生活中的我们可能暂时没有对象,但 ...
- bzoj3223Tyvj 1729 文艺平衡树
bzoj3223Tyvj 1729 文艺平衡树 题意: 一个数列,支持区间翻转操作. 题解: splay裸题.注意涉及到区间操作的一般用splay不用treap. 代码: #include <c ...
- MySQL事物原理及事务隔离级别
mysql事物 事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取.事务的正确执行使得数据库从一种状态转换为另一种状态. 事务必须服从ISO/IEC所制定的ACID原则.AC ...
- 图解:如何实现最小生成树(Prim算法与Kruskal算法)
这是图算法的第四篇文章 图解:如何实现最小生成树 文章目录: 1.概念和性质 2.思路探索 3.Kruskal算法 4.Prim算法 5.代码实现 1.概念和性质 今天我们考虑的模型是加权无向图,问题 ...
- Ubuntu构建Docker私有仓库(Repository) 配置过程笔记
一.准备: 1.服务器(或者虚拟机2台,我的服务环境[ 阿里云服务器-Ubuntu 1804 +百度云-Ubuntu 1604]) 2.有效镜像(我这里以上一篇随笔镜像作为有效镜像https://w ...