Compare commits

...

3 Commits

Author SHA1 Message Date
En Yi 8d94943547 (Temporary) Fix corner collision issue
Changelog:
- When player move diagonally into a corner, collision is missing.
  This is because collision is resolved one-by-one and will not
  move the player if the new position still causes collision. In this
  literal corner case, player will not be moved as the player collide
  with both solids and resolving in either direction would still result
  in collision in the new position, unless both is resolved at the same
  time.
  Temporary 'fix' this by not checking the new position. No real idea
  on how to solve this for now.
2023-02-28 20:56:54 +08:00
En Yi c8ea03359c Prevent crate bashing at the corner
Changelog:
- Allow two hitboxes in hitbox component
- Create a cross-shaped hitboxes for player
2023-02-28 20:54:48 +08:00
En Yi 22b4190947 Refactor collision function signature 2023-02-25 11:54:43 +08:00
5 changed files with 225 additions and 175 deletions

View File

@ -14,7 +14,7 @@ enum ComponentEnum
CJUMP_COMP_T,
CPLAYERSTATE_T,
CCONTAINER_T,
CHITBOX_T,
CHITBOXES_T,
CHURTBOX_T,
};
typedef enum ComponentEnum ComponentEnum_t;
@ -97,12 +97,12 @@ typedef struct _CContainer_t
ContainerItem_t item;
}CContainer_t;
typedef struct _CHitBox_t
typedef struct _CHitBoxes_t
{
Vector2 offset;
Vector2 size;
Rectangle boxes[2];
uint8_t n_boxes;
bool strong;
}CHitBox_t;
}CHitBoxes_t;
typedef struct _CHurtbox_t
{

View File

@ -12,7 +12,7 @@ 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 CHitBoxes_t chitboxes_buffer[MAX_COMP_POOL_SIZE];
static CHurtbox_t churtbox_buffer[MAX_COMP_POOL_SIZE];
// Use hashmap as a Set
@ -40,7 +40,7 @@ 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}},
{chitboxes_buffer, MAX_COMP_POOL_SIZE, sizeof(CHitBoxes_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}};

View File

@ -30,7 +30,7 @@
#define PLAYER_C_YOFFSET (PLAYER_HEIGHT - PLAYER_C_HEIGHT)
#define PLAYER_C_XOFFSET (PLAYER_WIDTH - PLAYER_C_WIDTH)
#define PLAYER_MAX_SPEED 1000
#define PLAYER_MAX_SPEED 800
#define Y_FRICTION 0.98
#define X_FRICTION 0.85

View File

@ -68,16 +68,19 @@ static void level_scene_render_func(Scene_t* scene)
}
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);
CHitBoxes_t* p_hitbox = get_component(&scene->ent_manager, p_ent, CHITBOXES_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);
for (uint8_t i=0;i<p_hitbox->n_boxes;++i)
{
Rectangle rec = {
.x = p_ct->position.x + p_hitbox->boxes[i].x,
.y = p_ct->position.y + p_hitbox->boxes[i].y,
.width = p_hitbox->boxes[i].width,
.height = p_hitbox->boxes[i].height,
};
DrawRectangleLinesEx(rec, 1.5, ORANGE);
}
}
if (p_hurtbox != NULL)
{
@ -129,6 +132,10 @@ static void level_scene_render_func(Scene_t* scene)
CMovementState_t* p_mstate = get_component(&scene->ent_manager, p_ent, CMOVEMENTSTATE_T);
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, "Vel: %.3f\n %.3f", p_ct->velocity.x, p_ct->velocity.y);
DrawText(buffer, tilemap.width * TILE_SIZE + 128, 15, 12, BLACK);
//sprintf(buffer, "Accel: %.3f\n %.3f", p_ct->accel.x, p_ct->accel.y);
//DrawText(buffer, tilemap.width * TILE_SIZE + 128, 60, 12, BLACK);
sprintf(buffer, "Jumps: %u", p_cjump->jumps);
DrawText(buffer, tilemap.width * TILE_SIZE + 1, 60, 12, BLACK);
sprintf(buffer, "Crouch: %u", p_pstate->is_crouch);
@ -181,9 +188,22 @@ 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};
CHitBoxes_t* p_hitbox = add_component(&scene->ent_manager, p_ent, CHITBOXES_T);
p_hitbox->n_boxes = 2;
p_hitbox->boxes[0] = (Rectangle)
{
.x = p_bbox->size.x / 4,
.y = -1,
.width = p_bbox->size.x / 2,
.height = p_bbox->size.y + 2,
};
p_hitbox->boxes[1] = (Rectangle)
{
.x = -1,
.y = p_bbox->size.y / 4,
.width = p_bbox->size.x + 2 ,
.height = p_bbox->size.y / 2,
};
}
static void toggle_block_system(Scene_t *scene)

View File

@ -34,18 +34,26 @@ typedef struct TileArea
unsigned int tile_y2;
}TileArea_t;
static bool check_collision(unsigned int self_idx, Vector2 pos, Vector2 bbox_sz, TileArea_t area_to_check, TileGrid_t* grid, EntityManager_t* p_manager)
typedef struct CollideEntity
{
for(unsigned int tile_y = area_to_check.tile_y1; tile_y <= area_to_check.tile_y2; tile_y++)
unsigned int idx;
Rectangle bbox;
TileArea_t area;
}CollideEntity_t;
// ------------------------- Collision functions ------------------------------------
static bool check_collision(const CollideEntity_t *ent, TileGrid_t* grid, EntityManager_t* p_manager)
{
for(unsigned int tile_y = ent->area.tile_y1; tile_y <= ent->area.tile_y2; tile_y++)
{
for(unsigned int tile_x = area_to_check.tile_x1; tile_x <= area_to_check.tile_x2; tile_x++)
for(unsigned int tile_x = ent->area.tile_x1; tile_x <= ent->area.tile_x2; tile_x++)
{
unsigned int tile_idx = tile_y*grid->width + tile_x;
if (grid->tiles[tile_idx].solid) return true;
unsigned int ent_idx;
sc_map_foreach_value(&grid->tiles[tile_idx].entities_set, ent_idx)
{
if (self_idx == ent_idx) continue;
if (ent->idx == ent_idx) continue;
Entity_t * p_ent = get_entity(p_manager, ent_idx);
CTransform_t *p_ctransform = get_component(p_manager, p_ent, CTRANSFORM_COMP_T);
CBBox_t *p_bbox = get_component(p_manager, p_ent, CBBOX_COMP_T);
@ -54,7 +62,7 @@ static bool check_collision(unsigned int self_idx, Vector2 pos, Vector2 bbox_sz,
//if (p_bbox->solid && !p_bbox->fragile)
if (p_bbox->solid)
{
if (find_AABB_overlap(pos, bbox_sz, p_ctransform->position, p_bbox->size, &overlap))
if (find_AABB_overlap((Vector2){ent->bbox.x, ent->bbox.y}, (Vector2){ent->bbox.width, ent->bbox.height}, p_ctransform->position, p_bbox->size, &overlap))
{
return true;
}
@ -69,27 +77,89 @@ static bool check_collision(unsigned int self_idx, Vector2 pos, Vector2 bbox_sz,
static bool check_collision_at(unsigned int ent_idx, Vector2 pos, Vector2 bbox_sz, TileGrid_t* grid, Vector2 point, EntityManager_t* p_manager)
{
Vector2 new_pos = Vector2Add(pos, point);
TileArea_t area = {
.tile_x1 = (new_pos.x) / TILE_SIZE,
.tile_y1 = (new_pos.y) / TILE_SIZE,
.tile_x2 = (new_pos.x + bbox_sz.x - 1) / TILE_SIZE,
.tile_y2 = (new_pos.y + bbox_sz.y - 1) / TILE_SIZE
CollideEntity_t ent =
{
.idx = ent_idx,
.bbox = (Rectangle){new_pos.x, new_pos.y, bbox_sz.x, bbox_sz.y},
.area = (TileArea_t){
.tile_x1 = (new_pos.x) / TILE_SIZE,
.tile_y1 = (new_pos.y) / TILE_SIZE,
.tile_x2 = (new_pos.x + bbox_sz.x - 1) / TILE_SIZE,
.tile_y2 = (new_pos.y + bbox_sz.y - 1) / TILE_SIZE
}
};
return check_collision(ent_idx, new_pos, bbox_sz, area, grid, p_manager);
return check_collision(&ent, grid, p_manager);
}
static inline bool check_on_ground(unsigned int ent_idx, Vector2 pos, Vector2 bbox_sz, TileGrid_t* grid, EntityManager_t* p_manager)
{
pos.y += 1;
TileArea_t area = {
.tile_x1 = (pos.x) / TILE_SIZE,
.tile_y1 = (pos.y + bbox_sz.y - 1) / TILE_SIZE,
.tile_x2 = (pos.x + bbox_sz.x - 1) / TILE_SIZE,
.tile_y2 = (pos.y + bbox_sz.y - 1) / TILE_SIZE,
};
return check_collision(ent_idx, pos, bbox_sz, area, grid, p_manager);
return check_collision_at(ent_idx, pos, bbox_sz, grid, (Vector2){0, 1}, p_manager);
}
static bool check_collision_and_move(EntityManager_t* p_manager, TileGrid_t* tilemap,
unsigned int ent_idx, CTransform_t *const p_ct, Vector2 sz,
Vector2 other_pos, Vector2 other_sz, bool other_solid,
uint32_t* collision_value
)
{
Vector2 overlap = {0,0};
Vector2 prev_overlap = {0,0};
if (find_AABB_overlap(p_ct->position, sz, other_pos, other_sz, &overlap))
{
// If there is collision, use previous overlap to determine direction
find_AABB_overlap(p_ct->prev_position, sz, other_pos, other_sz, &prev_overlap);
// Store collision event here
// Check collision on x or y axis
// Encode key and value, -ve is left and up, +ve is right and down
uint8_t dir_to_move = 0;
Vector2 offset = {0, 0};
if (fabs(prev_overlap.y) > fabs(prev_overlap.x))
{
offset.x = overlap.x;
*collision_value = (((overlap.x > 0?1:0)<< 14) | ( (uint16_t)(fabs(overlap.x)) ));
}
else if (fabs(prev_overlap.x) > fabs(prev_overlap.y))
{
dir_to_move = 1;
offset.y = overlap.y;
*collision_value = (((overlap.y > 0?3:2)<< 14) | ( (uint16_t)(fabs(overlap.y)) ));
}
else if (fabs(overlap.x) < fabs(overlap.y))
{
offset.x = overlap.x;
*collision_value = (((overlap.x > 0?1:0)<< 14) | ( (uint16_t)(fabs(overlap.x)) ));
}
else
{
dir_to_move = 1;
offset.y = overlap.y;
*collision_value = (((overlap.y > 0?3:2)<< 14) | ( (uint16_t)(fabs(overlap.y)) ));
}
// Resolve collision via moving player by the overlap amount only if other is solid
// also check for empty to prevent creating new collision. Not fool-proof, but good enough
//if (other_solid && !check_collision_at(ent_idx, p_ct->position, sz, tilemap, offset, p_manager))
if (other_solid)
{
p_ct->position = Vector2Add(p_ct->position, offset);
if (dir_to_move == 0)
//if (offset.x != 0)
{
p_ct->velocity.x = 0;
}
else
{
p_ct->velocity.y = 0;
}
}
return true;
}
return false;
}
static Vector2 shift_bbox(Vector2 bbox, Vector2 new_bbox, AnchorPoint_t anchor)
{
Vector2 p1;
@ -179,11 +249,13 @@ void player_movement_input_system(Scene_t* scene)
if (!in_water)
{
p_pstate->player_dir.y = 0;
p_ctransform->accel = Vector2Scale(Vector2Normalize(p_pstate->player_dir), MOVE_ACCEL/1.2);
p_ctransform->accel = Vector2Scale(Vector2Normalize(p_pstate->player_dir), MOVE_ACCEL);
}
else
{
p_ctransform->accel = Vector2Scale(Vector2Normalize(p_pstate->player_dir), MOVE_ACCEL);
// Although this can be achieved via higher friction, i'll explain away as the player is not
// good with swimming, resulting in lower movement acceleration
p_ctransform->accel = Vector2Scale(Vector2Normalize(p_pstate->player_dir), MOVE_ACCEL/1.2);
}
// Short Hop
@ -297,66 +369,14 @@ void player_bbox_update_system(Scene_t *scene)
set_bbox(p_bbox, new_bbox.x, new_bbox.y);
p_ctransform->position = Vector2Add(p_ctransform->position, offset);
}
CHitBoxes_t* p_hitbox = get_component(&scene->ent_manager, p_player, CHITBOXES_T);
p_hitbox->boxes[0].height = p_bbox->size.y + 2;
p_hitbox->boxes[1].y = p_bbox->size.y / 4;
p_hitbox->boxes[1].height = p_bbox->size.y / 2;
}
}
static bool check_collision_and_move(unsigned int ent_idx, EntityManager_t* p_manager, TileGrid_t* tilemap, CTransform_t *const p_ct, Vector2 sz, Vector2 other_pos, Vector2 other_sz, bool other_solid, uint32_t* collision_value)
{
Vector2 overlap = {0,0};
Vector2 prev_overlap = {0,0};
if (find_AABB_overlap(p_ct->position, sz, other_pos, other_sz, &overlap))
{
// If there is collision, use previous overlap to determine direction
find_AABB_overlap(p_ct->prev_position, sz, other_pos, other_sz, &prev_overlap);
// Store collision event here
// Check collision on x or y axis
// Encode key and value, -ve is left and up, +ve is right and down
uint8_t dir_to_move = 0;
Vector2 offset = {0, 0};
if (fabs(prev_overlap.y) > fabs(prev_overlap.x))
{
offset.x = overlap.x;
*collision_value = (((overlap.x > 0?1:0)<< 14) | ( (uint16_t)(fabs(overlap.x)) ));
}
else if (fabs(prev_overlap.x) > fabs(prev_overlap.y))
{
dir_to_move = 1;
offset.y = overlap.y;
*collision_value = (((overlap.y > 0?3:2)<< 14) | ( (uint16_t)(fabs(overlap.y)) ));
}
else if (fabs(overlap.x) < fabs(overlap.y))
{
offset.x = overlap.x;
*collision_value = (((overlap.x > 0?1:0)<< 14) | ( (uint16_t)(fabs(overlap.x)) ));
}
else
{
dir_to_move = 1;
offset.y = overlap.y;
*collision_value = (((overlap.y > 0?3:2)<< 14) | ( (uint16_t)(fabs(overlap.y)) ));
}
// Resolve collision via moving player by the overlap amount only if other is solid
// also check for empty to prevent creating new collision. Not fool-proof, but good enough
if (other_solid && !check_collision_at(ent_idx, p_ct->position, sz, tilemap, offset, p_manager))
{
p_ct->position = Vector2Add(p_ct->position, offset);
if (dir_to_move == 0)
//if (offset.x != 0)
{
p_ct->velocity.x = 0;
}
else
{
p_ct->velocity.y = 0;
}
}
return true;
}
return false;
}
void tile_collision_system(Scene_t *scene)
{
static bool checked_entities[MAX_COMP_POOL_SIZE] = {0};
@ -392,7 +412,7 @@ void tile_collision_system(Scene_t *scene)
other.x = (tile_idx % tilemap.width) * TILE_SIZE;
other.y = (tile_idx / tilemap.width) * TILE_SIZE; // Precision loss is intentional
check_collision_and_move(ent_idx, &scene->ent_manager, &tilemap, p_ctransform, p_bbox->size, other, TILE_SZ, true, &collision_value);
check_collision_and_move(&scene->ent_manager, &tilemap, ent_idx, p_ctransform, p_bbox->size, other, TILE_SZ, true, &collision_value);
}
else
@ -412,7 +432,7 @@ void tile_collision_system(Scene_t *scene)
if (p_other_bbox == NULL) continue;
CTransform_t *p_other_ct = get_component(&scene->ent_manager, p_other_ent, CTRANSFORM_COMP_T);
if (check_collision_and_move(ent_idx, &scene->ent_manager, &tilemap, p_ctransform, p_bbox->size, p_other_ct->position, p_other_bbox->size, p_other_bbox->solid, &collision_value))
if (check_collision_and_move(&scene->ent_manager, &tilemap, ent_idx, p_ctransform, p_bbox->size, p_other_ct->position, p_other_bbox->size, p_other_bbox->solid, &collision_value))
{
uint32_t collision_key = ((ent_idx << 16) | other_ent_idx);
sc_map_put_32(&data->collision_events, collision_key, collision_value);
@ -527,33 +547,37 @@ void global_external_forces_system(Scene_t *scene)
// Zero out acceleration for contacts with sturdy entites and tiles
Vector2 new_pos = p_ctransform->position;
new_pos.x--;
TileArea_t area = {
.tile_x1 = (p_ctransform->position.x - 1) / TILE_SIZE,
.tile_y1 = (p_ctransform->position.y) / TILE_SIZE,
.tile_x2 = (p_ctransform->position.x - 1) / TILE_SIZE,
.tile_y2 = (p_ctransform->position.y + p_bbox->size.y - 1) / TILE_SIZE,
//Vector2 new_pos = p_ctransform->position;
CollideEntity_t ent =
{
.idx = ent_idx,
.bbox = (Rectangle){p_ctransform->position.x - 1, p_ctransform->position.y, p_bbox->size.x, p_bbox->size.y},
.area = (TileArea_t){
.tile_x1 = (p_ctransform->position.x - 1) / TILE_SIZE,
.tile_y1 = (p_ctransform->position.y) / TILE_SIZE,
.tile_x2 = (p_ctransform->position.x - 1) / TILE_SIZE,
.tile_y2 = (p_ctransform->position.y + p_bbox->size.y - 1) / TILE_SIZE,
}
};
if (check_collision(ent_idx, new_pos, p_bbox->size, area, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.x < 0) p_ctransform->accel.x = 0;
if (check_collision(&ent, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.x < 0) p_ctransform->accel.x = 0;
new_pos.x += 2; // 2 to account for the previous subtraction
area.tile_x1 = (p_ctransform->position.x + p_bbox->size.x + 1) / TILE_SIZE;
area.tile_x2 = area.tile_x1;
if (check_collision(ent_idx, new_pos, p_bbox->size, area, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.x > 0) p_ctransform->accel.x = 0;
ent.bbox.x += 2; // 2 to account for the previous subtraction
ent.area.tile_x1 = (p_ctransform->position.x + p_bbox->size.x + 1) / TILE_SIZE;
ent.area.tile_x2 = ent.area.tile_x1;
if (check_collision(&ent, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.x > 0) p_ctransform->accel.x = 0;
new_pos.x -= 2;
new_pos.y--;
area.tile_x1 = (p_ctransform->position.x) / TILE_SIZE,
area.tile_x2 = (p_ctransform->position.x - 1) / TILE_SIZE,
area.tile_y1 = (p_ctransform->position.y - 1) / TILE_SIZE,
area.tile_y1 = area.tile_y2;
if (check_collision(ent_idx, new_pos, p_bbox->size, area, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.y < 0) p_ctransform->accel.y = 0;
ent.bbox.x -= 2;
ent.bbox.y--;
ent.area.tile_x1 = (p_ctransform->position.x) / TILE_SIZE,
ent.area.tile_x2 = (p_ctransform->position.x - 1) / TILE_SIZE,
ent.area.tile_y1 = (p_ctransform->position.y - 1) / TILE_SIZE,
ent.area.tile_y1 = ent.area.tile_y2;
if (check_collision(&ent, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.y < 0) p_ctransform->accel.y = 0;
new_pos.y += 2;
area.tile_y1 = (p_ctransform->position.y + p_bbox->size.y + 1) / TILE_SIZE,
area.tile_y1 = area.tile_y2;
if (check_collision(ent_idx, new_pos, p_bbox->size, area, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.y > 0) p_ctransform->accel.y = 0;
ent.bbox.y += 2;
ent.area.tile_y1 = (p_ctransform->position.y + p_bbox->size.y + 1) / TILE_SIZE,
ent.area.tile_y1 = ent.area.tile_y2;
if (check_collision(&ent, &data->tilemap, &scene->ent_manager) && p_ctransform->accel.y > 0) p_ctransform->accel.y = 0;
}
}
@ -723,73 +747,79 @@ void hitbox_update_system(Scene_t *scene)
TileGrid_t tilemap = data->tilemap;
unsigned int ent_idx;
CHitBox_t* p_hitbox;
CHitBoxes_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)
sc_map_foreach(&scene->ent_manager.component_map[CHITBOXES_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 (uint8_t i=0;i<p_hitbox->n_boxes;++i)
{
for (unsigned int tile_x=tile_x1; tile_x <= tile_x2; tile_x++)
Vector2 hitbox_pos = {
.x = p_ctransform->position.x + p_hitbox->boxes[i].x,
.y = p_ctransform->position.y + p_hitbox->boxes[i].y,
};
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->boxes[i].width - 1) / TILE_SIZE;
unsigned int tile_y2 = (hitbox_pos.y + p_hitbox->boxes[i].height - 1) / TILE_SIZE;
for (unsigned int tile_y=tile_y1; tile_y <= tile_y2; tile_y++)
{
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)
for (unsigned int tile_x=tile_x1; tile_x <= tile_x2; tile_x++)
{
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))
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 (!p_other_hurtbox->fragile) continue;
if (p_other_ent->m_tag == CRATES_ENT_TAG)
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, (Vector2){p_hitbox->boxes[i].width, p_hitbox->boxes[i].height}, hurtbox_pos, p_other_hurtbox->size, &overlap))
{
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
)
if (!p_other_hurtbox->fragile) continue;
if (p_other_ent->m_tag == CRATES_ENT_TAG)
{
p_ctransform->velocity.y = -400;
if (p_pstate->jump_pressed)
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 = -600;
CJump_t * p_cjump = get_component(&scene->ent_manager, p_ent, CJUMP_COMP_T);
p_cjump->short_hop = false;
p_cjump->jumped = true;
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;i<p_tilecoord->n_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);
CTileCoord_t *p_tilecoord = get_component(&scene->ent_manager, p_other_ent, CTILECOORD_COMP_T);
for (size_t i=0;i<p_tilecoord->n_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);
}
remove_entity(&scene->ent_manager, other_ent_idx);
}
}
}