爱心代码(让你变得不再单身)

该博客基于C++和Easyx库实现动态爱心。介绍了Easyx库函数,包括创建图形窗口、文字输出、设置字体样式和颜色等。讲述了笛卡尔爱心故事,分析爱心公式,用特殊字体打印轨迹。还阐述粒子喷射器原理,最后给出动态爱心代码的分部实现和源码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

成果展示

多说无益,上效果

我相信当你们看完成果之后一定会更有动力向下探索,因为这可是让你脱单的大好机会啊,当你拥有了此爱心,你就赢得了人生,从此不再单身,快来瞧瞧吧~

前言:

认识Easyx库中的函数
如果你想做一个非常漂亮的动态爱心,当然少不了Easyx库,有了它你就可以绘制图片,让我们一起向下学习吧

我把下载Easyx的官网放到这里了点进去下载即可:Easyx官网

注意Easyx图形库是基于C++封装的,所以在使用的时候把源文件创建为后缀.ccp文件

使用时先包含头文件include<easyx.h>


🚘进入正题

首先我们先认识一下如何创建图形窗口

创建图形库的函数:HWND initgraph( int width,int height,int flag = NULL);

windth:指定窗口宽度
height:指定窗口高度
flag:设置窗口模式

窗口模式有以下几种:

  1. EX_DBLCLKS (在绘图窗口中支持鼠标双击事件)
  2. EX_NOCLOSE(禁用绘图窗口的关闭按钮)
  3. EX_NOMINIMIZE(禁用绘图窗口的最小化按钮)
  4. EX_SHOWCONSOLE(显示控制台窗口)
创建图形窗口展示
代码写法
#include<easyx.h>

int main()
{
	initgraph(500, 500);
	getchar();    //防止直接退出
	return 0;
}

效果

在这里插入图片描述

如果加上窗口模式

#include<stdio.h>
#include<easyx.h>

int main()
{
	//此时加入了两种窗口模式,第一种是关闭按钮取消,第二种是最小化按钮取消
	initgraph(500, 500,EW_NOCLOSE|EW_NOMINIMIZE);
	getchar(); //防止直接退出
	return 0;
}

效果展示

在这里插入图片描述

小知识

图形窗口也是有坐标轴的

在这里插入图片描述

文字输出

当我们有了窗口时,如果想在窗口上输出自己喜欢人的名字该怎么办呢?我知道大家很急,但请大家先不要急,接下来我们认识一下输出文字的函数

文字输出函数:void outtextxy( int x, int y, LPCTSTR str );
参数:
x:字符串输出时头字母的 x 轴的坐标值
y:字符串输出时头字母的 y 轴的坐标值
str:想输入的文字(此文字是字符串需要加双引号)

常见错误

代码写法

在这里插入图片描述
会发现使用此函数是会报错,这是因为跟字符集有关此时我使用的字符集是如图所示

在这里插入图片描述

如何更改字符集

在这里插入图片描述
在这里插入图片描述

此时代码就不会报错了,可以顺利的打印出字

在这里插入图片描述

去除字的背景

用Easyx库打印出的字是会带背景的,我们需要用一个函数来去掉字的背景

此函数功能去掉字的背景:void setbkmode(int mode);

在这里插入图片描述

设置字体大小以及字体样式

我们会发现这个字体非常的丑陋,并且想更改字体的大小,如何做到呢?
接下来这个函数就可以做到以上功能

设置文字样式:void settextstyle( int nHeight, int nWidth, LPCTSTR lpszFace );
参数介绍
nHeight:设置字体的高度
nWidth:设置字体的宽度(一般只设置字体高度,宽度取0自适应高度)
lpszFace:字体名称

代码写法

#include<stdio.h>
#include<easyx.h>

int main()
{
	initgraph(500, 500);
	settextstyle(60, 0, "鸿雷行书简体");
	outtextxy(130, 180, "我是大帅比啊");
	getchar();
	return 0;
}

展示效果

在这里插入图片描述

字体颜色

接下来就是字体颜色的介绍了

设置字体颜色:void settextcolor(COLORREF color);
参数
color :填颜色英文单词大写

代码写法
这里以红色为例

#include<stdio.h>
#include<easyx.h>

int main()
{
	initgraph(500, 500);
	settextcolor(RED);	//RED 红色单词
	settextstyle(60, 0, "鸿雷行书简体");
	outtextxy(130, 180, "我是大帅比啊");
	getchar();
	return 0;
}

展示效果

在这里插入图片描述

BeginBatchDraw和EndBatchDraw函数

🦄BeginBatchDraw函数

功能:用于开始批量绘图。执行后,任何绘图操作都将暂时不输出到绘图窗口上,直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。

void BeginBatchDraw();

🐴EndBatchDraw函数

功能:这个函数用于结束批量绘制,并执行未完成的绘制任务。

// 结束批量绘制,并执行未完成的绘制任务
void EndBatchDraw();
🎵实现音乐播放

实现动态爱心,必然少不了音乐的渲染,有了音乐氛围不就来了吗?这样你表白还会失败吗?快来学学如何播放音乐吧~

播放音乐必须先包含这两个

#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")

播放音乐的函数

mciSendString("play 告白气球.mp3 repeat", 0, 0, 0);
播放:plya
音乐名:告白气球.mp3
模式:repeat(重复播放)
后三个参数全部传0即可

学了以上函数我们写这个动态爱心已经不成问题了
我们先不急着做爱心,让我们来一起看看爱心公式背后的精彩故事吧

💘笛卡尔的爱心故事

52岁的笛卡尔邂逅了18岁瑞典公主克莉丝汀。笛卡尔落魄无比,穷困潦倒又不愿意请求别人的施舍,每天只是拿着破笔破纸研究数学题。有一天克莉丝汀的马车路过街头发现了笛卡尔是在研究数学,公主便下车询问,最后笛卡尔发现公主很有数学天赋。
道别后的几天笛卡尔收到通知,国王要求他做克莉丝汀公主的数学老师。其后几年中相差34岁的笛卡尔和克莉丝汀相爱,国王发现并处死了笛卡尔。笛卡尔给公主写了十二封情书,不幸的是都被国王拦了下来。
在临死之前笛卡尔给公主写了第十三封情书,信里面没有一个字,只有一个方程。国王收到这封信后百思不得其解,于是召集了瑞典所有的数学家进行研究,还是一无所获,就把这封信交给了公主。公主很快就找到了答案,这个方程的对应曲线就是著名的心形线。
在这里插入图片描述

好了,故事说完了,该写代码了。问题是我们很多人数学并不好,很多程序员老鸟的数学也不好,如果因为这个东西,就要去重学数学,那这个撩妹成本也太了。所以直接“借鉴”方便的公式使用。

公式选择及其分析

笛卡尔曲线公式演变出很多公式,我选择了这个
在这里插入图片描述

(注意感觉这个公式绘制的心形比较苗条,有些公式绘制的效果像个大馒头,影响B格和效果)

因为笛卡尔公式是用极坐标表示的,所以我们先学习一下极坐标

在这里插入图片描述

在极坐标中,任意一点的位置,由r和θ决定,r表示这个点到“极点”O之间的距离,θ表示如上图所示的夹角。根据这个公式,我们可以直接写出如下代码:

/ angle表示角度θ,r表示ρ
double r = sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142) - 2 * sin(angle) + 2;

大家看到代码可能有几个函数不知道是干什么的,我在此逐个解释一下

如:sin()函数 ,cos()函数,sqrt()函数,fabs()函数,这几个函数都需要包含数学头文件#include<math.h>否则无法使用

sqrt()函数:是给括号内的数据加根号的,如sqrt(3) 其实可以翻译成根号3
fabs()函数:是给括号内部的数据取绝对值的,如fabs(-3) 其实可以翻译成|-3|

由于我们在使用代码进行绘制的时候,使用的都是直角坐标系,所以还需要把这个极坐标,转换成直角坐标系,转换公式如下

 x=rcos(0);
 y=rsin(0);

现在我们就的到了完整的曲线公式

r = sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142) - 2 * sin(angle) + 2;
x = r * cos(angle);
y = r * sin(angle);
轨迹测试(用 ' * ' 打印)
#include <stdio.h>
#include <easyx.h> 
#include <math.h>

int main(void)
{
	initgraph(800, 600);
	int R = 100;
	double angle = 0;
	for (angle = 0; angle <= 3.14 * 2; angle += 0.1)
	{
		double r = (sin(angle) * sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142)
			- 2 * sin(angle) + 2);
		int x = R * r * cos(angle)+400; //这里的400指的是向右偏移多少
		int y = -R * r * sin(angle)+100; //这里的100指的是向下偏移多少
		outtextxy(x, y, "*");
	}

	system("pause");
	return 0;
}

展示效果

在这里插入图片描述

用特殊字体打印爱心轨迹

到现在,我们已经把心形轨迹模拟出来了,但是每个轨迹点的“爱心”还没有实现。其实最简单的办法就是直接使用一个心形小图片,但是这样子不方便表白活动的展开,总不能给学妹分享你的B格代码时,还要额外附送一个心形图片,这样子就没有神秘感,B格维度直接降低到零点。

其实也很简单,只要把字体调整一下就可以了,把字体设置为“Webdings”,再直接输出字符Y即可得到一个心形,但是代码中可以不要直接输出Y, 可以在代码中输出Y的ASCII码值89, 这样就更神秘了

在这里插入图片描述

我把字体下载官网放在这里,有需要的可以点击下载:Webdings

下载好了字体再做一个测试

#include <stdio.h>
#include <easyx.h> 
#include <math.h>

int main(void) {
	initgraph(550, 500);
	int R = 100;
	double angle = 0;
	for (angle = 0; angle <= 3.14 * 2; angle += 0.1)
	{
		double r = (sin(angle) *sqrt(fabs(cos(angle))) / (sin(angle) + 1.4142)
			- 2 * sin(angle) + 2);
		int x = R * r * cos(angle) + 260;
		int y = -R * r * sin(angle) + 80; //垂直翻转
		setbkmode(TRANSPARENT);
		settextcolor(RED);
		settextstyle(40, 0, "Webdings");
		setbkmode(TRANSPARENT);
		outtextxy(x, y, 89); //89 就是 'Y'
	}
	system("pause");
	return 0;
}

展示效果

在这里插入图片描述

粒子喷射器原理

我们可以一次再爱心轨迹上随机创建20颗小爱心,打印,然后再对创建的20颗小爱心的大小(加大)和位置(向外偏移)进行修改,前后间隔30毫秒循环一次,当一颗小爱心被加大20次之后,即偏移20次之后,对这颗小爱心进行初始化,就这样一直循环就能得到爱心的动态效果。

动态爱心代码分部实现:
①main函数框架
int main()
{
	init();  //初始化
	while (1)
	{
		Creatlove();  //创建小爱心
		Printlove();  //打印小爱心
		Modifylove();  //修改爱心大小和位置

		Sleep(30);  //间隔30毫秒
	}

}

②定义爱心结构、放大倍数R和喷射池子的大小
#define R 100  //R为放大倍数
struct love 
{
	int x;
	int y;
	//爱心x,y坐标位置
	int height;   //控制字符大小
	double angle;   //角度
	double r;       //笛卡尔曲线半径
	int cuR;        //对半径的放大倍数
};

③初始化
void init()
{
	initgraph(700, 600);
	memset(movelove, 0, sizeof(struct love) * 400);  //初始化为零
	srand(time(NULL));   //设置随机种子
}
④创建小爱心
void Creatangle(int angles[], int count)
{
	int M = 3.14 * 2*100; //因为rand()函数返回的是整数所以只好把3.14放大一百倍
	for (int i = 0;i < count;i++)
	{
		x:
		int angle = rand() % M;
		
		for (int k = 0; k < i; k++)
		{
			if (angles[k] == angle)
			{
				goto x;
			}
		}
		angles[i] = angle;
	}
}

void Creatlove()
{
	int k = 0;
	for ( k = 0;k < 400 && movelove[k].cuR>0;k++);  //过滤已经创建的心心
		//创建随机角度
		int angles[20];
		Creatangle(angles, 20);

	//连续创建20个随机爱心
	for (int i = k;i < k + 20;i++)
	{
		movelove[i].angle = angles[i-k]*0.01;
		 movelove[i].r =(sin(movelove[i].angle) * sqrt(fabs(cos(movelove[i].angle)))) / (sin(movelove[i].angle) + 1.4142)
			- 2 * sin(movelove[i].angle) + 2;
		movelove[i].cuR = R;
		movelove[i].height = 0;  
		 movelove[i].x = movelove[i].cuR * movelove[i].r * movelove[i].angle + 360;
		 movelove[i].y = -movelove[i].cuR * movelove[i].r * movelove[i].angle + 170;
	}

}

⑤打印小爱心
void Printlove()
{
	BeginBatchDraw();
	cleardevice();   //清除当前窗口

	settextcolor(RED);
	for (int i = 0;i < 400;i++)
	{
		if (movelove[i].cuR == 0) continue;
		settextstyle(movelove[i].height+20, 0, "Webdings");
		setbkmode(TRANSPARENT);  //字符背景透明
		outtextxy(movelove[i].x+10, movelove[i].y-80, "Y");   //movelove[i].x加10和 movelove[i].y减80
		                                                      //是为了控制输出在窗口的中间
	}

	EndBatchDraw();
}

⑥修改小爱心
void Modifylove()
{
	for (int i = 0;i < 400;i++)
	{
		if (movelove[i].cuR == 0) continue;
		movelove[i].cuR++;  //字符位置往外移

		//一次随机创20颗爱心,创建20次,movelove[i].cuR初始值为100,当它大于120,让它回归最初状态
		if (movelove[i].cuR >= 120)
		{
			memset(&movelove[i], 0, sizeof(struct love));
		}
		movelove[i].height++;   //字符变大
		movelove[i].x = movelove[i].cuR * movelove[i].r * cos(movelove[i].angle) + 360;
		movelove[i].y = -movelove[i].cuR * movelove[i].r * sin(movelove[i].angle) + 170 ;

	}
}

🎉 源码
#define  _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <easyx.h> 
#include <math.h>
#include <time.h>

#define R 100
struct love 
{
	int x;
	int y;
	//爱心x,y坐标位置
	int height;   //控制字符大小
	double angle;   //角度
	double r;       //笛卡尔曲线半径
	int cuR;        //对半径的放大倍数
};

//一次创建20颗爱心,20轮
struct love movelove[20 * 20];  //存放爱心

void init()
{
	initgraph(700, 600);
	memset(movelove, 0, sizeof(struct love) * 400);
	srand(time(NULL));   //设置随机种子
}

void Creatangle(int angles[], int count)
{
	int M = 3.14 * 2 * 100;
	for (int i = 0;i < count;i++)
	{
		x:
		int angle = rand() % M;
		
		for (int k = 0; k < i; k++)
		{
			if (angles[k] == angle)
			{
				goto x;
			}
		}
		angles[i] = angle;
	}
}

void Creatlove()
{
	int k = 0;
	for ( k = 0;k < 400 && movelove[k].cuR>0;k++);  //过滤已经创建的心心
		//创建随机角度
		int angles[20];
		Creatangle(angles, 20);
	//连续创建20个随机爱心
	for (int i = k;i < k + 20;i++)
	{
		
		movelove[i].angle = angles[i-k]*0.01;
		 movelove[i].r =(sin(movelove[i].angle) * sqrt(fabs(cos(movelove[i].angle)))) / (sin(movelove[i].angle) + 1.4142)
			- 2 * sin(movelove[i].angle) + 2;
		movelove[i].cuR = R;
		movelove[i].height = 0;  
		 movelove[i].x = movelove[i].cuR * movelove[i].r * movelove[i].angle + 360;
		 movelove[i].y = -movelove[i].cuR * movelove[i].r * movelove[i].angle + 170;
	}

}
void Printlove()
{
	BeginBatchDraw();
	cleardevice();   //清除当前窗口

	settextcolor(RED);
	for (int i = 0;i < 400;i++)
	{
		if (movelove[i].cuR == 0) continue;
		settextstyle(movelove[i].height+20, 0, "Webdings");
		setbkmode(TRANSPARENT);  //字符背景透明
		outtextxy(movelove[i].x+10, movelove[i].y-80, "Y");   //movelove[i].x加10和 movelove[i].y减80
		                                                      //是为了控制输出在窗口的中间
	}

	EndBatchDraw();
}

void Modifylove()
{
	for (int i = 0;i < 400;i++)
	{
		if (movelove[i].cuR == 0) 
		{
			continue;
		}
		
		movelove[i].cuR++;  //字符位置往外移

		//一次随机创20颗爱心,创建20次,movelove[i].cuR初始值为100,当它大于120,让它回归最初状态
		if (movelove[i].cuR >= 120)
		{
			memset(&movelove[i], 0, sizeof(struct love));
		}
		movelove[i].height++;   //字符变大
		movelove[i].x = movelove[i].cuR * movelove[i].r * cos(movelove[i].angle) + 360;
		movelove[i].y = -movelove[i].cuR * movelove[i].r * sin(movelove[i].angle) + 170 ;

	}
}

int main()
{
	init();  //初始化
	while (1)
	{
		Creatlove();  //创建小爱心
		Printlove();  //打印小爱心
		Modifylove();  //修改爱心大小和位置

		Sleep(30);  //间隔30毫秒
	}

}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值