引言
本文核心主题
本文将深入解析两款控制台爱心图形代码——静态渐变爱心与3D动态粒子爱心的实现逻辑。
代码功能概述
- 静态爱心:基于笛卡尔心形公式,通过计算像素到爱心中心的距离实现多梯度粉色系渐变,在控制台固定位置绘制出视觉层次感的爱心图形。
- 3D动态粒子爱心:基于3D心形隐函数建模,结合时间因子驱动的动画逻辑与帧刷新机制,实现粒子化、波动效果的3D动态爱心,支持ESC键退出交互。
- 数学基础:2D笛卡尔心形公式$(x²+y²-1)³ – x²y³ ≤ 0$、3D心形隐函数$f(x,y,z)$;勾股定理计算距离、三角函数($\\sin$)实现动画波动、法线向量计算实现视觉亮度映射。
- 心形隐函数推导:笛卡尔心形公式$(x²+y²-1)³ – x²y³ ≤ 0$是判定坐标点是否在爱心区域的核心,公式中$x$、$y$为数学坐标系下的坐标,满足公式的点即属于爱心范围。
- 颜色控制封装:setColor函数封装SetConsoleTextAttribute,通过传入不同颜色宏(如FOREGROUND_RED)快速切换文本颜色。
附录
- 完整可运行源代码(静态/动态版本)
- 静态代码:
#include <stdio.h>
#include <windows.h>
#include <math.h>void setColor(int textColor) {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, textColor);
}void initConsole() {
system("cls");
system("mode con cols=80 lines=40");
system("chcp 65001 >nul");
SetConsoleTitleA("正立彩色爱心 – 最终修复版");
}int isInHeart(float x, float y) {
float scale = 6.0f;
float xScaled = x / scale;
float yScaled = y / scale;
float eq = pow(xScaled*xScaled + yScaled*yScaled – 1, 3) – xScaled*xScaled * pow(yScaled, 3);
return eq <= 0;
}int main() {
initConsole();const int COLOR_LIGHT_PINK = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const int COLOR_PINK = FOREGROUND_RED | FOREGROUND_BLUE;
const int COLOR_ROSE = FOREGROUND_RED | FOREGROUND_INTENSITY;
const int COLOR_RED = FOREGROUND_RED;
const int COLOR_DEEP_RED = FOREGROUND_RED | FOREGROUND_INTENSITY;int offsetX = 40;
int offsetY = 20; // 调整垂直偏移,让爱心更居中// 正立爱心:Y轴从上往下遍历,同时传入方程时翻转Y值
for (int y = offsetY – 8; y <= offsetY + 8; y++) {
for (int x = offsetX – 10; x <= offsetX + 10; x++) {
COORD pos = {x, y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);// 关键修复:将控制台Y值取反后传入方程
float heartX = x – offsetX;
float heartY = -(y – offsetY); // 翻转Y轴方向if (isInHeart(heartX, heartY)) {
float distance = sqrt(pow(heartX, 2) + pow(heartY, 2));
if (distance < 2) {
setColor(COLOR_DEEP_RED);
} else if (distance < 4) {
setColor(COLOR_RED);
} else if (distance < 6) {
setColor(COLOR_ROSE);
} else if (distance < 8) {
setColor(COLOR_PINK);
} else {
setColor(COLOR_LIGHT_PINK);
}
printf("*");
}
}
}setColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
COORD endPos = {0, offsetY + 10};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), endPos);
printf("\\n");return 0;
}实现效果如下图(有点丑):
-

-
动态代码爱心:
-
#include <stdio.h>
#include <math.h>
#include <windows.h>
#include <string.h>// 3D爱心核心公式
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.005f)
if (f(x, y, z) <= 0.0f)
return y;
return 0.0f;
}int main() {
// 1. 控制台初始化(一次性设置到位,避免兼容性问题)
system("cls");
system("mode con cols=80 lines=30"); // 固定窗口大小
system("chcp 936 >nul"); // GBK编码
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTitleA("终极稳定3D爱心");// 隐藏光标,避免闪烁
CONSOLE_CURSOR_INFO cursor = {1, FALSE};
SetConsoleCursorInfo(hConsole, &cursor);// 2. 固定字符梯度和颜色(避免视觉混乱)
char ramp[] = " .:-=+*#%@";
int color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; // 固定粉色
SetConsoleTextAttribute(hConsole, color);// 3. 帧缓冲区(精确匹配窗口大小)
char buffer[30][81]; // 30行×80列,每行1位结束符// 4. 主循环(彻底解决残留、错位问题)
for (float t = 0.0f;; t += 0.05f) {
// 彻底清空缓冲区,确保无残留
memset(buffer, ' ', sizeof(buffer));
for (int i = 0; i < 30; i++) buffer[i][80] = '\\0';int sy = 0;
float s = sinf(t);
float a = s * s * s * s * 0.15f;// 精确控制z轴循环,确保不越界
for (float z = 1.4f; z > -1.3f && sy < 30; z -= 0.09f) {
char *p = buffer[sy++];
float tz = z * (1.2f – a);// 精确控制x轴循环,确保不越界
for (float x = -1.6f; x < 1.6f && p – buffer[sy-1] < 80; x += 0.05f) {
float tx = x * (1.2f + a);
float v = f(tx, 0.0f, tz);if (v <= 0.0f) {
float y0 = h(tx, tz);
float ny = 0.01f;
float nx = h(tx + ny, tz) – y0;
float nz = h(tx, tz + ny) – y0;
float nd = 1.0f / sqrtf(nx * nx + ny * ny + nz * nz);
float d = (nx + ny – nz) * nd * 0.5f + 0.5f;// 确保索引不越界
int idx = (int)(d * 9.0f);
idx = idx < 0 ? 0 : (idx > 9 ? 9 : idx);
*p++ = ramp[idx];
} else {
*p++ = ' ';
}
}
}// 光标定位到左上角,确保无错位
COORD pos = {0, 0};
SetConsoleCursorPosition(hConsole, pos);// 输出完整30行,覆盖整个控制台
for (int i = 0; i < 30; i++) {
printf("%s\\n", buffer[i]);
}Sleep(30);
// ESC退出
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
break;
}
}// 恢复控制台默认样式
SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
system("cls");
printf("程序已退出\\n");
return 0;
}实现效果如下图所示:
-



