From 43aa821c184af34b0a660a53e9d151fee2fcd634 Mon Sep 17 00:00:00 2001 From: En Yi Date: Thu, 2 Nov 2023 22:42:18 +0800 Subject: [PATCH] Refactor particle system Changelog: - Config should contain constants that determine the spawning of an emitter. - Move user_data and update_func to emitter, since these values can change depending on the scene. - Assets now load in Emitter Configs --- engine/assets.c | 36 ++++++++++++++++++------------------ engine/assets.h | 5 +++-- engine/engine_conf.h | 5 +++-- engine/particle_sys.c | 32 +++++++++++++++++--------------- engine/particle_sys.h | 18 +++++++++--------- particle_test.c | 10 +++++----- 6 files changed, 55 insertions(+), 51 deletions(-) diff --git a/engine/assets.c b/engine/assets.c index 290d256..849fb04 100644 --- a/engine/assets.c +++ b/engine/assets.c @@ -36,18 +36,18 @@ typedef struct LevelPackData LevelPack_t pack; char name[MAX_NAME_LEN]; }LevelPackData_t; -typedef struct PartEmitterData +typedef struct EmitterConfData { - ParticleEmitter_t emitter; + EmitterConfig_t conf; char name[MAX_NAME_LEN]; -}ParticleEmitterData_t; +}EmitterConfData_t; static TextureData_t textures[MAX_TEXTURES]; static FontData_t fonts[MAX_FONTS]; static SoundData_t sfx[MAX_SOUNDS]; static SpriteData_t sprites[MAX_SPRITES]; static LevelPackData_t levelpacks[MAX_LEVEL_PACK]; -static ParticleEmitterData_t emitters[MAX_PARTICLE_EMITTER]; +static EmitterConfData_t emitter_confs[MAX_EMITTER_CONF]; #define DECOMPRESSOR_INBUF_LEN 4096 #define DECOMPRESSOR_OUTBUF_LEN 4096 @@ -142,16 +142,16 @@ Font* add_font(Assets_t* assets, const char* name, const char* path) return &fonts[fnt_idx].font; } -ParticleEmitter_t* add_part_emitter(Assets_t* assets, const char* name, Sprite_t* sprite) +EmitterConfig_t* add_emitter_conf(Assets_t* assets, const char* name, Sprite_t* sprite) { uint8_t emitter_idx = n_loaded[5]; - assert(emitter_idx < MAX_PARTICLE_EMITTER); - memset(emitters + emitter_idx, 0, sizeof(ParticleEmitterData_t)); - emitters[emitter_idx].emitter.spr = sprite; - strncpy(emitters[emitter_idx].name, name, MAX_NAME_LEN); - sc_map_put_s64(&assets->m_emitters, emitters[emitter_idx].name, emitter_idx); + assert(emitter_idx < MAX_EMITTER_CONF); + memset(emitter_confs + emitter_idx, 0, sizeof(EmitterConfData_t)); + emitter_confs[emitter_idx].conf.spr = sprite; + strncpy(emitter_confs[emitter_idx].name, name, MAX_NAME_LEN); + sc_map_put_s64(&assets->m_emitter_confs, emitter_confs[emitter_idx].name, emitter_idx); n_loaded[5]++; - return &emitters[emitter_idx].emitter; + return &emitter_confs[emitter_idx].conf; } LevelPack_t* add_level_pack(Assets_t* assets, const char* name, const char* path) @@ -357,7 +357,7 @@ void init_assets(Assets_t* assets) sc_map_init_s64(&assets->m_textures, MAX_TEXTURES, 0); sc_map_init_s64(&assets->m_sounds, MAX_SOUNDS, 0); sc_map_init_s64(&assets->m_levelpacks, MAX_LEVEL_PACK, 0); - sc_map_init_s64(&assets->m_emitters, MAX_PARTICLE_EMITTER, 0); + sc_map_init_s64(&assets->m_emitter_confs, MAX_EMITTER_CONF, 0); level_decompressor.ctx = ZSTD_createDCtx(); } @@ -385,7 +385,7 @@ void free_all_assets(Assets_t* assets) sc_map_clear_s64(&assets->m_sounds); sc_map_clear_s64(&assets->m_sprites); sc_map_clear_s64(&assets->m_levelpacks); - sc_map_clear_s64(&assets->m_emitters); + sc_map_clear_s64(&assets->m_emitter_confs); memset(n_loaded, 0, sizeof(n_loaded)); } @@ -397,7 +397,7 @@ void term_assets(Assets_t* assets) sc_map_term_s64(&assets->m_sounds); sc_map_term_s64(&assets->m_sprites); sc_map_term_s64(&assets->m_levelpacks); - sc_map_term_s64(&assets->m_emitters); + sc_map_term_s64(&assets->m_emitter_confs); ZSTD_freeDCtx(level_decompressor.ctx); } @@ -421,12 +421,12 @@ Sprite_t* get_sprite(Assets_t* assets, const char* name) return NULL; } -ParticleEmitter_t* get_emitter(Assets_t* assets, const char* name) +EmitterConfig_t* get_emitter_conf(Assets_t* assets, const char* name) { - uint8_t emitter_idx = sc_map_get_s64(&assets->m_emitters, name); - if (sc_map_found(&assets->m_emitters)) + uint8_t emitter_idx = sc_map_get_s64(&assets->m_emitter_confs, name); + if (sc_map_found(&assets->m_emitter_confs)) { - return &emitters[emitter_idx].emitter; + return &emitter_confs[emitter_idx].conf; } return NULL; } diff --git a/engine/assets.h b/engine/assets.h index e941909..acc4b01 100644 --- a/engine/assets.h +++ b/engine/assets.h @@ -13,7 +13,7 @@ typedef struct Assets struct sc_map_s64 m_fonts; struct sc_map_s64 m_sprites; struct sc_map_s64 m_levelpacks; - struct sc_map_s64 m_emitters; + struct sc_map_s64 m_emitter_confs; }Assets_t; typedef struct LevelTileInfo @@ -59,10 +59,11 @@ Texture2D* add_texture_rres(Assets_t* assets, const char* name, const char* file LevelPack_t* add_level_pack_rres(Assets_t* assets, const char* name, const char* filename, const RresFileInfo_t* rres_file); Sprite_t* add_sprite(Assets_t* assets, const char* name, Texture2D* texture); -ParticleEmitter_t* add_part_emitter(Assets_t* assets, const char* name, Sprite_t* sprite); +EmitterConfig_t* add_emitter_conf(Assets_t* assets, const char* name, Sprite_t* sprite); Texture2D* get_texture(Assets_t* assets, const char* name); Sprite_t* get_sprite(Assets_t* assets, const char* name); +EmitterConfig_t* get_emitter_conf(Assets_t* assets, const char* name); Sound* get_sound(Assets_t* assets, const char* name); Font* get_font(Assets_t* assets, const char* name); LevelPack_t* get_level_pack(Assets_t* assets, const char* name); diff --git a/engine/engine_conf.h b/engine/engine_conf.h index 8f0126c..d77d165 100644 --- a/engine/engine_conf.h +++ b/engine/engine_conf.h @@ -9,8 +9,9 @@ #define MAX_NAME_LEN 32 #define MAX_LEVEL_PACK 4 #define N_SFX 18 -#define MAX_PARTICLE_CONF 8 -#define MAX_PARTICLE_EMITTER 16 +#define MAX_EMITTER_CONF 8 +//#define MAX_PARTICLE_EMITTER 8 +#define MAX_ACTIVE_PARTICLE_EMITTER 32 #define MAX_PARTICLES 10 #define MAX_TILE_TYPES 16 diff --git a/engine/particle_sys.c b/engine/particle_sys.c index 2816be5..f2e2f15 100644 --- a/engine/particle_sys.c +++ b/engine/particle_sys.c @@ -1,4 +1,5 @@ #include "particle_sys.h" +#include "assets.h" #include #include #include @@ -10,14 +11,16 @@ void init_particle_system(ParticleSystem_t* system) { memset(system, 0, sizeof(ParticleSystem_t)); sc_queue_init(&system->free_list); - for ( uint32_t i = 1; i <= MAX_PARTICLE_EMITTER; ++i) + for ( uint32_t i = 1; i <= MAX_ACTIVE_PARTICLE_EMITTER; ++i) { sc_queue_add_last(&system->free_list, i); } system->tail_idx = 0; } -void add_particle_emitter(ParticleSystem_t* system, const ParticleEmitter_t* in_emitter) +void play_particle_emitter(ParticleSystem_t* system, const ParticleEmitter_t* in_emitter) { + if (in_emitter == NULL) return; + if (sc_queue_empty(&system->free_list)) return; uint32_t idx = sc_queue_del_first(&system->free_list); system->emitter_list[system->tail_idx].next = idx; @@ -33,24 +36,23 @@ void add_particle_emitter(ParticleSystem_t* system, const ParticleEmitter_t* in_ // Generate particles based on type for (uint32_t i = 0; i < emitter->n_particles; ++i) { - uint32_t lifetime = (emitter->config.particle_lifetime[1] - emitter->config.particle_lifetime[0]); - emitter->particles[i].timer = emitter->config.particle_lifetime[0]; + uint32_t lifetime = (emitter->config->particle_lifetime[1] - emitter->config->particle_lifetime[0]); + emitter->particles[i].timer = emitter->config->particle_lifetime[0]; emitter->particles[i].timer += rand() % lifetime; emitter->particles[i].alive = true; - float angle = emitter->config.launch_range[1] - emitter->config.launch_range[0]; + float angle = emitter->config->launch_range[1] - emitter->config->launch_range[0]; angle *= (float)rand() / (float)RAND_MAX; - angle += emitter->config.launch_range[0]; + angle += emitter->config->launch_range[0]; if(angle > 360) angle -= 360; if(angle < -360) angle += 360; - angle *= PI / 180; - float speed = emitter->config.speed_range[1] - emitter->config.speed_range[0]; + float speed = emitter->config->speed_range[1] - emitter->config->speed_range[0]; speed *= (float)rand() / (float)RAND_MAX; - speed += emitter->config.speed_range[0]; + speed += emitter->config->speed_range[0]; - emitter->particles[i].velocity.x = speed * cos(angle); - emitter->particles[i].velocity.y = speed * sin(angle); + emitter->particles[i].velocity.x = speed * cos(angle * PI / 180); + emitter->particles[i].velocity.y = speed * sin(angle * PI / 180); emitter->particles[i].position = emitter->position; emitter->particles[i].rotation = angle; emitter->particles[i].angular_vel = -10 + 20 * (float)rand() / (float)RAND_MAX; @@ -72,9 +74,9 @@ void update_particle_system(ParticleSystem_t* system) { if (emitter->particles[i].alive) { - if (emitter->config.update_func != NULL) + if (emitter->update_func != NULL) { - emitter->config.update_func(emitter->particles + i, emitter->config.user_data); + emitter->update_func(emitter->particles + i, emitter->user_data); } // Lifetime update @@ -119,7 +121,7 @@ void draw_particle_system(ParticleSystem_t* system) { if (part->alive) { - if (emitter->spr->texture == NULL || emitter->spr->texture->width == 0) + if (emitter->config->spr == NULL) { Rectangle rect = { .x = part->position.x, @@ -135,7 +137,7 @@ void draw_particle_system(ParticleSystem_t* system) } else { - draw_sprite(emitter->spr, part->position, part->rotation, false); + draw_sprite(emitter->config->spr, part->position, part->rotation, false); } } } diff --git a/engine/particle_sys.h b/engine/particle_sys.h index 09094d2..ffc3503 100644 --- a/engine/particle_sys.h +++ b/engine/particle_sys.h @@ -3,7 +3,7 @@ #include "raylib.h" #include "engine_conf.h" #include "sc_queue.h" -#include "assets.h" +#include "EC.h" #include #include @@ -32,21 +32,21 @@ typedef struct EmitterConfig float speed_range[2]; uint32_t particle_lifetime[2]; PartEmitterType_t type; - void* user_data; - particle_update_func_t update_func; + Sprite_t* spr; + bool one_shot; }EmitterConfig_t; typedef struct ParticleEmitter { - EmitterConfig_t config; + const EmitterConfig_t* config; Vector2 position; Particle_t particles[MAX_PARTICLES]; uint32_t n_particles; - Sprite_t* spr; uint32_t timer; - bool one_shot; bool finished; bool active; + void* user_data; + particle_update_func_t update_func; }ParticleEmitter_t; typedef struct IndexList @@ -56,8 +56,8 @@ typedef struct IndexList typedef struct ParticleSystem { - ParticleEmitter_t emitters[MAX_PARTICLE_EMITTER + 1]; - IndexList_t emitter_list[MAX_PARTICLE_EMITTER + 1]; + ParticleEmitter_t emitters[MAX_ACTIVE_PARTICLE_EMITTER + 1]; + IndexList_t emitter_list[MAX_ACTIVE_PARTICLE_EMITTER + 1]; struct sc_queue_64 free_list; uint32_t tail_idx; uint32_t n_configs; @@ -65,7 +65,7 @@ typedef struct ParticleSystem }ParticleSystem_t; void init_particle_system(ParticleSystem_t* system); -void add_particle_emitter(ParticleSystem_t* system, const ParticleEmitter_t* in_emitter); +void play_particle_emitter(ParticleSystem_t* system, const ParticleEmitter_t* in_emitter); void update_particle_system(ParticleSystem_t* system); void draw_particle_system(ParticleSystem_t* system); void deinit_particle_system(ParticleSystem_t* system); diff --git a/particle_test.c b/particle_test.c index 2473650..dd8d0c2 100644 --- a/particle_test.c +++ b/particle_test.c @@ -65,17 +65,17 @@ int main(void) }; EmitterConfig_t conf ={ + .one_shot = true, .launch_range = {0, 360}, .speed_range = {400, 2000}, .particle_lifetime = {30, 110}, - .update_func = &simple_particle_system_update + .spr = (tex.width == 0) ? NULL : &spr, }; ParticleEmitter_t emitter = { - .config = conf, + .config = &conf, .n_particles = MAX_PARTICLES, - .one_shot = true, - .spr = &spr, + .update_func = &simple_particle_system_update }; bool key_press = false; @@ -88,7 +88,7 @@ int main(void) else if (key_press && IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) { emitter.position = GetMousePosition(); - add_particle_emitter(&part_sys, &emitter); + play_particle_emitter(&part_sys, &emitter); key_press = false; } update_particle_system(&part_sys);