【c/c++】属于程序员的浪漫,基于easyx.h图形库实现3D Heart

小明 2025-05-07 08:19:16 16

文章目录

  • 😏专栏导读
  • 🤖文章导读
    • 🙀一、easyX图形库基本介绍?
    • 1、easyX的原理:
    • 2、easyX的安装
    • 🙀3D Heat源码描述
    • 😳3D Heat效果展示
    • ���结

      😏专栏导读

      👻作者简介:M malloc,致力于成为嵌入式大牛的男人

      👻专栏简介:本文收录于 初阶数据结构,本专栏主要内容讲述了初阶的数据结构,如顺序表,链表,栈,队列等等,专为小白打造的文章专栏。

      👻相关专栏推荐:LeetCode刷题集,C语言每日一题。


      🤖文章导读

      本章我将详细的讲解如何通过easyx.h实现3D Heat的知识点

      🙀一、easyX图形库基本介绍?

      1、easyX的原理:

      基于Windows图形编程,将Windows下的复杂程序过程进行封装,仅给用户提供一个简单熟悉的接口。用户对于图形库中函数的调用,最终都会由Windows底层的API实现。

      2、easyX的安装

      注意:easyX图形库仅支持VS的各个版本

      在浏览器搜索easyX官网,进入官网后,点击下载

      安装好就行啦!!!

      🙀3D Heat源码描述

      #define _CRT_SECURE_NO_WARNINGS 1
      #include 
      #define _USE_MATH_DEFINES
      #include 
      #include 
      using namespace std;
      // 宏定义屏幕宽度和高度
      #define SCREEN_WIDTH 640
      #define SCREEN_HEIGHT 480
      // 点 结构体
      struct Point
      {
      	int x = 0;
      	int y = 0;
      };
      // 粒子 结构体
      // width、height 分别定义了粒子的宽和高
      // x、y 表示粒子的三维坐标(z 坐标永为 0)
      // color 表示该粒子的颜色
      struct Atom
      {
      	static const int width = 2;
      	static const int height = 4;
      	int x = 0;
      	int y = 0;
      	COLORREF color;
      };
      // 全局变量定义
      vector _atomGroup;	// 粒子群
      vector _wordGroup;	// 文字粒子群
      double _angle_x = 0;		// 绕 x 轴旋转角度
      double _angle_y = 0;		// 绕 y 轴旋转角度
      ExMessage _lastMsg;			// 记录上次绘图时的鼠标消息
      ExMessage _nowMsg;			// 记录当前鼠标消息
      // 函数声明
      void InitQuietHeart();		// 创建静止的心形粒子群(已弃用,但仍保留)
      void BeatHeart();			// 创建跳动的心脏,每运行一次该函数,心跳一帧
      void InitBlessingWord();	// 创建祝福文字粒子群
      void Rotate();				// 计算旋转角度
      void Draw();				// 绘制三维投影
      Point GetConvertPoint(int x, int y);	// 将三维坐标转化为投影后的绘图物理坐标
      int main()
      {
      	initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);						// 初始化窗口
      	setorigin(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);				// 设置原点为屏幕中心
      	SetWindowText(GetHWnd(), _T("致你的七夕礼物 —— 3D Heart"));	// 设置窗口标题
      	BeatHeart();			// 创建跳动的心脏
      	InitBlessingWord();		// 创建文字
      	Draw();					// 进行一次绘图
      	bool beating = true;	// 控制心跳的变量
      	while (true)			// 进入主循环
      	{
      		ExMessage msg;
      		while (peekmessage(&msg, EX_MOUSE))	// 检测有无鼠标消息
      		{
      			// 按下鼠标左键时,记录鼠标位置
      			if (msg.message == WM_LBUTTONDOWN)
      			{
      				_lastMsg = msg;
      			}
      			// 鼠标左键按下,且鼠标正在移动时,进行旋转
      			if (msg.lbutton && msg.message == WM_MOUSEMOVE)
      			{
      				beating = false;	// 旋转图形时,停止心跳
      				_nowMsg = msg;		// 获取当前鼠标位置
      				Rotate();			// 通过对比上一次绘图时的鼠标位置,进行旋转
      				_lastMsg = _nowMsg;	// 记录下这一次的鼠标位置
      				Draw();				// 进行一次绘图
      				circle(0, 0, 2);	// 画出坐标原点
      			}
      			else if (msg.rbutton)
      			{
      				beating = false;	// 鼠标右键按下时,停止心跳
      			}
      			else
      			{
      				beating = true;		// 其他情况继续心跳
      			}
      		}
      		// 心脏跳动
      		if (beating)
      		{
      			BeatHeart();
      			Draw();
      		}
      		// 延时
      		Sleep(16);
      	}
      	// 关闭绘图环境
      	closegraph();
      	return 0;
      }
      // 计算心形时的辅助函数
      float f(float x, float y, float z)
      {
      	float a = x * x + 9.0f / 4.0f * y * y + z * z - 1;
      	return a * a * a - x * x * z * z * z - 9.0f / 80.0f * y * y * z * z * z;
      }
      // 计算心形时的辅助函数
      float h(float x, float z)
      {
      	for (float y = 1.0f; y >= 0.0f; y -= 0.001f)
      	{
      		if (f(x, y, z) 
      			return y;
      		}
      	}
      	return 0.0f;
      }
      void InitQuietHeart()
      {
      	// 添加心形粒子群
      	int _x = 0;
      	int _y = -30;
      	for (float z = 1.5f; z  -1.5f; z -= 0.05f)
      	{
      		_x = -60;
      		for (float x = -1.5f; x  -1.2f; z -= 0.05f)
      	{
      		float tz = z * (1.2f - a);
      		_x = -60;
      		for (float x = -1.5f; x  0 ? _angle_x -= 2 * M_PI : _angle_x += 2 * M_PI;
      	}
      	if (fabs(_angle_y) > 2 * M_PI)
      	{
      		_angle_y > 0 ? _angle_y -= 2 * M_PI : _angle_y += 2 * M_PI;
      	}
      }
      void Draw()
      {
      	static Point p;
      	// 开启批量绘图
      	BeginBatchDraw();
      	// 清空当前画面
      	cleardevice();
      	// 绘制粒子群
      	for (Atom a : _atomGroup)
      	{
      		// 设置颜色
      		setfillcolor(a.color);
      		// 获取投影坐标
      		p = GetConvertPoint(a.x, a.y);
      		// 绘制粒子
      		solidrectangle(p.x - Atom::width / 2, p.y - Atom::height / 2, p.x + Atom::width / 2, p.y + Atom::height / 2);
      	}
      	// 绘制文字粒子群
      	setfillcolor(WHITE);
      	for (Atom a : _wordGroup)
      	{
      		// 获取投影坐标
      		p = GetConvertPoint(a.x, a.y);
      		// 绘制粒子
      		solidrectangle(p.x - 1, p.y - 1, p.x + 1, p.y + 1);
      	}
      	// 停止批量绘图
      	EndBatchDraw();
      }
      Point GetConvertPoint(int x, int y)
      {
      	static int x0, y0;
      	// 将坐标乘以宽高
      	x *= Atom::width;
      	y *= Atom::height;
      	// 计算转换坐标
      	x0 = int(x * cos(_angle_x) + y * sin(_angle_y) * sin(_angle_x));
      	y0 = int(y * cos(_angle_y) + x * sin(_angle_x) * sin(_angle_y));
      	return Point({ x0, y0 });
      }
      

      😳3D Heat效果展示

      总结

      今天的分享到此就结束啦!我们下期再见,别忘了点赞关注加收藏哦!!!!我是爱你们的M malloc!

The End
微信