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

news2025/4/20 22:14:41

目录

球球大作战

一、开发环境

二、流程图预览

三、代码逻辑

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 吃 AI
            if (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 靠近 AI
            if (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 ;
                else
                    ai[i].x -= speed ;
            }
            else {
                if (ai[i].y < ai[min].y)
                    ai[i].y += speed ;
                else
                    ai[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++) {				// 画 AI
		if (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.coloradmin.cn/o/2338130.html

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

相关文章

《系统分析师-第三阶段—总结(一)》

背景 采用三遍读书法进行阅读&#xff0c;此阶段是第三遍。 过程 第一章 第二章 总结 在这个过程中&#xff0c;对导图的规范越来越清楚&#xff0c;开始结构化&#xff0c;找关系&#xff0c;找联系。

AI——K近邻算法

文章目录 一、什么是K近邻算法二、KNN算法流程总结三、Scikit-learn工具1、安装2、导入3、简单使用 三、距离度量1、欧式距离2、曼哈顿距离3、切比雪夫距离4、闵可夫斯基距离5、K值的选择6、KD树 一、什么是K近邻算法 如果一个样本在特征空间中的k个最相似&#xff08;即特征空…

用 NLP + Streamlit,把问卷变成能说话的反馈

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

TCP/IP和UDP协议的发展历程

TCP/IP和UDP协议的发展历程 引言 互联网的发展史是人类技术创新的辉煌篇章&#xff0c;而在这一发展过程中&#xff0c;通信协议发挥了奠基性的作用。TCP/IP&#xff08;传输控制协议/互联网协议&#xff09;和UDP&#xff08;用户数据报协议&#xff09;作为互联网通信的基础…

Function Calling的时序图(含示例)

&#x1f9cd; 用户&#xff1a; 发起请求&#xff0c;输入 prompt&#xff08;比如&#xff1a;“请告诉我北京的天气”&#xff09;。 &#x1f7ea; 应用&#xff1a; 将用户输入的 prompt 和函数定义&#xff08;包括函数名、参数结构等&#xff09;一起发给 OpenAI。 …

若依框架修改左侧菜单栏默认选中颜色

1.variables.sacc中修改为想要的颜色 2.给目标设置使用的颜色

搜广推校招面经七十八

字节推荐算法 一、实习项目&#xff1a;多任务模型中的每个任务都是做什么&#xff1f;怎么确定每个loss的权重 这个根据实际情况来吧。如果实习时候用了moe&#xff0c;就可能被问到。 loss权重的话&#xff0c;直接根据任务的重要性吧。。。 二、特征重要性怎么判断的&…

广搜bfs-P1443 马的遍历

P1443 马的遍历 题目来源-洛谷 题意 要求马到达棋盘上任意一个点最少要走几步 思路 国际棋盘规则是马的走法是-日字形&#xff0c;也称走马日&#xff0c;即x,y一个是走两步&#xff0c;一个是一步 要求最小步数&#xff0c;所以考虑第一次遍历到的点即为最小步数&#xff…

强化学习算法系列(六):应用最广泛的算法——PPO算法

强化学习算法 &#xff08;一&#xff09;动态规划方法——策略迭代算法(PI)和值迭代算法(VI) &#xff08;二&#xff09;Model-Free类方法——蒙特卡洛算法(MC)和时序差分算法(TD) &#xff08;三&#xff09;基于动作值的算法——Sarsa算法与Q-Learning算法 &#xff08;四…

AI Agents系列之AI代理架构体系

1. 引言 智能体架构是定义智能体组件如何组织和交互的蓝图,使智能体能够感知其环境、推理并采取行动。本质上,它就像是智能体的数字大脑——集成了“眼睛”(传感器)、“大脑”(决策逻辑)和“手”(执行器),用于处理信息并采取行动。 选择正确的架构对于构建有效的智能…

2025海外代理IP测评:Bright Data,ipfoxy,smartproxy,ipipgo,kookeey,ipidea哪个值得推荐?

近年来&#xff0c;随着全球化和跨境业务需求的不断扩大“海外代理IP”逐渐成为企业和个人在多样化场景中的重要工具。无论是进行数据采集、广告验证、社交媒体管理&#xff0c;还是跨境电商平台运营&#xff0c;选择合适的代理IP服务商都显得尤为重要。然而&#xff0c;市场上…

Android守护进程——Vold (Volume Daemon)

简介 介绍&#xff1a;Vold 是用来管理 android 系统的存储设备&#xff0c;如U盘、SD卡、磁盘等移动设备的热插拔、挂载、卸载、格式化 框架结构&#xff1a;Vold 在系统中以守护进程存在&#xff0c;是一个单独的进程。处于Kernel和Framework之间&#xff0c;是两个层级连接…

vue3+vite 实现.env全局配置

首先创建.env文件 VUE_APP_BASE_APIhttp://127.0.0.1/dev-api 然后引入依赖&#xff1a; pnpm install dotenv --save-dev 引入完成后&#xff0c;在vite.config.js配置文件内加入以下内容&#xff1a; const env dotenv.config({ path: ./.env }).parsed define: { // 将…

AI 组件库是什么?如何影响UI的开发?

AI组件库是基于人工智能技术构建的、面向用户界面&#xff08;UI&#xff09;开发的预制模块集合。它们结合了传统UI组件&#xff08;如按钮、表单、图表&#xff09;与AI能力&#xff08;如机器学习、自然语言处理、计算机视觉&#xff09;&#xff0c;旨在简化开发流程并增强…

OpenCV day6

函数内容接上文&#xff1a;OpenCV day4-CSDN博客 , OpenCV day5-CSDN博客 目录 平滑&#xff08;模糊&#xff09; 25.cv2.blur()&#xff1a; 26.cv2.boxFilter(): 27.cv2.GaussianBlur()&#xff1a; 28.cv2.medianBlur(): 29.cv2.bilateralFilter()&#xff1a; 锐…

【AI飞】AutoIT入门七(实战):python操控autoit解决csf视频批量转换(有点难,AI都不会)

背景&#xff1a; 终极目标&#xff1a;通过python调用大模型&#xff0c;获得结果&#xff0c;然后根据返回信息&#xff0c;控制AutoIT操作电脑软件&#xff0c;执行具体工作。让AI更具有执行力。 已完成部分&#xff1a; 关于python调用大模型的&#xff0c;可以参考之前的…

MARA/MARC表 PSTAT字段

最近要开发一个维护物料视图的功能。其中PSTAT字段是来记录已经维护的视图的。这里记录一下视图和其对应的字母。 MARA还有个VPSTA&#xff08;完整状态&#xff09;字段&#xff0c;不过在我试的时候每次PSTAT出现一个它就增加一个&#xff0c;不知道具体是为什么。 最近一直…

学习型组织与系统思考

真正的学习型组织不是只关注个人的学习&#xff0c;而是关注整个系统的学习。—彼得圣吉 在这两年里&#xff0c;越来越多的企业开始询问是否可以将系统思考的内容内化给自己的内训师&#xff0c;进而在公司内部进行教学。我非常理解企业这样做的动机&#xff0c;毕竟内部讲师…

支持mingw g++14.2 的c++23 功能print的vscode tasks.json生成调试

在mingw14.2版本中, print库的功能默认没有开启, 生成可执行文件的tasks.json里要显式加-lstdcexp, 注意放置顺序. tasks.json (支持mingw g14.2 c23的print ) {"version": "2.0.0","tasks": [{"type": "cppbuild","…

守护者进程小练习

守护者进程含义 定义&#xff1a;守护进程&#xff08;Daemon&#xff09;是运行在后台的特殊进程&#xff0c;独立于控制终端&#xff0c;周期性执行任务或等待事件触发。它通常以 root 权限运行&#xff0c;名称常以 d 结尾&#xff08;如 sshd, crond&#xff09;。 特性&a…