九折俄罗斯方块?我上我也行!

如果你对其他的C++案例或知识感兴趣,请考虑阅读我的专栏:

C++学习【专栏】

须知

本文仅作学习笔记使用,仅在CSDN网站发布,如果在其他网站发现,均为侵权行为,请举报。作者:小王在努力。

说明

 本案例使用的是Easyx实现的,如果没有安装Easyx的朋友可能不能运行这个案例的源码(但是下方的exe文件还是可以运行的),Easyx的官网地址如下:
Easyx官网,官网中有详细的下载教程、安装过程、以及Easyx的帮助文档等。

一、游戏展示

 1.游戏文件

  百度网盘地址:俄罗斯方块.exe(无BGM)。 提取码:elsf
  百度网盘地址:俄罗斯方块.zip(有BGM) 。 提取码:elsf
  强烈推荐大家下载带BGM版本的。如果大家对百度云的网速不信任的话,请点赞,然后再评论区留下你的邮箱,我会将游戏源码以及游戏文件发送到你的邮箱中。

 2.游戏画面

在这里插入图片描述

 3.游戏挑战

  目前游戏难度最高为等级4。由于前几天属实闲的没事,便玩了一会,破了自己的记录,大家有兴趣的可以挑战一下这个分数:
在这里插入图片描述

二、案例实现

 1.案例分析

我将整个游戏的主界面划分为三个部分:背景部分、界面部分、方块部分。按照这个思想就能实现这个游戏,接下来详细介绍这几个部分如何实现。

  1.1 背景部分

    这里说的背景部分指的是下面这张图片:
在这里插入图片描述
    这个东西想必大家都可以看出来,也就是方块的活动区域,这个部分我们只需要让他显示在方块后面即可,他需要做的只有一件事:
    1.输出背景:Back类 void showBack();

  1.2 界面部分

    这里说的界面部分指的是:

在这里插入图片描述
    界面部分是我们显示游戏信息、操作按钮的区域。这部分我们要完成的操作也很简单:
    1.在指定位置输出当前的分数和等级信息:Surface类.void showSurface();
    2.在指定位置输出下一个方块的信息:Surface类.void showSurface();

  1.3 方块部分

    这里说的方块部分指的是俄罗斯方块中的七种方块(图片来自网络,侵删):
在这里插入图片描述
    这些方块我是通过一个个方格组合起来的,方格:
在这里插入图片描述

   那么是如何组合起来的呢?我们以第一个正方形方块为例:
    1.首先定义一个大小为18的一维数组,同时将正方形的方块信息存储在这个数组中:

int d[18]={0,
			0,0,0,0,
			0,0,0,0,
			1,1,0,0,
			1,1,0,0};

    2.将这个一维数组转换为二维数组(自定义函数set()实现)

this->bl[4].set(d);//此处的set函数的功能就是一维转二维

    3.根据这个二维数组的元素值输出方格,如果是0就不输出图片,如果是1就输出方格。这样讲整个二维数组遍历输出一边就能得到一个方块。

//输出当前下落的方块
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(this->bl[this->i].s[i][j]==1)//判断方块信息数组  
				putimage(this->bl_xy[this->i][1]+(j-1)*30,this->bl_xy[this->i][2]+(i-1)*30,&this->img);//输出当前下落的方块

    在了解了一个二维数组代表了一个方块的信息之后,我们就应该明确方块要做哪些事情:
    1.输出方块:Block类void showBlock();
    2.方块自动下落:Block类void move();
    3.方块变换(左/右移、逆时针旋转):Block类void transform();
    4.判断游戏是否结束:Block类void isVectory();

  1.4 总结

    我们只需要将每一部分要完成的任务完成,这个游戏就能做出来了。至于每一部分的任务如何实现,后面都有对应类对应的函数来实现它,大家可以在下面类的设计中寻找相应的函数,关于具体功能如何实现的,函数中有较为明确的说明。

 2.类的设计

根据上述的三个部分,我们决定设计三个类:背景部分(Back类)、界面部分(Surface类)、方块类(Block类)。

  2.1 Back类

    头文件:

#pragma once
#include<graphics.h>
class Back
{
private:
	IMAGE img;//存储图片的对象

public:
	
	Back(void);
	~Back(void);
	void showBack();//输出背景
};


    源文件:

#include "Back.h"


Back::Back(void)
{
	loadimage(&this->img,_T("IMAGE"),_T("背景.jpg"));//将背景图片加载到 img中
}


Back::~Back(void)
{
}


void Back::showBack()
{
	putimage(0,0,&this->img);//将img中的图片输出到指定位置
}

  2.2 Surface类

    头文件:

#pragma once
#include<graphics.h>
#include"Block.h"
class Surface
{
private:
	IMAGE img;//存储图片的对象
public:
	Surface(void);
	~Surface(void);

	void showSurface(Block b);//输出界面函数
};


    源文件:

#include "Surface.h"


Surface::Surface(void)
{
	loadimage(&this->img,_T("IMAGE"),_T("界面.jpg"));//将界面.jpg图片加载到img对象中
}


Surface::~Surface(void)
{

}

//输出界面函数
//界面函数主要包括几部分:1、分数和等级
//						  2、下一个方块 


void Surface::showSurface(Block b)
{
	putimage(300,0,&this->img);//在指定位置输出img对象中保存的图片

	int temp_x=343;
	int temp_y=63;
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(b.bl[b.nexti].s[i][j]==1)//根据下一块方块信息,输出下一块方块
				putimage(temp_x+(j-1)*30,temp_y+(i-1)*30,&b.img);//在指定位置输出下一块方块

	setbkmode(TRANSPARENT);
	settextstyle(24,16,_T("楷体"));//设置字体的格式
	settextcolor(LIGHTGRAY);//设置字体颜色
	TCHAR grade[10];
	_stprintf_s(grade, _T("%d"), b.grade);
	outtextxy(390, 205, grade);//在指定位置输出分数
	TCHAR level[10];
	_stprintf_s(level, _T("%d"), b.level);
	outtextxy(390, 241, level);//在指定位置输出游戏等级 
}

  2.1 Block类

    头文件:

#pragma once
#include"Shape.h"
#include<graphics.h>
#include<windows.h>
#include<cstdlib>
#include<ctime>
#include"Back.h"
class Block
{
public:
	IMAGE img;//存储图片的对象
	Shape bl[8];//用于方块信息的对象数组,其中Shape为二维数组(由于不会用三维数组)
	int bc[21][11];//背景数组(将整个游戏区域划分为10×20的数组)
	int i;//当前方块的序号
	int nexti;//下一个方块的序号
	int bl_xy[8][3];//输出图片的左上角坐标
	int b_flag;//标志
	int a[3];//存放方块序号的数组
	int grade;//游戏分数
	int level;//游戏等级
public:
	Block(void);
	~Block(void);

	void showBlock();//输出方块
	void move(Back b,int &flag);//方块移动函数
	void transform(int x,Back b,int &flag);//方块变换函数
	void newBlock();//随机产生下一个方块的函数
	void isVectory(Back b,int &flag);//判断游戏结束函数
	void rotate();//方块旋转函数
};


    源文件:

#include "Block.h"


Block::Block(void)
{
	
	int a[18]={0,
			0,0,0,0,
			0,0,0,0,
			0,1,0,0,
			1,1,1,0};
	this->bl[1].set(a);//第一个方块的数组值赋值

	int b[18]={0,
			0,0,0,0,
			0,0,0,0,
			1,1,0,0,
			0,1,1,0};
	this->bl[2].set(b);//第二个方块的数组值赋值

	int c[18]={0,
			0,0,0,0,
			0,0,0,0,
			0,1,1,0,
			1,1,0,0};
	this->bl[3].set(c);//第三个方块的数组值赋值

	int d[18]={0,
			0,0,0,0,
			0,0,0,0,
			1,1,0,0,
			1,1,0,0};
	this->bl[4].set(d);//第四个方块的数组值赋值

	int e[18]={0,
			0,0,0,0,
			1,0,0,0,
			1,0,0,0,
			1,1,0,0};
	this->bl[5].set(e);//第五个方块的数组值赋值

	int f[18]={0,
			0,0,0,0,
			0,1,0,0,
			0,1,0,0,
			1,1,0,0};
	this->bl[6].set(f);//第六个方块的数组值赋值

	int g[18]={0,
			0,1,0,0,
			0,1,0,0,
			0,1,0,0,
			0,1,0,0};
	this->bl[7].set(g);//第七个方块的数组值赋值

	loadimage(&this->img,_T("IMAGE"),_T("方块.jpg"));//加载图片到img对象中,方便后续输出


	for(int i=1;i<=20;i++)//初始化背景数组
		for(int j=1;j<=10;j++)
			this->bc[i][j]=0;
	

	this->i=0;
	srand((int(time(0))));//设置随机数种子
	

	this->bl_xy[this->i][1]=90;//设置每个方块的起始x坐标
	this->bl_xy[this->i][2]=-90;//设置每个方块的起始y坐标

	this->b_flag=1;
	this->grade=0;//设置游戏初始分数为0
	this->level=1;//设置游戏初始难度等级为1

}


Block::~Block(void)
{
}

//输出方块函数
//输出当前下落的方块以及已经下落的方块
void Block::showBlock()
{
	//输出当前下落的方块
	for(int i=1;i<=4;i++)
		for(int j=1;j<=4;j++)
			if(this->bl[this->i].s[i][j]==1)//判断方块信息数组  
				putimage(this->bl_xy[this->i][1]+(j-1)*30,this->bl_xy[this->i][2]+(i-1)*30,&this->img);//输出当前下落的方块
				
	
	//输出以及下落的方块
	for(int i=1;i<=20;i++)
		for(int j=1;j<=10;j++)
			if(this->bc[i][j]==1)
				putimage((j-1)*30,(i-1)*30,&this->img);


	
}

//方块移动函数
//实现方法:1、先找到当前方块的最低点坐标
//			2、判断是否达到下界
//			3、达到下界就将当前方块加入到已经下落方块中,输出背景,输出方块
//			4、没有达到下界就继续移动,判断是否与已经下落的方块重合
//			5、重合的话就停止下降,并将此方块加入到已经下落方块中,输出背景,输出方块
//			6、如果没有重合,继续下降
void Block::move(Back b,int &flag)
{
	int a= 0; 
	for(int j=4;j>=1;j--)
	{
		for(int i=1;i<=4;i++)
			if(this->bl[this->i].s[j][i]==1)//找到当前方块最下面的方格
			{
				if(this->bl_xy[this->i][2]+(j+1)*30<=600)//下一步移动 没有到达下界
				{
					for(int j=1;j<=4;j++)
									for(int i=1;i<=4;i++)
										if(this->bl[this->i].s[j][i]==1)//判断最下面一行的方块
											if(this->bc[(this->bl_xy[this->i][2])/30+j+1][(this->bl_xy[this->i][1])/30+i]==1)//判断与背景的方块是否有重合
											{
												for(int i=1;i<=4;i++)
													for(int j=1;j<=4;j++)
														if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j]==0)
															this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j] = this->bl[this->i].s[i][j];//修改背景方块信息
												b.showBack();//输出方块
												showBlock();//输出背景
												flag=1;//设置返回信息
												break;
											}
								if(!flag)//如果与背景不重合
								{
									this->bl_xy[this->i][2]+=30;//方块继续下降
									b.showBack();//输出方块
									showBlock();//输出背景
								}
						}else//下一步移动达到下界
						{
							for(int i=1;i<=4;i++)
								for(int j=1;j<=4;j++)
									if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j]==0)
										this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j] = this->bl[this->i].s[i][j];//修改背景方块信息
							b.showBack();
							showBlock();
							flag=1;//设置返回信息
							break;

						}

									a=1;
									break;
					}
					
								if(a) break;
				}
			
	
	
}

//方块变换函数
//实现方块的:左/右移动、旋转、加速下降
void Block::transform(int x,Back b,int &flag)
{
	int temp=0;
	for(int j=4;j>=1;j--)
		for(int i=1;i<=4;i++)
		{
			if(this->bl[this->i].s[j][i]==1)
				{
					temp=j;
					break;
				}
		}
	if(this->bl_xy[this->i][2]+(temp+1)*30<=600)//当没有下降到最低点的时候
	{
		int flag=0;
			switch(x)
				{
				case 's':
					{
						int a= 0; 
						for(int j=4;j>=1;j--)
						{
							for(int i=1;i<=4;i++)
								if(this->bl[this->i].s[j][i]==1)//判断最下面一行的方块
								{
									if(this->bl_xy[this->i][2]+(j+1)*30<=600)
									{
									for(int j=1;j<=4;j++)
										for(int i=1;i<=4;i++)
											if(this->bl[this->i].s[j][i]==1)//判断最下面一行的方块
												if(this->bc[(this->bl_xy[this->i][2])/30+j+1][(this->bl_xy[this->i][1])/30+i]==1)//判断与背景的方块是否有重合
												{
													for(int i=1;i<=4;i++)
														for(int j=1;j<=4;j++)
															if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j]==0)
																this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j] = this->bl[this->i].s[i][j];//修改背景方块信息
													b.showBack();
													showBlock();
													flag=1;//设置返回信息
													break;
												}
									if(!flag)//如果与背景不重合
									{
										this->bl_xy[this->i][2]+=30;
										b.showBack();
										showBlock();
									}


								}
									a=1;
									break;
								}
								if(a) break;
						}

					};break;
				case 'a':
					{
						int a=0;
						for(int j=1;j<=4;j++)
						{
								for(int i=1;i<=4;i++)
									if(this->bl[this->i].s[i][j]==1)//找到最左边的方块
									{
										if(this->bl_xy[this->i][1]+(j-2)*30>=0)//判断是否在左边界处
											{
												for(int j=1;j<=4;j++)
													for(int i=1;i<=4;i++)
														if(this->bl[this->i].s[i][j]==1)//判断最左边一列的方块
															if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j-1]==1)//判断与背景的方块是否有重合
															{
		
																flag=1;//设置返回信息
																break;

															}
												if(!flag)
												{
												this->bl_xy[this->i][1]-=30;
												b.showBack();
												showBlock();
												}
											}
										a=1;
										break;
									}
									if(a) break;
						}
					};break;
				case 'd':
					{
						int a=0;
						for(int j=4;j>=1;j--)
						{
								for(int i=1;i<=4;i++)
									if(this->bl[this->i].s[i][j]==1)//找到最右边的方块
									{
										if(this->bl_xy[this->i][1]+j*30<300)//判断是否在边界处
											{
											for(int j=1;j<=4;j++)
												for(int i=1;i<=4;i++)
													if(this->bl[this->i].s[i][j]==1)//判断最左边一列的方块
														if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j+1]==1)//判断与背景的方块是否有重合
														{
		
															flag=1;//设置返回信息
															break;

														}
											if(!flag)
											{
											this->bl_xy[this->i][1]+=30;
											b.showBack();
											showBlock();
											}

										}
										a=1;
										break;
									}
									if(a) break;
						}
					};break;
				case 'w':
					{
						rotate();
						b.showBack();
						showBlock();
					};break;
				}
	}
	else
	{
		for(int i=1;i<=4;i++)
			for(int j=1;j<=4;j++)
				if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j]==0)
				this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j] = this->bl[this->i].s[i][j];
		b.showBack();
		showBlock();
		//Sleep(1000-(speed-1)*200);

	}
}

//随机产生方块函数
//随机产生两个新的方块的序号
//一个是当前的方块的序号。另一个是下一个方块的序号
//实现方法:在一开始,产生两个随机数,第一个为当前方块的序号
//			第二个为下一个方块的序号,然后每次只用产生一个方
//			块的序号即可
void Block::newBlock()
{

	if(this->b_flag)//一开始,产生两个随机数,代表随机产生两个方块
	{
		this->a[1] = (rand()%7)+1;
		this->a[2] = (rand()%7)+1;
		this->b_flag=0;
	}
	else//后面就只需要产生第二个方块的序号即可
		this->a[2] = (rand()%7)+1;
	this->i=a[1];//第一个方块的序号赋值
	a[1]=a[2];//数组元素前移
	this->nexti=a[2];//第二个方块的序号赋值

	this->bl_xy[this->i][1]=90;//
	this->bl_xy[this->i][2]=-90;//
}
//判断游戏结束函数
//实现功能:消除和判断游戏结束
void Block::isVectory(Back b,int &flag)
{
	for(int i=1;i<=20;i++)//逐行判断 有一行满了就将该行全部清0 输出
	{
		int sum=0;
		for(int j =1;j<=10;j++)
		{
			if(this->bc[i][j]==1)
				sum++;
			
		}
		if(sum==10)
		{
			//for(int j =1;j<=10;j++)//将被消除的一行数组元素值设置为0代表被消除
			//	this->bc[i][j]=0;

			for(int p=i;p>=2;p--)
				for(int q=1;q<=10;q++)
					this->bc[p][q]=this->bc[p-1][q];
			for(int q=1;q<=10;q++)
				this->bc[1][q]=0;
			this->grade+=(10*this->level);
			switch(this->grade)
			{
			case 100:this->level+=1;;break;
			case 300:this->level+=1;break;
			case 900:this->level+=1;break;
			}
			b.showBack();
			showBlock();

		}
	}



	int sum=0;
	for(int i=1;i<=20;i++)//逐列判断  如果有一列全满,就设置结束标志  游戏结束
	{
		for(int j = 1;j<=10;j++)
			if(this->bc[i][j]==1)
			{
				sum++;
				break;
			}
	}
	if(sum==20)
	{
		flag = 2;
		setbkmode(TRANSPARENT);
		settextcolor(DARKGRAY);
		settextstyle(50,32,_T("黑体"));
		outtextxy(10, 250, _T("游戏结束!"));
	}
			
}


//方块旋转函数
//实现方块的逆时针旋转
//大体思路也就是将存储方块信息的二维数组逆时针旋转90度
//举个简单的例子:
//将原数组a[3][3]:{1,2,3,
//					4,5,6,
//					7,8,9}逆时针旋转90度
//
//旋转后的数组a`[3][3]:{1,4,7,
//						 2,5,8,
//						 3,6,9}
//只要找到他们之间的对应关系,然后对原数组赋值就可以实现旋转了(用temp保存原数组值,因为过程中原数组值被修改了)
//他们之间对应的关系为:a[i][j]=temp[j][i];
void Block::rotate()
{

	if(this->i!=4)//正方形方块
		if(this->i==7)//长条方块
		{
			


				if(this->bl[this->i].s[1][2]==1)
				{
					int g[18]={0,
					0,0,0,0,
					0,0,0,0,
					1,1,1,1,
					0,0,0,0};
					this->bl[7].set(g);//第七个方块的数组值赋值
					//右边界判断
						int flag_r=0;
						for(int j=4;j>=1;j--)
						{
							for(int i=1;i<=4;i++)
								if(this->bl[this->i].s[i][j]==1)//找到最右边的方块
										if(this->bl_xy[this->i][1]+j*30>300)//判断是否在边界处
										{
											flag_r=1;
											break;
										}
										if(flag_r) break;
						}
						//左边界判断
						int flag_l=0;
						for(int j=1;j<=4;j++)
						{
							for(int i=1;i<=4;i++)
								if(this->bl[this->i].s[i][j]==1)//找到最左边的方块
									if(this->bl_xy[this->i][1]+(j-1)*30<0)//判断是否在左边界处
									{
										flag_l=1;
										break;
									}
									if(flag_l) break;
						}
						int flag=0;
						for(int j=1;j<=4;j++)
						{	
							for(int i=1;i<=4;i++)
									if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j-1]==1)//判断与背景的方块是否有重合
									{
										flag=1;
										break;
									}
							if(flag) break;
						}
						if(flag||flag_r||flag_l)
						{
							int g[18]={0,
							0,1,0,0,
							0,1,0,0,
							0,1,0,0,
							0,1,0,0};
							this->bl[7].set(g);//第七个方块的数组值赋值	
							
						}
						
				}
				else
				{
						int g[18]={0,
						0,1,0,0,
						0,1,0,0,
						0,1,0,0,
						0,1,0,0};
						this->bl[7].set(g);//第七个方块的数组值赋值	

						//右边界判断
						int flag_r=0;
						for(int j=4;j>=1;j--)
						{
							for(int i=1;i<=4;i++)
								if(this->bl[this->i].s[i][j]==1)//找到最右边的方块
										if(this->bl_xy[this->i][1]+j*30>300)//判断是否在边界处
										{
											flag_r=1;
											break;
										}
										if(flag_r) break;
						}
						//左边界判断
						int flag_l=0;
						for(int j=1;j<=4;j++)
						{
							for(int i=1;i<=4;i++)
								if(this->bl[this->i].s[i][j]==1)//找到最左边的方块
									if(this->bl_xy[this->i][1]+(j-1)*30<0)//判断是否在左边界处
									{
										flag_l=1;
										break;
									}
									if(flag_l) break;
						}
						int flag=0;
						for(int j=1;j<=4;j++)
						{	
							for(int i=1;i<=4;i++)
									if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j-1]==1)//判断与背景的方块是否有重合
									{
										flag=1;
										break;
									}
							if(flag) break;
						}
						if(flag||flag_r||flag_l)
						{
							int g[18]={0,
							0,0,0,0,
							0,0,0,0,
							1,1,1,1,
							0,0,0,0};
							this->bl[7].set(g);//第七个方块的数组值赋值
						}
				}
		}
		else
		{
			int temp[4][4];
			for(int i=1;i<=3;i++)
				for(int j=1;j<=3;j++)
					temp[i][j]=this->bl[this->i].s[i+1][j];

			for(int i=2;i<=4;i++)
				for(int j=1;j<=3;j++)
					this->bl[this->i].s[i][j]=temp[j][5-i];
			//右边界判断
			int flag_r=0;
			for(int j=4;j>=1;j--)
			{
				for(int i=1;i<=4;i++)
					if(this->bl[this->i].s[i][j]==1)//找到最右边的方块
							if(this->bl_xy[this->i][1]+j*30>300)//判断是否在边界处
							{
								for(int i=1;i<=3;i++)
								for(int j=1;j<=3;j++)
									this->bl[this->i].s[i+1][j]=temp[i][j];
								flag_r=1;
								break;
							}
							if(flag_r) break;
			}
			//左边界判断
			int flag_l=0;
			for(int j=1;j<=4;j++)
			{
				for(int i=1;i<=4;i++)
					if(this->bl[this->i].s[i][j]==1)//找到最左边的方块
						if(this->bl_xy[this->i][1]+(j-1)*30<0)//判断是否在左边界处
						{
							for(int i=1;i<=3;i++)
								for(int j=1;j<=3;j++)
									this->bl[this->i].s[i+1][j]=temp[i][j];
							flag_l=1;
							break;
						}
						if(flag_l) break;
			}
			//背景判断
			int flag_b=0;
			for(int j=1;j<=4;j++)
			{
				for(int i=1;i<=4;i++)
					if(this->bl[this->i].s[j][i]==1)//判断最下面一行的方块
						if(this->bc[(this->bl_xy[this->i][2])/30+i][(this->bl_xy[this->i][1])/30+j-1]==1)//判断与背景的方块是否有重合
						{
							for(int i=1;i<=3;i++)
								for(int j=1;j<=3;j++)
									this->bl[this->i].s[i+1][j]=temp[i][j];
							flag_b=1;
							break;
						}

				if(flag_b) break;
			}

		}
}

三、完整源码

  如果大家对完整源码感兴趣,请点赞博文,然后再评论区留下邮箱,我会发送到大家的邮箱中的。(只留邮箱不点赞的,恕不发送,请尊重每个人的劳动成果)

后话

  1. 首先给大家说一下,博主经常在线,如果有什么问题或者想法,可以在下方评论,我会积极反馈的。
  2. 其次还是要请大家能够多多指出问题,我也会在评论区等候大家!
    在这里插入图片描述 .

猜你喜欢

转载自blog.csdn.net/vangoudan/article/details/107573561