From 6fc231764788a41aee640300e1f1fce73bb6a857 Mon Sep 17 00:00:00 2001 From: En Yi Date: Fri, 13 Jan 2023 21:13:39 +0800 Subject: [PATCH] Add entity<->entity collision checks Changelog: - Add solid field in bbox component - Ground check now checks for solid entities - Reset acceleration after movement update - Crates are considered solid - Print info on spawning entities and spawned entities --- components.h | 1 + scene_impl.c | 106 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 81 insertions(+), 26 deletions(-) diff --git a/components.h b/components.h index 50e4819..63961c2 100644 --- a/components.h +++ b/components.h @@ -22,6 +22,7 @@ typedef struct _CBBox_t Vector2 size; Vector2 offset; Vector2 half_size; + bool solid; }CBBox_t; typedef struct _CTransform_t diff --git a/scene_impl.c b/scene_impl.c index 6314a07..36472ec 100644 --- a/scene_impl.c +++ b/scene_impl.c @@ -89,15 +89,30 @@ static bool check_collision_at(Vector2 pos, Vector2 bbox_sz, TileGrid_t* grid, V return false; } -static inline bool check_on_ground(Vector2 pos, Vector2 bbox_sz, TileGrid_t* grid) +static inline bool check_on_ground(unsigned int ent_idx, Vector2 pos, Vector2 bbox_sz, TileGrid_t* grid, Scene_t* scene) { + pos.y += 1; unsigned int tile_x1 = (pos.x) / TILE_SIZE; unsigned int tile_x2 = (pos.x + bbox_sz.x - 1) / TILE_SIZE; - unsigned int tile_y = (pos.y + bbox_sz.y) / TILE_SIZE; + unsigned int tile_y = (pos.y + bbox_sz.y - 1) / TILE_SIZE; for(unsigned int tile_x = tile_x1; tile_x <= tile_x2; tile_x++) { - if (grid->tiles[tile_y*grid->width + tile_x].solid) return true; + unsigned int tile_idx = tile_y*grid->width + tile_x; + if (grid->tiles[tile_idx].solid) return true; + + unsigned int other_ent_idx; + sc_map_foreach_key(&grid->tiles[tile_idx].entities_set, other_ent_idx) + { + Vector2 overlap; + if (other_ent_idx == ent_idx) continue; + Entity_t *p_other_ent = get_entity(&scene->ent_manager, other_ent_idx); + CBBox_t *p_other_bbox = get_component(&scene->ent_manager, p_other_ent, CBBOX_COMP_T); + if (p_other_bbox == NULL || !p_other_bbox->solid) continue; + + CTransform_t *p_other_ct = get_component(&scene->ent_manager, p_other_ent, CTRANSFORM_COMP_T); + if (find_AABB_overlap(pos, bbox_sz, p_other_ct->position, p_other_bbox->size, &overlap)) return true; + } } return false; } @@ -243,13 +258,13 @@ static void level_scene_render_func(Scene_t* scene) } // For DEBUG + char buffer[64]; sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_ent) { CTransform_t* p_ct = get_component(&scene->ent_manager, p_ent, CTRANSFORM_COMP_T); CJump_t* p_cjump = get_component(&scene->ent_manager, p_ent, CJUMP_COMP_T); CPlayerState_t* p_pstate = get_component(&scene->ent_manager, p_ent, CPLAYERSTATE_T); CMovementState_t* p_mstate = get_component(&scene->ent_manager, p_ent, CMOVEMENTSTATE_T); - char buffer[64]; sprintf(buffer, "Pos: %.3f\n %.3f", p_ct->position.x, p_ct->position.y); DrawText(buffer, tilemap.width * TILE_SIZE + 1, 15, 12, BLACK); sprintf(buffer, "Jumps: %u", p_cjump->jumps); @@ -260,9 +275,13 @@ static void level_scene_render_func(Scene_t* scene) DrawText(buffer, tilemap.width * TILE_SIZE + 1, 90, 12, BLACK); sprintf(buffer, "Water: %s", p_mstate->water_state & 1? "YES":"NO"); DrawText(buffer, tilemap.width * TILE_SIZE + 1, 120, 12, BLACK); - sprintf(buffer, "Spawn Entity: %u", current_spawn_selection); - DrawText(buffer, tilemap.width * TILE_SIZE + 1, 240, 12, BLACK); } + sprintf(buffer, "Spawn Entity: %u", current_spawn_selection); + DrawText(buffer, tilemap.width * TILE_SIZE + 1, 240, 12, BLACK); + sprintf(buffer, "Number of Entities: %u", sc_map_size_64v(&scene->ent_manager.entities)); + 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 void player_movement_input_system(Scene_t* scene) @@ -281,8 +300,6 @@ static void player_movement_input_system(Scene_t* scene) CTransform_t* p_ctransform = get_component(&scene->ent_manager, p_player, CTRANSFORM_COMP_T); CJump_t* p_cjump = get_component(&scene->ent_manager, p_player, CJUMP_COMP_T); CMovementState_t* p_mstate = get_component(&scene->ent_manager, p_player, CMOVEMENTSTATE_T); - p_ctransform->accel.x = 0; - p_ctransform->accel.y = 0; bool in_water = (p_mstate->water_state & 1); if (!in_water) @@ -498,7 +515,8 @@ static void movement_update_system(Scene_t* scene) p_ctransform->position, Vector2Scale(p_ctransform->velocity, delta_time) ); - + p_ctransform->accel.x = 0; + p_ctransform->accel.y = 0; } } @@ -596,27 +614,62 @@ static void tile_collision_system(Scene_t *scene) } else { + unsigned int other_ent_idx; // TODO: check against the entities of each involved tiles + sc_map_foreach_key(&tilemap.tiles[tile_idx].entities_set, other_ent_idx) + { + if (other_ent_idx == ent_idx) continue; + Entity_t *p_other_ent = get_entity(&scene->ent_manager, other_ent_idx); + CBBox_t *p_other_bbox = get_component(&scene->ent_manager, p_other_ent, CBBOX_COMP_T); + if (p_other_bbox == NULL || !p_other_bbox->solid) continue; + + CTransform_t *p_other_ct = get_component(&scene->ent_manager, p_other_ent, CTRANSFORM_COMP_T); + if (find_AABB_overlap(p_ctransform->position, p_bbox->size, p_other_ct->position, p_other_bbox->size, &overlap)) + { + find_AABB_overlap(p_ctransform->prev_position, p_bbox->size, p_other_ct->prev_position, p_other_bbox->size, &prev_overlap); + if (fabs(prev_overlap.y) > fabs(prev_overlap.x)) + { + p_ctransform->position.x += overlap.x; + p_ctransform->velocity.x = 0; + } + else if (fabs(prev_overlap.x) > fabs(prev_overlap.y)) + { + p_ctransform->position.y += overlap.y; + p_ctransform->velocity.y = 0; + } + else if (fabs(overlap.x) < fabs(overlap.y)) + { + p_ctransform->position.x += overlap.x; + p_ctransform->velocity.x = 0; + } + else + { + p_ctransform->position.y += overlap.y; + p_ctransform->velocity.y = 0; + } + } + } } - // Level boundary collision - unsigned int level_width = tilemap.width * TILE_SIZE; - if(p_ctransform->position.x < 0 || p_ctransform->position.x + p_bbox->size.x > level_width) - { - p_ctransform->position.x = (p_ctransform->position.x < 0) ? 0 : p_ctransform->position.x; - p_ctransform->position.x = (p_ctransform->position.x + p_bbox->size.x > level_width) ? level_width - p_bbox->size.x : p_ctransform->position.x; - p_ctransform->velocity.x *= -1; - } - - unsigned int level_height = tilemap.height * TILE_SIZE; - if(p_ctransform->position.y < 0 || p_ctransform->position.y + p_bbox->size.y > level_height) - { - p_ctransform->position.y = (p_ctransform->position.y < 0) ? 0 : p_ctransform->position.y; - p_ctransform->position.y = (p_ctransform->position.y + p_bbox->size.y > level_height) ? level_height - p_bbox->size.y : p_ctransform->position.y; - p_ctransform->velocity.y *= -1; - } } } + + // Level boundary collision + unsigned int level_width = tilemap.width * TILE_SIZE; + if(p_ctransform->position.x < 0 || p_ctransform->position.x + p_bbox->size.x > level_width) + { + p_ctransform->position.x = (p_ctransform->position.x < 0) ? 0 : p_ctransform->position.x; + p_ctransform->position.x = (p_ctransform->position.x + p_bbox->size.x > level_width) ? level_width - p_bbox->size.x : p_ctransform->position.x; + p_ctransform->velocity.x *= -1; + } + + unsigned int level_height = tilemap.height * TILE_SIZE; + if(p_ctransform->position.y < 0 || p_ctransform->position.y + p_bbox->size.y > level_height) + { + p_ctransform->position.y = (p_ctransform->position.y < 0) ? 0 : p_ctransform->position.y; + p_ctransform->position.y = (p_ctransform->position.y + p_bbox->size.y > level_height) ? level_height - p_bbox->size.y : p_ctransform->position.y; + p_ctransform->velocity.y *= -1; + } // Deal with float precision, by rounding when it is near to an integer enough by 2 dp float decimal; float fractional = modff(p_ctransform->position.x, &decimal); @@ -657,7 +710,7 @@ static void state_transition_update_system(Scene_t *scene) CBBox_t *p_bbox = get_component(&scene->ent_manager, p_ent, CBBOX_COMP_T); if (p_ctransform == NULL || p_bbox == NULL) continue; - bool on_ground = check_on_ground(p_ctransform->position, p_bbox->size, &data->tilemap); + bool on_ground = check_on_ground(ent_idx, p_ctransform->position, p_bbox->size, &data->tilemap, scene); bool in_water = false; if (!(p_mstate->water_state & 1)) { @@ -743,6 +796,7 @@ static void spawn_crate(Scene_t *scene, unsigned int tile_idx) Entity_t *p_crate = add_entity(&scene->ent_manager, CRATES_ENT_TAG); CBBox_t *p_bbox = add_component(&scene->ent_manager, p_crate, CBBOX_COMP_T); set_bbox(p_bbox, TILE_SIZE, TILE_SIZE); + p_bbox->solid = true; CTransform_t *p_ctransform = add_component(&scene->ent_manager, p_crate, CTRANSFORM_COMP_T); p_ctransform->position.x = (tile_idx % data->tilemap.width) * TILE_SIZE; p_ctransform->position.y = (tile_idx / data->tilemap.width) * TILE_SIZE;