From 0b5f34b9f3aeae10686960f57a923b0a9d26a97a Mon Sep 17 00:00:00 2001 From: En Yi Date: Tue, 14 Nov 2023 22:31:28 +0800 Subject: [PATCH] Modify water upthrust behaviour Changelog: - Upthrust now depends on water area overlap with entity - Fix complete overlap checks --- engine/AABB.c | 10 ++-- engine/EC.h | 1 + scenes/game_systems.c | 115 ++++++++++++++++-------------------------- 3 files changed, 51 insertions(+), 75 deletions(-) diff --git a/engine/AABB.c b/engine/AABB.c index 17a896b..ee2d48b 100644 --- a/engine/AABB.c +++ b/engine/AABB.c @@ -3,13 +3,17 @@ uint8_t find_1D_overlap(Vector2 l1, Vector2 l2, float* overlap) { // No Overlap - if (l1.y <= l2.x || l2.y <= l1.x) return 0; + if (l1.y < l2.x || l2.y < l1.x) return 0; - if (l1.x >= l2.x && l1.y <= l2.y) + if ( + (l1.x >= l2.x && l1.y <= l2.y) + || (l2.x >= l1.x && l2.y <= l1.y) + ) { // Complete Overlap, any direction is possible // Cannot give a singular value, but return something anyways - *overlap = l2.y-l2.x + l1.y-l1.x; + //*overlap = l2.y-l2.x + l1.y-l1.x; + *overlap = fmin(fabs(l2.y-l2.x), fabs(l1.y-l1.x)); return 2; } //Partial overlap diff --git a/engine/EC.h b/engine/EC.h index b5aa6d5..8de97b7 100644 --- a/engine/EC.h +++ b/engine/EC.h @@ -59,6 +59,7 @@ typedef struct _CMovementState_t { uint8_t ground_state; uint8_t water_state; uint8_t x_dir; + float water_overlap; } CMovementState_t; // This is to store the occupying tiles diff --git a/scenes/game_systems.c b/scenes/game_systems.c index c565c00..14b9986 100644 --- a/scenes/game_systems.c +++ b/scenes/game_systems.c @@ -916,37 +916,55 @@ void global_external_forces_system(Scene_t* scene) continue; } - if (!(p_mstate->ground_state & 1)) + // Upthrust depends on water overlapping + if (p_bbox != NULL) { - // Only apply upthrust if center is in water - // If need more accuracy, need to find area of overlap - if (p_mstate->water_state & 1) + unsigned int tile_x1 = (p_ctransform->position.x) / TILE_SIZE; + unsigned int tile_y1 = (p_ctransform->position.y) / TILE_SIZE; + unsigned int tile_x2 = (p_ctransform->position.x + p_bbox->size.x) / TILE_SIZE; + unsigned int tile_y2 = (p_ctransform->position.y + p_bbox->size.y) / TILE_SIZE; + float water_area = 0; + for (unsigned int tile_y = tile_y1; tile_y <= tile_y2; tile_y++) { - Vector2 player_center = (Vector2){ - .x = p_ctransform->position.x + p_bbox->half_size.x, - .y = p_ctransform->position.y + p_bbox->half_size.y, - }; - unsigned int tile_idx = get_tile_idx( - player_center.x, - player_center.y, - data->tilemap.width - ); - if (data->tilemap.tiles[tile_idx].water_level > 0) + for (unsigned int tile_x = tile_x1; tile_x <= tile_x2; tile_x++) { - uint32_t water_height = data->tilemap.tiles[tile_idx].water_level * WATER_BBOX_STEP; - Rectangle box = { - .x = (tile_idx % data->tilemap.width) * data->tilemap.tile_size, - .y = (tile_idx / data->tilemap.width + 1) * data->tilemap.tile_size - water_height, - .width = data->tilemap.tile_size, - .height = water_height, - }; - - if (point_in_AABB(player_center, box)) + unsigned int tile_idx = tile_y * data->tilemap.width + tile_x; + if (data->tilemap.tiles[tile_idx].water_level > 0) { - p_ctransform->accel = Vector2Multiply(Vector2Add(p_ctransform->accel, UPTHRUST), p_ctransform->shape_factor); + uint32_t water_height = data->tilemap.tiles[tile_idx].water_level * WATER_BBOX_STEP; + Vector2 water_tl = { + .x = (tile_idx % data->tilemap.width) * data->tilemap.tile_size, + .y = (tile_idx / data->tilemap.width + 1) * data->tilemap.tile_size - water_height}; + + Vector2 water_sz = { + .x = data->tilemap.tile_size, + .y = water_height, + }; + + Vector2 overlap; + if (find_AABB_overlap( + p_ctransform->position, p_bbox->size, + water_tl, water_sz, &overlap + )) + { + water_area += fabs(overlap.x * overlap.y); + } } } } + p_mstate->water_overlap = water_area/(p_bbox->size.x * p_bbox->size.y); + } + + if (!(p_mstate->ground_state & 1)) + { + p_ctransform->accel = Vector2Multiply( + Vector2Add( + p_ctransform->accel, + Vector2Scale(UPTHRUST, p_mstate->water_overlap) + ), + p_ctransform->shape_factor + ); + p_ctransform->accel = Vector2Add(p_ctransform->accel, GRAVITY); } @@ -1407,54 +1425,7 @@ void state_transition_update_system(Scene_t* scene) p_ctransform->grav_timer = p_ctransform->grav_delay; } - bool in_water = false; - if (!(p_mstate->water_state & 1)) - { - Vector2 player_center = (Vector2){ - .x = p_ctransform->position.x + p_bbox->half_size.x, - .y = p_ctransform->position.y + p_bbox->half_size.y, - }; - unsigned int tile_idx = get_tile_idx( - player_center.x, - player_center.y, - data->tilemap.width - ); - if (data->tilemap.tiles[tile_idx].water_level > 0) - { - uint32_t water_height = data->tilemap.tiles[tile_idx].water_level * WATER_BBOX_STEP; - Rectangle box = { - .x = (tile_idx % data->tilemap.width) * data->tilemap.tile_size, - .y = (tile_idx / data->tilemap.width + 1) * data->tilemap.tile_size - water_height, - .width = data->tilemap.tile_size, - .height = water_height, - }; - - in_water = point_in_AABB(player_center, box); - } - } - else - { - unsigned int tile_x1 = (p_ctransform->position.x) / TILE_SIZE; - unsigned int tile_y1 = (p_ctransform->position.y) / TILE_SIZE; - unsigned int tile_x2 = (p_ctransform->position.x + p_bbox->size.x) / TILE_SIZE; - unsigned int tile_y2 = (p_ctransform->position.y + p_bbox->size.y) / 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 * data->tilemap.width + tile_x; - if (data->tilemap.tiles[tile_idx].water_level == 0) continue; - - uint32_t water_height = data->tilemap.tiles[tile_idx].water_level * WATER_BBOX_STEP; - Vector2 tl = {tile_x * data->tilemap.tile_size, (tile_y + 1) * data->tilemap.tile_size - water_height}; - in_water |= find_AABB_overlap( - p_ctransform->position, p_bbox->size, - tl, (Vector2){data->tilemap.tile_size, water_height} - , NULL - ) > 0; - } - } - } + bool in_water = p_mstate->water_overlap > 0.4; p_mstate->ground_state <<= 1; p_mstate->ground_state |= on_ground? 1:0; p_mstate->ground_state &= 3;