粒子系统初步

This commit is contained in:
2026-08-14 19:03:49 +08:00
parent 1ab6463c92
commit fa9734d81b
8 changed files with 357 additions and 5 deletions
+1 -1
View File
@@ -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"
#include "render/dl_particle.h"
+142
View File
@@ -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<std::string> 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);
}
}
+116
View File
@@ -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<Particle>;
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<ParicleNode> _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<std::string, ParticleConfig> _allConfig;
dl::Memory::Reuse<Particle> _memoryReuse;
std::list<Particle*> _listDelete;
void _update();
};
extern ParticleSystem* g_particle;
}
+3 -4
View File
@@ -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;
+2
View File
@@ -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);
+73
View File
@@ -0,0 +1,73 @@
{
"__desc": "2d粒子配置",
"__name": "2d粒子配置",
"node": {
"__desc": "粒子参数",
"__name": "粒子参数",
"lifetime": {
"__desc": "存活时间",
"__name": "存活时间",
"type": "array<float, 2>",
"value": [
1.0,
2.0
]
},
"speed": {
"__desc": "速度",
"__name": "速度",
"type": "array<float, 2>",
"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<float, 2>",
"value": [
0.0,
9.800000190734863
]
},
"max_num": {
"__desc": "粒子数量上限",
"__name": "粒子数量上限",
"type": "uint",
"value": 1024
}
}
}
+16
View File
@@ -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();
}
+4
View File
@@ -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()