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

目录

  • 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);//初始化aifor (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();//绘制aifor (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);//初始化aifor (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();//绘制aifor (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.mzph.cn/news/49336.shtml

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

相关文章

《动手学深度学习》-20卷积层里的填充和步幅

沐神版《动手学深度学习》学习笔记&#xff0c;记录学习过程&#xff0c;详细的内容请大家购买书籍查阅。 b站视频链接 开源教程链接 卷积层里的填充和步幅 应用5x5大小的卷积核&#xff0c;输入32x32&#xff0c;输出会变为28x28。 更大的卷积核更快地减小输出大小。 导致网…

【数据治理】什么是数据库归档

文章目录 前言什么是数据归档 前言 如果您的日常工作中需要对数据库进行管理&#xff0c;那您肯定已经或即将遭遇这样的困惑&#xff1a;随着业务的蓬勃发展&#xff0c;数据库文件的大小逐渐增大&#xff0c;您需要为在线业务提供越来越大的高性能磁盘容量&#xff0c;但数据…

Angular中 ng-template 和 ng-content 有何区别?

在Angular中&#xff0c;ng-template 和 ng-content 都是用于管理和展示内容的指令&#xff0c;但它们在使用和功能上有一些区别。让我为你解释一下它们的区别&#xff0c;并提供一些示例来说明。 ng-template: ng-template 是一个用来定义可重用模板的容器。它本身不会被渲染…

微信公众号网页开发调用扫一扫及苹果手机(iOS)无反应问题解决方案

二维码大家都很常见&#xff0c;使用场景也很多&#xff0c;但是日常使用中有两种场景比较常见。 1、二维码背后的内容是一个网址&#xff0c;扫描后直接跳转到对应的网址&#xff0c;比如&#xff1a;宣传海报&#xff0c;跳转到直播间、微官网或者微信公众号。 2、二维码背后…

鲁图中大许少辉博士八一新书《乡村振兴战略下传统村落文化旅游设计》山东省图书馆典藏

鲁图中大许少辉博士八一新书《乡村振兴战略下传统村落文化旅游设计》山东省图书馆典藏

ubuntu 安装 postgresql以及 wal回滚

安装 sudo apt install postgresql postgresql-contrib设置远程连接 修改/etc/postgresql/12/main/postgresql.conf **将listen_addresses 改成 ***修改/etc/postgresql/12/main/pg_hba.conf 找到如下信息 #IPv4 local connections: 修改为 host all all 0.0.0.0/0 md5 重启…

Git问题:解决“ssh:connect to host github.com port 22: Connection timed out”

操作系统 Windows11 使用Git IDEA 连接方式&#xff1a;SSH 今天上传代码出现如下报错&#xff1a;ssh:connect to host github.com port 22: Connection timed out 再多尝试几次&#xff0c;依然是这样。 解决 最终发现两个解决方案&#xff1a;&#xff08;二选一&#xf…

反转链表II

江湖一笑浪滔滔&#xff0c;红尘尽忘了 题目 示例 思路 链表这部分的题&#xff0c;不少都离不开单链表的反转&#xff0c;参考&#xff1a;反转一个单链表 这道题加上哨兵位的话会简单很多&#xff0c;如果不加的话&#xff0c;还需要分情况一下&#xff0c;像是从头节点开始…

剑指Offer51.数组中的逆序对 C++

1、题目描述 在数组中的两个数字&#xff0c;如果前面一个数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。输入一个数组&#xff0c;求出这个数组中的逆序对的总数。 示例 1: 输入: [7,5,6,4] 输出: 5 2、VS2019上运行 使用方法一&#xff1a;归并排序 #inclu…

创建型(一) - 简单工厂模式、工厂方法模式和抽象工厂模式

本文使用了王争老师设计模式课程中的例子&#xff0c;写的很清晰&#xff0c;而且中间穿插了代码优化。 由于设计模式就是解决问题的一种思路&#xff0c;所以每个设计模式会从问题出发&#xff0c;这样比较好理解设计模式出现的意义。 一、简单工厂模式 解决问题&#xff1a…

淘宝Tmall1688京东API接口系列,海量数据值得get!

Api接口也就是所谓的应用程序接口&#xff0c;api接口的全称是Application Program Interface&#xff0c;通过API接口可以实现计算机软件之间的相互通信&#xff0c;开发人员可以通过API接口程序开发应用程序&#xff0c;可以减少编写无用程序&#xff0c;减轻编程任务&#x…

Docker入门知识讲解与实践

文章目录 Dockeryum在线安装安装yum-utils下载aliyun的repo源下载Docker配置加速器 Docker基本操作拉取镜像UbuntuCentos 创建两个容器容器的停止/重启查看容器退出容器交互式非交互式 查看容器内部信息查看Docker相关命令帮助docker rundocker image Docker save与Docker expo…

HJ53 杨辉三角的变形

以上三角形的数阵&#xff0c;第一行只有一个数1&#xff0c;以下每行的每个数&#xff0c;是恰好是它上面的数、左上角数和右上角的数&#xff0c;3个数之和&#xff08;如果不存在某个数&#xff0c;认为该数就是0&#xff09;。 求第n行第一个偶数出现的位置。如果没有偶数…

2023年计算机设计大赛国三 数据可视化 (源码可分享)

2023年暑假参加了全国大学生计算机设计大赛&#xff0c;并获得了国家三等奖&#xff08;国赛答辩出了点小插曲&#xff09;。在此分享和记录本次比赛的经验。 目录 一、作品简介二、作品效果图三、设计思路四、项目特色 一、作品简介 本项目实现对农产品近期发展、电商销售、灾…

金九银十面试题之《JVM》

&#x1f42e;&#x1f42e;&#x1f42e; 辛苦牛&#xff0c;掌握主流技术栈&#xff0c;包括前端后端&#xff0c;已经7年时间&#xff0c;曾在税务机关从事开发工作&#xff0c;目前在国企任职。希望通过自己的不断分享&#xff0c;可以帮助各位想或者已经走在这条路上的朋友…

删除链表的中间节点

题目&#xff1a; 示例&#xff1a; 思路&#xff1a; 这个题类似于寻找链表中间的数字&#xff0c;slow和fast都指向head&#xff0c;slow走一步&#xff0c;fast走两步&#xff0c;也许你会有疑问&#xff0c;节点数的奇偶不考虑吗&#xff1f;while执行条件写成fast&&…

Docker 的数据管理 网络通信

目录 1.管理容器数据的方式 数据卷 数据卷的容器 2.操作命令 3.Docker 镜像的创建 1.管理容器数据的方式 数据卷 可以独立于容器生命周期存储的机制 可提供持久化 数据共享 docker run -v /var/www:/data1 --name web1 -it centos:7 /bin/bash 数据卷的容器 用来提供持久化数…

那么多优秀的自动化测试工具,而你只知道Selenium?

如今&#xff0c;作为一名软件测试工程师&#xff0c;几乎所有人都需要具备自动化测试相关的知识&#xff0c;并且懂得如何去利用工具&#xff0c;来为企业减少时间成本和错误成本。这是为什么呢&#xff1f; 在以前&#xff0c;测试人员一般都只需要扮演终端用户&#xff0c;…

「隐语小课」拆分学习之“水平拆分学习”

一、引言 拆分学习是 2018 年由 MIT 最先提出的分布式算法。本文结合该领域的相关英文文献&#xff0c;介绍水平拆分学习的基本方法&#xff0c;同时还将对比拆分模型与中心化模型、联邦模型在不同条件下模型效率和准确性。拆分学习作为主流的隐私计算学习范式之一&#xff0c…

layui tree组件取消勾选

layui(2.8.15) tree的api中&#xff0c;只有 tree.setChecked(id, idArr) 方法&#xff0c;没有取消勾选的方法。 我的需求是&#xff1a;勾选后做判断&#xff0c;如果不符合条件则取消勾选。 实现方法&#xff1a; 使用 tree的oncheck事件&#xff0c;在回调函数中做判断&…