From 5d96a0228470ea001d01aa232a2c43c449fae926 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Sun, 28 Jan 2024 14:09:27 +0100 Subject: [PATCH] Fix hitboxes for entities --- game/buildings.c | 6 ++++-- game/entity_factory.c | 14 ++++++++++---- game/entity_factory.h | 2 +- game/game_tileset.h | 32 ++++++++++++++++---------------- game/main.c | 8 ++++---- game/map_init.c | 7 +++++-- game/systems/s_entity.c | 12 +++--------- game/systems/s_input.c | 11 ++++------- game/systems/systems.c | 18 ++++++++++++++++-- game/systems/systems.h | 4 +++- scripts/extract_tileset.py | 2 +- 11 files changed, 67 insertions(+), 49 deletions(-) diff --git a/game/buildings.c b/game/buildings.c index 500187f..b63d87a 100644 --- a/game/buildings.c +++ b/game/buildings.c @@ -28,7 +28,7 @@ bool canPlaceBuilding(Game *game, BuildingType type, BzTile tileX, BzTile tileY) BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, buildArea.x, buildArea.y, buildArea.width, buildArea.height); while (bzSpatialGridQueryNext(&it)) { ecs_entity_t entity = *(ecs_entity_t *) it.data; Rectangle bounds; - if (!getEntityHitBox(entity, NULL, &bounds)) continue; + if (!entityGetHitBox(entity, NULL, &bounds)) continue; if (CheckCollisionRecs(buildArea, bounds)) return false; @@ -62,6 +62,7 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type, .x = sizeX * tileWidth, .y = sizeY * tileHeight, }; + pos.y += size.y; HitBox hitbox = { .x = 0.0f, .y = 0.0f, .width = size.x, @@ -73,8 +74,9 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type, ecs_set_ptr(ECS, building, HitBox, &hitbox); ecs_set(ECS, building, Rotation, {0}); + HitBox tHitBox = entityTransformHitBox(pos, hitbox); SpatialGridID gridID = bzSpatialGridInsert(game->entityGrid, &building, - pos.x, pos.y, hitbox.width, hitbox.height); + tHitBox.x, tHitBox.y, tHitBox.width, tHitBox.height); ecs_set_ptr(ECS, building, SpatialGridID, &gridID); ecs_set(ECS, building, Owner, {player}); BzTileset *tileset = &game->tileset; diff --git a/game/entity_factory.c b/game/entity_factory.c index 6b2e99c..9ea8b84 100644 --- a/game/entity_factory.c +++ b/game/entity_factory.c @@ -8,7 +8,7 @@ ecs_entity_t entityCreateEmpty() { return e; } -ecs_entity_t entityCreateBaseUnit(const Position position, Player player, +ecs_entity_t entityCreateBaseUnit(const Position position, f32 size, Player player, EntityType type, AnimType startAnim, Game *game) { BzTileset *tileset = &game->tileset; BzTileID tileID = getEntityTile(type); @@ -19,7 +19,13 @@ ecs_entity_t entityCreateBaseUnit(const Position position, Player player, HitBox hitbox = getEntityHitBoxRec(tileID); ecs_entity_t e = entityCreateEmpty(); ecs_set_ptr(ECS, e, Position, &position); - //ecs_set_ptr(ECS, e, HitBox, &hitbox); + f32 scl = size / region.rec.width; + ecs_set(ECS, e, Size, {region.rec.width * scl, region.rec.height * scl}); + hitbox.x *= scl; + hitbox.y *= scl; + hitbox.width *= scl; + hitbox.height *= scl; + ecs_set_ptr(ECS, e, HitBox, &hitbox); BzSpatialGridID spatialID = bzSpatialGridInsert(game->entityGrid, &e, position.x + hitbox.x, position.y + hitbox.y, hitbox.width, hitbox.height); @@ -60,13 +66,13 @@ ecs_entity_t entityCreateBaseUnit(const Position position, Player player, } ecs_entity_t entityCreateSoldier(const Position position, Player player, Game *game) { - ecs_entity_t e = entityCreateBaseUnit(position, player, ENTITY_SOLDIER, ANIM_IDLE, game); + ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_SOLDIER, ANIM_IDLE, game); return e; } ecs_entity_t entityCreateWorker(const Position position, Player player, Game *game) { BzTileset *tileset = &game->tileset; - ecs_entity_t e = entityCreateBaseUnit(position, player, ENTITY_WORKER, ANIM_IDLE, game); + ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_WORKER, ANIM_IDLE, game); ecs_set(ECS, e, Worker, { .collectSpeed = 0.8f, diff --git a/game/entity_factory.h b/game/entity_factory.h index 66e93a7..e9aa07f 100644 --- a/game/entity_factory.h +++ b/game/entity_factory.h @@ -6,7 +6,7 @@ ecs_entity_t entityCreateEmpty(); -ecs_entity_t entityCreateBaseUnit(const Position position, Player player, +ecs_entity_t entityCreateBaseUnit(const Position position, f32 size, Player player, EntityType type, AnimType startAnim, Game *game); ecs_entity_t entityCreateSoldier(const Position position, Player player, Game *game); ecs_entity_t entityCreateWorker(const Position position, Player player, Game *game); diff --git a/game/game_tileset.h b/game/game_tileset.h index b6f3657..624e840 100644 --- a/game/game_tileset.h +++ b/game/game_tileset.h @@ -1717,23 +1717,23 @@ static bool hasEntityHitBoxRec(BzTile tile) { static Rectangle getEntityHitBoxRec(BzTile tile) { switch (tile) { case 27: return (Rectangle) {4, 2, 8, 12}; - case 539: return (Rectangle) {4, 0, 8, 14}; - case 1051: return (Rectangle) {4, 0, 8, 14}; - case 1563: return (Rectangle) {4, 0, 8, 14}; - case 2075: return (Rectangle) {4, 1, 8, 13}; - case 2587: return (Rectangle) {4, 3, 8, 11}; - case 5888: return (Rectangle) {4, 4, 8, 9}; - case 5889: return (Rectangle) {3, 7, 10, 7}; - case 5890: return (Rectangle) {6, 4, 4, 10}; - case 5891: return (Rectangle) {6, 4, 4, 10}; - case 6146: return (Rectangle) {6, 4, 4, 10}; - case 6147: return (Rectangle) {6, 4, 4, 10}; - case 6402: return (Rectangle) {6, 4, 4, 10}; - case 6403: return (Rectangle) {6, 4, 4, 10}; - case 6656: return (Rectangle) {6, 4, 4, 10}; - case 6912: return (Rectangle) {6, 4, 4, 10}; + case 539: return (Rectangle) {4, 2, 8, 14}; + case 1051: return (Rectangle) {4, 2, 8, 14}; + case 1563: return (Rectangle) {4, 2, 8, 14}; + case 2075: return (Rectangle) {4, 2, 8, 13}; + case 2587: return (Rectangle) {4, 2, 8, 11}; + case 5888: return (Rectangle) {4, 3, 8, 9}; + case 5889: return (Rectangle) {3, 2, 10, 7}; + case 5890: return (Rectangle) {6, 2, 4, 10}; + case 5891: return (Rectangle) {6, 2, 4, 10}; + case 6146: return (Rectangle) {6, 2, 4, 10}; + case 6147: return (Rectangle) {6, 2, 4, 10}; + case 6402: return (Rectangle) {6, 2, 4, 10}; + case 6403: return (Rectangle) {6, 2, 4, 10}; + case 6656: return (Rectangle) {6, 2, 4, 10}; + case 6912: return (Rectangle) {6, 2, 4, 10}; case 7170: return (Rectangle) {3, 3, 10, 10}; - case 7171: return (Rectangle) {3, 4, 10, 9}; + case 7171: return (Rectangle) {3, 3, 10, 9}; case 7172: return (Rectangle) {1, 3, 14, 10}; default: return (Rectangle) { 0.0f, 0.0f, 0.0f, 0.0f}; } diff --git a/game/main.c b/game/main.c index 0d086b4..ebf1687 100644 --- a/game/main.c +++ b/game/main.c @@ -386,10 +386,10 @@ static void renderGame(Game *game, float dt) { Rotation *r = ecs_field(&it, Rotation, 3); TextureRegion *t = ecs_field(&it, TextureRegion, 4); for (i32 i = 0; i < it.count; i++) { - f32 sclX = s[i].x / t[i].rec.width; - f32 sclY = s[i].y / t[i].rec.height; - Rectangle dst = {p[i].x, p[i].y, - t[i].rec.width * sclX, t[i].rec.height * sclY}; + Rectangle dst = {p[i].x, p[i].y - s[i].y, + s[i].x, s[i].y}; + + DrawCircleV(p[i], 1.0f, BLUE); Vector2 origin = {0.0f, 0.0f}; //dst.x += origin.x - dst.width * 0.5f; //dst.y += origin.y - dst.height * 0.5f; diff --git a/game/map_init.c b/game/map_init.c index 88062e0..24f4c52 100644 --- a/game/map_init.c +++ b/game/map_init.c @@ -8,6 +8,7 @@ #include "game_state.h" #include "map_layers.h" #include "utils.h" +#include "systems/systems.h" bool initGameObjectsLayer(BzTileMap *map, BzTileObjectGroup *objectGroup) { Game *game = ecs_singleton_get_mut(ECS, Game); @@ -163,10 +164,12 @@ bool initTreesLayer(BzTileMap *map, BzTileLayer *layer) { f32 sizeY = tileset->tileHeight; f32 posX = layer->offsetX + x * sizeX; f32 posY = layer->offsetY + y * sizeY; + posY += sizeY; ecs_entity_t e = entityCreateEmpty(); + HitBox tHitBox = entityTransformHitBox((Position) {posX, posY}, hb); SpatialGridID gridID = bzSpatialGridInsert(game->entityGrid, &e, - posX + hb.x, posY + hb.y, - hb.width, hb.height); + tHitBox.x, tHitBox.y, + tHitBox.width, tHitBox.height); ecs_set(ECS, e, SpatialGridID, {gridID}); ecs_set(ECS, e, Position, {posX, posY}); ecs_set(ECS, e, Size, {sizeX, sizeY}); diff --git a/game/systems/s_entity.c b/game/systems/s_entity.c index 18168f2..2a2d50f 100644 --- a/game/systems/s_entity.c +++ b/game/systems/s_entity.c @@ -101,12 +101,8 @@ void entityUpdateSpatialID(ecs_iter_t *it) { BZ_UNUSED(velocity); for (i32 i = 0; i < it->count; i++) { - Rectangle rec = { - position[i].x + hitbox[i].x, - position[i].y + hitbox[i].y, - hitbox[i].width, hitbox[i].height - }; - bzSpatialGridUpdate(game->entityGrid, id[i], rec.x, rec.y, rec.width, rec.height); + HitBox hb = entityTransformHitBox(position[i], hitbox[i]); + bzSpatialGridUpdate(game->entityGrid, id[i], hb.x, hb.y, hb.width, hb.height); } } @@ -227,9 +223,7 @@ void renderColliders(ecs_iter_t *it) { HitBox *hitbox = ecs_field(it, HitBox , 2); for (i32 i = 0; i < it->count; i++) { - HitBox hb = hitbox[i]; - hb.x += pos[i].x; - hb.y += pos[i].y; + HitBox hb = entityTransformHitBox(pos[i], hitbox[i]); DrawRectangleLinesEx(hb, 1.0f, RED); } } diff --git a/game/systems/s_input.c b/game/systems/s_input.c index 3c41c6e..f8164b4 100644 --- a/game/systems/s_input.c +++ b/game/systems/s_input.c @@ -309,22 +309,19 @@ void drawPlayerInputUIGround() { for (i32 i = 0; i < it.count; i++) { ecs_entity_t entity = it.entities[i]; f32 radius = BZ_MAX(hitbox[i].width, hitbox[i].height); + Position center = entityGetCenter(pos[i], hitbox[i]); radius *= 0.8f; const f32 lineThickness = 1.0f; if (ecs_has(ECS, entity, Building)) { const f32 padding = 2.0f; Rectangle bounds = { pos[i].x + hitbox[i].x - padding, - pos[i].y - hitbox[i].y - padding, + pos[i].y - hitbox[i].height - padding, hitbox[i].width + padding * 2, hitbox[i].height + padding * 2, }; DrawRectangleLinesEx(bounds, lineThickness, GREEN); } else { - Position center = { - pos[i].x + hitbox[i].x + hitbox[i].width * 0.5f, - pos[i].y + hitbox[i].y + hitbox[i].height * 0.5f, - }; DrawRing(center, radius, radius + lineThickness, 0, 360, 12, GREEN); } } @@ -372,7 +369,7 @@ ecs_entity_t queryEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t if (!ecs_has_id(ECS, entity, tag)) continue; Vector2 pos; Rectangle hitbox; - if (!getEntityHitBox(entity, &pos, &hitbox)) continue; + if (!entityGetHitBox(entity, &pos, &hitbox)) continue; if (!CheckCollisionPointRec(point, hitbox)) continue; @@ -410,7 +407,7 @@ void selectUnits(BzSpatialGrid *entityGrid, Rectangle area, Player player) { } if (!ecs_has_id(ECS, entity, ecs_id(Unit))) continue; Rectangle hitbox; - if (!getEntityHitBox(entity, NULL, &hitbox)) continue; + if (!entityGetHitBox(entity, NULL, &hitbox)) continue; if (!CheckCollisionRecs(area, hitbox)) continue; ecs_add(ECS, entity, Selected); diff --git a/game/systems/systems.c b/game/systems/systems.c index 9490fc2..62a8eb3 100644 --- a/game/systems/systems.c +++ b/game/systems/systems.c @@ -2,7 +2,7 @@ #include "../game_state.h" -bool getEntityHitBox(ecs_entity_t entity, Position *outPos, Rectangle *outHitBox) { +bool entityGetHitBox(ecs_entity_t entity, Position *outPos, Rectangle *outHitBox) { if (!ecs_is_alive(ECS, entity)) return false; @@ -18,11 +18,25 @@ bool getEntityHitBox(ecs_entity_t entity, Position *outPos, Rectangle *outHitBox if (outHitBox) { *outHitBox = *hitbox; outHitBox->x += pos->x; - outHitBox->y += pos->y; + outHitBox->y = pos->y - hitbox->y - hitbox->height; } return true; } +Rectangle entityTransformHitBox(Position position, HitBox hitBox) { + return (Rectangle) { + position.x + hitBox.x, + position.y - hitBox.y - hitBox.height, + hitBox.width, + hitBox.height + }; +} +Vector2 entityGetCenter(Position position, HitBox hitBox) { + return (Vector2) { + position.x + hitBox.x + hitBox.width * 0.5f, + position.y - hitBox.y - hitBox.height * 0.5f + }; +} ecs_entity_t renderCollidersSystem; ecs_entity_t renderOrientDirSystem; diff --git a/game/systems/systems.h b/game/systems/systems.h index cac75dc..db77c6b 100644 --- a/game/systems/systems.h +++ b/game/systems/systems.h @@ -199,7 +199,9 @@ void drawSettingsUI(Game *game, f32 dt); * Utils **********************************/ -bool getEntityHitBox(ecs_entity_t entity, Position *outPos, Rectangle *outHitBox); +bool entityGetHitBox(ecs_entity_t entity, Position *outPos, Rectangle *outHitBox); +Rectangle entityTransformHitBox(Position position, HitBox hitBox); +Vector2 entityGetCenter(Position position, HitBox hitBox); /********************************** * MISC diff --git a/scripts/extract_tileset.py b/scripts/extract_tileset.py index f3fbdc8..9380f72 100644 --- a/scripts/extract_tileset.py +++ b/scripts/extract_tileset.py @@ -106,7 +106,7 @@ tile_writer.output_index_tile_offset("getTileOffset", "player", 256, TILE_WIDTH, vec2_transform = ["Vector2", "(Vector2) {0.0f, 0.0f}", lambda x: f"(Vector2) {{{x['x']}, {x['y']}}}"] rec_transform = ["Rectangle", "(Rectangle) { 0.0f, 0.0f, 0.0f, 0.0f}", - lambda x: f"(Rectangle) {{{x['x']}, {x['y']}, {x['width']}, {x['height']}}}"] + lambda x: f"(Rectangle) {{{x['x']}, {TILE_HEIGHT - x['y'] - x['height']}, {x['width']}, {x['height']}}}"] tile_writer.output_has_object("hasItemHandlePoint", "handle") tile_writer.output_get_object("getItemHandlePoint", "handle", *vec2_transform)