【C++实战】C++实现贪吃蛇(含源代码)—基于easyx图形库

news2024/12/24 10:17:31

                                        食用指南:本文在有C++基础的情况下食用更佳  

                                       🍀本文前置知识:C++基础

                                       ♈️今日夜电波:toge—あよ

                                                                0:36 ━━━━━━️💟──────── 4:03
                                                                    🔄   ◀️   ⏸   ▶️    ☰ 

                                      💗关注👍点赞🙌收藏您的每一次鼓励都是对我莫大的支持😍 


目录

📱一、前置条件—easyx图形库的安装

        easyx简介

        easyx安装

        easyx安装步骤

🐍二、进入正题!—贪吃蛇的实现!

        1、大致实现思路

        2、具体实现思路

        父类:

        蛇类 :

        食物类:

        游戏场景的实现(重要):

📑三、 实现效果以及源代码

        1、运行效果

        2、总体代码 

              🔑3、一些注意事项


📱一、前置条件—easyx图形库的安装

easyx简介

        easyx 是一款基于 C /C++的图形库,它提供了简单易用的接口,可以方便地进行图形绘制和交互操作。通过引入 easyx,开发者可以快速实现基于 Windows 平台的图形界面应用程序开发。

        easyx 提供了一系列的绘图函数,例如画线、画圆、填充颜色等,开发者可以利用这些函数创建各种图形效果。同时,easyx 还提供了键盘和鼠标事件的处理函数,方便用户与图形界面进行交互。

        easyx 的优势在于它的简洁易用性和适用性。它不仅适用于初学者学习 C /C++图形编程,也可以用于快速原型开发和小型项目。易于安装和使用,对于想要学习图形编程的开发者来说是一个很好的选择。

easyx安装

        easyx安装地址(本文为EasyX 2023大暑版 )

easyx安装步骤

        简单又快捷的安装  😍  我可太爱了!

        根据相应的提示安装即可


🐍二、进入正题!—贪吃蛇的实现!

        1、大致实现思路

        话不多说,先上一张图୧(๑•̀◡•́๑)૭

         通过父类与子类节点继承的关系这样可以使得代码连贯以及紧密相连(其实只是作者想复习一下前段时间学的父类跟子类的知识而已( ̄3 ̄)a)大体的功能实现如上图。


          2、具体实现思路

        父类:

class sprite//父类
{
public:
	int m_x;
	int m_y;
	COLORREF m_color;
public:
	sprite() :sprite(0, 0) {};
	sprite(int x, int y) :m_x(x), m_y(y), m_color(BLUE) {};//初始化坐标,颜色
	virtual void draw()
	{
		setfillcolor(m_color);

		fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
	}
	virtual void draw(COLORREF a)
	{
		setfillcolor(a);

		fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
	}
	void moveby(int dx,int dy)
	{
		m_x += dx;
		m_y += dy;
	}

	bool collision(const sprite& ote)//碰撞食物检测
	{
		return m_x == ote.m_x && m_y == ote.m_y;
	}
};

        作为最基本的类,所要实现的最基本任务就是储存数据,对此我做了坐标数据的储存以及蛇颜色数据的储存。接着是对于基本绘图需求实现函数、移动需求实现函数以及配置检查函数。这几个函数也是对于蛇基本的逻辑判断以及移动的需求。

        蛇类 :


class Snake:public sprite//蛇体
{
public:
	Snake() :Snake(0, 0) {};
	Snake(int x, int y):sprite(x, y),dir(VK_RIGHT),grade(0) //初始化三节蛇
	{
		nodes.push_back(sprite(120, 100));//蛇头
		nodes.push_back(sprite(110, 100));
		nodes.push_back(sprite(100, 100));
	};
	void draw()
	{
		for (int i = 0; i < nodes.size(); i++)
		{
			nodes[i].draw();
		}
	}
	void move()
	{
		for (int i=nodes.size()-1;i>0;i--)//整体移动
		{
			nodes[i] = nodes[i - 1];
		}
		switch (dir)//控制方向
		{
		case VK_UP:
			nodes[0].moveby(0,-10);
			break;
		case VK_DOWN:
			nodes[0].moveby(0, 10);
			break;
		case VK_LEFT:
			nodes[0].moveby(-10, 0);
			break;
		case VK_RIGHT:
			nodes[0].moveby(10, 0);
			break;
		}
	}

	bool collision(const sprite& ote)
	{
		return nodes[0].collision(ote);
	}

	void increase()//长度增加一节
	{
		nodes.push_back(sprite());
		grade++;
	}

	void cotget()//计分
	{
		string str = "当前得分为:";
		str += to_string(grade);
		char Outscore[1024];
		strcpy_s(Outscore, sizeof(Outscore), str.c_str());
		settextstyle(15, 0, "宋体");
		settextcolor(GREEN);
		outtextxy(20, 20, Outscore);
		
	}

	bool dead()//死亡检测
	{
		for (int i = 1; i < nodes.size(); i++)//撞到自己
		{
			if (nodes[0].m_x == nodes[i].m_x && nodes[0].m_y == nodes[i].m_y)
			{
				cleardevice();
				return true;
			}
		}
		
		if (nodes[0].m_x == 0 || nodes[0].m_y == 0 || nodes[0].m_x == 630 || nodes[0].m_y == 470)//撞到墙
			return true;

		return false;
	}
private:
	vector<sprite> nodes;//存蛇节
	
public:
	int dir;//蛇的方向
	int grade;//得分
};

        这个类就是具体的蛇体实现的过程了。主要是实现了蛇的初始化以及所有逻辑判断。在原父类的基础上还进行了蛇的方向、得分、蛇节点等数据的添加。

         食物类:


class Food :public sprite//食物
{
public:
	Food() :sprite(0, 0) 
	{
		changefood();
	};

	void draw()
	{
		setfillcolor(RED);

		fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
	}
	//生成食物
	void changefood()
	{
		//随机生成坐标
		m_x = rand() % 64 * 10;
		if (m_x == 0)
			m_x += 10;
		else if (m_x == 640)
			m_x -= 20;
		else if (m_x == 630)
			m_x -= 10;

		m_y = rand() % 48 * 10;
		if (m_y == 0)
			m_y += 10;
		else if (m_y == 480)
			m_y -= 30;
		else if (m_x == 470)
			m_y -= 20;
	}

	
};

        这个类就是在父类的基础上实现了食物的随机位置生成,基于坐标数据所生成的。

         游戏场景的实现(重要):


class gameScreen//游戏场景
{
private:
	Snake snake;
	Food food;
public:
	gameScreen() {};
	void run()
	{
		//双缓冲绘图
		setbkcolor(YELLOW);
		BeginBatchDraw();
		
		cleardevice();
		
		wall();
		snake.draw();//蛇生成
		food.draw();//实物生成
		snake.cotget();
		snake.dead();
		EndBatchDraw();
		//移动
		snake.move();
		//吃食物
		SnakeEat();
		
		//获取信息
		ExMessage msg = { 0 };
		while (peekmessage(&msg, EX_KEY))
		{
			onmesg(msg);
		}
	}
	//改变蛇的方向 通过方向键 
	void onmesg(const ExMessage& msg)
	{
		//判断键盘有没有方向按键按下
		if (msg.message == WM_KEYDOWN)//接受↑↓←→信息
		{
			switch (msg.vkcode)//不让蛇头向后走
			{
			case VK_UP:
				if(snake.dir!= VK_DOWN)
					snake.dir = msg.vkcode;
				break;
			case VK_DOWN:
				if (snake.dir != VK_UP)
					snake.dir = msg.vkcode;
				break;
			case VK_LEFT:
				if (snake.dir != VK_RIGHT)
					snake.dir = msg.vkcode;
				break;
			case VK_RIGHT:
				if (snake.dir != VK_LEFT)
					snake.dir = msg.vkcode;
				break;
			}
			
		}
	}

	void SnakeEat()
	{
		if (snake.collision(food))//吃到了食物
		{
			//蛇节数增加
			snake.increase();
			//食物重新生成
			food.changefood();
		}
	}

	void deadcot()//死亡结算
	{
		string str = "您的最终得分为:";
		str += to_string(snake.grade);
		char Outscore[1024];
		strcpy_s(Outscore, sizeof(Outscore), str.c_str());
		settextstyle(30, 0, "宋体");
		settextcolor(GREEN);
		outtextxy(200, 210, Outscore);
	}

	void realdead()//判死
	{
		if (snake.dead())
		{
			deadcot();
			Sleep(3000);
			closegraph();
		}
			
	}

	void wall()//生成墙
	{
		sprite wa;
		for (int i = 0; i < 480; i+=10) {
			//首先声明颜色,否则第一个格子怪怪的
			wa.draw(GREEN);
			wa.moveby(0, 10);
		}
		sprite wb;
		{
			for (int i = 0; i < 640; i += 10) {
				//首先声明颜色,否则第一个格子怪怪的
				wb.draw(GREEN);
				wb.moveby(10, 0);
			}
		}
		sprite sa(630, 470);
		for (int i = 0; i < 480; i += 10) {
			//首先声明颜色,否则第一个格子怪怪的
			sa.draw(GREEN);
			sa.moveby(0, -10);
		}

		sprite sb(630, 470);
		for (int i = 0; i < 640; i += 10) {
			//首先声明颜色,否则第一个格子怪怪的
			sb.draw(GREEN);
			sb.moveby(-10, 0);
		}
	}
	
};

        这个类实现的就是将前面所实现的类进行整合,然后再进行有些稍微的调节。比如:增加了接受方向键的函数omsg,得以操控蛇的运动。这个类也进行了蛇活动场景的搭建等等。


        📑三、 实现效果以及源代码

        1、运行效果

        游戏开始界面:

        游戏运行界面:

        游戏结算界面: 


        2、总体代码 

#include<iostream>
#include<easyx.h>
#include<vector>
#include<stdlib.h>
#include<time.h>
#include<string>
#include<conio.h>

using namespace std;

class sprite//父类
{
public:
	int m_x;
	int m_y;
	COLORREF m_color;
public:
	sprite() :sprite(0, 0) {};
	sprite(int x, int y) :m_x(x), m_y(y), m_color(BLUE) {};//初始化坐标,颜色
	virtual void draw()
	{
		setfillcolor(m_color);

		fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
	}
	virtual void draw(COLORREF a)
	{
		setfillcolor(a);

		fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
	}
	void moveby(int dx,int dy)
	{
		m_x += dx;
		m_y += dy;
	}

	bool collision(const sprite& ote)//碰撞食物检测
	{
		return m_x == ote.m_x && m_y == ote.m_y;
	}
};


class Snake:public sprite//蛇体
{
public:
	Snake() :Snake(0, 0) {};
	Snake(int x, int y):sprite(x, y),dir(VK_RIGHT),grade(0) //初始化三节蛇
	{
		nodes.push_back(sprite(120, 100));//蛇头
		nodes.push_back(sprite(110, 100));
		nodes.push_back(sprite(100, 100));
	};
	void draw()
	{
		for (int i = 0; i < nodes.size(); i++)
		{
			nodes[i].draw();
		}
	}
	void move()
	{
		for (int i=nodes.size()-1;i>0;i--)//整体移动
		{
			nodes[i] = nodes[i - 1];
		}
		switch (dir)//控制方向
		{
		case VK_UP:
			nodes[0].moveby(0,-10);
			break;
		case VK_DOWN:
			nodes[0].moveby(0, 10);
			break;
		case VK_LEFT:
			nodes[0].moveby(-10, 0);
			break;
		case VK_RIGHT:
			nodes[0].moveby(10, 0);
			break;
		}
	}

	bool collision(const sprite& ote)
	{
		return nodes[0].collision(ote);
	}

	void increase()//长度增加一节
	{
		nodes.push_back(sprite());
		grade++;
	}

	void cotget()//计分
	{
		string str = "当前得分为:";
		str += to_string(grade);
		char Outscore[1024];
		strcpy_s(Outscore, sizeof(Outscore), str.c_str());
		settextstyle(15, 0, "宋体");
		settextcolor(GREEN);
		outtextxy(20, 20, Outscore);
		
	}

	bool dead()//死亡检测
	{
		for (int i = 1; i < nodes.size(); i++)//撞到自己
		{
			if (nodes[0].m_x == nodes[i].m_x && nodes[0].m_y == nodes[i].m_y)
			{
				cleardevice();
				return true;
			}
		}
		
		if (nodes[0].m_x == 0 || nodes[0].m_y == 0 || nodes[0].m_x == 630 || nodes[0].m_y == 470)//撞到墙
			return true;

		return false;
	}
private:
	vector<sprite> nodes;//存蛇节
	
public:
	int dir;//蛇的方向
	int grade;//得分
};


class Food :public sprite//食物
{
public:
	Food() :sprite(0, 0) 
	{
		changefood();
	};

	void draw()
	{
		setfillcolor(RED);

		fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
	}
	//生成食物
	void changefood()
	{
		//随机生成坐标
		m_x = rand() % 64 * 10;
		if (m_x == 0)
			m_x += 10;
		else if (m_x == 640)
			m_x -= 20;
		else if (m_x == 630)
			m_x -= 10;

		m_y = rand() % 48 * 10;
		if (m_y == 0)
			m_y += 10;
		else if (m_y == 480)
			m_y -= 30;
		else if (m_x == 470)
			m_y -= 20;
	}

	
};

class gameScreen//游戏场景
{
private:
	Snake snake;
	Food food;
public:
	gameScreen() {};
	void run()
	{
		//双缓冲绘图
		setbkcolor(YELLOW);
		BeginBatchDraw();
		
		cleardevice();
		
		wall();
		snake.draw();//蛇生成
		food.draw();//实物生成
		snake.cotget();
		snake.dead();
		EndBatchDraw();
		//移动
		snake.move();
		//吃食物
		SnakeEat();
		
		//获取信息
		ExMessage msg = { 0 };
		while (peekmessage(&msg, EX_KEY))
		{
			onmesg(msg);
		}
	}
	//改变蛇的方向 通过方向键 
	void onmesg(const ExMessage& msg)
	{
		//判断键盘有没有方向按键按下
		if (msg.message == WM_KEYDOWN)//接受↑↓←→信息
		{
			switch (msg.vkcode)//不让蛇头向后走
			{
			case VK_UP:
				if(snake.dir!= VK_DOWN)
					snake.dir = msg.vkcode;
				break;
			case VK_DOWN:
				if (snake.dir != VK_UP)
					snake.dir = msg.vkcode;
				break;
			case VK_LEFT:
				if (snake.dir != VK_RIGHT)
					snake.dir = msg.vkcode;
				break;
			case VK_RIGHT:
				if (snake.dir != VK_LEFT)
					snake.dir = msg.vkcode;
				break;
			}
			
		}
	}

	void SnakeEat()
	{
		if (snake.collision(food))//吃到了食物
		{
			//蛇节数增加
			snake.increase();
			//食物重新生成
			food.changefood();
		}
	}

	void deadcot()//死亡结算
	{
		string str = "您的最终得分为:";
		str += to_string(snake.grade);
		char Outscore[1024];
		strcpy_s(Outscore, sizeof(Outscore), str.c_str());
		settextstyle(30, 0, "宋体");
		settextcolor(GREEN);
		outtextxy(200, 210, Outscore);
	}

	void realdead()//判死
	{
		if (snake.dead())
		{
			deadcot();
			Sleep(3000);
			closegraph();
		}
			
	}

	void wall()//生成墙
	{
		sprite wa;
		for (int i = 0; i < 480; i+=10) {
			//首先声明颜色,否则第一个格子怪怪的
			wa.draw(GREEN);
			wa.moveby(0, 10);
		}
		sprite wb;
		{
			for (int i = 0; i < 640; i += 10) {
				//首先声明颜色,否则第一个格子怪怪的
				wb.draw(GREEN);
				wb.moveby(10, 0);
			}
		}
		sprite sa(630, 470);
		for (int i = 0; i < 480; i += 10) {
			//首先声明颜色,否则第一个格子怪怪的
			sa.draw(GREEN);
			sa.moveby(0, -10);
		}

		sprite sb(630, 470);
		for (int i = 0; i < 640; i += 10) {
			//首先声明颜色,否则第一个格子怪怪的
			sb.draw(GREEN);
			sb.moveby(-10, 0);
		}
	}
	
};

void play()
{
	cleardevice();
	//initgraph(640, 480);
	srand(time(nullptr));
	gameScreen game;
	while (1)
	{
		Sleep(100);
		game.run();
		game.realdead();
	}
	

	getchar();

}


void menu()
{
	char str_0[] = "》 -贪吃蛇- 《";
	char str_1[] = "1.play";
	char str_2[] = "2.游戏帮助";
	char str_3[] = "按任意键退出";
	settextstyle(20, 0, "宋体");
	outtextxy(200, 150, str_0);
	outtextxy(220, 190, str_1);
	outtextxy(220, 230, str_2);
	outtextxy(220, 270, str_3);
}

void intro()
{
	cleardevice();
	char str_0[] = "【帮助】";
	char str_1[] = "操作技巧:↑↓← →控制蛇的方向";
	char str_2[] = "什么?你说你没方向键?";
	char str_3[] = "亲,请点右上角";
	char str_4[] = "制作者:慕斯";
	char str_5[] = "按任意键返回";
	settextstyle(20, 0, "宋体");
	outtextxy(200, 120, str_0);
	outtextxy(180, 160, str_1);
	outtextxy(180, 200, str_2);
	outtextxy(180, 240, str_3);
	outtextxy(180, 280, str_4);
	outtextxy(180, 320, str_5);
	int leb = 0;
	leb = _getch();
}

void SNAKE()
{
	int leb = 0;
	int kk = 1;
	do
	{
		initgraph(640, 480);
		menu();
		leb = _getch();
		switch (leb)
		{
		case 49:
			play();
			break;
		case 50:
			intro();
			break;
		default:
			kk = 0;
			break;
		}
	} while (kk);
	
	
}

int main()
{
	SNAKE();
	//play();
	return 0;
}

        🔑3、一些注意事项

        由于有些字符的限制,我们需要按以下步骤去更改一下字符集,将字符集改为使用多字节字符集以解决其中一些报错!报错情况如下:

         如果你出现以上报错,请按以下步骤进行多字节字符集设置:


                 感谢你耐心的看到这里ღ( ´・ᴗ・` )比心,如有哪里有错误请踢一脚作者o(╥﹏╥)o!  

                                 

                                                                 给个三连再走嘛~      

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

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

相关文章

springboot整合jquery实现前后端数据交互

一 实施逻辑 1.1 前端 <!doctype html> <html lang"en"><head><meta charset"UTF-8"><meta name"Generator" content"EditPlus"><meta name"Author" content""><meta n…

Centos7 |Canal Admin搭建Canal Server集群|

一: 使用CanalAdmin来搭建一个canal集群 1.1 环境规划 服务名称|主机节点 机器IP 节点 备注 canal admin | docker0 192.168.1.100 192.168.1.100:8888 canal admin 机器 canal server 1 | docker1 192.168.1.101 192.168.1.100:8888 canal se…

Kafka3.0.0版本——Leader Partition自动平衡

目录 一、Leader Partition自动平衡的概述二、Leader Partition自动平衡的相关配置参数三、Leader Partition自动平衡的示例 一、Leader Partition自动平衡的概述 正常情况下&#xff0c;Kafka本身会自动把Leader Partition均匀分散在各个机器上&#xff0c;来保证每台机器的读…

Mac“其他文件”存放着什么?“其他文件”的清理方法

很多Mac用户在清理磁盘空间时发现&#xff0c;内存占用比例比较大的除了有iCloud云盘、应用程序、影片、音频、照片等项目之外&#xff0c;还有一个“其他文件”的项目磁盘占用比也非常大&#xff0c;想要清理却无从下手。那么Mac“其他文件”里存放的是什么文件&#xff1f;我…

HBuilderX修改manifest.json设置,解决跨域问题(CORS、Cross-Origin)

搭建一个前台uniapp&#xff0c;后台springboot的开发环境时&#xff0c;遇到了跨域问题。 console提示错误信息&#xff1a; Access to XMLHttpRequest at http://10.0.180.203/api/cms/getAdList?apId1 from origin http://localhost:8080 has been blocked by CORS policy…

常用框架分析(7)-Flutter

框架分析&#xff08;7&#xff09;-Flutter 专栏介绍Flutter核心思想Flutter的特点快速开发跨平台高性能美观的用户界面 Flutter的架构框架层引擎层平台层 开发过程使用Dart语言编写代码编译成原生代码热重载工具和插件 优缺点优点跨平台开发高性能美观的用户界面热重载强大的…

pinia——添加插件——基础积累

问题&#xff1a;是否给pinia添加过插件&#xff1f;具体添加的方式是什么&#xff1f; 在pinia中&#xff0c;我们可以为仓库添加插件&#xff0c;通过添加插件能够扩展以下的内容&#xff1a; 为 store 添加新的属性 定义 store 时增加新的选项 为 store 增加新的方法 包装现…

怎么传输大文件跨国,如何跨国快速传输大文件

在当前数字化时代的背景下&#xff0c;跨国传输大文件已经成为企业和个人工作中不可避免的挑战。尽管存在技术障碍和阻碍&#xff0c;但借助先进的技术和服务&#xff0c;我们仍能高效完成跨国大文件传输任务。接下来将介绍几种常见的跨国快速传输大文件的方法。 一、FTP文件传…

固定资产台账怎么管理

固定资产台账是指企业对固定资产进行登记、分类、统计和管理的账簿。固定资产管理系统是一款专业的固定资产管理软件&#xff0c;可以帮助企业实现资产全生命周期管理&#xff0c;包括资产采购、入库、领用、归还、维修、报废等环节。系统具有实时监控、预警提醒、报表分析等功…

PostgreSQL数据导入导出【亲测】有图有真相

pg_dump是用于备份PostgreSQL数据库的工具。它可以在数据库正在使用的时候进行完整一致的备份&#xff0c;并不阻塞其它用户对数据库的访问。 有图有真相 文章目录 导出导入压缩方法 导出 pg_dump -h 127.0.0.1 -p 5432 -U readuser mydatabase > dum.sql导入 1、导入整个…

函数和方法回顾、cbv源码分析、APIView执行流程分析、序列化组件介绍、序列化组件快速使用之序列化、常用字段类和参数、序列化组件之校验

一 函数和方法回顾 函数和方法-函数:使用def关键字定义的函数,有几个参数&#xff0c;就要传几个参数&#xff0c;不能多&#xff0c;不能少-----》按位置传&#xff0c;按关键字传-方法&#xff1a;定义在类内部&#xff0c;可以自动传值的函数称之为方法---》绑定给对象的方…

vue3+ts+tinynce在富文本编辑器菜单栏实现下拉框选择

实现效果 代码&#xff1a; <script lang"ts" setup> import Editor from tinymce/tinymce-vue import tinymce from tinymce; import { getIndicator } from /api/data-assets/data-dictoryimport {computed, ref} from "vue"; const props defin…

Linux centos7 bash编程——-求质数和

训练项目&#xff1a;使用函数求质数和。 定义一个函数IsPrime()&#xff0c;据此判断一个数是否为质数 由用户输入一个整数&#xff0c;求出比此数大的两个最小质数之和。 一、解决思路: 1.先在键盘上输入一个整数 2.求出比此数大的最小质数 3.再求出比此质数大的另一个…

【word技巧】word隐藏文字的方法

Word文件中有些内容想要隐藏&#xff0c;该如何隐藏&#xff1f;今天分享几个方法给大家 方法一&#xff1a; 最简单的方法&#xff0c;将字体颜色与背景颜色设置为一致的&#xff0c;这样就达到了隐藏的效果&#xff0c;选中文字再修改颜色就可以恢复字体 方法二&#xff1a…

HCIP-OpenStack组件之网络服务Neutron(ovs、ovn)

1、Linux网络虚拟化基础 Neutron最为核心的工作是对二层物理网络的抽象与管理&#xff0c;物理服务器虚拟化后&#xff0c;虚拟机的网络功能由虚拟网卡&#xff08;vNIC&#xff09;和虚拟交换机&#xff08;vSwitch&#xff09;提供&#xff0c;各个vNIC连接在vSwitch的端口上…

DDD 与 CQRS 才是黄金组合

在日常工作中&#xff0c;你是否也遇到过下面几种情况&#xff1a; 使用一个已有接口进行业务开发&#xff0c;上线后出现严重的性能问题&#xff0c;被老板当众质疑&#xff1a;“你为什么不使用缓存接口&#xff0c;这个接口全部走数据库&#xff0c;这怎么能抗住&#xff01…

前端(十六)——微信小程序语音转文字,文字转语音功能的实现

&#x1f60a;博主&#xff1a;小猫娃来啦 &#x1f60a;文章核心&#xff1a;微信小程序语音转文字&#xff0c;文字转语音功能的实现 文章目录 资源下载链接最关键的问题控制台报错30003语音转文字文字转语音效果图应用场景作用和优势实现思路 资源下载链接 CSDN资源下载&am…

【C51基础实验 LED闪烁】

51单片机项目基础篇 LED闪烁1、硬件电路设计和原理分析2、软件设计2.1、功能实现&#xff1a;LED闪烁2.2、通过 KEIL 软件自带仿真查看延时时间 4、编译结果5、结束语 LED闪烁 前言&#xff1a; 前一篇学会了点亮一颗LED以及驱动原理&#xff0c;那么这篇紧接着就来解锁LED的新…

智慧排水监测系统:创新监测技术保障排水系统安全运行

城市排水系统作为城市基础设施的重要组成部分&#xff0c;其安全运行直接关系到环境卫生、居民生活和城市发展。为了确保排水系统的顺畅运行&#xff0c;传统的监测手段已经不能满足日益复杂的城市排水需求&#xff0c;物联网技术的快速发展为排水系统的监测带来了巨大的便利&a…