文章目录

  • 前言
  • 一、准备工作
    • (1)安装EasyX图形库
      • 1)原理
      • 2)安装
      • 3)帮助文档
      • 4)本质
    • (2)新建项目
      • 1)建立空项目
      • 2)添加新建项
      • 3)添加文件
  • 二、文字效果
    • (1)主函数
    • (2)包含图形库
    • (3)创建图形窗口
    • (4)开始界面文字
      • 1)写函数
      • 2)输出文字
      • 3)改变文字大小
      • 4)文字居中显示
      • 5)输出大量文字
      • 6)设置文字颜色
    • (5)开始界面星星
    • (6)播放音乐
  • 三、星星
    • (1)定义结构体
    • (2)初始化星星
    • (3)绘制星星
    • (4)调用
      • 1)初始化
      • 2)绘制
      • 3)问题解答
    • (5)移动星星
    • (6)拓展
  • 四、流星
    • (1)加载图片
    • (2)输出图片
    • (3)写入主函数
    • (4)定义结构体
    • (5)初始化流星
    • (6)流星生成范围
    • (7)绘制流星
    • (8)移动流星
  • 五、设置背景颜色
  • 六、设置背景图片
  • 七、所有代码

前言

今天是星期五,八月五号,因为文章太长,写了好久,拖到今天才发。文章很详细,不过也要有一点C语言基础,代码都是用C语言写的。
我是一个平平无奇的普通人,也有自己喜欢的人,喜欢的事情。不知道在昨天有多少人在思考自己,亦或是羡慕他人。
本人并没有体会过爱情的美好,也没有任何经验。但有喜欢的人,和说不出的话、不能做的事。这也许,就是遗憾吧。但不是每一段故事,都要有美好的结局啊。诚挚地去爱过,不管结果如何,你都是那个最棒地自己!
在这个特殊的日子,不知是表示甜,还是表示苦,人生有很多遗憾和无奈,也有很多快乐和希望。这里祝福所有的有情人终成眷属,在纷纷扰扰的世间,遇见有缘人,恩爱一生,白头偕老!不必羡慕他人,不必懊恼自己,我觉得爱情,是世间最美好、最奇妙的感情,你我一定会遇到属于自己的美好爱情!
这次要做的效果,很常见,但我并不想直接把效果和代码一放,无事走人。
大家在忙碌之中,看我的文章,我也想让大家学点东西,有点收获。
如果你想直接拿走代码,可以翻到最后;如果想看看如何做的,可以一步一步跟着学,一定有你不会的东西。
好啦,看一下这次的效果

一、准备工作

(1)安装EasyX图形库

1)原理

2)安装

直接百度搜索EasyX

点击第一个。

然后点击下载EasyX

双击文件。

“下一步”。

然后会自动查找到你自己电脑里面安装的编译器。这里就以VS2019为例,点击“安装”即可。

然后“关闭”。

3)帮助文档

帮助文档链接:https://docs.easyx/zh-cn/intro

下载好安装包,解压即可。

然后双击这个文件就可以打开了。

4)本质

本质是,查找Vs的安装目录,并将相关文件分别拷贝至lib目录和include目录。

安装成功后,包含头文件graphics.h即可开始快乐学习了。

(2)新建项目

1)建立空项目

注意:本次项目使用的编译器是VS2019。

这里选择建立“空项目”。

2)添加新建项

点击“源文件”,右键“添加”–>“新建项”。

3)添加文件

将后缀名写为.cpp

二、文字效果

(1)主函数

创建完文件,开始写主函数。

运行一下,看看有没有什么错误。

好啦,出现下列提示就是创建没有问题,可以进行接下来的操作。

(2)包含图形库

接下来,我们要包含EasyX图形库。

直接在主函数之前写上:

#include<easyx.h> 

easyx是第三方图形库。

在C语言中,除了stdio这种标准输入输出的,以及标准头文件之外。还有很多插件(需要安装)。

(3)创建图形窗口

刚才我们看了效果,是一个黑窗口。

我们绘制图片、形状,很难做到,那么我们就需要另外一个窗口。

这个窗口如何创建呢?

有这样一个函数:initgraph()

我们这里就可以利用这个函数,创建一个窗口。

initgraph(1200,800);

函数有三个参数:宽度和高度和窗口标识。(窗口标识可以显示控制台窗口等等,用到的时候再具体讲解)

我们运行一下。

一闪而过?

我们来让它停留一下,加一行代码:

getchar();

如下:

然后运行一下。

出来了一个黑窗口,名字就是我们项目的名称。

(4)开始界面文字

1)写函数

刚才我们的效果图有一个开始界面(文字渐变等)。

现在我们写一个welcome函数。

2)输出文字

在这个函数里面,输出一些文字

outtextxy函数:输出(out)文本(text)到指定位置(xy)。

有三个参数,x、y、字符(字符串)。

这里介绍一下,窗口具体的坐标体系。

了解之后,咱们再来写具体位置。

比如:

outtextxy(50,50,"风筝有风,海豚有海,而我有你");

运行之后发现错误:

字符集问题

解决办法:在字符串前面用_T()包裹,给它进行转换。

就像这样:

outtextxy(50,50,_T("风筝有风,海豚有海,而我有你"));

然后继续运行一下:(文字就出现在窗口啦)

3)改变文字大小

上面显示的文字有点小,怎么变大呢?

这里用到函数settextstyle:设置(set)文字(text)样式(style)。

将逗号敲上,参数就可以看到了。第一个是高度,第二个是宽度,第三个是字体名称(本地字体)。

这里咱们设置高度40,宽度为0(自适应),字体名称为华文行楷(你的电脑里边有的字体,写在这里都可以)。

如下:

         settextstyle(40,0,"华文行楷");

这个地方有下划线,不正确。

上面说了,这是字符集的问题。

我们用_T()将它们包裹即可。

只要是EasyX图形库的字符串的,都要用_T()进行转换。

那么就可以这样来写:

   settextstyle(40,0,_T("华文行楷"));

直接改成多字节太麻烦?

这次的案例,必须使用UniCode,因为要输出爱心,这个爱心是UniCode字符集。改成多字节看不了!

写完之后,运行看一下。

可以看到,字体变大了,而且字体变化了。

4)文字居中显示

刚才文字是我们自己定义的坐标,现在我想让文字居中显示

要想居中显示,就要知道居中的具体坐标。(只需要知道X坐标即可,X坐标居中,文字就居中啦)

看图:

由上图可知,我们只需要用(窗口宽度-文字宽度)/2,就得到了文字块的X坐标。

具体的求法如下:

窗口宽度:getwidth()
文字宽度:textwidth()
文字:_T("XXX")

那么我们求X坐标,就可以得到这样的代码:

int tx=(getwidth()-textwidth(_T("风筝有风,海豚有海,而我有你")))/2;
//这里的tx用来接收x坐标位置

这样的话,输出文字的X坐标就可以用tx表示:

outtextxy(tx, 50, _T("风筝有风,海豚有海,而我有你"));

输出看一下效果:

5)输出大量文字

接下来,咱们就可以输出很多文字啦。

我这里统一将X坐标设为300,y坐标每一行加50隔开距离。

	outtextxy(300, 100, _T("织女牵牛送夕阳,临看不觉鹊桥长"));
	outtextxy(300, 150, _T("此夜星繁河正白,人传织女牵牛客"));
	outtextxy(300, 200, _T("烟外柳丝湖外水,山眉澹碧月眉黄"));
	outtextxy(300, 250, _T("相逢一醉是前缘,风雨散飘然何处"));
	outtextxy(300, 300, _T("别离还有经年客,怅望不如河鼓星"));
	outtextxy(300, 350, _T("迢迢牵牛星,皎皎河汉女"));
	outtextxy(300, 400, _T("此日六军同驻马,当时七夕笑牵牛"));
	outtextxy(300, 450, _T("七夕今宵看碧霄,牵牛织女渡河桥"));
	outtextxy(300, 500, _T("天上分金镜,人间望玉钩"));
	outtextxy(300, 550, _T("乌鹊桥成上界通,千秋灵会此宵同"));

为了将效果更好的展现,这里将第一个标题改一下文字。

	int tx = (getwidth() - textwidth(_T("此生都是你"))) / 2;
	outtextxy(tx, 50, _T("此生都是你"));

输出看一下效果:

6)设置文字颜色

可以用函数settextcolor()来设置文字颜色。

先来设置一下文本的字体颜色(不包括标题),比如蓝色:

settextcolor(BLUE);

看一下效果。


不太美观,现在想让文字颜色变化起来。

要用RGB合成颜色。

每个颜色都是由三原色构成。比如这个浅蓝色:

将这个RGB值输入进来。

settextcolor(RGB(179,161,248));

运行一下,文字颜色就改变啦。


现在,不想只要一种颜色。

让它变动起来!

所有的颜色,都是黑白之间的。

黑色RGB:0,0,0

白色RGB:255,255,255

那我们现在让它随机生成0-256之间的数。

rand()函数随机生成就好啦,这个函数左闭右开,所以取值范围是0-256。

如下:

settextcolor(RGB(rand()%256,rand()%256,rand()%256));

用随机函数,得要包含一下头文件:

#include<time.h>;

然后在welcome函数前面,用srand()函数设置随机数种子。

srand()seed种子。

种子需要一个不断变化的数据(每次运行都不同的数据)。

这里将当前系统的时间作为种子。

类型不一致,这里强转成unsigned类型。

如下:

srand((unsigned)time(NULL));

每次运行的颜色都不一样。


现在想让它不断变化,而不是运行一次一个样。

让它不断循环,设置颜色。

不断绘制就好。

while(true){
    
}

将所有的文字,放在这个死循环当中。

while (true) {
		//设置文字颜色
		settextcolor(RGB(rand() % 256, rand() % 256, rand() % 256));

		outtextxy(300, 100, _T("织女牵牛送夕阳,临看不觉鹊桥长"));
		outtextxy(300, 150, _T("此夜星繁河正白,人传织女牵牛客"));
		outtextxy(300, 200, _T("烟外柳丝湖外水,山眉澹碧月眉黄"));
		outtextxy(300, 250, _T("相逢一醉是前缘,风雨散飘然何处"));
		outtextxy(300, 300, _T("别离还有经年客,怅望不如河鼓星"));
		outtextxy(300, 350, _T("迢迢牵牛星,皎皎河汉女"));
		outtextxy(300, 400, _T("此日六军同驻马,当时七夕笑牵牛"));
		outtextxy(300, 450, _T("七夕今宵看碧霄,牵牛织女渡河桥"));
		outtextxy(300, 500, _T("天上分金镜,人间望玉钩"));
		outtextxy(300, 550, _T("乌鹊桥成上界通,千秋灵会此宵同"));
}

然后运行看一下:

哎呀,一直闪,眼睛都要闪瞎了。

现在让它慢下来。

这里用Sleep()函数,1秒变化一次,就是1000毫秒。(在文字末输入这个函数)

Sleep(1000);

再次运行。

(5)开始界面星星

这里还是用outtextxy函数。(放在while循环里)

先将它随便放在一个位置。(❤就是直接用中文输入法,敲aixin,然后第五个就是这个小爱心啦)

outtextxy(20,20,_T("❤"));

这里点击“是”就好。

运行之后,看一下效果:

这个小爱心还可以不停地闪烁呢。


一颗星不好,而且位置太固定。

①先随机生成坐标。

rand函数,只要在窗口内部就都合适。

宽度就膜上窗口宽度(getwidth()),高度就膜上窗口高度(getheight())。

outtextxy(rand()%getwidth(),rand()%getheight(),_T("❤"));

②将它放入循环里边。

for(size_t i=0;i<10;i++){
    outtextxy(rand()%getwidth(),rand()%getheight(),_T("❤"));
}

看一下效果:


哎呀,这个爱心咋越来越多嘞。

不是想像中的样子。

可以让每次画之前,将原来的清除掉

而且,可以看到,文字会把星星盖住唉,这样不是很好。

设置背景模式,将文字背景透明。(在while函数外边设置)

这里就要用到setbkmode()函数,有这样一个参数TRANSPARENT

setbkmode(TRANSPARENT);

清屏

在while函数前边,写上:

cleardevice();

看一下效果:

标题不见了,忘记移进来了。

问题不大。

放到while循环里边就好。


刚才的爱心变化,和字体颜色变化一致不太好。

这里让爱心与字体产生不同颜色。

直接将上面的settextcolor函数放进for循环即可。

for(size_t i=0;i<10;i++){
    settextcolor(RGB(rand() % 256, rand() % 256, rand() % 256));
    outtextxy(rand()%getwidth(),rand()%getheight(),_T("❤"));
}

看一下效果:

(6)播放音乐

将这些文件复制到项目的当前路径中。

当前路径:右键项目名称,打开“文件资源管理器”。

将刚才的文件夹复制粘贴进来。

一定要和.cpp在同一个目录下。

然后包含头文件。

#include<mmsystem.h>

包含库文件。

#pragma comment(lib,"winmm.lib")

包含之后,就可以来播放音乐啦。

welcome前边添加mciSendString()函数。

解释一下:

mci:media(多媒体) device(设备) interface(接口)
Send:发送
String:字符串
合起来就是,向多媒体设备接口发送字符串。

看一下参数。(就看第一个就好,后边的不用管)

既然要播放音乐,首先得打开(open)音乐(当前路径下的音乐)。

mciSendString(_T("open ./images/音乐.mp3"), NULL, 0, NULL);

打开音乐之后,播放音乐。

mciSendString(_T("play ./images/音乐.mp3"), NULL, 0, NULL);

然后就可以运行播放啦!

这里不太好演示,大家自行播放。

这里介绍一种简洁写法:

最后,在主函数里面进行调用welcome函数。

三、星星

(1)定义结构体

在图形库上绘制任何东西,都要有坐标。

咱们先来定义一个结构体。

struct Star {	 //小星星
	int x;	//x坐标
	int y;	//y坐标
	int speed;	//速度
	COLORREF color;	//颜色
};

定义一个结构体数组:(绘制500个)

#define STAR_NUM 500
struct Star star[STAR_NUM];

(2)初始化星星

定义一个函数,来初始化星星。

传一个下标进来,对指定位置的星星进行初始化。

void initStar(int i) {
	
}

初始化x。(只要在窗口里面就是合法的)

star[i].x = rand() % getwidth();

初始化y

star[i].y=rand()%getheight();

初始化speed。速度不要太快,这里膜上5,就是0、1、2、3、4。

star[i].speed=rand()%5;

初始化颜色color。随机生成颜色,上面说过随机生成颜色:RGB(rand() % 256, rand() % 256, rand() % 256)

star[i].color=RGB(rand() % 256, rand() % 256, rand() % 256);

这样,初始化星星就好啦。

(3)绘制星星

现在来绘制星星。

定义一个函数。

void drawStar() {

}

这里就不传进来了,对所有的都进行绘制。

既然对所有的进行绘制,就要用到循环。

for(size_t i=0;i<STAR_NUM;i++){
	
}

这里绘制的星星,是一个像素点

像素点是用putpixel()绘制的。

参数分别是xycolor

三个参数我们之前定义好啦,直接拿进来。

putpixel(star[i].x,star[i].y,star[i].color);

(4)调用

现在函数是定义好了,并没有调用。

那怎么调用呢?

1)初始化

在主函数里边。

初始化星星。

initStar();

然后传参数,每一个都要进行初始化。

照样需要遍历一下。

for(size_t i=0;i<STAR_NUM;i++){
    initStar(i);
}

2)绘制

接下来要进行绘制。

drawStar();

3)问题解答

①运行一下并没有星星出现。

为啥呢?

当时我们的welcome函数里面用了while死循环!

没有退出条件,就在那里卡死了。

这里我们再次包含一个头文件:

#include<conio.h>

这个头文件里面有一个函数_kbhit()

有按键,就会返回一个真,没有按键就返回假。

这里给它加上一个!,取反。如果没有按键,就一直循环;如果有按键,就退出循环。

将初始化放在welcome函数调用之前。

然后进行welcome函数,有按键,就退出循环。

继续执行drawStar函数,画星星。

②执行一下,按了任意键之后,退出了?

咱们将画星星循环起来。

while(true){
    drawStar();
}

然后运行,就有了漫天的星星。

但是文字没有消失。

这里可以清屏(cleardevice)一下。

while(true){
    cleardevice();
    drawStar();
}

再运行,然后按下任意键,就可以看到漫天闪烁的星星了。

③其实这是一个Bug,因为是一直画星星,一直在清屏,所以星星会闪。

这里为了解决闪屏,用到另一个技术:双缓冲绘图

分别在循环前、后、中间写上:

然后再运行,就不会闪烁啦。

(5)移动星星

现在的星星是不动的,我们想让它移动,怎么办?

再来写一个函数moveStar

void moveStar(){
    
}

这里要遍历没有一个星星,就要用到循环。

for(size_t i=0;i<STAR_NUM;i++){
	
}

从左向右移动,要改变x坐标。(这里一个像素一个像素地移动)

for(size_t i=0;i<STAR_NUM;i++){
	star[i].x++;
}

写好了函数,接下来在主函数循环里边对它进行调用。

运行看一下效果:

这儿咱们做一下优化。

因为星星本来就有速度,可以这样写:

for(size_t i=0;i<STAR_NUM;i++){
	star[i].x+=star[i].speed;
}

上边的效果,也不是咱们想要的。

可以看到,星星走了之后,没有啦。

我想让它们走了再回来!(超过窗口边界之后,转身回头)

在循环里边做一个判断就好:

if(star[i].x>getwidth()){  //如果x坐标超出窗口
    star[i].x=0;		//让x坐标重新为0
}

写这儿就对啦,别写错地方了:

这样就会有源源不断的星星

自己去运行一下试试。

(6)拓展

有人可能会说,星星不够亮。

这里可以画圆。

比如:

solidcircle(star[i].x, star[i].y, star[i].speed); 
//前面两个参数是x和y,最后一个是圆的半径,这里就拿星星速度做演示了(将星星速度作为半径)

然后将它的颜色改为随机的。

setfillcolor(star[i].color);

就是这样:

运行一下看看:

好像这个更好看。

干脆来个半径吧,上面用速度当作半径来着。

这里咱们搞个半径。

同样在初始化的时候,对半径也进行一下初始化。让圆的半径小一点,这里膜上3加1。

然后在绘制里边,改一下半径。

运行看一下效果:

四、流星

(1)加载图片

接下来,我们来做流星。

其实和上边做星星差不多,只不过这次用图片来做。

图片也是数据,这里定义一个数组。

IMAGE img[1]; //这里提供1张流星图片

然后定义一个加载函数。

void loadImg(){
    
}

通过函数给图片初始化。

loadimage();

这个函数有好几个参数。

第一个参数是图片的指针,直接将数组名写入。

第二个是图片路径。

后边是图片宽度和高度。

loadimage(img + 0, _T("./images/流星1.png"));
//img+0是为了让它对齐。

(2)输出图片

用函数putimage输出图片。

这里随便输出到窗口,比如(10,10)的位置。

putimage(10,10,img);

放在主函数while循环里面输出。

(3)写入主函数

然后将函数写入主函数。

图片太大,可以进行一下缩放。

(4)定义结构体

和上边星星一样,我们要先定义一个结构体。

struct Meteor {
	int x;
	int y;
	int speed;
};

然后定义一个变量。

#define METEOR_NUM 100
struct Meteor meteor[METEOR_NUM];

(5)初始化流星

void initMeteor(int i) {

}

然后:

void initMeteor(int i) {
	meteor[i].x;
	meteor[i].y;
	meteor[i].speed;
}

(6)流星生成范围

如果只是在屏幕里边,会显得不和谐。

最少要在这个范围产生一些流星。(绿色范围)

这里就当是窗口的宽高来计算,比较省事。

现在我们将上边的数值改变一下。

①第一个x

先分析一下:

meteor[i].x=rand()%getwidth();  //[0,1200)
现在想要[-1200,1200)
     2*getwidth()          ---> [0,2400)
     2*getwidth()-getwidth ---> [-1200,1200)

然后得出:

meteor[i].x=rand()%(2*getwidth())-getwidth();

②第二个y

一开始就让它产生在负的地方,从上边往下落。

可以这样:

meteor[i].y=20-200;

③第三个speed

meteor[i].speed=rand()%15+1;

(7)绘制流星

接下来就是绘制流星了。

定义一个函数。

void drawMeteor() {

}

再遍历一下,给每一个都进行绘制。(随机绘制)

for (size_t i = 0; i < METEOR_NUM; i++) {
		putimage(meteor[i].x, meteor[i].y, img + 0);
}

如果你有两张图,可以这样写,来随机贴一张。

for (size_t i = 0; i < METEOR_NUM; i++) {
		putimage(meteor[i].x, meteor[i].y, img + rand()%2);
}

主函数里边的贴图就可以不要了。

(8)移动流星

定义一个函数。

void moveMeteor(){
    
}

然后遍历。(x和y都要移动)

for (size_t i = 0; i < METEOR_NUM; i++) {
		meteor[i].x+=meteor[i].speed;
    	meteor[i].y+=meteor[i].speed;
}

主函数里边,初始化:

	for (size_t i = 0; i < METEOR_NUM;i++) {
		initMeteor(i);

	}

然后是绘制和移动。(在while循环里)

①接下来,在移动流星里,要做一些小处理,让流星降落之后,又返回重新开始

xy都要判断。

if(meteor[i].x>=getwidth() || meteor[i].y>=getheight()){
    initMeteor(i); //哪一个消失就初始化哪一个
}

写在这个地方:

②流星在下坠的时候,会有一个背景颜色,遮挡住星星。

这里我们将它的背景颜色清除

putimage函数后边,还可以加一个参数SRCPAINT

五、设置背景颜色

我们可以在主函数,设置一下背景颜色。

比如灰色。

	setbkcolor(RGB(82, 164, 143));
	cleardevice();

如下:

哎呀,不好看。

这里我就不设置了。

六、设置背景图片

可以自行去找一张图。

保存进images文件夹。

直接在主函数里面写:

IMAGE bk;
loadimage(&bk, _T("./images/图.png"), getwidth(), getheight());

如下:

注意,贴图要在循环里边。

这里有cleardevice,不写的话是看不到的。

这个地方贴:

改一下位置:(一开始要贴图片的话,就要将它作为全局变量)

再将putimage复制一个,放在清屏之后。

七、所有代码

这里将所有代码奉上,供大家学习使用:

#include<stdio.h>
#include<easyx.h> //第三方图形库,需要安装
#include<time.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
#include<conio.h>

#define STAR_NUM 500
#define METEOR_NUM 100

struct Star {	 //小星星
	int x;	//x坐标
	int y;	//y坐标
	int r;
	int speed;	//速度
	COLORREF color;	//颜色
};
struct Meteor {
	int x;
	int y;
	int speed;
};

struct Star star[STAR_NUM];
struct Meteor meteor[METEOR_NUM];

/*星星*/
//初始化星星
void initStar(int i) {
	star[i].x = rand() % getwidth();
	star[i].y = rand() % getheight();
	star[i].r = rand() % 3 + 1;
	star[i].speed = rand() % 5;
	star[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
}

//绘制星星
void drawStar() {
	for (size_t i = 0; i < STAR_NUM; i++) {
		//putpixel(star[i].x, star[i].y, star[i].color);
		setfillcolor(star[i].color);
		solidcircle(star[i].x, star[i].y, star[i].r);
	}
}

//移动星星
void moveStar() {
	for (size_t i = 0; i < STAR_NUM; i++) {
		star[i].x += star[i].speed;
		if (star[i].x > getwidth()) {  //如果x坐标超出窗口
			star[i].x = 0;		//让x坐标重新为0
		}
	}
}


/*流星*/
IMAGE img[1];
IMAGE bk;
void loadImg() {
	loadimage(img + 0, _T("./images/流星1.png"),50,50);
	
}
//初始化流星
void initMeteor(int i) {
	meteor[i].x = rand() % (2 * getwidth()) - getwidth();
	meteor[i].y = 20 - 200;
	meteor[i].speed = rand() % 15 + 1;
}
//绘制流星:贴图
void drawMeteor() {
	for (size_t i = 0; i < METEOR_NUM; i++) {
		putimage(meteor[i].x, meteor[i].y, img + 0,SRCPAINT);
	}
}
//移动流星
void moveMeteor() {
	for (size_t i = 0; i < METEOR_NUM; i++) {
		meteor[i].x += meteor[i].speed;
		meteor[i].y += meteor[i].speed;
		if (meteor[i].x >= getwidth() || meteor[i].y >= getheight()) {
			initMeteor(i); //哪一个消失就初始化哪一个
		}
	}
}



void welcome() {

	//播放音乐
	mciSendString(_T("open ./images/音乐.mp3"), NULL, 0, NULL);//打开音乐
	mciSendString(_T("play ./images/音乐.mp3"), NULL, 0, NULL);//播放音乐

	//设置随机数种子
	srand((unsigned)time(NULL));

	//设置背景模式
	setbkmode(TRANSPARENT);

	//设置文字样式
	settextstyle(40, 0, _T("华文行楷"));
	
	//如果没有按键按下,就一直循环
	while (!_kbhit()) {

		//清屏
		cleardevice();
		putimage(0, 0, &bk);

		//设置文字颜色
		settextcolor(RGB(rand() % 256, rand() % 256, rand() % 256));

		//输出文字
		int tx = (getwidth() - textwidth(_T("此生都是你"))) / 2;
		outtextxy(tx, 50, _T("此生都是你"));

		outtextxy(300, 100, _T("织女牵牛送夕阳,临看不觉鹊桥长"));
		outtextxy(300, 150, _T("此夜星繁河正白,人传织女牵牛客"));
		outtextxy(300, 200, _T("烟外柳丝湖外水,山眉澹碧月眉黄"));
		outtextxy(300, 250, _T("相逢一醉是前缘,风雨散飘然何处"));
		outtextxy(300, 300, _T("别离还有经年客,怅望不如河鼓星"));
		outtextxy(300, 350, _T("迢迢牵牛星,皎皎河汉女"));
		outtextxy(300, 400, _T("此日六军同驻马,当时七夕笑牵牛"));
		outtextxy(300, 450, _T("七夕今宵看碧霄,牵牛织女渡河桥"));
		outtextxy(300, 500, _T("天上分金镜,人间望玉钩"));
		outtextxy(300, 550, _T("乌鹊桥成上界通,千秋灵会此宵同"));

		for (size_t i = 0; i < 10; i++) {
			settextcolor(RGB(rand() % 256, rand() % 256, rand() % 256));
			outtextxy(rand() % getwidth(), rand() % getheight(), _T("❤"));
		}

		Sleep(1000);
	}

	

}

int main() {
	//1.创建图形窗口
	initgraph(1200,800);

	//设置背景颜色
	//setbkcolor(RGB(82, 164, 143));
	//cleardevice();

	
	loadimage(&bk, _T("./images/图.png"), getwidth(), getheight());

	for (size_t i = 0; i < STAR_NUM; i++) {
		initStar(i);
	}

	for (size_t i = 0; i < METEOR_NUM;i++) {
		initMeteor(i);

	}

	loadImg();

	welcome();

	//双缓冲绘图
	BeginBatchDraw();

	while (true) {
		cleardevice();

		putimage(0, 0, &bk);

		drawStar();
		moveStar();

		drawMeteor();
		moveMeteor();

		//putimage(10, 10, img);

		FlushBatchDraw();
	}

	EndBatchDraw();

	getchar();
	return 0;
}

图片啥的大家可以自己改。
网盘链接放在评论区,需要源文件的自取。
PDF文件也会上传到资源里面。
希望文章对你有帮助!
拜拜~

更多推荐

手把手教你用C语言制作七夕流星雨---优雅永不过时(详细教程)