游戏背景

《球球大作战》是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. 每日一题 - 剑指 Offer 39. 数组中出现次数超过一半的数字

    题目信息 时间: 2019-06-29 题目链接:Leetcode tag: 数组 哈希表 难易程度:简单 题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 假设数组是非空的 ...

  2. 微信小程序获取index索引值的方法

    功能:点击某一项,底部出现粉色边框 首先需要通过 bindtap 为每一个item项绑定一个点击事件,其次需要添加自定义属性 data-* = {{index}} ,以便在函数中获取到被点击item项 ...

  3. 「疫期集训day6」雨林

    是的,他们击退了我们,那又怎样,他们饥肠辘辘,弹尽粮绝...----阿尔贡森林中的士兵 今天考试一般,感觉难度比第一次考试要大的多,T2板子整合(元宵节原题,然而那次考试我都没参加),T1搜索,T3有 ...

  4. 12个Visual Studio调试效率技巧

    在这篇文章中,我们假定读者了解VS基本的调试知识,如: F5 开始使用调试器运行程序 F9 在当前行设置断点 F10 运行到下一个断点处 F5 从被调试的已停止程序恢复执行 F11 步进到函数内(如果 ...

  5. HotSpot的类模型(4)

    我们继续接着上一篇 HotSpot的类模型(3)分析,这次主要分析表示java数组的C++类. 4.ArrayKlass类 ArrayKlass继承自Klass,是所有数组类的抽象基类,类及重要属性的 ...

  6. db2数据库字段更新当前时间

    db2数据库中想要将字段的时间通过sql语句的方式更新: 例如: Update tablename set 字段1='打酱油', 字段2 = TO_CHAR(current timestamp,'YY ...

  7. OSCP Learning Notes - Exploit(9)

    Tool: Metasploit 1. Start the msfconsole tool. msfconsole 2.Search ssh related modules. 3.Use the &q ...

  8. Ubuntu构建Docker私有仓库(Repository) 配置过程笔记

    一.准备: 1.服务器(或者虚拟机2台,我的服务环境[  阿里云服务器-Ubuntu 1804 +百度云-Ubuntu 1604]) 2.有效镜像(我这里以上一篇随笔镜像作为有效镜像https://w ...

  9. 牛客练习赛 66B题解

    前言 当初思路 开始没想到异或这么多的性质,于是认为对于每个点\(u\),可以和它连边的点\(v\)的点权 \(a_v=a_u \oplus k\)(证明:\(\because\) \(a_u\opl ...

  10. 数据结构 | 30行代码,手把手带你实现Trie树

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是算法和数据结构专题的第28篇文章,我们一起来聊聊一个经典的字符串处理数据结构--Trie. 在之前的4篇文章当中我们介绍了关于博弈论的 ...