游戏背景

《球球大作战》是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语言开发球球大作战(源码分享),你想试试吗?的更多相关文章

  1. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  2. C/C++编程笔记:C语言成绩管理系统!链式结构的管理系统源码分享

    最近很多同学因为学校的要求,需要完成自己的那个C语言课程设计,于是就有很多人私信或者加我私聊我,问的最多的还是<学生成绩管理系统>,其实当你项目写多了你就会发现:其实各类的管理系统都离不开 ...

  3. C/C++编程笔记:C语言实现连连看游戏,小白练手项目(源码分享)

    本篇文章分享看题目就知道是写给初学者的,学的比较好的小伙伴也可以将自动算法等一些知识给加进去,希望对大家有帮助! 好了,当我们所有的准备工作做好之后,我们就可以来编写我们的C语言连连看游戏了! 其实这 ...

  4. GO语言slice详解(结合源码)

    一.GO语言中slice的定义 slice 是一种结构体类型,在源码中的定义为: src/runtime/slice.go type slice struct { array unsafe.Point ...

  5. hadoop2.5.2学习及实践笔记(二)—— 编译源代码及导入源码至eclipse

    生产环境中hadoop一般会选择64位版本,官方下载的hadoop安装包中的native库是32位的,因此运行64位版本时,需要自己编译64位的native库,并替换掉自带native库. 源码包下的 ...

  6. 基于python语言的tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)

    基于python语言的tensorflow的‘端到端’的字符型验证码识别 1   Abstract 验证码(CAPTCHA)的诞生本身是为了自动区分 自然人 和 机器人 的一套公开方法, 但是近几年的 ...

  7. Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍

    最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...

  8. 用GO语言开发editplus编辑器插件(附源码)

    我要开发的插件功能极为简单,就是对用户选中的内容进行base64编码或解密工作. 其中所涉及的技术部分主要是GO语言程序开发和editplus插件配置的部分,首先我们来看一下GO语言代码的写法,如下: ...

  9. C语言学生管理系统源码分享

    大家好 我就是如假包换的...陈玲 自从运营了C语言程序设计微信公众号 很多粉丝都给我备注 ...奇葩 实在是不敢当 也被人开始叫玲玲姐 我知道 很多人都想看我出境 我本人也有 年多的舞台演讲训练 实 ...

随机推荐

  1. 深度学习论文翻译解析(九):Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

    论文标题:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition 标题翻译:用于视觉识别的深度卷积神 ...

  2. 【MySQL】Merge Index导致死锁

    水稻:最近有个朋友生产环境出现MySQL死锁问题,一听是死锁,那必须去看看啊,于是饶(si)有(qu)兴(huo)致(lai)的研究了好几天 菜瓜:MySQL死锁,赶紧分享一下 水稻:能否先让我装完X ...

  3. TKCTF-学校内部的校赛

    *Reverse easy_C easy_re1.exe 在网络百度到解决逆向需要用到软件IDA 然后用IDA打开一条条的找我找到了一条很怪的ZmxhZ3s1ZWU1ZjYyOC1mMzVhLTQxN ...

  4. postman 进阶技巧

    cookie 清除缓存 code 生成接口自动化测试脚本 响应部分 pretty 响应以json或xml显示 raw 响应以文本显示 preview 以HTML网页行驶显示 断言 断言:用于判断接口请 ...

  5. day45 如何完全删除mysql服务

    卸载mysql之后,mysql的服务无法删除 解决方案 在我们在卸载mysql后会有一些东西没有删除干净,当我们把这些内容清除干净后,服务自然就消失了 步骤一: 如果是默认安装的话 在这三个文件内都有 ...

  6. Python-break/continue

    break:用于终止整个循环 continue:用于终止本次循环,而不终止整个循环的执行

  7. node子进程(Child Process)获取硬盘分区

    node   child_process文档 child_process.exec(command[, options][, callback]) command <string> The ...

  8. flask 源码专题(一):app.run()的背后

    当我们用Flask写好一个app后, 运行app.run()表示监听指定的端口, 对收到的request运行app生成response并返回. 现在分析一下, 运行app.run()后具体发生了什么事 ...

  9. 数据可视化之powerBI技巧(十九)DAX作图技巧:使用度量值动态分组和配色

    有了前两篇关于分组的铺垫,这篇文章就来学习一个分组的经典应用,图表的动态分组,并对分组动态配色. 假设有十几个产品,每个产品的销售额,是随着时间而变化的,想知道某个时间的每一个产品的销售额与平均销售额 ...

  10. 数据分析01 /numpy模块

    数据分析01 /数据分析之numpy模块 目录 数据分析01 /数据分析之numpy模块 1. numpy简介 2. numpy的创建 3. numpy的方法 4. numpy的常用属性 5. num ...