C++ EasyX 动态烟花模拟源码与实现解析

宋时安
宋时安
发布时间:2026-10-13| 6人浏览过
原创

本文介绍如何利用 C++ 的 EasyX 图形库实现动态烟花特效。通过定义数据结构管理烟花状态,结合三角函数计算爆炸轨迹及简易物理算法,模拟粒子上升与绽放过程。文章解析了从初始化到绘制的核心逻辑,并提供完整可运行代码。

项目准备与环境配置

开发本案例需要 C++ 基础以及 EasyX 图形库的支持。该库为初学者提供了简便的图形界面操作接口,无需复杂处理即可实现绘图功能。

  • 依赖库:下载并安装 graphics.h(EasyX)。
  • 开发环境:Visual Studio 或其他支持 C++11 及以上标准的编译器。
  • 宏定义参数:根据预设窗口大小调整常量,例如宽度 WIDTH 为 640,高度 HEIGHT 为 480,同时设定烟花最大数量 MAXNUM。

核心逻辑解析

第1步:构建烟花对象结构体

使用 struct 封装单个烟花粒子的属性,便于批量管理。

  • nowx / nowy:当前坐标位置。
  • endy:目标爆炸高度 Y 轴阈值。
  • explode:爆炸进度值,用于驱动后续扩散逻辑。
  • radio:爆炸的最大半径范围。
  • rgb[3]:颜色数组,记录红绿蓝分量。

第2步:随机初始化与资源分配

在启动阶段,为每个烟花实例赋予随机属性。

  • 入口:调用 Init() 函数。
  • 动作:生成随机的 X 轴初始位置(屏幕宽度内),Y 轴起始位置位于可视区域下方(HEIGHT + rand() % 250 + 50),确保动画开始时烟花从底部升起。
  • 颜色选择:从预设的颜色矩阵中随机抽取一组 RGB 值并赋值给实例。

第3步:运动逻辑与状态判断

在每一帧刷新时更新位置,决定是继续上升还是进入爆炸阶段。

  • 上升:当当前 Y 坐标大于设定的爆炸高度 endy 时,Y 轴数值递减(模拟向上飞行)。
  • 爆炸触发:一旦越过临界点,切换逻辑分支,让 explode 变量自增,并检测是否达到 radio 最大值。若已达上限,则重新初始化该烟花实例。

第4步:可视化渲染与数学模拟

利用图形库绘制圆形,并通过数学函数模拟真实物理效果。

  • 上升阶段绘制:以多层同心圆形式绘制,通过调整 RGB 值的透明度或亮度差来体现光晕效果。
  • 爆炸阶段计算:核心在于将时间(爆炸进度)转化为角度坐标。
    - 使用 cos() 和 sin() 结合 explode 值计算 X、Y 偏移量。
    - 引入重力加速度近似算法:y + (HEIGHT - y) * 0.1,模拟粒子在下落过程中的抛物线轨迹。

完整源码

以下是完整的 C++ 实现代码,包含主循环、批次绘制优化(防闪烁)以及上述所有逻辑:

/*******************************
* 项目名称:新年烟花
* 开发环境:vs2022 + Easyx
* 作者:轩
* 代码长度:137 行
* 完成时间:2023.1.20
*******************************/
#include <graphics.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#define MAXNUM 15
#define WIDTH 640
#define HEIGHT 480
#define PI 3.1415926

struct Fire
{
	int nowx;
	int nowy;
	int endy;
	int radio;
	int explode;
	int rgb[3];
	COLORREF color;
}fire[MAXNUM];

void Init()
{
	for (int i = 0; i < MAXNUM; i++)
	{
		fire[i].nowx = rand() % WIDTH;
		fire[i].nowy = HEIGHT + rand() % 250 + 50;
		fire[i].endy = rand() % 100 + 10;
		fire[i].radio = rand() % 50 + 120;
		fire[i].explode = 0;
		int c[][3] = { {255, 0, 0}, {210, 190, 255}, {255, 120, 0}, {255, 0, 150}, {255, 240, 100}, {10, 255, 255}, {160, 10, 255}, {255, 200, 60} };
		int n = rand() % 8;
		fire[i].color = RGB(c[n][0], c[n][1], c[n][2]);
		fire[i].rgb[0] = c[n][0];
		fire[i].rgb[1] = c[n][1];
		fire[i].rgb[2] = c[n][2];
	}
}

void Draw()
{
	for (int i = 0; i < MAXNUM; i++)
	{
		if (fire[i].nowy > fire[i].endy)
		{
			for (int size = 5; size > 0; size--)
			{
				int temp[] = { fire[i].rgb[0], fire[i].rgb[1], fire[i].rgb[2] };
				for (int k = 0; k < 3; k++)
				{
					temp[k] += 50 * (5 - size);
					if (temp[k] > 255) temp[k] = 255;
				}
				setfillcolor(RGB(temp[0], temp[1], temp[2]));
				solidcircle(fire[i].nowx, fire[i].nowy + 15*(10 - size), size);
			}
		}
		else
		{
			for (int a = 0; a < 360; a += 30)
			{
				for (int size = 5; size > 0; size--)
				{
					int x = cos(a * PI / 180.0) * (fire[i].explode + size * 10) + fire[i].nowx;
					int y = sin(a * PI / 180.0) * (fire[i].explode + size * 10) + fire[i].nowy + fire[i].radio / 2;
					int temp[] = { fire[i].rgb[0], fire[i].rgb[1], fire[i].rgb[2] };
					for (int k = 0; k < 3; k++)
					{
						temp[k] += 50 * (5 - size);
						if (temp[k] > 255) temp[k] = 255;
					}
					setfillcolor(RGB(temp[0], temp[1], temp[2]));
					solidcircle(x, y + (HEIGHT - y) * 0.1 + size * (size - 2), size);
				}
			}
		}
	}
}

void Move()
{
	for (int i = 0; i < MAXNUM; i++)
	{
		if (fire[i].nowy > fire[i].endy)
		{
			fire[i].nowy -= 3;
		}
		else
		{
			if (fire[i].explode >= fire[i].radio)
			{
				fire[i].nowx = rand() % WIDTH;
				fire[i].nowy = HEIGHT + rand() % 250 + 50;
				fire[i].endy = rand() % 100 + 10;
				fire[i].radio = rand() % 50 + 120;
				fire[i].explode = 0;
				int c[][3] = { {255, 0, 0}, {210, 190, 255}, {255, 120, 0}, {255, 0, 150}, {255, 240, 100}, {10, 255, 255}, {160, 10, 255}, {255, 200, 60} };
				int n = rand() % 8;
				fire[i].color = RGB(c[n][0], c[n][1], c[n][2]);
				fire[i].rgb[0] = c[n][0];
				fire[i].rgb[1] = c[n][1];
				fire[i].rgb[2] = c[n][2];
			}
			else fire[i].explode++;
		}
	}
}

int main()
{
	srand(time(NULL));
	initgraph(640, 480);
	Init();
	BeginBatchDraw();
	while (true)
	{
		cleardevice();
		Draw();
		Move();
		FlushBatchDraw();
		Sleep(2);
	}
	EndBatchDraw();
	closegraph();
	return 0;
}

总结

通过该方案,我们实现了基于几何计算的简单粒子系统。掌握坐标变换和物理模拟基础后,可以进一步扩展为更复杂的特效程序。以上就是 C++ EasyX 实现动态烟花效果的详细内容,更多关于 C++ 图形化编程的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。