diff --git a/engine/EC/components.h b/engine/EC/components.h index 0464812..0b9392f 100644 --- a/engine/EC/components.h +++ b/engine/EC/components.h @@ -4,7 +4,7 @@ #include // TODO: Look at sc to use macros to auto generate functions -#define N_COMPONENTS 7 +#define N_COMPONENTS 9 enum ComponentEnum { CBBOX_COMP_T, @@ -14,6 +14,8 @@ enum ComponentEnum CJUMP_COMP_T, CPLAYERSTATE_T, CCONTAINER_T, + CHITBOX_T, + CHURTBOX_T, }; typedef enum ComponentEnum ComponentEnum_t; @@ -95,6 +97,20 @@ typedef struct _CContainer_t ContainerItem_t item; }CContainer_t; +typedef struct _CHitBox_t +{ + Vector2 offset; + Vector2 size; + bool strong; +}CHitBox_t; + +typedef struct _CHurtbox_t +{ + Vector2 offset; + Vector2 size; + bool fragile; +}CHurtbox_t; + static inline void set_bbox(CBBox_t* p_bbox, unsigned int x, unsigned int y) { p_bbox->size.x = x; diff --git a/engine/EC/entManager.c b/engine/EC/entManager.c index 771e0f9..ea25654 100644 --- a/engine/EC/entManager.c +++ b/engine/EC/entManager.c @@ -31,9 +31,10 @@ void update_entity_manager(EntityManager_t *p_manager) sc_map_foreach (&p_entity->components, comp_type_idx, comp_idx) { free_component_to_mempool((ComponentEnum_t)comp_type_idx, comp_idx); - sc_map_del_64v(&p_manager->component_map[comp_type_idx], comp_idx); + sc_map_del_64v(&p_manager->component_map[comp_type_idx], e_idx); sc_map_del_64v(&p_manager->entities_map[p_entity->m_tag], e_idx); } + sc_map_clear_64(&p_entity->components); free_entity_to_mempool(e_idx); sc_map_del_64v(&p_manager->entities, e_idx); } @@ -93,8 +94,11 @@ void remove_entity(EntityManager_t *p_manager, unsigned long id) if(!sc_map_found(&p_manager->entities)) return; // This only marks the entity for deletion // Does not free entity. This is done during the update - p_entity->m_alive = false; - sc_queue_add_last(&p_manager->to_remove, id); + if (p_entity->m_alive) + { + p_entity->m_alive = false; + sc_queue_add_last(&p_manager->to_remove, id); + } } Entity_t *get_entity(EntityManager_t *p_manager, unsigned long id) diff --git a/engine/EC/entManager.h b/engine/EC/entManager.h index 3acc62f..92c3604 100644 --- a/engine/EC/entManager.h +++ b/engine/EC/entManager.h @@ -7,9 +7,9 @@ typedef struct EntityManager { // All fields are Read-Only - struct sc_map_64v entities; // id : entity - struct sc_map_64v entities_map[N_TAGS]; // [{id: ent}] - struct sc_map_64v component_map[N_COMPONENTS]; // [{id: comp}, ...] + struct sc_map_64v entities; // ent id : entity + struct sc_map_64v entities_map[N_TAGS]; // [{ent id: ent}] + struct sc_map_64v component_map[N_COMPONENTS]; // [{ent id: comp}, ...] struct sc_queue_uint to_add; struct sc_queue_uint to_remove; }EntityManager_t; diff --git a/engine/EC/mempool.c b/engine/EC/mempool.c index 9c573a5..f3fc960 100644 --- a/engine/EC/mempool.c +++ b/engine/EC/mempool.c @@ -1,6 +1,7 @@ #include "mempool.h" #include "sc/queue/sc_queue.h" #include +#include // Static allocate buffers static Entity_t entity_buffer[MAX_COMP_POOL_SIZE]; @@ -11,6 +12,8 @@ static CMovementState_t cmstate_buffer[MAX_COMP_POOL_SIZE]; static CJump_t cjump_buffer[1]; // Only player is expected to have this static CPlayerState_t cplayerstate_buffer[1]; // Only player is expected to have this static CContainer_t ccontainer_buffer[MAX_COMP_POOL_SIZE]; +static CHitBox_t chitbox_buffer[MAX_COMP_POOL_SIZE]; +static CHurtbox_t churtbox_buffer[MAX_COMP_POOL_SIZE]; // Use hashmap as a Set // Use list will be used to check if an object exist @@ -37,6 +40,8 @@ static MemPool_t comp_mempools[N_COMPONENTS] = {cjump_buffer, 1, sizeof(CJump_t), NULL, {0}}, {cplayerstate_buffer, 1, sizeof(CPlayerState_t), NULL, {0}}, {ccontainer_buffer, MAX_COMP_POOL_SIZE, sizeof(CContainer_t), NULL, {0}}, + {chitbox_buffer, MAX_COMP_POOL_SIZE, sizeof(CHitBox_t), NULL, {0}}, + {churtbox_buffer, MAX_COMP_POOL_SIZE, sizeof(CHurtbox_t), NULL, {0}}, }; static MemPool_t ent_mempool = {entity_buffer, MAX_COMP_POOL_SIZE, sizeof(Entity_t), NULL, {0}}; @@ -150,6 +155,15 @@ void free_component_to_mempool(ComponentEnum_t comp_type, unsigned long idx) if (comp_mempools[comp_type].use_list[idx]) { comp_mempools[comp_type].use_list[idx] = false; - sc_queue_add_first(&comp_mempools[comp_type].free_list, idx); + sc_queue_add_last(&comp_mempools[comp_type].free_list, idx); + } +} + +void print_mempool_stats(char* buffer) +{ + int written = 0; + for (size_t i=0; ient_manager.entities, p_ent) { CTransform_t* p_ct = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T); @@ -66,11 +67,32 @@ static void level_scene_render_func(Scene_t* scene) colour = BLACK; } DrawRectangle(p_ct->position.x, p_ct->position.y, p_bbox->size.x, p_bbox->size.y, colour); + CHurtbox_t* p_hurtbox = get_component(&scene->ent_manager, p_ent, CHURTBOX_T); + CHitBox_t* p_hitbox = get_component(&scene->ent_manager, p_ent, CHITBOX_T); + if (p_hitbox != NULL) + { + Rectangle rec = { + .x = p_ct->position.x + p_hitbox->offset.x, + .y = p_ct->position.y + p_hitbox->offset.y, + .width = p_hitbox->size.x, + .height = p_hitbox->size.y, + }; + DrawRectangleLinesEx(rec, 1.5, ORANGE); + } + if (p_hurtbox != NULL) + { + Rectangle rec = { + .x = p_ct->position.x + p_hurtbox->offset.x, + .y = p_ct->position.y + p_hurtbox->offset.y, + .width = p_hurtbox->size.x, + .height = p_hurtbox->size.y, + }; + DrawRectangleLinesEx(rec, 1.5, PURPLE); + } } for (size_t i=0; ient_manager.entities_map[PLAYER_ENT_TAG], p_ent) { CTransform_t* p_ct = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T); @@ -121,6 +142,10 @@ static void level_scene_render_func(Scene_t* scene) DrawText(buffer, tilemap.width * TILE_SIZE + 1, 270, 12, BLACK); sprintf(buffer, "FPS: %u", GetFPS()); DrawText(buffer, tilemap.width * TILE_SIZE + 1, 320, 12, BLACK); + + static char mempool_stats[512]; + print_mempool_stats(mempool_stats); + DrawText(mempool_stats, tilemap.width * TILE_SIZE + 1, 350, 12, BLACK); } static void spawn_crate(Scene_t *scene, unsigned int tile_idx, bool metal) @@ -136,6 +161,9 @@ static void spawn_crate(Scene_t *scene, unsigned int tile_idx, bool metal) p_ctransform->position.y = (tile_idx / data->tilemap.width) * TILE_SIZE; add_component(&scene->ent_manager, p_crate, CMOVEMENTSTATE_T); add_component(&scene->ent_manager, p_crate, CTILECOORD_COMP_T); + CHurtbox_t* p_hurtbox = add_component(&scene->ent_manager, p_crate, CHURTBOX_T); + p_hurtbox->size = p_bbox->size; + p_hurtbox->fragile = !metal; } static void spawn_player(Scene_t *scene) @@ -143,7 +171,7 @@ static void spawn_player(Scene_t *scene) Entity_t *p_ent = add_entity(&scene->ent_manager, PLAYER_ENT_TAG); CBBox_t *p_bbox = add_component(&scene->ent_manager, p_ent, CBBOX_COMP_T); - set_bbox(p_bbox, 30, 45); + set_bbox(p_bbox, PLAYER_WIDTH, PLAYER_HEIGHT); add_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T); CJump_t *p_cjump = add_component(&scene->ent_manager, p_ent, CJUMP_COMP_T); p_cjump->jump_speed = 680; @@ -153,6 +181,9 @@ static void spawn_player(Scene_t *scene) add_component(&scene->ent_manager, p_ent, CPLAYERSTATE_T); add_component(&scene->ent_manager, p_ent, CTILECOORD_COMP_T); add_component(&scene->ent_manager, p_ent, CMOVEMENTSTATE_T); + CHitBox_t* p_hitbox = add_component(&scene->ent_manager, p_ent, CHITBOX_T); + p_hitbox->size = Vector2Add(p_bbox->size, (Vector2){2,2}); + p_hitbox->offset = (Vector2){-1, -1}; } static void toggle_block_system(Scene_t *scene) @@ -272,6 +303,7 @@ void init_level_scene(LevelScene_t *scene) sc_array_add(&scene->scene.systems, &movement_update_system); sc_array_add(&scene->scene.systems, &update_tilemap_system); sc_array_add(&scene->scene.systems, &tile_collision_system); + sc_array_add(&scene->scene.systems, &hitbox_update_system); //sc_array_add(&scene->scene.systems, &update_tilemap_system); sc_array_add(&scene->scene.systems, &state_transition_update_system); sc_array_add(&scene->scene.systems, &player_ground_air_transition_system); diff --git a/engine/game_systems.c b/engine/game_systems.c index f590c83..8839bdd 100644 --- a/engine/game_systems.c +++ b/engine/game_systems.c @@ -405,6 +405,7 @@ void tile_collision_system(Scene_t *scene) checked_entities[other_ent_idx] = true; Entity_t *p_other_ent = get_entity(&scene->ent_manager, other_ent_idx); + if (!p_other_ent->m_alive) continue; // To only allow one way collision check if (p_other_ent->m_tag < p_ent->m_tag) continue; // To only allow one way collision check CBBox_t *p_other_bbox = get_component(&scene->ent_manager, p_other_ent, CBBOX_COMP_T); if (p_other_bbox == NULL) continue; @@ -421,51 +422,15 @@ void tile_collision_system(Scene_t *scene) } // TODO: Resolve all collision events - uint32_t collision_key; - sc_map_foreach(&data->collision_events, collision_key, collision_value) - { - ent_idx = (collision_key >> 16); - uint other_ent_idx = (collision_key & 0xFFFF); - Entity_t *p_ent = get_entity(&scene->ent_manager, ent_idx); - Entity_t *p_other_ent = get_entity(&scene->ent_manager, other_ent_idx); - if (!p_ent->m_alive || !p_other_ent->m_alive) continue; - if (p_ent->m_tag == PLAYER_ENT_TAG && p_other_ent->m_tag == CRATES_ENT_TAG) - { - CBBox_t *p_other_bbox = get_component(&scene->ent_manager, p_other_ent, CBBOX_COMP_T); - if (!p_other_bbox->fragile) continue; - - CTransform_t *p_ctransform = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T); - CBBox_t * p_bbox = get_component(&scene->ent_manager, p_ent, CBBOX_COMP_T); - CPlayerState_t * p_pstate = get_component(&scene->ent_manager, p_ent, CPLAYERSTATE_T); - CTransform_t *p_other_ct = get_component(&scene->ent_manager, p_other_ent, CTRANSFORM_COMP_T); - if ( - // TODO: Check Material of the crates - p_ctransform->position.y + p_bbox->size.y <= p_other_ct->position.y - ) - { - p_ctransform->velocity.y = -400; - if (p_pstate->jump_pressed) - { - p_ctransform->velocity.y = -600; - CJump_t * p_cjump = get_component(&scene->ent_manager, p_ent, CJUMP_COMP_T); - p_cjump->short_hop = false; - p_cjump->jumped = true; - } - } - - { - CTileCoord_t *p_tilecoord = get_component(&scene->ent_manager, p_other_ent, CTILECOORD_COMP_T); - for (size_t i=0;in_tiles;++i) - { - // Use previously store tile position - // Clear from those positions - unsigned int tile_idx = p_tilecoord->tiles[i]; - sc_map_del_64(&(tilemap.tiles[tile_idx].entities_set), other_ent_idx); - } - remove_entity(&scene->ent_manager, other_ent_idx); - } - } - } + //uint32_t collision_key; + //sc_map_foreach(&data->collision_events, collision_key, collision_value) + //{ + // ent_idx = (collision_key >> 16); + // uint other_ent_idx = (collision_key & 0xFFFF); + // Entity_t *p_ent = get_entity(&scene->ent_manager, ent_idx); + // Entity_t *p_other_ent = get_entity(&scene->ent_manager, other_ent_idx); + // if (!p_ent->m_alive || !p_other_ent->m_alive) continue; + //} sc_map_clear_32(&data->collision_events); // Level boundary collision @@ -749,6 +714,89 @@ void update_tilemap_system(Scene_t *scene) } } +void hitbox_update_system(Scene_t *scene) +{ + static bool checked_entities[MAX_COMP_POOL_SIZE] = {0}; + + LevelSceneData_t *data = (LevelSceneData_t *)scene->scene_data; + TileGrid_t tilemap = data->tilemap; + + unsigned int ent_idx; + CHitBox_t* p_hitbox; + //sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player) + sc_map_foreach(&scene->ent_manager.component_map[CHITBOX_T], ent_idx, p_hitbox) + { + Entity_t *p_ent = get_entity(&scene->ent_manager, ent_idx); + CTransform_t* p_ctransform = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T); + Vector2 hitbox_pos = Vector2Add(p_ctransform->position, p_hitbox->offset); + + unsigned int tile_x1 = (hitbox_pos.x) / TILE_SIZE; + unsigned int tile_y1 = (hitbox_pos.y) / TILE_SIZE; + unsigned int tile_x2 = (hitbox_pos.x + p_hitbox->size.x - 1) / TILE_SIZE; + unsigned int tile_y2 = (hitbox_pos.y + p_hitbox->size.y - 1) / TILE_SIZE; + + for (unsigned int tile_y=tile_y1; tile_y <= tile_y2; tile_y++) + { + for (unsigned int tile_x=tile_x1; tile_x <= tile_x2; tile_x++) + { + unsigned int tile_idx = tile_y * tilemap.width + tile_x; + unsigned int other_ent_idx; + memset(checked_entities, 0, sizeof(checked_entities)); + sc_map_foreach_key(&tilemap.tiles[tile_idx].entities_set, other_ent_idx) + { + if (other_ent_idx == ent_idx) continue; + if (checked_entities[other_ent_idx]) continue; + + Entity_t *p_other_ent = get_entity(&scene->ent_manager, other_ent_idx); + if (!p_other_ent->m_alive) continue; // To only allow one way collision check + if (p_other_ent->m_tag < p_ent->m_tag) continue; // To only allow one way collision check + + CHurtbox_t *p_other_hurtbox = get_component(&scene->ent_manager, p_other_ent, CHURTBOX_T); + if (p_other_hurtbox == NULL) continue; + CTransform_t *p_other_ct = get_component(&scene->ent_manager, p_other_ent, CTRANSFORM_COMP_T); + Vector2 hurtbox_pos = Vector2Add(p_other_ct->position, p_other_hurtbox->offset); + + Vector2 overlap; + if (find_AABB_overlap(hitbox_pos, p_hitbox->size, hurtbox_pos, p_other_hurtbox->size, &overlap)) + { + if (!p_other_hurtbox->fragile) continue; + if (p_other_ent->m_tag == CRATES_ENT_TAG) + { + + CBBox_t * p_bbox = get_component(&scene->ent_manager, p_ent, CBBOX_COMP_T); + CPlayerState_t * p_pstate = get_component(&scene->ent_manager, p_ent, CPLAYERSTATE_T); + if ( + // TODO: Check Material of the crates + p_ctransform->position.y + p_bbox->size.y <= p_other_ct->position.y + ) + { + p_ctransform->velocity.y = -400; + if (p_pstate->jump_pressed) + { + p_ctransform->velocity.y = -600; + CJump_t * p_cjump = get_component(&scene->ent_manager, p_ent, CJUMP_COMP_T); + p_cjump->short_hop = false; + p_cjump->jumped = true; + } + } + + CTileCoord_t *p_tilecoord = get_component(&scene->ent_manager, p_other_ent, CTILECOORD_COMP_T); + for (size_t i=0;in_tiles;++i) + { + // Use previously store tile position + // Clear from those positions + unsigned int tile_idx = p_tilecoord->tiles[i]; + sc_map_del_64(&(tilemap.tiles[tile_idx].entities_set), other_ent_idx); + } + remove_entity(&scene->ent_manager, other_ent_idx); + } + } + } + } + } + } +} + void init_level_scene_data(LevelSceneData_t *data) { sc_map_init_32(&data->collision_events, 128, 0); diff --git a/engine/game_systems.h b/engine/game_systems.h index 05975e4..4ae2247 100644 --- a/engine/game_systems.h +++ b/engine/game_systems.h @@ -12,4 +12,5 @@ void movement_update_system(Scene_t* scene); void player_ground_air_transition_system(Scene_t* scene); void state_transition_update_system(Scene_t *scene); void update_tilemap_system(Scene_t *scene); +void hitbox_update_system(Scene_t *scene); #endif // __GAME_SYSTEMS_H