基于EasyX库开发的球球大作战游戏

目录

球球大作战

一、开发环境

二、流程图预览

三、代码逻辑

1、初始化时间

2、设置开始界面大小

3、设置开始界面

4、让玩家选择速度

5、设置玩家小球、人机小球、食物的属性

6、一次性把图绘制到界面里

7、进入死循环

8、移动玩家小球

9、移动人机

10、食物刷新

11、画出边界、食物、人机、玩家、小地图,添加击杀数、半径(质量)、玩家名字

12、将内存中的绘图操作批量地绘制到屏幕上,从而提高绘图效率

四、代码预览+运行结果


球球大作战

一、开发环境

VisualStudio专业版:

所需依赖库:EasyX库

二、流程图预览

由于上面的比较模糊,下面分开截取流程图图片

三、代码逻辑

1、初始化时间

starttime();

2、设置开始界面大小

initgraph(WIDTH, HEIGHT);

3、设置开始界面

void start() {setbkcolor(WHITE);                          // 白色背景cleardevice();                              // 初始化背景settextcolor(BLACK);                            // 改字体setbkmode(TRANSPARENT);                 //设置背景是透明的//加载背景图片IMAGE image;loadimage(&image, _T("D:\\桌面\\file2\\球球大作战\\source\\Ball Ball\\x64\\img\\10.jpg"), WIDTH, HEIGHT);//在当前设备上绘制指定图像putimage(0, 0, &image);//加入提示信息settextcolor(WHITE);settextstyle(22, 0, _T("黑体"));outtextxy(50, 480, _T("请选择关卡:"));outtextxy(50, 550, _T("1.小试牛刀"));outtextxy(200, 550, _T("2.炉火纯青"));outtextxy(350, 550, _T("3.登峰造极"));settextstyle(15, 0, _T("宋体"));outtextxy(600, 550, _T("注:按序号选择,默认选择关卡1;游戏中按空格键可以暂停。"));settextcolor(BLACK);settextstyle(22, 0, _T("黑体"));TCHAR s[5];//_stprintf(s, _T("%d"), readCount());_stprintf_s(s, _countof(s), _T("%d"), readCount());outtextxy(810, 200, _T("欢迎进入游戏!"));outtextxy(810, 240, _T("游戏次数:"));outtextxy(910, 240, s);
}

4、让玩家选择速度

void ChooseSpeed() {switch (_getch()) {case 1:speed = 4;case 2:speed = 3;case 3:speed = 2;default:speed = 4;}
}

5、设置玩家小球、人机小球、食物的属性

void setall() {srand((unsigned)time(NULL));                    // 随机数mover.color = RGB(rand() % 256, rand() % 256, rand() % 256);        // 随机颜色mover.life = 1;                             // 赋初值1//把玩家的球一直放在屏幕中央mover.x = int(WIDTH * 0.5);mover.y = int(HEIGHT * 0.5);//设置半径mover.r = 20;
​for (int i = 0; i < AINUM; i++) {               // AI 的属性ai[i].life = 1;ai[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);//ai[i].r = float(rand() % 10 + 10);ai[i].r = 20;ai[i].x = rand() % (MAPW - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);ai[i].y = rand() % (MAPH - int(ai[i].r + 0.5)) + int(ai[i].r + 0.5);}
​for (int i = 0; i < FNUM; i++) {                // 食物的属性food[i].eat = 1;food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);food[i].x = rand() % MAPW;food[i].y = rand() % MAPH;food[i].type = rand() % 10 + 1;}
​pBuffer = GetImageBuffer(NULL);                 // 获取显存指针setbkcolor(WHITE);                          // 白色背景cleardevice();                              // 初始化背景settextcolor(LIGHTRED);                     // 改字体//设置背景是透明的setbkmode(TRANSPARENT);settextstyle(16, 0, _T("宋体"));
​
}

6、一次性把图绘制到界面里

BeginBatchDraw();

7、进入死循环

8、移动玩家小球

void move(BALL* ball) {if (ball->r <= 0)ball->life = false;if (ball->life == false) {                      // 判定游戏是否接束HWND hwnd = GetHWnd();MessageBox(hwnd, _T("你被吃了"), _T("游戏结束"), MB_ICONEXCLAMATION);endtime();
​}
​if (eaten + ai_eaten == AINUM)                  // 是否吃掉所有 AI{HWND hwnd = GetHWnd();MessageBox(hwnd, _T("恭喜过关"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION);   // 结束endtime();}
​for (int i = 0; i < AINUM; i++) {               // 玩家吃 AI 判定if (ball->r >= ai[i].r) {if (ai[i].life == 0)    continue;if (DISTANCE(ball->x, ball->y, ai[i].x, ai[i].y) < (4 / 5.0 * (ball->r + ai[i].r))) {ai[i].life = 0;                 //AI被吃ball->r = sqrt(ai[i].r * ai[i].r + ball->r * ball->r);eaten++;}}}
​for (int n = 0; n < FNUM; n++) {                // 玩家吃食物if (food[n].eat == 0)   continue;if (DISTANCE(ball->x, ball->y, food[n].x, food[n].y) < ball->r) {ball->r += 4 / ball->r;             // 增加面积food[n].eat = 0;                        // 食物被吃}}
​static int mx = 0, my = 0;                      // 记录偏移量
​//判断怎么移动if (GetAsyncKeyState(VK_UP) && (ball->y - ball->r > 0 && ball->y <= (MAPH - ball->r + 10))) {ball->y -= speed;my += speed;}if (GetAsyncKeyState(VK_DOWN) && (ball->y - ball->r >= -10 && ball->y < (MAPH - ball->r))) {ball->y += speed;my -= speed;}if (GetAsyncKeyState(VK_LEFT) && ball->x - ball->r > 0 && (ball->x <= (MAPW - ball->r + 10))) {ball->x -= speed;mx += speed;}if (GetAsyncKeyState(VK_RIGHT) && ball->x - ball->r >= -10 && (ball->x < (MAPW - ball->r))) {ball->x += speed;mx -= speed;}
​//判断是否输入其他用于退出、暂停、继续的按键if (GetAsyncKeyState(VK_SPACE)) {settextcolor(WHITE);settextstyle(32, 0, _T("宋体"));outtextxy(384 - mx, 350 - my, _T("游戏已暂停!"));outtextxy(20 - mx, 500 - my, _T("(ESC)退出"));outtextxy(780 - mx, 500 - my, _T("(回车键)继续"));FlushBatchDraw();_getch();if (GetAsyncKeyState(VK_ESCAPE))exit(0);else_getch();}
​setorigin(mx, my);                          //坐标修正
}

9、移动人机

void AI() {for (int i = 0; i < AINUM; i++) {               // AI 吃玩家if (ai[i].r > mover.r) {if (DISTANCE(mover.x, mover.y, ai[i].x, ai[i].y) < (ai[i].r + mover.r)) {ai[i].r = sqrt(ai[i].r * ai[i].r + mover.r * mover.r);mover.life = 0;mover.r = 0;}}for (int j = 0; j < AINUM; j++) {           // AI 吃 AIif (ai[i].r > ai[j].r) {if (ai[j].life == 0) continue;if (DISTANCE(ai[i].x, ai[i].y, ai[j].x, ai[j].y) < (ai[i].r + ai[j].r)) {ai[i].r = sqrt(ai[i].r * ai[i].r + ai[j].r * ai[j].r);ai[j].life = 0;ai[j].r = 0;ai_eaten++;}}}
​double min_DISTANCE = 100000;int min = -1;for (int k = 0; k < AINUM; k++) {           // AI 靠近 AIif (ai[i].r > ai[k].r && ai[k].life != 0) {if (DISTANCE(ai[i].x, ai[i].y, ai[k].x, ai[k].y) < min_DISTANCE) {min_DISTANCE = DISTANCE(ai[i].x, ai[i].y, ai[k].x, ai[k].y);min = k;}}}if ((min != -1) && (rand() % 2 == 1) && (ai[i].y - ai[i].r > 0 && ai[i].y <= (MAPH - ai[i].r + 10))) {if (rand() % 2) {if (ai[i].x < ai[min].x)ai[i].x += speed ;elseai[i].x -= speed ;}else {if (ai[i].y < ai[min].y)ai[i].y += speed ;elseai[i].y += speed ;}}for (int n = 0; n < FNUM; n++) {            // AI 吃食物if (food[n].eat == 0) continue;if (DISTANCE(ai[i].x, ai[i].y, food[n].x, food[n].y) < ai[i].r) {ai[i].r += 4 / ai[i].r;food[n].eat = 0;}}}
}

10、食物刷新

void Food() {for (int i = 0; i < FNUM; i++) {				// 食物刷新if (food[i].eat == 0) {food[i].eat = 1;food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);food[i].x = rand() % MAPW;food[i].y = rand() % MAPH;food[i].type = rand() % 10 + 1;}}
}

11、画出边界、食物、人机、玩家、小地图,添加击杀数、半径(质量)、玩家名字

void draw() {float asp = 1;//清空裁剪区,超出区域的绘图操作将被裁剪掉clearcliprgn();IMAGE image;loadimage(&image, _T(""), WIDTH * 4, HEIGHT * 4);putimage(0, 0, &image);//绘画出一个矩形框setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 20);		// 改变笔的颜色、状态setlinecolor(RGB(0, 100, 0));line(-20, MAPH + 20, -20, -20);				// 左竖line(-20, MAPH + 20, MAPW + 20, MAPH + 20);		// 上横line(-20, -20, MAPW + 20, -20);				// 下横line(MAPW + 20, -20, MAPW + 20, MAPH + 20);		// 右竖setfillcolor(GREEN);//当球接近边界时,会在边界外侧绘制一个绿色的填充矩形,// 是用来表示碰撞或者边界的视觉效果if (mover.x - 0.5 * WIDTH / asp < -20)floodfill(-20 - 11, mover.y, RGB(0, 100, 0));if (mover.x + 0.5 * WIDTH / asp > MAPW + 20)floodfill(MAPW + 20 + 11, mover.y, RGB(0, 100, 0));if (mover.y - 0.5 * HEIGHT / asp < -20)floodfill(mover.x, -20 - 11, RGB(0, 100, 0));if (mover.y + 0.5 * HEIGHT / asp > MAPH + 20)floodfill(mover.x, MAPH + 20 + 11, RGB(0, 100, 0));setlinecolor(WHITE);setlinestyle(PS_NULL);for (int i = 0; i < FNUM; i++) {				// 画出食物if (food[i].eat == 0) continue;setfillcolor(food[i].color);switch (food[i].type) {					// 形状case 1:		solidellipse(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4); break;case 2:		solidellipse(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2);	break;case 3:		solidrectangle(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2); break;case 4:		solidrectangle(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4); break;case 5:		solidroundrect(food[i].x, food[i].y, food[i].x + 2, food[i].y + 4, 2, 2); break;case 6:		solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 2); break;case 7:		solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 4, 2); break;case 8:		solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 2, 4); break;case 9:		solidroundrect(food[i].x, food[i].y, food[i].x + 4, food[i].y + 2, 1, 1); break;case 10:	fillcircle(food[i].x, food[i].y, 4); break;}}for (int i = 0; i < AINUM; i++) {				// 画 AIif (ai[i].life == 0) continue;setfillcolor(ai[i].color);//绘圆fillcircle(ai[i].x, ai[i].y, int(ai[i].r + 0.5));}setfillcolor(mover.color);						// 画玩家fillcircle(mover.x, mover.y, int(mover.r + 0.5));IMAGE map(150, 100);							// 小地图SetWorkingImage(&map);setbkcolor(RGB(120, 165, 209));					// 浅灰色背景cleardevice();for (int i = 0; i < AINUM; i++)				// 画 AI(小地图){if (ai[i].life == 0) continue;setfillcolor(ai[i].color);fillcircle(ai[i].x * 150 / WIDTH / 4, ai[i].y * 100 / HEIGHT / 4, int(ai[i].r / 28 + 1.5));}setfillcolor(mover.color);						// 画玩家(小地图)fillcircle(mover.x * 150 / WIDTH / 4, mover.y * 100 / HEIGHT / 4, int(mover.r / 28 + 3.5));setlinecolor(RGB(0, 100, 0));SetWorkingImage();							// 恢复绘图背景putimage(mover.x + int(0.5 * WIDTH) - 150, mover.y - int(0.5 * HEIGHT), 150, 100, &map, 0, 0);						// 画出小地图setlinecolor(LIGHTBLUE);setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 4);line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT), mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99);	// 地图边框线line(mover.x + int(0.5 * WIDTH) - 151, mover.y - int(0.5 * HEIGHT) + 99, mover.x + int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT) + 99);	// 地图边框线setlinestyle(PS_NULL);							// 恢复笔TCHAR str[32];swprintf_s(str, _T("质量:%.1fg  击杀:%d"), mover.r, eaten);settextcolor(WHITE);							// 改字体outtextxy(mover.x - int(0.5 * WIDTH), mover.y - int(0.5 * HEIGHT), str);settextcolor(WHITE);outtextxy(mover.x - 20, mover.y, _T("itlsl"));
}

12、将内存中的绘图操作批量地绘制到屏幕上,从而提高绘图效率

FlushBatchDraw();

四、代码预览+运行结果

源代码+流程图+README资源:https://download.csdn.net/download/2403_82436914/90623088?spm=1001.2014.3001.5503

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

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

相关文章

aslist和list的区别

‌Arrays.asList和List的主要区别在于它们的固定长度和不可变性、与原始数组的关系、性能以及使用场景。 一、固定长度和不可变性 ‌Arrays.asList‌&#xff1a;通过Arrays.asList方法创建的List是一个固定长度的List&#xff0c;其长度与原始数组相同。这意味着你不能通过添…

大模型预标注和自动化标注在OCR标注场景的应用

OCR&#xff0c;即光学字符识别&#xff0c;简单来说就是利用光学设备去捕获图像并识别文字&#xff0c;最终将图片中的文字转换为可编辑和可搜索的文本。在数字化时代&#xff0c;OCR&#xff08;光学字符识别&#xff09;技术作为处理图像中文字信息的关键手段&#xff0c;其…

stm32工程,拷贝到另一台电脑编译,错误提示头文件找不到cannot open source input file “core_cm4.h”

提示 cannot open source input file “core_cm4.h” ,找不到 [ core_cm4.h ] 这个头文件 . 于是我在原电脑工程文件里找也没有找到这个头文件 接下来查看原电脑keil的头文件引入配置,发现只引入了工程文件下的头文件, 那么core_cm4.h到底哪里来的? (到现在我也不清楚怎…

STM32 模块化开发指南 · 第 2 篇 如何编写高复用的外设驱动模块(以 UART 为例)

本文是《STM32 模块化开发实战指南》的第 2 篇,聚焦于“串口驱动模块的设计与封装”。我们将从一个最基础的裸机 UART 初始化开始,逐步实现:中断支持、环形缓冲收发、模块接口抽象与测试策略,构建一个可移植、可扩展、可复用的 UART 驱动模块。 一、模块化 UART 的设计目标…

【NLP 59、大模型应用 —— 字节对编码 bpe 算法】

目录 一、词表的构造问题 二、bpe(byte pair encoding) 压缩算法 算法步骤 示例&#xff1a; 步骤 1&#xff1a;初始化符号表和频率统计 步骤 2&#xff1a;统计相邻符号对的频率 步骤 3&#xff1a;合并最高频的符号对 步骤 4&#xff1a;重复合并直至终止条件 三、bpe在NLP中…

TMS320F28P550SJ9学习笔记15:Lin通信SCI模式结构体寄存器

今日初步认识与配置使用Lin通信SCI模式&#xff0c;用结构体寄存器的方式编程 文章提供完整工程下载、测试效果图 我的单片机平台是这个&#xff1a; LIN通信引脚&#xff1a; LIN通信PIE中断&#xff1a; 这个 PIE Vector Table 表在手册111页&#xff1a; 这是提到LINa的PI…

linux-设置每次ssh登录服务器的时候提醒多久需要修改密码

在 Linux 系统中,你可以通过设置 motd(Message of the Day)或 sshd 配置来在用户通过 SSH 登录时提醒他们密码即将过期。以下是具体步骤: 方法 1: 使用 motd 文件 motd 文件在用户登录时显示,你可以通过脚本动态生成内容,提醒用户密码过期时间。 编辑 /etc/motd 文件:…

matlab求和∑函数方程编程?

matlab求和∑函数方程编程&#xff1f; 一 题目&#xff1a;求下列函数方程式的和 二&#xff1a;代码如下&#xff1a; >> sum_result 0; % 初始化求和变量 for x 1:10 % 设…

electron桌面端开发-打开指定软件和文件

electron桌面端开发 现在越来越多的软件开发已经趋向于简单化&#xff0c;桌面端开发已经不在依赖之前的java、c等主流技术&#xff0c;目前基于node的开发越来越广泛。功能点也越来越多元化。 文章目录 electron桌面端开发前言一、打开文件的方式&#xff1f;二、exec使用步骤…

ShenNiusModularity项目源码学习(17:ShenNius.Admin.Mvc项目分析-2)

ShenNiusModularity项目的后台管理主页面如下图所示&#xff0c;该页面为ShenNius.Admin.Mvc项目的Views\Home\Index.cshtml&#xff0c;使用的是layuimini后台模板&#xff08;参考文献2&#xff09;&#xff0c;在layuimini的GitHub主页中提供有不同样式的页面模版链接&#…

SpringBoot 与 Vue3 实现前后端互联全解析

在当前的互联网时代&#xff0c;前后端分离架构已经成为构建高效、可维护且易于扩展应用系统的主流方式。本文将详细介绍如何利用 SpringBoot 与 Vue3 构建一个前后端分离的项目&#xff0c;展示两者如何通过 RESTful API 实现无缝通信&#xff0c;让读者了解从环境搭建、代码实…

portainer.io篇

Portainer‌是一个轻量级的容器管理工具&#xff0c;支持Docker、Kubernetes、Docker Swarm、ACI和Nomad等多种平台。它提供了一个直观的Web界面&#xff0c;使用户能够轻松地管理和监控容器&#xff0c;包括创建、启动、停止、删除容器&#xff0c;以及查看容器的日志和配置信…

Dockerfile 文件常见命令及其作用

Dockerfile 文件包含一系列命令语句&#xff0c;用于定义 Docker 镜像的内容、配置和构建过程。以下是一些常见的命令及其作用&#xff1a; FROM&#xff1a;指定基础镜像&#xff0c;后续的操作都将基于该镜像进行。例如&#xff0c;FROM python:3.9-slim-buster 表示使用 Pyt…

Android Studio开发知识:从基础到进阶

引言 Android开发作为移动应用开发的主流方向之一&#xff0c;曾吸引了无数开发者投身其中。然而&#xff0c;随着市场饱和和技术迭代&#xff0c;当前的Android开发就业形势并不乐观&#xff0c;竞争日益激烈。尽管如此&#xff0c;掌握扎实的开发技能仍然是脱颖而出的关键。本…

大表查询的优化方案

‌单表优化‌&#xff1a; ‌字段选择‌&#xff1a;尽量使用TINYINT、SMALLINT、MEDIUMINT作为整数类型&#xff0c;而非INT&#xff1b;如果字段值非负&#xff0c;可以使用UNSIGNED。对于字符串字段&#xff0c;使用枚举或整数代替字符串类型&#xff0c;使用TIMESTAMP而非D…

常见MQ及类MQ对比:Redis Stream、Redis Pub/Sub、RocketMQ、Kafka 和 RabbitMQ

常见MQ及类MQ对比 基于Grok调研 Redis Stream、Redis Pub/Sub、RocketMQ、Kafka 和 RabbitMQ 关键点&#xff1a; Redis Pub/Sub 适合简单实时消息&#xff0c;但不持久化&#xff0c;消息可能丢失。Redis Stream 提供持久化&#xff0c;适合需要消息历史的场景&#xff0c;但…

DAPP实战篇:使用ethersjs连接智能合约并输入地址查询该地址余额

本系列目录 专栏:区块链入门到放弃查看目录-CSDN博客文章浏览阅读400次。为了方便查看将本专栏的所有内容列出目录,按照顺序查看即可。后续也会在此规划一下后续内容,因此如果遇到不能点击的,代表还没有更新。声明:文中所出观点大多数源于笔者多年开发经验所总结,如果你…

库magnet使用指南

Magnet 多线程控制库使用指南 目录 库功能概述环境配置核心类与接口基础使用示例代码生成工具高级功能与改进建议完整示例代码常见问题解答 https://blink.csdn.net/details/1872803?spm1001.2014.3001.5501 1. 库功能概述 Magnet 库提供以下核心功能&#xff1a; 多线程…

SpringCloud-快速通关(三)

SpringCloud-快速通关(一) SpringCloud-快速通关(二) SpringCloud-快速通关(三) SpringCloud-快速通关(三) 七、Seata - 分布式事务7.1、环境搭建7.1.1、简介7.1.2、环境搭建7.1.3、seata-server7.1.4、微服务配置7.1.5、测试7.2、事务模式7.2.1、AT模式7.2.2、XA模式…

STM32 TDS+温度补偿

#define POLAR_CONSTANT (513385) /* 电导池常数&#xff0c;可通过与标准TDS测量仪对比计算反推 */ #define TDS_COEFFICIENT (55U) /* TDS 0.55 * 电子传导率*/void TDS_Value_Conversion() {u32 ad0;u8 i;float compensationCoefficient;float compens…