From fa9734d81bc9c9bbbbeaad78035cda8f695cc166 Mon Sep 17 00:00:00 2001 From: Lveyou <1339484752@qq.com> Date: Fri, 14 Aug 2026 19:03:49 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B2=92=E5=AD=90=E7=B3=BB=E7=BB=9F=E5=88=9D?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dl/dl_render.h | 2 +- dl/render/dl_particle.cpp | 142 +++++++++++++++++++++++++ dl/render/dl_particle.h | 116 ++++++++++++++++++++ dl/system/dl_engine.cpp | 7 +- project/dl_test/head.cpp | 2 + project/dl_test/res/particle/fire.json | 73 +++++++++++++ project/dl_test/ui_sprite.cpp | 16 +++ project/dl_test/ui_sprite.h | 4 + 8 files changed, 357 insertions(+), 5 deletions(-) create mode 100644 dl/render/dl_particle.cpp create mode 100644 dl/render/dl_particle.h create mode 100644 project/dl_test/res/particle/fire.json diff --git a/dl/dl_render.h b/dl/dl_render.h index 3aec681b..b8e277d8 100644 --- a/dl/dl_render.h +++ b/dl/dl_render.h @@ -17,4 +17,4 @@ #include "render/dl_action.h" #include "render/dl_animation.h" #include "render/dl_light.h" -#include "render/dl_particle_config.h" \ No newline at end of file +#include "render/dl_particle.h" \ No newline at end of file diff --git a/dl/render/dl_particle.cpp b/dl/render/dl_particle.cpp new file mode 100644 index 00000000..3112472b --- /dev/null +++ b/dl/render/dl_particle.cpp @@ -0,0 +1,142 @@ +#include "dl_particle.h" + +#include "io/dl_json.h" +#include "system/dl_time.h" +#include "io/dl_file.h" +#include "render/dl_factory.h" + +namespace dl +{ + ParticleSystem* g_particle; + + Particle* ParticleSystem::Create(std::string_view name) + { + auto iter = _allConfig.find(std::string{ name }); + if (iter == _allConfig.end()) + { + log_err("查找粒子配置失败:{}", name); + return {}; + } + Particle* ret = _memoryReuse.New(&iter->second); + ret->_reset(); + return ret; + } + + void ParticleSystem::Delete(Particle* par, bool wait /*= true*/) + { + bool delete_now = true; + if (wait) + {// + + } + if (delete_now) + { + _memoryReuse.Delete(par); + } + else + _listDelete.push_back(par); + } + + void ParticleSystem::Load(std::string_view path) + { + std::vector vec; + File::GetPathFileAll(path, vec, ".json", true); + + for (auto& iter : vec) + { + json j = Json::ParseFile(iter); + if(j.is_null()) + continue; + ParticleConfig config; + config.Load(j); + + std::string name = String::GetResName(path, iter); + log_msg("成功加载到粒子配置:{} <- {}", name, iter); + _allConfig[name] = config; + } + } + + void ParticleSystem::_update() + { + for (auto iter = _listDelete.begin(); iter != _listDelete.end();) + { + Particle* par = *iter; + if (par->GetConfig()->system.duration == 0 + || !par->IsActive()) + { + _memoryReuse.Delete(par); + iter = _listDelete.erase(iter); + } + else + ++iter; + } + } + + void Particle::Render() + { + if (!_active) + return; + float t = g_time->GetCurrent(); + float duration = _config->system.duration; + if (duration != 0) + { + if (t >= _tCreate + duration) + { + _active = false; + return; + } + } + //------------------发射 + // 每个粒子 发射需要多少毫秒 + float dt_shoot_one = 1.0f / _config->shooter.rate; + + float shoot_num = (t - _tShoot) / dt_shoot_one; + unsigned real_shoot_num = 0; + if (shoot_num < 1.0f) + ; + else + { + _tShoot = t; + real_shoot_num = (unsigned)shoot_num; + } + + + for (ParicleNode& node : _allNode) + { + if (node._active) + { + if(!node._spr) + node._spr = g_factory->CloneSprite(_spr); + node.Render(); + } + else + { + node._active = true; + } + } + } + + void Particle::SetSprite(gcSprite spr) + { + _spr = spr; + // todo refersh + } + + Particle::Particle(ParticleConfig* config) : + _config{ config } + { + _reset(); + _spr = g_factory->CreateSpriteDefault(); + } + + void Particle::_reset() + { + float t = g_time->GetCurrent(); + _active = true; + _tCreate = t; + _tShoot = t; + _allNode.resize(_config->system.max_num); + } + +} + diff --git a/dl/render/dl_particle.h b/dl/render/dl_particle.h new file mode 100644 index 00000000..8d20856b --- /dev/null +++ b/dl/render/dl_particle.h @@ -0,0 +1,116 @@ +/** +* @file dl_particle.h +* @brief 粒子系统 +* +* +* @version 粒子系统 +* @author 1.0 +* @date lveyou +* +* @note 26-08-14 +*/ +#pragma once + +#include "io/dl_log.h" +#include "render/dl_particle_config.h" + +#include "memory/dl_memory_reuse.h" +#include "render/dl_sprite.h" + +namespace dl +{ + //! 2d粒子精灵 + struct ParicleNode + { + bool _active; // 是否活动中 + Position _v; + float _tEnd; + + gcSprite _spr; + + void Render() + { + _spr->Render(); + } + + ParicleNode() : + _active{ false } + {} + }; + + //! 2d粒子实体 + class Particle + { + friend class ParticleSystem; + friend class Memory::Reuse; + public: + /** + * @brief 执行逻辑并渲染 + */ + void Render(); + /** + * @brief 设置基础精灵 + */ + void SetSprite(gcSprite spr); + /** + * @brief 是否激活状态(播放完成后,进入非激活状态) + */ + bool IsActive() + { + return _active; + } + /** + * @brief 返回配置 + */ + const ParticleConfig* GetConfig() + { + return _config; + } + private: + Particle(ParticleConfig* config); + ~Particle() {} + + ParticleConfig* _config; + bool _active; + float _tCreate; // 创建时间 + float _tShoot; // 上次发射时间 + gcSprite _spr; // 模板精灵 + + std::vector _allNode; + + void _reset(); + }; + + //! 2d粒子系统 + class ParticleSystem + { + public: + /** + * @brief 创建粒子实体 + * @parma[in] name 资源名 + * @note 必须通过 Delete回收,可以立即回收 + */ + Particle* Create(std::string_view name); + /** + * @brief 删除粒子实体 + * @parma[in] par 实例 + * @parma[in] wait 是否等待播放完成后,再删除(如果是无限循环的粒子,则立即删除) + * @note 调用后由系统接管 生命周期并绘制 + */ + void Delete(Particle* par, bool wait = true); + /** + * @brief 加载粒子配置 + * @parma[in] path 文件夹 + */ + void Load(std::string_view path); + private: + std::unordered_map _allConfig; + + dl::Memory::Reuse _memoryReuse; + std::list _listDelete; + + void _update(); + }; + + extern ParticleSystem* g_particle; +} \ No newline at end of file diff --git a/dl/system/dl_engine.cpp b/dl/system/dl_engine.cpp index ada1b161..bf85bada 100644 --- a/dl/system/dl_engine.cpp +++ b/dl/system/dl_engine.cpp @@ -31,6 +31,7 @@ #include "system/dl_test.h" #include "misc/dl_value.h" #include "vk/dl_vk.h" +#include "render/dl_particle.h" namespace dl @@ -81,8 +82,6 @@ void Engine::Init() File::InitFileSystem(); log_msg0("3.文件系统初始化完成!"); - //g_modelLoader = new ModelLoader; - g_value = new ValueSystem; g_lua = _param._useLua ? new LuaScript : nullptr; g_time = _param._useTime ? new Time : nullptr; @@ -96,6 +95,7 @@ void Engine::Init() g_gfx = new Graphics; g_scene = _param._useScene ? new UI::SceneManager : nullptr; g_mod = new ModManager; + g_particle = new ParticleSystem; #endif g_physics = _param._useFreetype ? new Physics : nullptr; g_script = new ScriptSystem; @@ -159,6 +159,7 @@ void Engine::Release() delete g_as; delete g_script; #ifndef DL_DISABLE_RENDER + delete g_particle; delete g_mod; delete g_scene; delete g_gfx; @@ -170,8 +171,6 @@ void Engine::Release() delete g_freetype; #endif delete g_physics; - //delete g_lang; - //delete g_modelLoader; delete g_time; delete g_lua; delete g_thread; diff --git a/project/dl_test/head.cpp b/project/dl_test/head.cpp index a3d94afb..2ef30c68 100644 --- a/project/dl_test/head.cpp +++ b/project/dl_test/head.cpp @@ -14,6 +14,8 @@ void Test() Tool::Manager* g_Tool; void Init() { + g_particle->Load("particle/"); + g_Tool = Tool::Manager::Create(); g_Tool->SetVisible(false); diff --git a/project/dl_test/res/particle/fire.json b/project/dl_test/res/particle/fire.json new file mode 100644 index 00000000..60f39a44 --- /dev/null +++ b/project/dl_test/res/particle/fire.json @@ -0,0 +1,73 @@ +{ + "__desc": "2d粒子配置", + "__name": "2d粒子配置", + "node": { + "__desc": "粒子参数", + "__name": "粒子参数", + "lifetime": { + "__desc": "存活时间", + "__name": "存活时间", + "type": "array", + "value": [ + 1.0, + 2.0 + ] + }, + "speed": { + "__desc": "速度", + "__name": "速度", + "type": "array", + "value": [ + 100.0, + 200.0 + ] + } + }, + "shooter": { + "__desc": "发射器设置", + "__name": "发射器", + "rate": { + "__desc": "发射速率,每秒多少个", + "__name": "发射速率", + "type": "uint", + "value": 20 + }, + "shape": { + "__desc": "发射区域", + "__name": "发射区域", + "type": "string", + "value": "circle" + } + }, + "system": { + "__desc": "主要参数", + "__name": "主要参数", + "delay": { + "__desc": "启动延时", + "__name": "启动延时", + "type": "float", + "value": 0.0 + }, + "duration": { + "__desc": "持续时间(单位秒)", + "__name": "持续时间", + "type": "float", + "value": 0.0 + }, + "gravity": { + "__desc": "重力方向和大小", + "__name": "重力方向和大小", + "type": "array", + "value": [ + 0.0, + 9.800000190734863 + ] + }, + "max_num": { + "__desc": "粒子数量上限", + "__name": "粒子数量上限", + "type": "uint", + "value": 1024 + } + } +} \ No newline at end of file diff --git a/project/dl_test/ui_sprite.cpp b/project/dl_test/ui_sprite.cpp index b53d0677..dca750bb 100644 --- a/project/dl_test/ui_sprite.cpp +++ b/project/dl_test/ui_sprite.cpp @@ -55,6 +55,13 @@ UISprite::UISprite() btn->SetString("帧动画"); panel_menu->Add(btn); } + { + UI::ButtonSprite* btn = g_ui->CreateButtonSpriteDefault( + UI::ButtonStyle::LONG); + btn->SetMode(UI::ButtonMode::RADIO); + btn->SetString("粒子系统"); + panel_menu->Add(btn); + } _panelMenu = panel_menu; // @@ -263,6 +270,8 @@ UISprite::UISprite() _txtAni->GetCoor()->SetParent(_panelMenu->GetCoorRef()); _txtAni->GetCoor()->SetPosition({ 0, 100 }); + + _par = g_particle->Create("fire"); } UISprite::~UISprite() @@ -284,6 +293,8 @@ void UISprite::Update() _update_tile(); else if (index == 5) _update_animation(); + else if (index == 6) + _update_particle(); } constexpr Position SIZE_MAP_NODE = { 32, 32 }; @@ -649,3 +660,8 @@ void UISprite::_update_animation() txt->GetCoor()->SetPosition({ 0, 300 }); txt->SetString("wasd移动,j攻击,space滚动"); } + +void UISprite::_update_particle() +{ + _par->Render(); +} diff --git a/project/dl_test/ui_sprite.h b/project/dl_test/ui_sprite.h index d4b18e1b..e688b1dd 100644 --- a/project/dl_test/ui_sprite.h +++ b/project/dl_test/ui_sprite.h @@ -90,6 +90,9 @@ private: }_fsmAni; gcText _txtAni; + // 粒子系统 + Particle* _par; + void _init_tile_map(); void _update_base(); void _update_effect(); @@ -97,6 +100,7 @@ private: void _update_performance(); void _update_tile(); void _update_animation(); + void _update_particle(); void _add_test(); void _del_test()