2026春节近了!用C++为你送上烟花祝福!

2026春节近了!用C++为你送上烟花祝福!

2026新年烟花庆祝程序

效果展示

【2026春节来了!C++为你呈现烟花视觉盛宴】

第一部分:环境准备

1.1 系统要求

本程序设计在WSL(Windows Subsystem for Linux)的Fedora系统上运行,需要以下环境:

  • WSL 2.0或更高版本
  • Fedora Linux发行版
  • C++编译器(g++)
  • SFML图形库

1.2 安装依赖

在Fedora终端中执行以下命令:

# 1. 更新系统包管理器sudo dnf update # 2. 安装C++编译器和构建工具sudo dnf install gcc-c++ make cmake # 3. 安装SFML图形库(注意:Fedora中SFML包名可能有差异)sudo dnf install SFML SFML-devel # 如果上述SFML安装失败,尝试以下命令:sudo dnf install sfml sfml-devel # 4. 安装中文字体(可选,但推荐)sudo dnf install wqy-microhei-fonts wqy-zenhei-fonts 

1.3 验证安装

安装完成后,验证关键组件:

# 验证g++版本 g++ --version # 验证SFML是否安装成功(检查头文件路径)ls /usr/include/SFML/ 

第二部分:代码结构详解

2.1 整体架构

程序采用面向对象设计,主要包含以下类:

  • Particle:粒子结构体,代表单个烟花粒子
  • Firework:烟花结构体,包含多个粒子
  • TextParticle:文字粒子结构体
  • FireworksDisplay:主显示类,管理所有烟花和界面

2.2 核心数据结构

2.2.1 Particle结构体
structParticle{ sf::Vector2f position;// 粒子位置 sf::Vector2f velocity;// 粒子速度 sf::Color color;// 粒子颜色float lifetime;// 当前寿命float maxLifetime;// 最大寿命float size;// 粒子大小bool isTrail;// 是否为尾迹粒子};

功能说明

  • 每个粒子有独立的物理属性(位置、速度)
  • 寿命系统控制粒子显示时间
  • isTrail标志区分爆炸粒子和尾迹粒子
2.2.2 Firework结构体
structFirework{ sf::Vector2f position;// 烟花当前位置 sf::Vector2f velocity;// 烟花上升速度 sf::Color color;// 烟花颜色float timer;// 计时器float explosionHeight;// 爆炸高度bool exploded;// 是否已爆炸 std::vector<Particle> particles;// 粒子集合int type;// 烟花类型(0-5)float sizeFactor;// 大小因子int pattern;// 运动模式float speedMultiplier;// 速度乘数};

类型说明

  • 类型0:大量细小粒子散射(普通烟花)
  • 类型1:心形烟花
  • 类型2:螺旋形烟花
  • 类型3:星形烟花
  • 类型4:多重圆环烟花
  • 类型5:文字效果烟花

2.3 核心算法解析

2.3.1 烟花爆炸算法

普通烟花(类型0)采用大量细小粒子散射算法:

voidcreateTinyScatteringExplosion(Firework& fw,int particleCount){for(int i =0; i < particleCount;++i){// 1. 随机角度和速度float angle =dist(rng)*2.0f* M_PI;float speed =dist(rng)*40.0f+20.0f;// 2. 设置粒子速度和位置 Particle p; p.position = fw.position; p.velocity = sf::Vector2f(cos(angle)* speed,sin(angle)* speed);// 3. 随机颜色选择int colorType =static_cast<int>(dist(rng)*6);// ... 颜色设置代码// 4. 设置粒子属性 p.lifetime =dist(rng)*1.2f+0.8f; p.size =(dist(rng)*0.8f+0.3f)* fw.sizeFactor *0.1f; fw.particles.push_back(p);}}

算法特点

  • 粒子数量:2000-3000个
  • 粒子大小:非常细小(原始大小的10%)
  • 颜色多样:6种随机颜色
  • 散射方向:360度全向散射
2.3.2 心形烟花算法

基于心形参数方程创建爱心形状:

voidcreateHeartExplosion(Firework& fw,int particleCount){for(int i =0; i < particleCount;++i){// 心形参数方程float t =dist(rng)*2.0f* M_PI;float x =16*pow(sin(t),3);float y =13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t);// 缩放和随机化float scale =(dist(rng)*0.8f+0.2f)* fw.sizeFactor; x *= scale *1.5f; y *=-scale *1.5f;// 反转Y轴// 设置粒子 Particle p; p.position = fw.position; p.velocity = sf::Vector2f(x * speed, y * speed);// ... 其他属性设置}}
2.3.3 UTF-8中文显示解决方案

根据链接内容,采用显式UTF-8转换解决中文乱码:

// 使用sf::String::fromUtf8()进行显式转换 std::string titleUtf8 ="2026 新春快乐 - 烟花庆祝"; titleText.setString(sf::String::fromUtf8(titleUtf8.begin(), titleUtf8.end()));

关键点

  • 所有中文文本必须通过sf::String::fromUtf8()转换
  • 确保使用支持中文的字体(如微软雅黑)
  • 字体文件路径需要正确配置

2.4 物理模拟系统

2.4.1 运动更新
voidupdate(float deltaTime){// 更新烟花位置 fw.position += fw.velocity * deltaTime;// 更新粒子位置 it->position += it->velocity * deltaTime;// 重力影响 it->velocity.y +=9.8f* deltaTime *0.1f;// 空气阻力 it->velocity *=0.98f;// 寿命衰减 it->lifetime -= deltaTime;}
2.4.2 尾迹效果
// 尾迹粒子生成if(fw.timer >0.005f){for(int i =0; i <5;++i){ Particle trail; trail.position = fw.position; trail.velocity = fw.velocity *0.1f+ 随机偏移; trail.color = 稍亮的颜色; trail.isTrail =true; fw.particles.push_back(trail);} fw.timer =0.0f;}

第三部分:编译与运行

3.1 创建项目文件

  1. 在WSL中创建项目目录:
mkdir fireworks2026 cd fireworks2026 
  1. 创建源文件:
# 将完整代码保存为fireworks.cppnano fireworks.cpp # 粘贴代码,按Ctrl+X,然后Y,回车保存

3.2 编译命令

# 基本编译命令 g++ -std=c++11 -O2 -o fireworks fireworks.cpp \ -lsfml-graphics -lsfml-window -lsfml-system # 如果遇到链接错误,尝试完整路径 g++ -std=c++11 -O2 -o fireworks fireworks.cpp \ -I/usr/include/SFML \ -L/usr/lib64 \ -lsfml-graphics -lsfml-window -lsfml-system 

3.3 编译脚本

创建compile.sh脚本:

#!/bin/bashecho"编译2026新年烟花程序..."echo""# 检查依赖echo"检查SFML库..."if[! -f /usr/include/SFML/Graphics.hpp ];thenecho"错误: SFML未安装,请先运行: sudo dnf install SFML SFML-devel"exit1fi# 编译echo"开始编译..." g++ -std=c++11 -O3 -o fireworks fireworks.cpp \ -lsfml-graphics -lsfml-window -lsfml-system # 检查编译结果if[$? -eq 0];thenecho"编译成功!"echo"运行命令: ./fireworks"elseecho"编译失败,请检查错误信息"fi

赋予执行权限:

chmod +x compile.sh ./compile.sh 

3.4 字体配置

如果中文显示异常,配置字体:

# 方案1:从Windows复制字体cp /mnt/c/Windows/Fonts/msyh.ttc .# 方案2:创建字体链接sudoln -s /mnt/c/Windows/Fonts/msyh.ttc /usr/share/fonts/msyh.ttc # 方案3:修改代码中的字体路径# 在loadFont()函数中添加当前目录字体路径 fontPaths.push_back("./msyh.ttc");

第四部分:程序操作指南

4.1 启动程序

# 编译后直接运行 ./fireworks 

4.2 操作快捷键

按键功能效果描述
空格键发射更多烟花随机位置发射5个不同类型烟花
鼠标点击指定位置爆炸在点击位置立即爆炸烟花
回车键显示祝福语显示彩色祝福文字动画
R键重置烟花重新开始开场表演
ESC键退出程序安全退出烟花程序

4.3 视觉效果说明

4.3.1 开场效果
  • 程序启动时自动发射两个超大爱心烟花
  • 爱心烟花位于屏幕中间偏左和偏右位置
  • 3秒后开始随机生成其他烟花
4.3.2 烟花类型
  1. 普通烟花:大量细小粒子散射,2000-3000个微小粒子
  2. 爱心烟花:红色心形图案,适当缩小显示
  3. 螺旋烟花:彩虹色螺旋图案
  4. 星形烟花:五角星形状,金色到橙色渐变
  5. 多重圆环:多个同心圆环,不同颜色
  6. 文字烟花:金色粒子散射效果
4.3.3 祝福语效果

按回车键触发:

  • 显示三行彩色祝福文字
  • 文字以粒子动画形式出现
  • 持续8秒后自动消失

文字内容:

新的一年,愿你 马不停蹄奔赴山海, 一马当先奔向热爱! 

4.4 性能优化提示

4.4.1 帧率调整
// 在构造函数中调整帧率 window.setFramerateLimit(60);// 默认60FPS// 如果需要更高帧率(性能允许) window.setFramerateLimit(120);
4.4.2 粒子数量控制
// 调整普通烟花粒子数量 particleCount =2000+static_cast<int>(1000* fw.sizeFactor);// 如果需要降低性能消耗,减少粒子数量 particleCount =1000+static_cast<int>(500* fw.sizeFactor);
4.4.3 同时显示烟花数量
// 控制最大烟花数量if(fireworks.size()<25){// 当前限制25个// 创建新烟花}

第五部分:故障排除

5.1 常见编译错误

错误1:SFML库找不到
fatal error: SFML/Graphics.hpp: No such file or directory 

解决方案

# 确认SFML安装sudo dnf install SFML-devel # 检查头文件位置find /usr -name "Graphics.hpp"2>/dev/null 
错误2:链接错误
undefined reference to `sf::... 

解决方案

# 确保链接所有必要的SFML库 g++ ... -lsfml-graphics -lsfml-window -lsfml-system -lsfml-audio 

5.2 运行时问题

问题1:窗口无法打开
Failed to open window 

解决方案

  • 确保在图形环境下运行
  • WSL需要X11转发支持
  • 安装X11服务器(如VcXsrv)
问题2:中文显示为方框

解决方案

  1. 确认字体文件存在
  2. 使用正确的UTF-8转换
  3. 修改字体加载路径
问题3:程序运行缓慢

解决方案

  1. 减少粒子数量
  2. 降低帧率限制
  3. 减少同时显示的烟花数量

5.3 WSL特定配置

X11转发配置
# 在Windows端安装VcXsrv# 启动XLaunch,选择"Disable access control"# 在WSL中设置DISPLAY变量exportDISPLAY=$(grep -m 1 nameserver /etc/resolv.conf |awk'{print $2}'):0 # 测试X11转发 xeyes # 应该能看到眼睛跟随鼠标
音频支持(可选)
# 安装脉冲音频支持sudo dnf install pulseaudio-utils # Windows端安装PulseAudio

第六部分:扩展与定制

6.1 自定义烟花效果

添加新烟花类型
// 1. 在Firework结构体中增加类型// 2. 在explodeFirework()中添加新类型处理case6:// 新烟花类型 particleCount = 自定义数量;createCustomExplosion(fw, particleCount);break;// 3. 实现新的爆炸函数voidcreateCustomExplosion(Firework& fw,int particleCount){// 自定义爆炸算法}
修改颜色方案
// 在createFirework()中修改颜色分配switch(type){case0: fw.color = sf::Color(自定义RGB);break;// ... 其他类型}

6.2 自定义祝福文字

// 修改setupText()中的祝福文字 std::string blessingLines[3]={"你的祝福语第一行","你的祝福语第二行","你的祝福语第三行"};// 修改颜色 blessingText[0].setFillColor(自定义颜色);

6.3 添加背景音乐

// 1. 添加音频头文件#include<SFML/Audio.hpp>// 2. 添加音乐对象 sf::Music backgroundMusic;// 3. 加载和播放音乐if(backgroundMusic.openFromFile("music.ogg")){ backgroundMusic.setLoop(true); backgroundMusic.play();}

第七部分:完整编译运行示例

7.1 一键安装脚本

创建install_and_run.sh

#!/bin/bashecho"=== 2026新年烟花程序安装脚本 ==="echo""# 检查WSL版本echo"检查WSL版本..."if!grep -q "WSL2" /proc/version 2>/dev/null;thenecho"警告: 推荐使用WSL2以获得更好性能"fi# 安装依赖echo"安装系统依赖..."sudo dnf install -y gcc-c++ make SFML SFML-devel # 下载中文字体echo"配置中文字体..."if[ -f "/mnt/c/Windows/Fonts/msyh.ttc"];thencp"/mnt/c/Windows/Fonts/msyh.ttc".echo"微软雅黑字体已复制"elseecho"使用系统默认字体"fi# 编译程序echo"编译烟花程序..." g++ -std=c++11 -O3 -o fireworks fireworks.cpp \ -lsfml-graphics -lsfml-window -lsfml-system if[$? -eq 0];thenecho""echo"=== 编译成功! ==="echo""echo"运行程序: ./fireworks"echo""echo"操作说明:"echo" 空格键 - 发射更多烟花"echo" 鼠标点击 - 指定位置爆炸"echo" 回车键 - 显示祝福语"echo" R键 - 重置烟花"echo" ESC键 - 退出程序"echo""elseecho"编译失败,请检查错误信息"fi

7.2 测试运行

# 赋予执行权限chmod +x install_and_run.sh # 运行安装脚本 ./install_and_run.sh # 如果一切正常,运行程序 ./fireworks 

最后附上完整源代码

#include<SFML/Graphics.hpp>#include<vector>#include<cmath>#include<random>#include<chrono>// 粒子结构体structParticle{ sf::Vector2f position; sf::Vector2f velocity; sf::Color color;float lifetime;float maxLifetime;float size;bool isTrail;};// 烟花结构体structFirework{ sf::Vector2f position; sf::Vector2f velocity; sf::Color color;float timer;float explosionHeight;bool exploded; std::vector<Particle> particles;int type;float sizeFactor;int pattern;float speedMultiplier;};// 文字粒子效果structTextParticle{ sf::Vector2f position; sf::Vector2f targetPosition; sf::Vector2f velocity; sf::Color color;float lifetime;float maxLifetime;float size;};classFireworksDisplay{private: sf::RenderWindow window; sf::Font font; sf::Text titleText; sf::Text infoText; sf::Text blessingText[3]; sf::Clock clock; std::vector<Firework> fireworks; std::vector<TextParticle> blessingParticles; std::mt19937 rng; std::uniform_real_distribution<float> dist; std::uniform_real_distribution<float> sizeDist; std::uniform_real_distribution<float> speedDist;bool showBlessing;float blessingTimer;bool fontLoaded;float timeSinceStart;bool initialShowDone;public:FireworksDisplay():window(sf::VideoMode(1200,800),"2026 新春快乐 - 烟花庆祝"),rng(std::chrono::steady_clock::now().time_since_epoch().count()),dist(0.0f,1.0f),sizeDist(0.8f,2.0f),speedDist(0.2f,3.0f),showBlessing(false),blessingTimer(0.0f),fontLoaded(false),timeSinceStart(0.0f),initialShowDone(false){ window.setVerticalSyncEnabled(false); window.setFramerateLimit(60);loadFont();initializeOpeningFireworks();setupText();}voidloadFont(){// 尝试多种字体路径 std::vector<std::string> fontPaths ={"/mnt/c/Windows/Fonts/msyh.ttc","/mnt/c/Windows/Fonts/msyhbd.ttc","/mnt/c/Windows/Fonts/simhei.ttf","/mnt/c/Windows/Fonts/simkai.ttf","/mnt/c/Windows/Fonts/simsun.ttc","msyh.ttc","simhei.ttf"};for(constauto& path : fontPaths){if(font.loadFromFile(path)){ fontLoaded =true;break;}}}voidsetupText(){if(!fontLoaded)return;// 方案二:显式UTF-8转换 - 根据链接内容// 设置标题文本 std::string titleUtf8 ="2026 新春快乐 - 烟花庆祝"; titleText.setFont(font); titleText.setString(sf::String::fromUtf8(titleUtf8.begin(), titleUtf8.end())); titleText.setCharacterSize(48); titleText.setFillColor(sf::Color::Yellow); titleText.setStyle(sf::Text::Bold); titleText.setOutlineColor(sf::Color::Red); titleText.setOutlineThickness(2); sf::FloatRect titleBounds = titleText.getLocalBounds(); titleText.setOrigin(titleBounds.left + titleBounds.width/2.0f, titleBounds.top + titleBounds.height/2.0f); titleText.setPosition(window.getSize().x/2.0f,40);// 设置操作说明文本 std::string infoUtf8 ="空格键: 更多烟花 | 鼠标点击: 指定位置爆炸 | 回车键: 显示祝福 | ESC: 退出"; infoText.setFont(font); infoText.setString(sf::String::fromUtf8(infoUtf8.begin(), infoUtf8.end())); infoText.setCharacterSize(20); infoText.setFillColor(sf::Color(200,200,255)); infoText.setPosition(10, window.getSize().y -30);// 设置祝福文本 std::string blessingLines[3]={"新的一年,愿你","马不停蹄奔赴山海,","一马当先奔向热爱!"};for(int i =0; i <3;++i){ blessingText[i].setFont(font); blessingText[i].setString(sf::String::fromUtf8(blessingLines[i].begin(), blessingLines[i].end())); blessingText[i].setCharacterSize(48); blessingText[i].setStyle(sf::Text::Bold); blessingText[i].setOutlineThickness(2);// 设置不同颜色switch(i){case0: blessingText[i].setFillColor(sf::Color::Red); blessingText[i].setOutlineColor(sf::Color::Yellow);break;case1: blessingText[i].setFillColor(sf::Color::Green); blessingText[i].setOutlineColor(sf::Color::White);break;case2: blessingText[i].setFillColor(sf::Color::Blue); blessingText[i].setOutlineColor(sf::Color::Yellow);break;} sf::FloatRect bounds = blessingText[i].getLocalBounds(); blessingText[i].setOrigin(bounds.left + bounds.width/2.0f, bounds.top + bounds.height/2.0f); blessingText[i].setPosition(window.getSize().x/2.0f,200+ i *60);}}voidinitializeOpeningFireworks(){ fireworks.clear(); blessingParticles.clear();// 创建两个爱心烟花createFirework(window.getSize().x *0.4f, window.getSize().y,1,0,3.5f,speedDist(rng));createFirework(window.getSize().x *0.6f, window.getSize().y,1,0,3.5f,speedDist(rng));}voidcreateFirework(float x,float y,int type,int pattern,float customSizeFactor =-1.0f,float speedMultiplier =1.0f){ Firework fw; fw.position = sf::Vector2f(x, y); fw.pattern = pattern; fw.speedMultiplier = speedMultiplier;float baseSpeed =100.0f;switch(pattern){case0: fw.velocity = sf::Vector2f((dist(rng)-0.5f)*10.0f,-(dist(rng)*20.0f+ baseSpeed)* speedMultiplier);break;case1: fw.velocity = sf::Vector2f(-(dist(rng)*10.0f+5.0f),-(dist(rng)*20.0f+ baseSpeed)* speedMultiplier);break;case2: fw.velocity = sf::Vector2f(dist(rng)*10.0f+5.0f,-(dist(rng)*20.0f+ baseSpeed)* speedMultiplier);break;} fw.explosionHeight = window.getSize().y *(0.05f+dist(rng)*0.3f); fw.timer =0.0f; fw.exploded =false; fw.type = type;if(customSizeFactor >0){ fw.sizeFactor = customSizeFactor;}else{ fw.sizeFactor =sizeDist(rng);}switch(type){case0: fw.color = sf::Color(255,255,255);break;case1: fw.color = sf::Color(255,50,50);break;case2: fw.color = sf::Color(0,255,100);break;case3: fw.color = sf::Color(100,100,255);break;case4: fw.color = sf::Color(255,100,255);break;case5: fw.color = sf::Color(100,255,255);break;} fireworks.push_back(fw);}voidexplodeFirework(Firework& fw){int particleCount =0;switch(fw.type){case0: particleCount =2000+static_cast<int>(1000* fw.sizeFactor);createTinyScatteringExplosion(fw, particleCount);break;case1: particleCount =400+static_cast<int>(300* fw.sizeFactor);createHeartExplosion(fw, particleCount);break;case2: particleCount =600+static_cast<int>(600* fw.sizeFactor);createSpiralExplosion(fw, particleCount);break;case3: particleCount =700+static_cast<int>(600* fw.sizeFactor);createStarExplosion(fw, particleCount);break;case4: particleCount =800+static_cast<int>(800* fw.sizeFactor);createMultiRingExplosion(fw, particleCount);break;case5: particleCount =600+static_cast<int>(600* fw.sizeFactor);createTextExplosion(fw, particleCount);break;}}voidcreateTinyScatteringExplosion(Firework& fw,int particleCount){for(int i =0; i < particleCount;++i){float angle =dist(rng)*2.0f* M_PI;float speed =dist(rng)*40.0f+20.0f; Particle p; p.position = fw.position; p.velocity = sf::Vector2f(cos(angle)* speed,sin(angle)* speed);int colorType =static_cast<int>(dist(rng)*6);switch(colorType){case0: p.color = sf::Color(255,255,255);break;case1: p.color = sf::Color(255,200,100);break;case2: p.color = sf::Color(100,255,100);break;case3: p.color = sf::Color(100,100,255);break;case4: p.color = sf::Color(255,100,255);break;default: p.color = sf::Color(255,150,50);break;} p.lifetime =dist(rng)*1.2f+0.8f; p.maxLifetime = p.lifetime; p.size =(dist(rng)*0.8f+0.3f)* fw.sizeFactor *0.1f; p.isTrail =false; fw.particles.push_back(p);}createTrailParticles(fw,200+static_cast<int>(200* fw.sizeFactor));}voidcreateHeartExplosion(Firework& fw,int particleCount){float sizeMultiplier =0.8f;for(int i =0; i < particleCount;++i){float t =dist(rng)*2.0f* M_PI;float x =16*pow(sin(t),3);float y =13*cos(t)-5*cos(2*t)-2*cos(3*t)-cos(4*t);float scale =(dist(rng)*0.8f+0.2f)* fw.sizeFactor; x *= scale *1.5f; y *=-scale *1.5f;float speed =dist(rng)*6.0f+3.0f; Particle p; p.position = fw.position; p.velocity = sf::Vector2f(x * speed, y * speed);float colorFactor =dist(rng); p.color = sf::Color(255,50+static_cast<int>(205* colorFactor),50+static_cast<int>(130* colorFactor)); p.lifetime =dist(rng)*2.0f+1.0f; p.maxLifetime = p.lifetime; p.size =(dist(rng)*2.0f+1.0f)* fw.sizeFactor * sizeMultiplier; p.isTrail =false; fw.particles.push_back(p);}createTrailParticles(fw,80+static_cast<int>(80* fw.sizeFactor));}voidcreateSpiralExplosion(Firework& fw,int particleCount){for(int i =0; i < particleCount;++i){float angle =dist(rng)*10.0f* M_PI;float radius = angle *0.1f;float speed =dist(rng)*15.0f+7.0f; Particle p; p.position = fw.position; p.velocity = sf::Vector2f(cos(angle)* radius * speed,sin(angle)* radius * speed); p.color =hsvToRgb(i %360,1.0f,1.0f); p.lifetime =dist(rng)*2.0f+1.0f; p.maxLifetime = p.lifetime; p.size =(dist(rng)*2.5f+1.0f)* fw.sizeFactor; p.isTrail =false; fw.particles.push_back(p);}createTrailParticles(fw,100+static_cast<int>(100* fw.sizeFactor));}voidcreateStarExplosion(Firework& fw,int particleCount){int points =5+static_cast<int>(dist(rng)*3);for(int i =0; i < particleCount;++i){float angle =(static_cast<float>(i % points)/ points)*2.0f* M_PI;float radius =(1.0f+0.3f*sin(points * angle))*8.0f* fw.sizeFactor;float speed =dist(rng)*18.0f+9.0f; Particle p; p.position = fw.position; p.velocity = sf::Vector2f(cos(angle)* radius * speed,sin(angle)* radius * speed); p.color = sf::Color(255,140+static_cast<int>(115*dist(rng)),50); p.lifetime =dist(rng)*2.0f+1.0f; p.maxLifetime = p.lifetime; p.size =(dist(rng)*3.0f+1.5f)* fw.sizeFactor; p.isTrail =false; fw.particles.push_back(p);}createTrailParticles(fw,120+static_cast<int>(120* fw.sizeFactor));}voidcreateMultiRingExplosion(Firework& fw,int particleCount){int rings =3+static_cast<int>(fw.sizeFactor);int particlesPerRing = particleCount / rings;for(int ring =0; ring < rings;++ring){float ringRadius =(ring +1)*3.0f* fw.sizeFactor;for(int i =0; i < particlesPerRing;++i){float angle =(static_cast<float>(i)/ particlesPerRing)*2.0f* M_PI;float speed =dist(rng)*12.0f+6.0f; Particle p; p.position = fw.position; p.velocity = sf::Vector2f(cos(angle)* ringRadius * speed,sin(angle)* ringRadius * speed); p.color =hsvToRgb((ring *60+ i *2)%360,1.0f,1.0f); p.lifetime =dist(rng)*2.0f+1.0f; p.maxLifetime = p.lifetime; p.size =(dist(rng)*2.5f+1.0f)* fw.sizeFactor; p.isTrail =false; fw.particles.push_back(p);}}createTrailParticles(fw,150+static_cast<int>(150* fw.sizeFactor));}voidcreateTextExplosion(Firework& fw,int particleCount){for(int i =0; i < particleCount;++i){float angle =dist(rng)*2.0f* M_PI;float speed =dist(rng)*36.0f+18.0f; Particle p; p.position = fw.position; p.velocity = sf::Vector2f(cos(angle)* speed,sin(angle)* speed); p.color = sf::Color(255,215,0); p.lifetime =dist(rng)*2.5f+1.5f; p.maxLifetime = p.lifetime; p.size =(dist(rng)*4.0f+2.0f)* fw.sizeFactor; p.isTrail =false; fw.particles.push_back(p);}createTrailParticles(fw,180+static_cast<int>(180* fw.sizeFactor));}voidcreateTrailParticles(Firework& fw,int count){for(int i =0; i < count;++i){ Particle p; p.position = fw.position;float angle =(dist(rng)-0.5f)* M_PI *0.5f;float speed =dist(rng)*25.0f+12.0f; p.velocity = sf::Vector2f(sin(angle)* speed,-cos(angle)* speed); p.color = sf::Color( std::min(255, fw.color.r +50), std::min(255, fw.color.g +50), std::min(255, fw.color.b +50),200); p.lifetime =dist(rng)*0.4f+0.2f; p.maxLifetime = p.lifetime; p.size =(dist(rng)*2.0f+1.0f)* fw.sizeFactor *0.5f; p.isTrail =true; fw.particles.push_back(p);}}voidcreateBlessingTextEffect(){ blessingParticles.clear();// 创建粒子形成祝福文字效果for(int i =0; i <1500;++i){ TextParticle tp; tp.position = sf::Vector2f(dist(rng)* window.getSize().x, window.getSize().y +dist(rng)*100.0f);// 目标位置形成祝福文字的形状int row = i %3;int col =(i /3)%50; tp.targetPosition = sf::Vector2f( window.getSize().x *0.3f+ col *15.0f+(dist(rng)-0.5f)*20.0f,200+ row *60+(dist(rng)-0.5f)*30.0f); sf::Vector2f direction = tp.targetPosition - tp.position;float distance =sqrt(direction.x * direction.x + direction.y * direction.y);float speed =8.0f+dist(rng)*6.0f; tp.velocity =(direction / distance)* speed;int hue =(i *10)%360; tp.color =hsvToRgb(hue,1.0f,1.0f); tp.lifetime =8.0f; tp.maxLifetime =8.0f; tp.size =dist(rng)*4.0f+2.0f; blessingParticles.push_back(tp);} showBlessing =true; blessingTimer =8.0f;} sf::Color hsvToRgb(int h,float s,float v){float c = v * s;float x = c *(1-abs(fmod(h /60.0f,2)-1));float m = v - c;float r, g, b;if(h >=0&& h <60){ r = c; g = x; b =0;}elseif(h >=60&& h <120){ r = x; g = c; b =0;}elseif(h >=120&& h <180){ r =0; g = c; b = x;}elseif(h >=180&& h <240){ r =0; g = x; b = c;}elseif(h >=240&& h <300){ r = x; g =0; b = c;}else{ r = c; g =0; b = x;}return sf::Color(static_cast<int>((r + m)*255),static_cast<int>((g + m)*255),static_cast<int>((b + m)*255));}voidupdate(float deltaTime){ timeSinceStart += deltaTime;if(!initialShowDone && timeSinceStart >3.0f){ initialShowDone =true;}if(initialShowDone &&!showBlessing &&dist(rng)<0.08f&& fireworks.size()<25){int pattern =static_cast<int>(dist(rng)*3);int type =static_cast<int>(dist(rng)*6);float speedMultiplier =speedDist(rng);createFirework(dist(rng)* window.getSize().x, window.getSize().y, type, pattern,-1.0f, speedMultiplier);}if(showBlessing){ blessingTimer -= deltaTime;if(blessingTimer <=0.0f){ showBlessing =false; blessingParticles.clear();}}for(auto& fw : fireworks){if(!fw.exploded){ fw.position += fw.velocity * deltaTime; fw.timer += deltaTime;if(fw.timer >0.005f){for(int i =0; i <5;++i){ Particle trail; trail.position = fw.position; trail.velocity = sf::Vector2f( fw.velocity.x *0.1f+(dist(rng)-0.5f)*6.0f, fw.velocity.y *0.1f+(dist(rng)-0.5f)*6.0f); trail.color = sf::Color( std::min(255, fw.color.r +80), std::min(255, fw.color.g +80), std::min(255, fw.color.b +80),240); trail.lifetime =0.2f+dist(rng)*0.2f; trail.maxLifetime = trail.lifetime; trail.size =(dist(rng)*1.5f+0.5f)* fw.sizeFactor *0.6f; trail.isTrail =true; fw.particles.push_back(trail);} fw.timer =0.0f;}if(fw.position.y <= fw.explosionHeight || fw.velocity.y >=0){ fw.exploded =true;explodeFirework(fw);}}for(auto it = fw.particles.begin(); it != fw.particles.end();){ it->position += it->velocity * deltaTime;if(it->isTrail){ it->velocity.y +=9.8f* deltaTime *0.02f;}else{ it->velocity.y +=9.8f* deltaTime *0.1f;} it->velocity *=0.98f; it->lifetime -= deltaTime;if(it->lifetime <=0.0f){ it = fw.particles.erase(it);}else{++it;}}}for(auto& tp : blessingParticles){ sf::Vector2f direction = tp.targetPosition - tp.position;float distance =sqrt(direction.x * direction.x + direction.y * direction.y);if(distance >1.0f){float speed = std::min(12.0f, distance *0.2f); tp.velocity =(direction / distance)* speed; tp.position += tp.velocity * deltaTime;}else{ tp.velocity.x +=(dist(rng)-0.5f)*3.0f* deltaTime; tp.velocity.y +=(dist(rng)-0.5f)*3.0f* deltaTime; tp.position += tp.velocity * deltaTime;if(abs(tp.position.x - tp.targetPosition.x)>10.0f){ tp.velocity.x =-tp.velocity.x *0.1f;}if(abs(tp.position.y - tp.targetPosition.y)>10.0f){ tp.velocity.y =-tp.velocity.y *0.1f;}} tp.lifetime -= deltaTime *0.02f;} fireworks.erase( std::remove_if(fireworks.begin(), fireworks.end(),[](const Firework& fw){return fw.exploded && fw.particles.empty();}), fireworks.end());}voiddraw(){ window.clear(sf::Color(5,5,25));for(constauto& fw : fireworks){for(constauto& particle : fw.particles){float alpha =(particle.lifetime / particle.maxLifetime)*255; sf::Color particleColor = particle.color; particleColor.a =static_cast<sf::Uint8>(alpha); sf::CircleShape shape(particle.size); shape.setFillColor(particleColor); shape.setPosition(particle.position); shape.setOrigin(particle.size, particle.size);if(particle.isTrail){ sf::CircleShape glow(particle.size *2.5f); glow.setFillColor(sf::Color(particleColor.r, particleColor.g, particleColor.b, particleColor.a /3)); glow.setPosition(particle.position); glow.setOrigin(particle.size *2.5f, particle.size *2.5f); window.draw(glow);} window.draw(shape);}if(!fw.exploded){ sf::CircleShape head(4.0f* fw.sizeFactor); head.setFillColor(fw.color); head.setPosition(fw.position); head.setOrigin(4.0f* fw.sizeFactor,4.0f* fw.sizeFactor); window.draw(head); sf::CircleShape glow(6.0f* fw.sizeFactor); glow.setFillColor(sf::Color(fw.color.r, fw.color.g, fw.color.b,180)); glow.setPosition(fw.position); glow.setOrigin(6.0f* fw.sizeFactor,6.0f* fw.sizeFactor); window.draw(glow);}}for(constauto& tp : blessingParticles){float alpha =(tp.lifetime / tp.maxLifetime)*255; sf::Color particleColor = tp.color; particleColor.a =static_cast<sf::Uint8>(alpha); sf::CircleShape shape(tp.size); shape.setFillColor(particleColor); shape.setPosition(tp.position); shape.setOrigin(tp.size, tp.size); sf::CircleShape glow(tp.size *1.8f); glow.setFillColor(sf::Color(particleColor.r, particleColor.g, particleColor.b, particleColor.a /2)); glow.setPosition(tp.position); glow.setOrigin(tp.size *1.8f, tp.size *1.8f); window.draw(glow); window.draw(shape);}// 绘制所有中文文本if(fontLoaded){ window.draw(titleText); window.draw(infoText);if(showBlessing){for(int i =0; i <3;++i){ window.draw(blessingText[i]);}}} window.display();}voidrun(){ sf::Clock deltaClock;while(window.isOpen()){ sf::Event event;while(window.pollEvent(event)){if(event.type == sf::Event::Closed){ window.close();}if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space){for(int i =0; i <5;++i){int pattern =static_cast<int>(dist(rng)*3);int type =static_cast<int>(dist(rng)*6);float speedMultiplier =speedDist(rng);createFirework(dist(rng)* window.getSize().x, window.getSize().y, type, pattern,-1.0f, speedMultiplier);}}if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Enter){createBlessingTextEffect();}if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape){ window.close();}if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::R){initializeOpeningFireworks(); timeSinceStart =0.0f; initialShowDone =false; showBlessing =false; blessingParticles.clear();}if(event.type == sf::Event::MouseButtonPressed){int type =static_cast<int>(dist(rng)*6);int pattern =static_cast<int>(dist(rng)*3);float speedMultiplier =speedDist(rng);createFirework(event.mouseButton.x, event.mouseButton.y, type, pattern,-1.0f, speedMultiplier);}}float deltaTime = deltaClock.restart().asSeconds();update(deltaTime);draw();}}};intmain(){ FireworksDisplay display; display.run();return0;}

祝大家2026年新春快乐,编程愉快!

Read more

Flutter for OpenHarmony:Flutter 三方库 os_detect — 精准洞察鸿蒙系统的底层脉络(适配鸿蒙 HarmonyOS Next ohos)

Flutter for OpenHarmony:Flutter 三方库 os_detect — 精准洞察鸿蒙系统的底层脉络(适配鸿蒙 HarmonyOS Next ohos)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net。 Flutter for OpenHarmony:Flutter 三方库 os_detect — 精准洞察鸿蒙系统的底层脉络(适配鸿蒙 HarmonyOS Next ohos) 在进行 Flutter for OpenHarmony 跨平台开发时,我们经常需要处理“差异化”的需求。有的功能可能只在真正的 OpenHarmony 原生环境下运行(如特定的 N-API 调用),而在 Web 或其他桌面模拟器环境下则需要进行降级处理。 传统的 Platform.isAndroid 或 kIsWeb 在处理日渐复杂的鸿蒙生态环境时,往往显得力不从心。os_detect 库提供了一套更轻量、更可靠的系统环境感知方案,能帮助我们精准识别应用正跑在哪个“灵魂”之下。 一、为什么需要系统环境检测?

By Ne0inhk
【故事分享】从一个“自动脚本”的开始:我与 AutoHotkey 的邂逅(深入 AHK + AHI 的自动化开发实战)

【故事分享】从一个“自动脚本”的开始:我与 AutoHotkey 的邂逅(深入 AHK + AHI 的自动化开发实战)

从一个“自动脚本”的开始:我与 AutoHotkey 的一场较量(深入 AHK + AHI 的自动化开发实战) 📘关键词:AutoHotkey、AutoHotInterception、键盘钩子、自动化脚本、游戏辅助脚本、AHK脚本开发、输入拦截驱动、AHI教程、键鼠控制、键盘事件监听 文章目录 * 从一个“自动脚本”的开始:我与 AutoHotkey 的一场较量(深入 AHK + AHI 的自动化开发实战) * 一、故事的开始:当我决定写一个自动脚本 * 二、从简单到复杂:脚本在游戏中失效 * 1. 检查 Send 模式 * 三、深入探索:AHK 的局限与 AHI 的登场 * 四、需求分析:

By Ne0inhk
OpenClaw 原版和汉化版windows 和Linux 下的部署实践

OpenClaw 原版和汉化版windows 和Linux 下的部署实践

简介 OpenClaw(曾用名:Clawdbot、Moltbot),一款可以部署在个人电脑上的AI代理,采用“龙虾”图标设计,slogan是“The AI that actually does things”,由程序员彼得·斯坦伯格开发。 核心开发语言为TypeScript, 是一个采用“龙虾”图标设计的开源AI智能体项目。该项目定位为个人AI代理,具备操作软件与长期记忆功能。2026年1月,特斯拉前AI主管Karpathy曾公开提及此项目。 * 官方版本:https://github.com/openclaw/openclaw * 官方文档:https://docs.openclaw.ai/zh-CN * 汉化版:https://github.com/jiulingyun/openclaw-cn * 汉化版官网:https://clawd.org.cn/ 一.

By Ne0inhk
【Linux】poll 多路转接:select 的改良版,以及它留下的遗憾

【Linux】poll 多路转接:select 的改良版,以及它留下的遗憾

文章目录 * poll 多路转接:select 的改良版,以及它留下的遗憾 * 一、select 的痛点回顾 * 1.1 select 的问题在哪里? * 二、poll 函数接口详解 * 2.1 函数原型 * 2.2 核心数据结构:pollfd * 2.3 参数详解 * 2.4 返回值 * 三、poll vs select:对比分析 * 3.1 数据结构对比 * 3.2 使用方式对比 * 3.3 优缺点总结 * 四、poll 执行过程图解 * 4.1 一次 poll

By Ne0inhk