【C++/C 实现球球大作战】

news2025/1/13 3:35:01

目录

  • 1.引言
  • 2.游戏设计:概述游戏的玩法和操作方式。
  • 3.游戏实现
    • (1)函数 GameInit() 初始化游戏的函数。
    • (2)函数 GameDraw() 用于绘制游戏场景的函数。
    • (3)函数 keyControl(int speed) 负责处理键盘控制玩家球体移动
    • (4)函数 eatFood() 负责处理玩家吃食物
    • (5)函数 aiMove() 是用于AI角色移动
    • (6)主函数 int main() 控制游戏的主循环和整体
  • 4.最终代码

1.引言

这篇文章主要为大家详细介绍了C语言实现——《球球大作战项目》,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
在这里插入图片描述
游戏介绍:
这是一个大球吃小球的世界,玩家的目标是要努力吃成最大的球球。在游戏一开始,玩家出现在地图上随机位置,地图里洒满了小彩豆,玩家吃掉小彩豆体积就会增大,当增大到比别人的球大时,就可以吃别人的球啦,当然也得躲避更大的球。小球速度快,大球速度慢。球球到达一定重量后,可以分身,一个球变成等大的两个球,可以再次分身,但是最多可以拥有16个分身。
效果图展示
在这里插入图片描述

2.游戏设计:概述游戏的玩法和操作方式。

1.操作方式:
使用键盘控制球体的移动,如W、A、S、D 或者 上、下、左、右方向键。
2.玩法:
玩家控制的球体通过键盘控制进行移动,可以朝不同的方向移动以吞噬其他球体。
球体可以通过碰撞来吞噬其他较小的球体,从而增大自己的体积。

3.游戏实现

此处包含需要用到的头文件,一些声明和定义 声明一个结构体可以让食物,玩家和ai玩家用,避免重复的定义。

#include<stdio.h>
#include<easyx.h>//包含图形库头文件
#include<stdlib.h>
#include<time.h>
#include<math.h>
#define FOOD_NUM 200 //食物数量
#define WIDTH 1024
#define HEIGHT 640
#define HEIFGT  10
#define AI_NUM 10//人工智障数量
/*
做游戏:1.窗口,画图,贴图。。。。。easyx图形库的
食物:圆(圆心坐标,半径,颜色,是否存在的标志)
*/

并且要明确要定义的对象
如下

struct Ball//小球结构,玩家,食物,人工智障
{
	int x;
	int y;
	int r;//半径
	DWORD color;//颜色
	bool flag;//是否存在
};
struct Ball food[FOOD_NUM];
struct Ball player;//玩家
struct Ball ai[AI_NUM];

(1)函数 GameInit() 初始化游戏的函数。

1.设置随机数种子:通过调用 srand((unsigned)time(NULL)),将随机数种子设置为当前时间的秒数,以确保每次游戏运行时生成的随机数序列是不同的。

2.初始化食物数据:通过循环遍历每个食物球体,为每个食物设置随机的位置、半径、颜色,并将存在标志 flag 设置为 true,表示初始状态下食物存在。

3.初始化玩家数据:生成玩家球体的初始位置、半径、颜色,并将存在标志 flag 设置为 true。

4.初始化人工智能角色(AI)数据:通过循环遍历每个 AI 角色,为每个角色设置随机的位置、半径和颜色,并将存在标志 flag 设置为 true。

void GameInit()
{
	//设置随机数种子,时间是在不断变化的
	srand((unsigned)time(NULL));
	for (int i = 0;i < FOOD_NUM; ++i)
	{
		food[i].x = rand() % WIDTH;
		food[i].y = rand() % HEIGHT;
		food[i].flag = true;//刚开始食物存在
		food[i].r = rand() % 6 + 1;
		food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
	}
	//初始化玩家数据
	player.x = rand() & WIDTH+1;
	player.y = rand() % HEIGHT+1;
	player.r = 18;//只要比食物大就可以
	player.flag = true;
	player.color= RGB(rand() % 256, rand() % 256, rand() % 256);
	//初始化ai
	for (int i = 0; i < AI_NUM; ++i)
	{
		ai[i].x = rand() % WIDTH;
		ai[i].y = rand() % HEIGHT;
		ai[i].r = rand() % 10 + 5;
		ai[i].flag = true;
		ai[i].color= RGB(rand() % 256, rand() % 256, rand() % 256);
	}
}

(2)函数 GameDraw() 用于绘制游戏场景的函数。

BeginBatchDraw() 函数开始绘制,这可以避免屏幕闪烁。

setbkcolor(WHITE) 设置背景色为白色。

cleardevice() 清空屏幕,将整个屏幕颜色填充为背景色。

循环遍历每个食物球体(FOOD_NUM 个),进行绘制。

如果 food[i].flag 为真,表示食物存在,则根据 food[i] 的坐标和半径,绘制一个填充圆,颜色为 food[i].color。
否则,表示食物已经消失,在随机位置重新生成一个食物。

void GameDraw()
{
	//防止闪屏
	BeginBatchDraw();
	setbkcolor(WHITE);
	cleardevice();//清屏
	for (int i = 0; i < FOOD_NUM; ++i)
	{
		if (food[i].flag)
		{
			setfillcolor(food[i].color);//设置填充颜色
			solidcircle(food[i].x, food[i].y,food[i].r);//画一个填充圆
		}
		else
		{
			food[i].x = rand() % WIDTH;
			food[i].y = rand() % HEIGHT;
			food[i].flag = true;//刚开始食物存在
			food[i].r = rand() % 6 + 1;
			food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
		}
	}

绘制玩家球体:
设置填充颜色为 player.color。
根据玩家的坐标和半径,绘制一个填充圆。
设置文本颜色为绿色。
设置文本样式为大小为 30、字体为黑体。
设置文字背景为透明。
输出文字在玩家球体的位置上。

//绘制玩家
	setfillcolor(player.color);//设置填充颜色
	solidcircle(player.x, player.y, player.r);
	settextcolor(GREEN);
	settextstyle(30, 0, L"黑体");
	setbkmode(0);//设置文字背景透明
	outtextxy(player.x-50, player.y, L"我是最靓的崽仔");
	EndBatchDraw();
	//绘制ai
	for (int i = 0; i < AI_NUM;++i)
	{
		if (ai[i].flag)
		{
			setfillcolor(ai[i].color);
			solidcircle(ai[i].x, ai[i].y, ai[i].r);
		}
	}
}

(3)函数 keyControl(int speed) 负责处理键盘控制玩家球体移动

1.GetAsyncKeyState() 函数用于获取键盘消息,判断是否按下了特定的键。
2.键盘控制包括上、下、左、右四个方向键。根据按下的键,判断移动的方向并更新玩家球体的位置。
3.如果按下了 ‘W’ 键或者上方向键 (VK_UP),并且玩家球体的 y 坐标大于等于 0,则向上移动,即 player.y -= speed。
其他位置都如上
4.根据按键的状态和边界限制,函数根据移动速度 speed 更新玩家球体的 函数

void keyControl(int speed)
{
	//获取键盘消息,按的是哪一个键 
	if ((GetAsyncKeyState('W') || GetAsyncKeyState(VK_UP))&&player.y>=0)//按了上键
	{
		player.y -= speed;
	}
	if ((GetAsyncKeyState('S') || GetAsyncKeyState(VK_DOWN))&& player.y<=HEIGHT)//按了下键
	{  
		player.y += speed;
	}  
	if ((GetAsyncKeyState('A') || GetAsyncKeyState(VK_LEFT))&& player.x >= 0)//按了左键
	{  
		player.x -= speed;
	}  
	if ((GetAsyncKeyState('D') || GetAsyncKeyState(VK_RIGHT))&& player.x<=WIDTH)//按了右键
	{  
		player.x += speed;
	}
}

特别注意边界,不能越界

(4)函数 eatFood() 负责处理玩家吃食物

函数通过遍历所有的食物球体,检查玩家球体是否和食物重叠,并进行吃食物的操作。
对于每一个食物球体:
如果食物存在(food[i].flag 为真)且食物球体和玩家球体的距离小于等于玩家球体的半径 player.r,则表示玩家球体吃到了该食物。
吃到食物后,将食物的存在标志 food[i].flag 设置为假,表示食物消失。
将玩家球体的半径 player.r 增加吃到食物球体半径 food[i].r 的1/4,以增加玩家球体的大小。
其中为判断是否被吃,也就是距离问题,需要引入求距离函数

double distance(struct Ball a, struct Ball b)
{
	return sqrt((double)(a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

玩家吃食物

void eatFood()
{
	for (int i = 0; i < FOOD_NUM; ++i)
	{
		if (food[i].flag && distance(food[i], player) <= player.r)
		{
			food[i].flag = false;
			player.r += food[i].r / 4;
		}
	}
}

(5)函数 aiMove() 是用于AI角色移动

1.对于每个AI角色(AI_NUM 个):
2.如果AI角色存在(ai[i].flag 为真),则分别生成随机的X轴和Y轴偏移量。
3.X轴偏移量通过 rand() % 5 - 2 生成一个介于-2到2之间的随机数。
4.Y轴偏移量同样通过 rand() % 5 - 2 生成一个介于-2到2之间的随机数。
5.将随机生成的偏移量加到AI角色的当前位置上,实现随机移动的效果。

void aiMove()
{
	for (int i = 0; i < AI_NUM; ++i)
	{
		if (ai[i].flag)
		{
			ai[i].x += rand() % 5 - 2;  // 生成随机的X轴偏移量
			ai[i].y += rand() % 5 - 2;  // 生成随机的Y轴偏移量
		}
	}
}

以下是优化版本

void aiMove()
{
	for (int i = 0; i < AI_NUM; ++i)
	{
		if (ai[i].flag)
		{
			int xOffset = rand() % 5 - 2; // 生成随机的X轴偏移量
			int yOffset = rand() % 5 - 2; // 生成随机的Y轴偏移量

			ai[i].x += xOffset;
			ai[i].y += yOffset;

			// 限制AI角色移动的范围,确保不超出窗口边界
			if (ai[i].x < 0)
				ai[i].x = 0;
			else if (ai[i].x > WIDTH)
				ai[i].x = WIDTH;

			if (ai[i].y < 0)
				ai[i].y = 0;
			else if (ai[i].y > HEIGHT)
				ai[i].y = HEIGHT;
		}
	}
}

优化说明:
1.使用变量 xOffset 和 yOffset 存储随机生成的X轴和Y轴的偏移量,以减少重复的随机数生成。
2.限制AI角色移动的范围,确保AI角色的位置不会超出窗口的边界。通过比较偏移量后的位置和窗口宽度和高度的大小来限制移动范围。

(6)主函数 int main() 控制游戏的主循环和整体

int main()
{
	initgraph(WIDTH, HEIGHT);
	GameInit();
	while (1)
	{
		keyControl(1);
		GameDraw();
		eatFood();
		aiMove();
	}
	getchar();
	return 0;
}

4.最终代码

#include<stdio.h>
#include<easyx.h>//包含图形库头文件
#include<stdlib.h>
#include<time.h>
#include<math.h>
#define FOOD_NUM 200 //食物数量
#define WIDTH 1024
#define HEIGHT 640
#define HEIFGT  10
#define AI_NUM 10//人工智障数量
/*
做游戏:1.窗口,画图,贴图。。。。。easyx图形库的
食物:圆(圆心坐标,半径,颜色,是否存在的标志)
*/
struct Ball//小球结构,玩家,食物,人工智障
{
	int x;
	int y;
	int r;//半径
	DWORD color;//颜色
	bool flag;//是否存在
};
struct Ball food[FOOD_NUM];
struct Ball player;//玩家
struct Ball ai[AI_NUM];
void GameInit()
{
	//设置随机数种子,时间是在不断变化的
	srand((unsigned)time(NULL));
	for (int i = 0; i < FOOD_NUM; ++i)
	{
		food[i].x = rand() % WIDTH;
		food[i].y = rand() % HEIGHT;
		food[i].flag = true;//刚开始食物存在
		food[i].r = rand() % 6 + 1;
		food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
	}
	//初始化玩家数据
	player.x = rand() & WIDTH + 1;
	player.y = rand() % HEIGHT + 1;
	player.r = 18;//只要比食物大就可以
	player.flag = true;
	player.color = RGB(rand() % 256, rand() % 256, rand() % 256);
	//初始化ai
	for (int i = 0; i < AI_NUM; ++i)
	{
		ai[i].x = rand() % WIDTH;
		ai[i].y = rand() % HEIGHT;
		ai[i].r = rand() % 10 + 5;
		ai[i].flag = true;
		ai[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
	}
}
//绘制
void GameDraw()
{
	//防止闪屏
	BeginBatchDraw();
	setbkcolor(WHITE);
	cleardevice();//清屏
	for (int i = 0; i < FOOD_NUM; ++i)
	{
		if (food[i].flag)
		{
			setfillcolor(food[i].color);//设置填充颜色
			solidcircle(food[i].x, food[i].y,food[i].r);//画一个填充圆
		}
		else
		{
			food[i].x = rand() % WIDTH;
			food[i].y = rand() % HEIGHT;
			food[i].flag = true;//刚开始食物存在
			food[i].r = rand() % 6 + 1;
			food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
		}
	}
	//绘制玩家
	setfillcolor(player.color);//设置填充颜色
	solidcircle(player.x, player.y, player.r);
	settextcolor(GREEN);
	settextstyle(30, 0, L"黑体");
	setbkmode(0);//设置文字背景透明
	outtextxy(player.x-50, player.y, L"我是最靓的崽仔");
	EndBatchDraw();
	//绘制ai
	for (int i = 0; i < AI_NUM;++i)
	{
		if (ai[i].flag)
		{
			setfillcolor(ai[i].color);
			solidcircle(ai[i].x, ai[i].y, ai[i].r);
		}
	}
}
void keyControl(int speed)
{
	//获取键盘消息,按的是哪一个键 
	if ((GetAsyncKeyState('W') || GetAsyncKeyState(VK_UP))&&player.y>=0)//按了上键
	{
		player.y -= speed;
	}
	if ((GetAsyncKeyState('S') || GetAsyncKeyState(VK_DOWN))&& player.y<=HEIGHT)//按了下键
	{  
		player.y += speed;
	}  
	if ((GetAsyncKeyState('A') || GetAsyncKeyState(VK_LEFT))&& player.x >= 0)//按了左键
	{  
		player.x -= speed;
	}  
	if ((GetAsyncKeyState('D') || GetAsyncKeyState(VK_RIGHT))&& player.x<=WIDTH)//按了右键
	{  
		player.x += speed;
	}
}
//求两点之间的距离
double distance(struct Ball a, struct Ball b)
{
	return sqrt((double)(a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
//玩家吃食物
void eatFood()
{
	for (int i = 0; i < FOOD_NUM; ++i)
	{
		if (food[i].flag && distance(food[i], player) <= player.r)
		{
			food[i].flag = false;
			player.r += food[i].r / 4;
		}
	}
}
//ai移动
void aiMove()
{
	for (int i = 0; i < AI_NUM; ++i)
	{
		if (ai[i].flag)
		{
			ai[i].x += rand() % 5-2;
			ai[i].y += rand() % 5 - 2;
		}
	}
}
int main()
{
	initgraph(WIDTH, HEIGHT);
	GameInit();
	while (1)
	{
		keyControl(1);
		GameDraw();
		eatFood();
		aiMove();
	}
	getchar();
	return 0;
}

其他具体功能读者可自行添加。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/917331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新能源汽车技术的最新进展和未来趋势

文章目录 电池技术的进步智能驾驶与自动驾驶技术充电基础设施建设新能源汽车共享和智能交通未来趋势展望结论 &#x1f389;欢迎来到AIGC人工智能专栏~探索新能源汽车技术的最新进展和未来趋势 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客…

请注意:名字里千万不要有凶数

人与人之间相处&#xff0c;最重要的就是信任二字。 而被人相信和被人欣赏一样&#xff0c;都是值得我们喜乐和感动的事情。 曾经&#xff0c;峰民在常德工作室接待一位预约福主&#xff0c; 这位福主一见面就给了峰民一个感恩红包&#xff0c;峰民非常感动。 这位福主是非常的…

RISC-V公测平台发布 · 在SG2042上配置Jupiter+Octave科学计算环境

简介 JupyterHub是一个开源的共享计算平台&#xff0c;它为每个用户管理一个单独的 Jupyter 环境&#xff0c; 可以用于学生班级、企业数据科学小组或科学研究小组。它是一个多用户中心&#xff0c;可以生成、管理和代理多个单用户Jupyter笔记本服务器的实例。 GNU Octave是一…

分布式下的session共享问题

首页我们确定在分布式的情况下session是不能共享的。 1.不同的服务&#xff0c;session不能共享&#xff0c;也就是微服务的情况下 2.同一服务在分布式情况&#xff0c;session同样不能共享&#xff0c;也会是分布式情况 分布式下session共享问题解决方案(域名相同) 1.session复…

基于 Android 剧院购票APP的开发与设计

摘要&#xff1a;近年来&#xff0c;随着社会的发展和科技方面的创新&#xff0c;越来越多的人选择使用手机应用程序来购买剧场票。本文将探讨基于 Android 平台的剧院购票应用程序的开发和设计。该应用程序将为用户提供浏览剧场列表、查看剧场详情、选择座位并购买剧场票的功能…

sas数据转pandas

1999年以后的nhanes数据都是以xpt文件格式发布的&#xff0c;而更早的数据有很多是以dat原始数据格式发布&#xff0c;需要将原始数据转为数据表以做进一步统计分析。 以 NHANES III 为例&#xff0c;其中有一个数据Household Youth File&#xff0c;包含3个数据文件youth.dat…

Type C接口的PCB布局布线要求

USB Type C&#xff0c;又称为USB-C。需要注意的是Type-C只是一种接口&#xff0c;和USB的版本没有任何关系。该接口的亮点在于更加纤薄的设计、更快的传输速度&#xff08;最高10Gbps以及更强悍的电力传输&#xff08;最高100W)。 Type-C双面可插接口最大的特点的支持USB接口…

【 OpenGauss源码学习 —— 列存储(Insert)】

列存储&#xff08;Insert&#xff09; 概述相关函数ExecInsertRelationData 结构体FormData_pg_class 结构体HeapInsertCStore函数InsertArg 结构体CStoreInsert 类CStoreInsert::InitInsertArg函数heap_deform_tuple 函数bulkload_rows 结构体append_one_tuple 函数bulkload_…

在线图片怎么转换成PDF?在线图片转换成PDF步骤介绍

文件格式要转化不知道怎么办?想要网上下载文件格式转换软件&#xff0c;但是却不知道下载哪个好?今天小编小编就给大家分享一下靠谱的小圆象PDF转换器工具&#xff0c;想知道这款软件好不好用?在线图片怎么转换成PDF?那就进来看看吧。 在线图片怎么转换成PDF 小圆象PDF转换…

LeetCode——二叉树篇(八)

刷题顺序及思路来源于代码随想录&#xff0c;网站地址&#xff1a;https://programmercarl.com 目录 236. 二叉树的最近公共祖先 235. 二叉搜索树的最近公共祖 迭代 递归 701. 二叉搜索树中的插入操作 450. 删除二叉搜索树中的节点 236. 二叉树的最近公共祖先 给定一个二…

数据加密技术——对称加密和非对称加密

一、数据加密技术 加密是指对数据进行编码变换&#xff0c;使其看起来毫无意义&#xff0c;但同时却仍可以保持其可恢复的形式的过程。在这个过程中&#xff0c;被变换的数据称为明文&#xff0c;它可以是一段有意义的文字或者数据&#xff0c;变换后的数据称为密文。加密机制有…

学习笔记|认识数码管|控制原理|数码管实现0-9的显示|段码跟位码|STC32G单片机视频开发教程(冲哥)|第九集:数码管静态显示

文章目录 1.认识数码管2.控制原理十进制转换为任意进制其它进制转十进制 3.数码管实现0-9的显示1.用数组定义0-9的内码段码跟位码的区别2.尝试用延时实现0-9的循环显示3.用按键控制数字的加或者减。 总结课后练习&#xff1a; 1.认识数码管 数码管按段数可分为七段数码管和八段…

C#与西门子PLC1500的ModbusTcp服务器通信4--搭建ModbusTcp客户端

1、客户端选择 客户端可以是一个程序或一个设备&#xff0c;这里我以C#WINFORM程序来实现客户机与PLC的Modbustcp服务器通信&#xff0c;开发环境是VS2019&#xff0c;.NET Framework版本是4.7.2 2、创建winform程序 3、引入Nmodbus协议 4、界面布局如下&#xff1a; 布局中…

无涯教程-PHP - Filtered反序列化

PHP 7引入了Filtered unserialize()函数&#xff0c;以在对不受信任的数据上的对象进行反序列化时提供更好的安全性。 <?phpclass MyClass1 { public $obj1prop; }class MyClass2 {public $obj2prop;}$obj1new MyClass1();$obj1->obj1prop1;$obj2new MyClass2();$obj…

java 版本企业招标投标管理系统源码+功能描述+tbms+及时准确+全程电子化 tbms

​ 功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查…

Java串口开发

网上搜索了关于java串口开发的资料,发现都不是特别的全,故写下一些心得以帮助其他人能快速上手java串口开发,如有错漏之处&#xff0c;敬请指正 串口开发会用到一个javax.comm和RXTXcomm库,&#xff0c;javax.comm库不支持64位操作系统。该库仅适用于32位操作系统,所以接下来主…

SAP S/4 BP(Business Partner)之一次性客商设置

目录 前言 一、一次性客商是什么&#xff1f; 二、BP创建步骤 1.开始步骤 总结 前言 在ECC里的一次性客商跟在S/4有一些区别&#xff0c;本文主要介绍在S/4里创建一次性BP的步骤。 一、一次性客商是什么&#xff1f; 一次性供应商是指我们通常不经常从其采购材料的供应商…

课程实录 | Ingress Controller 的工作原理(下)

原文作者&#xff1a;陶辉 - 杭州智链达数据有限公司&#xff0c;联合创始人兼 CTO 原文链接&#xff1a;课程实录 | Ingress Controller 的工作原理&#xff08;下&#xff09; 转载来源&#xff1a;NGINX 开源社区 NGINX 唯一中文官方社区 &#xff0c;尽在 nginx.org.cn 编者…

Android Lottie加载gson文件动画

一&#xff1a;Lottie的使用 在你工程的build.gradle文件里添加如下配置 implementation com.airbnb.android:lottie:3.4.0二&#xff1a;布局文件直接引入LottieAnimationView <com.airbnb.lottie.LottieAnimationViewandroid:id"id/lottie_view"android:layout…

axios 介绍

axios 介绍 axios 是一款基于 javascript xhr 进行封装的插件&#xff0c;自己通过 xhr 进行编写 ajax 请求&#xff0c;实现起来逻辑比较复杂&#xff0c;axios 封装后将复杂的逻辑写在插件的内部&#xff0c;我们用户只需要关心如何调用即可。对我们的开发带来了很大的便捷。…