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
scene_man
En Yi 2023-11-02 22:42:18 +08:00
parent 7939b8753e
commit 43aa821c18
6 changed files with 55 additions and 51 deletions

View File

@ -36,18 +36,18 @@ typedef struct LevelPackData
LevelPack_t pack; LevelPack_t pack;
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
}LevelPackData_t; }LevelPackData_t;
typedef struct PartEmitterData typedef struct EmitterConfData
{ {
ParticleEmitter_t emitter; EmitterConfig_t conf;
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
}ParticleEmitterData_t; }EmitterConfData_t;
static TextureData_t textures[MAX_TEXTURES]; static TextureData_t textures[MAX_TEXTURES];
static FontData_t fonts[MAX_FONTS]; static FontData_t fonts[MAX_FONTS];
static SoundData_t sfx[MAX_SOUNDS]; static SoundData_t sfx[MAX_SOUNDS];
static SpriteData_t sprites[MAX_SPRITES]; static SpriteData_t sprites[MAX_SPRITES];
static LevelPackData_t levelpacks[MAX_LEVEL_PACK]; 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_INBUF_LEN 4096
#define DECOMPRESSOR_OUTBUF_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; 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]; uint8_t emitter_idx = n_loaded[5];
assert(emitter_idx < MAX_PARTICLE_EMITTER); assert(emitter_idx < MAX_EMITTER_CONF);
memset(emitters + emitter_idx, 0, sizeof(ParticleEmitterData_t)); memset(emitter_confs + emitter_idx, 0, sizeof(EmitterConfData_t));
emitters[emitter_idx].emitter.spr = sprite; emitter_confs[emitter_idx].conf.spr = sprite;
strncpy(emitters[emitter_idx].name, name, MAX_NAME_LEN); strncpy(emitter_confs[emitter_idx].name, name, MAX_NAME_LEN);
sc_map_put_s64(&assets->m_emitters, emitters[emitter_idx].name, emitter_idx); sc_map_put_s64(&assets->m_emitter_confs, emitter_confs[emitter_idx].name, emitter_idx);
n_loaded[5]++; 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) 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_textures, MAX_TEXTURES, 0);
sc_map_init_s64(&assets->m_sounds, MAX_SOUNDS, 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_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(); 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_sounds);
sc_map_clear_s64(&assets->m_sprites); sc_map_clear_s64(&assets->m_sprites);
sc_map_clear_s64(&assets->m_levelpacks); 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)); 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_sounds);
sc_map_term_s64(&assets->m_sprites); sc_map_term_s64(&assets->m_sprites);
sc_map_term_s64(&assets->m_levelpacks); 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); ZSTD_freeDCtx(level_decompressor.ctx);
} }
@ -421,12 +421,12 @@ Sprite_t* get_sprite(Assets_t* assets, const char* name)
return NULL; 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); uint8_t emitter_idx = sc_map_get_s64(&assets->m_emitter_confs, name);
if (sc_map_found(&assets->m_emitters)) if (sc_map_found(&assets->m_emitter_confs))
{ {
return &emitters[emitter_idx].emitter; return &emitter_confs[emitter_idx].conf;
} }
return NULL; return NULL;
} }

View File

@ -13,7 +13,7 @@ typedef struct Assets
struct sc_map_s64 m_fonts; struct sc_map_s64 m_fonts;
struct sc_map_s64 m_sprites; struct sc_map_s64 m_sprites;
struct sc_map_s64 m_levelpacks; struct sc_map_s64 m_levelpacks;
struct sc_map_s64 m_emitters; struct sc_map_s64 m_emitter_confs;
}Assets_t; }Assets_t;
typedef struct LevelTileInfo 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); 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); 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); Texture2D* get_texture(Assets_t* assets, const char* name);
Sprite_t* get_sprite(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); Sound* get_sound(Assets_t* assets, const char* name);
Font* get_font(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); LevelPack_t* get_level_pack(Assets_t* assets, const char* name);

View File

@ -9,8 +9,9 @@
#define MAX_NAME_LEN 32 #define MAX_NAME_LEN 32
#define MAX_LEVEL_PACK 4 #define MAX_LEVEL_PACK 4
#define N_SFX 18 #define N_SFX 18
#define MAX_PARTICLE_CONF 8 #define MAX_EMITTER_CONF 8
#define MAX_PARTICLE_EMITTER 16 //#define MAX_PARTICLE_EMITTER 8
#define MAX_ACTIVE_PARTICLE_EMITTER 32
#define MAX_PARTICLES 10 #define MAX_PARTICLES 10
#define MAX_TILE_TYPES 16 #define MAX_TILE_TYPES 16

View File

@ -1,4 +1,5 @@
#include "particle_sys.h" #include "particle_sys.h"
#include "assets.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
@ -10,14 +11,16 @@ void init_particle_system(ParticleSystem_t* system)
{ {
memset(system, 0, sizeof(ParticleSystem_t)); memset(system, 0, sizeof(ParticleSystem_t));
sc_queue_init(&system->free_list); 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); sc_queue_add_last(&system->free_list, i);
} }
system->tail_idx = 0; 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; if (sc_queue_empty(&system->free_list)) return;
uint32_t idx = sc_queue_del_first(&system->free_list); uint32_t idx = sc_queue_del_first(&system->free_list);
system->emitter_list[system->tail_idx].next = idx; 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 // Generate particles based on type
for (uint32_t i = 0; i < emitter->n_particles; ++i) for (uint32_t i = 0; i < emitter->n_particles; ++i)
{ {
uint32_t lifetime = (emitter->config.particle_lifetime[1] - 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 = emitter->config->particle_lifetime[0];
emitter->particles[i].timer += rand() % lifetime; emitter->particles[i].timer += rand() % lifetime;
emitter->particles[i].alive = true; 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 *= (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;
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 *= (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.x = speed * cos(angle * PI / 180);
emitter->particles[i].velocity.y = speed * sin(angle); emitter->particles[i].velocity.y = speed * sin(angle * PI / 180);
emitter->particles[i].position = emitter->position; emitter->particles[i].position = emitter->position;
emitter->particles[i].rotation = angle; emitter->particles[i].rotation = angle;
emitter->particles[i].angular_vel = -10 + 20 * (float)rand() / (float)RAND_MAX; 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->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 // Lifetime update
@ -119,7 +121,7 @@ void draw_particle_system(ParticleSystem_t* system)
{ {
if (part->alive) if (part->alive)
{ {
if (emitter->spr->texture == NULL || emitter->spr->texture->width == 0) if (emitter->config->spr == NULL)
{ {
Rectangle rect = { Rectangle rect = {
.x = part->position.x, .x = part->position.x,
@ -135,7 +137,7 @@ void draw_particle_system(ParticleSystem_t* system)
} }
else else
{ {
draw_sprite(emitter->spr, part->position, part->rotation, false); draw_sprite(emitter->config->spr, part->position, part->rotation, false);
} }
} }
} }

View File

@ -3,7 +3,7 @@
#include "raylib.h" #include "raylib.h"
#include "engine_conf.h" #include "engine_conf.h"
#include "sc_queue.h" #include "sc_queue.h"
#include "assets.h" #include "EC.h"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
@ -32,21 +32,21 @@ typedef struct EmitterConfig
float speed_range[2]; float speed_range[2];
uint32_t particle_lifetime[2]; uint32_t particle_lifetime[2];
PartEmitterType_t type; PartEmitterType_t type;
void* user_data; Sprite_t* spr;
particle_update_func_t update_func; bool one_shot;
}EmitterConfig_t; }EmitterConfig_t;
typedef struct ParticleEmitter typedef struct ParticleEmitter
{ {
EmitterConfig_t config; const EmitterConfig_t* config;
Vector2 position; Vector2 position;
Particle_t particles[MAX_PARTICLES]; Particle_t particles[MAX_PARTICLES];
uint32_t n_particles; uint32_t n_particles;
Sprite_t* spr;
uint32_t timer; uint32_t timer;
bool one_shot;
bool finished; bool finished;
bool active; bool active;
void* user_data;
particle_update_func_t update_func;
}ParticleEmitter_t; }ParticleEmitter_t;
typedef struct IndexList typedef struct IndexList
@ -56,8 +56,8 @@ typedef struct IndexList
typedef struct ParticleSystem typedef struct ParticleSystem
{ {
ParticleEmitter_t emitters[MAX_PARTICLE_EMITTER + 1]; ParticleEmitter_t emitters[MAX_ACTIVE_PARTICLE_EMITTER + 1];
IndexList_t emitter_list[MAX_PARTICLE_EMITTER + 1]; IndexList_t emitter_list[MAX_ACTIVE_PARTICLE_EMITTER + 1];
struct sc_queue_64 free_list; struct sc_queue_64 free_list;
uint32_t tail_idx; uint32_t tail_idx;
uint32_t n_configs; uint32_t n_configs;
@ -65,7 +65,7 @@ typedef struct ParticleSystem
}ParticleSystem_t; }ParticleSystem_t;
void init_particle_system(ParticleSystem_t* system); 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 update_particle_system(ParticleSystem_t* system);
void draw_particle_system(ParticleSystem_t* system); void draw_particle_system(ParticleSystem_t* system);
void deinit_particle_system(ParticleSystem_t* system); void deinit_particle_system(ParticleSystem_t* system);

View File

@ -65,17 +65,17 @@ int main(void)
}; };
EmitterConfig_t conf ={ EmitterConfig_t conf ={
.one_shot = true,
.launch_range = {0, 360}, .launch_range = {0, 360},
.speed_range = {400, 2000}, .speed_range = {400, 2000},
.particle_lifetime = {30, 110}, .particle_lifetime = {30, 110},
.update_func = &simple_particle_system_update .spr = (tex.width == 0) ? NULL : &spr,
}; };
ParticleEmitter_t emitter = { ParticleEmitter_t emitter = {
.config = conf, .config = &conf,
.n_particles = MAX_PARTICLES, .n_particles = MAX_PARTICLES,
.one_shot = true, .update_func = &simple_particle_system_update
.spr = &spr,
}; };
bool key_press = false; bool key_press = false;
@ -88,7 +88,7 @@ int main(void)
else if (key_press && IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) else if (key_press && IsMouseButtonReleased(MOUSE_BUTTON_LEFT))
{ {
emitter.position = GetMousePosition(); emitter.position = GetMousePosition();
add_particle_emitter(&part_sys, &emitter); play_particle_emitter(&part_sys, &emitter);
key_press = false; key_press = false;
} }
update_particle_system(&part_sys); update_particle_system(&part_sys);