Compare commits

...

5 Commits

Author SHA1 Message Date
En Yi 0fb1fe27de Display time scaling in sandbox 2024-04-24 22:15:52 +08:00
En Yi 204329d2aa Use float for timing in particle system
Also, update the assets_loader due to this
2024-04-24 21:47:58 +08:00
En Yi 6bcccf7412 Fix regression in water air timer 2024-04-24 21:30:34 +08:00
En Yi c76ceba9bf Add delta time into particle system updates
Only update the callbacks to use it
2024-04-24 21:06:57 +08:00
En Yi 0a3f56f730 Fix out-of-bound access in water check function 2024-04-24 20:58:54 +08:00
7 changed files with 56 additions and 52 deletions

View File

@ -1,8 +1,8 @@
#include "particle_sys.h" #include "particle_sys.h"
#include "assets.h" #include "assets.h"
#include "raymath.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
void init_particle_system(ParticleSystem_t* system) void init_particle_system(ParticleSystem_t* system)
{ {
@ -30,9 +30,9 @@ static inline float generate_randrange(float lo, float hi)
static inline void spawn_particle(ParticleEmitter_t* emitter, uint32_t idx) static inline void spawn_particle(ParticleEmitter_t* emitter, uint32_t idx)
{ {
uint32_t lifetime = (emitter->config->particle_lifetime[1] - emitter->config->particle_lifetime[0]); float lifetime = (emitter->config->particle_lifetime[1] - emitter->config->particle_lifetime[0]);
emitter->particles[idx].timer = emitter->config->particle_lifetime[0]; emitter->particles[idx].timer = emitter->config->particle_lifetime[0];
emitter->particles[idx].timer += rand() % lifetime; emitter->particles[idx].timer += lifetime * rand()/ (float)RAND_MAX;
emitter->particles[idx].alive = true; emitter->particles[idx].alive = true;
float angle = generate_randrange(emitter->config->launch_range[0], emitter->config->launch_range[1]); float angle = generate_randrange(emitter->config->launch_range[0], emitter->config->launch_range[1]);
@ -92,7 +92,7 @@ void play_emitter_handle(ParticleSystem_t* system, uint16_t handle)
{ {
// TODO: deal with stream type // TODO: deal with stream type
//spawn_particle(emitter, 0); //spawn_particle(emitter, 0);
uint32_t incr = 0; float incr = 0;
for (uint32_t i = 0; i < emitter->n_particles; ++i) for (uint32_t i = 0; i < emitter->n_particles; ++i)
{ {
emitter->particles[i].timer = incr; emitter->particles[i].timer = incr;
@ -163,7 +163,7 @@ void update_particle_system(ParticleSystem_t* system, float delta_time)
if (emitter->emitter_update_func != NULL && emitter->active) if (emitter->emitter_update_func != NULL && emitter->active)
{ {
emitter->active = emitter->emitter_update_func(emitter); emitter->active = emitter->emitter_update_func(emitter, delta_time);
} }
for (uint32_t i = 0; i < emitter->n_particles; ++i) for (uint32_t i = 0; i < emitter->n_particles; ++i)
@ -175,13 +175,13 @@ void update_particle_system(ParticleSystem_t* system, float delta_time)
{ {
if (emitter->update_func != NULL) if (emitter->update_func != NULL)
{ {
emitter->update_func(emitter->particles + i, emitter->user_data); emitter->update_func(emitter->particles + i, emitter->user_data, delta_time);
} }
} }
// Lifetime update
if (emitter->particles[i].timer > 0) emitter->particles[i].timer--; emitter->particles[i].timer -= delta_time;
if (emitter->particles[i].timer == 0) if (emitter->particles[i].timer <= 0.0f)
{ {
if (emitter->particles[i].spawned) if (emitter->particles[i].spawned)
{ {
@ -222,6 +222,10 @@ void update_particle_system(ParticleSystem_t* system, float delta_time)
{ {
emitter->finished = true; emitter->finished = true;
} }
}
if (emitter->finished)
{
system->emitter_list[prev_idx].next = system->emitter_list[emitter_idx].next; system->emitter_list[prev_idx].next = system->emitter_list[emitter_idx].next;
system->emitter_list[emitter_idx].next = 0; system->emitter_list[emitter_idx].next = 0;
system->emitter_list[emitter_idx].playing = false; system->emitter_list[emitter_idx].playing = false;

View File

@ -22,15 +22,15 @@ typedef struct Particle
float rotation; float rotation;
float angular_vel; float angular_vel;
float size; float size;
uint32_t timer; float timer;
bool alive; bool alive;
bool spawned; bool spawned;
}Particle_t; }Particle_t;
typedef struct ParticleEmitter ParticleEmitter_t; typedef struct ParticleEmitter ParticleEmitter_t;
typedef void (*particle_update_func_t)(Particle_t* part, void* user_data); typedef void (*particle_update_func_t)(Particle_t* part, void* user_data, float delta_time);
typedef bool (*emitter_check_func_t)(const ParticleEmitter_t* emitter); typedef bool (*emitter_check_func_t)(const ParticleEmitter_t* emitter, float delta_time);
typedef struct EmitterConfig typedef struct EmitterConfig
{ {
@ -38,8 +38,8 @@ typedef struct EmitterConfig
float speed_range[2]; float speed_range[2];
float angle_range[2]; float angle_range[2];
float rotation_range[2]; float rotation_range[2];
uint32_t particle_lifetime[2]; float particle_lifetime[2];
uint32_t initial_spawn_delay; float initial_spawn_delay;
PartEmitterType_t type; PartEmitterType_t type;
bool one_shot; bool one_shot;
}EmitterConfig_t; }EmitterConfig_t;
@ -51,7 +51,7 @@ struct ParticleEmitter
Vector2 position; Vector2 position;
Particle_t particles[MAX_PARTICLES]; Particle_t particles[MAX_PARTICLES];
uint32_t n_particles; uint32_t n_particles;
uint32_t timer; float timer;
bool finished; bool finished;
bool active; bool active;
void* user_data; void* user_data;

View File

@ -6,9 +6,9 @@
#include "constants.h" #include "constants.h"
static const Vector2 GRAVITY = {0, GRAV_ACCEL}; static const Vector2 GRAVITY = {0, GRAV_ACCEL};
void simple_particle_system_update(Particle_t* part, void* user_data) void simple_particle_system_update(Particle_t* part, void* user_data, float delta_time)
{ {
float delta_time = *(float*)user_data; // TODO: Will need to think about delta time handling (void)user_data;
part->rotation += part->angular_vel; part->rotation += part->angular_vel;
part->velocity = part->velocity =
@ -44,7 +44,7 @@ void simple_particle_system_update(Particle_t* part, void* user_data)
} }
} }
static bool check_mouse_click(const ParticleEmitter_t* emitter) static bool check_mouse_click(const ParticleEmitter_t* emitter, float delta_time)
{ {
return IsMouseButtonDown(MOUSE_RIGHT_BUTTON); return IsMouseButtonDown(MOUSE_RIGHT_BUTTON);
} }
@ -108,7 +108,7 @@ int main(void)
.update_func = &simple_particle_system_update, .update_func = &simple_particle_system_update,
.emitter_update_func = &check_mouse_click, .emitter_update_func = &check_mouse_click,
.spr = (tex.width == 0) ? NULL : &spr, .spr = (tex.width == 0) ? NULL : &spr,
.user_data = &delta_time, .user_data = NULL,
}; };
bool key_press = false; bool key_press = false;

View File

@ -41,7 +41,7 @@ static bool parse_emitter_info(char* emitter_info_str, EmitterConfig_t* conf)
char emitter_type; char emitter_type;
uint8_t one_shot; uint8_t one_shot;
int data_count = sscanf( int data_count = sscanf(
emitter_info_str, "%c,%f-%f,%f-%f,%f-%f,%f-%f,%u-%u,%u,%c", emitter_info_str, "%c,%f-%f,%f-%f,%f-%f,%f-%f,%f-%f,%f,%c",
&emitter_type, &emitter_type,
conf->launch_range, conf->launch_range + 1, conf->launch_range, conf->launch_range + 1,
conf->speed_range, conf->speed_range + 1, conf->speed_range, conf->speed_range + 1,

View File

@ -123,6 +123,9 @@ static void level_scene_render_func(Scene_t* scene)
draw_pos.y += SELECTION_TILE_SIZE + 5; draw_pos.y += SELECTION_TILE_SIZE + 5;
sprintf(buffer, "Crate %s on spawn", crate_activation? "active" : "inactive"); sprintf(buffer, "Crate %s on spawn", crate_activation? "active" : "inactive");
DrawText(buffer, draw_pos.x, draw_pos.y, 20, BLACK); DrawText(buffer, draw_pos.x, draw_pos.y, 20, BLACK);
draw_pos.y += SELECTION_TILE_SIZE + 5;
sprintf(buffer, "Time scale: %.2f", scene->time_scale);
DrawText(buffer, draw_pos.x, draw_pos.y, 20, BLACK);
// For DEBUG // For DEBUG
const int gui_x = data->game_rec.x + data->game_rec.width + 10; const int gui_x = data->game_rec.x + data->game_rec.width + 10;
@ -972,7 +975,7 @@ static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed)
} }
else else
{ {
scene->time_scale = 0.5f; scene->time_scale = 0.25f;
} }
} }
break; break;

View File

@ -6,9 +6,9 @@
#include "constants.h" #include "constants.h"
#include <stdio.h> #include <stdio.h>
void simple_particle_system_update(Particle_t* part, void* user_data); void simple_particle_system_update(Particle_t* part, void* user_data, float delta_time);
void floating_particle_system_update(Particle_t* part, void* user_data); void floating_particle_system_update(Particle_t* part, void* user_data, float delta_time);
bool check_in_water(const ParticleEmitter_t* emitter); bool check_in_water(const ParticleEmitter_t* emitter, float delta_time);
static const Vector2 GRAVITY = {0, GRAV_ACCEL}; static const Vector2 GRAVITY = {0, GRAV_ACCEL};
static const Vector2 UPTHRUST = {0, -GRAV_ACCEL * 1.1}; static const Vector2 UPTHRUST = {0, -GRAV_ACCEL * 1.1};
@ -24,11 +24,11 @@ typedef enum AnchorPoint {
AP_BOT_RIGHT, AP_BOT_RIGHT,
} AnchorPoint_t; } AnchorPoint_t;
static inline unsigned int get_tile_idx(int x, int y, unsigned int tilemap_width) static inline unsigned int get_tile_idx(int x, int y, TileGrid_t gridmap)
{ {
unsigned int tile_x = x / TILE_SIZE; unsigned int tile_x = x / gridmap.tile_size;
unsigned int tile_y = y / TILE_SIZE; unsigned int tile_y = y / gridmap.tile_size;
return tile_y * tilemap_width + tile_x; return tile_y * gridmap.width + tile_x;
} }
static inline void destroy_tile(LevelSceneData_t* lvl_data, unsigned int tile_idx) static inline void destroy_tile(LevelSceneData_t* lvl_data, unsigned int tile_idx)
@ -369,7 +369,7 @@ void player_movement_input_system(Scene_t* scene)
unsigned int tile_idx = get_tile_idx( unsigned int tile_idx = get_tile_idx(
p_player->position.x + p_bbox->half_size.x, p_player->position.x + p_bbox->half_size.x,
p_player->position.y + p_bbox->half_size.y, p_player->position.y + p_bbox->half_size.y,
data->tilemap.width data->tilemap
); );
if (tilemap.tiles[tile_idx].tile_type == LADDER && p_ctransform->velocity.y >= 0) if (tilemap.tiles[tile_idx].tile_type == LADDER && p_ctransform->velocity.y >= 0)
{ {
@ -386,7 +386,7 @@ void player_movement_input_system(Scene_t* scene)
tile_idx = get_tile_idx( tile_idx = get_tile_idx(
p_player->position.x + p_bbox->half_size.x, p_player->position.x + p_bbox->half_size.x,
p_player->position.y + p_bbox->size.y, p_player->position.y + p_bbox->size.y,
data->tilemap.width data->tilemap
); );
} }
else else
@ -394,7 +394,7 @@ void player_movement_input_system(Scene_t* scene)
tile_idx = get_tile_idx( tile_idx = get_tile_idx(
p_player->position.x + p_bbox->half_size.x, p_player->position.x + p_bbox->half_size.x,
p_player->position.y + p_bbox->half_size.y, p_player->position.y + p_bbox->half_size.y,
data->tilemap.width data->tilemap
); );
} }
if (tile_idx < tilemap.n_tiles && tilemap.tiles[tile_idx].tile_type == LADDER) if (tile_idx < tilemap.n_tiles && tilemap.tiles[tile_idx].tile_type == LADDER)
@ -1757,7 +1757,7 @@ void boulder_destroy_wooden_tile_system(Scene_t* scene)
unsigned int tile_idx = get_tile_idx( unsigned int tile_idx = get_tile_idx(
p_boulder->position.x + p_bbox->half_size.x, p_boulder->position.x + p_bbox->half_size.x,
p_boulder->position.y + p_bbox->size.y + 1, p_boulder->position.y + p_bbox->size.y + 1,
tilemap.width tilemap
); );
unsigned int tile_x = (p_boulder->position.x + p_bbox->half_size.x) / tilemap.tile_size; unsigned int tile_x = (p_boulder->position.x + p_bbox->half_size.x) / tilemap.tile_size;
@ -1895,8 +1895,7 @@ void airtimer_update_system(Scene_t* scene)
Entity_t* p_ent = get_entity(&scene->ent_manager, ent_idx); Entity_t* p_ent = get_entity(&scene->ent_manager, ent_idx);
if (!p_ent->m_alive) continue; if (!p_ent->m_alive) continue;
CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T); CBBox_t* p_bbox = get_component(p_ent, CBBOX_COMP_T);
CMovementState_t* p_movement = get_component(p_ent, CMOVEMENTSTATE_T); if (p_bbox == NULL) continue;
if (p_bbox == NULL || p_movement == NULL) continue;
Vector2 point_to_check = { Vector2 point_to_check = {
p_ent->position.x + p_bbox->half_size.x, p_ent->position.x + p_bbox->half_size.x,
@ -1906,7 +1905,7 @@ void airtimer_update_system(Scene_t* scene)
unsigned int tile_idx = get_tile_idx( unsigned int tile_idx = get_tile_idx(
point_to_check.x, point_to_check.x,
point_to_check.y, point_to_check.y,
tilemap.width tilemap
); );
bool in_water = false; bool in_water = false;
@ -2117,7 +2116,7 @@ void level_end_detection_system(Scene_t* scene)
unsigned int tile_idx = get_tile_idx( unsigned int tile_idx = get_tile_idx(
p_flag->position.x, p_flag->position.x,
p_flag->position.y, p_flag->position.y,
tilemap.width tilemap
); );
unsigned int other_ent_idx; unsigned int other_ent_idx;
@ -2145,11 +2144,9 @@ void level_end_detection_system(Scene_t* scene)
static inline bool is_point_in_water(Vector2 pos, TileGrid_t tilemap) static inline bool is_point_in_water(Vector2 pos, TileGrid_t tilemap)
{ {
unsigned int tile_idx = get_tile_idx( unsigned int tile_idx = get_tile_idx(pos.x, pos.y, tilemap);
pos.x, if (tile_idx >= tilemap.n_tiles) return false;
pos.y,
tilemap.width
);
int tile_x = tile_idx % tilemap.width; int tile_x = tile_idx % tilemap.width;
int tile_y = tile_idx / tilemap.width; int tile_y = tile_idx / tilemap.width;
uint32_t water_height = tilemap.tiles[tile_idx].water_level * WATER_BBOX_STEP; uint32_t water_height = tilemap.tiles[tile_idx].water_level * WATER_BBOX_STEP;
@ -2160,19 +2157,20 @@ static inline bool is_point_in_water(Vector2 pos, TileGrid_t tilemap)
); );
} }
bool check_in_water(const ParticleEmitter_t* emitter) bool check_in_water(const ParticleEmitter_t* emitter, float delta_time)
{ {
LevelSceneData_t* lvl_data = (LevelSceneData_t*)emitter->user_data; (void)delta_time;
TileGrid_t tilemap = lvl_data->tilemap;
LevelScene_t* scene = (LevelScene_t*)emitter->user_data;
TileGrid_t tilemap = scene->data.tilemap;
return is_point_in_water(emitter->position, tilemap); return is_point_in_water(emitter->position, tilemap);
} }
void simple_particle_system_update(Particle_t* part, void* user_data) void simple_particle_system_update(Particle_t* part, void* user_data, float delta_time)
{ {
LevelScene_t* scene = (LevelScene_t*)user_data; LevelScene_t* scene = (LevelScene_t*)user_data;
TileGrid_t tilemap = scene->data.tilemap; TileGrid_t tilemap = scene->data.tilemap;
float delta_time = scene->scene.delta_time;
part->velocity = part->velocity =
Vector2Add( Vector2Add(
part->velocity, part->velocity,
@ -2210,12 +2208,11 @@ void simple_particle_system_update(Particle_t* part, void* user_data)
} }
} }
void simple_float_particle_system_update(Particle_t* part, void* user_data) void simple_float_particle_system_update(Particle_t* part, void* user_data, float delta_time)
{ {
LevelScene_t* scene = (LevelScene_t*)user_data; LevelScene_t* scene = (LevelScene_t*)user_data;
TileGrid_t tilemap = scene->data.tilemap; TileGrid_t tilemap = scene->data.tilemap;
float delta_time = scene->scene.delta_time;
part->position = Vector2Add( part->position = Vector2Add(
part->position, part->position,
Vector2Scale(part->velocity, delta_time) Vector2Scale(part->velocity, delta_time)
@ -2238,9 +2235,9 @@ void simple_float_particle_system_update(Particle_t* part, void* user_data)
} }
} }
void floating_particle_system_update(Particle_t* part, void* user_data) void floating_particle_system_update(Particle_t* part, void* user_data, float delta_time)
{ {
simple_float_particle_system_update(part, user_data); simple_float_particle_system_update(part, user_data, delta_time);
LevelScene_t* scene = (LevelScene_t*)user_data; LevelScene_t* scene = (LevelScene_t*)user_data;
TileGrid_t tilemap = scene->data.tilemap; TileGrid_t tilemap = scene->data.tilemap;

View File

@ -98,8 +98,8 @@ Entity_t* create_player(EntityManager_t* ent_manager)
CAirTimer_t* p_air = add_component(p_ent, CAIRTIMER_T); CAirTimer_t* p_air = add_component(p_ent, CAIRTIMER_T);
p_air->max_count = 10; p_air->max_count = 10;
p_air->curr_count = 10; p_air->curr_count = 10;
p_air->max_ftimer = 300; p_air->max_ftimer = 1.0f;
p_air->decay_rate = 5; p_air->decay_rate = 1.0f;
CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T); CSprite_t* p_cspr = add_component(p_ent, CSPRITE_T);
p_cspr->sprites = player_sprite_map; p_cspr->sprites = player_sprite_map;