Add hitboxes

This commit is contained in:
2024-01-28 11:00:32 +01:00
parent 0a4c1fd154
commit a61768e912
15 changed files with 494 additions and 200 deletions

View File

@@ -31,12 +31,6 @@ bool entitySetPath(const ecs_entity_t entity, const Vector2 target, Game *game)
}
static Position getBottomLeftPos(Position pos, Size size) {
return (Position) {pos.x - size.x * 0.5f, pos.y - size.y * 0.5f};
}
void entityPathRemove(ecs_iter_t *it) {
Game *game = ecs_singleton_get_mut(ECS, Game);
for (i32 i = 0; i < it->count; i++) {
@@ -101,13 +95,18 @@ void entityUnConsumePopCapacity(ecs_iter_t *it) {
void entityUpdateSpatialID(ecs_iter_t *it) {
Game *game = ecs_singleton_get_mut(ECS, Game);
Position *position = ecs_field(it, Position, 1);
Position *size = ecs_field(it, Size, 2);
//Velocity *velocity = ecs_field(it, Velocity, 3);
HitBox *hitbox = ecs_field(it, HitBox, 2);
Velocity *velocity = ecs_field(it, Velocity, 3);
SpatialGridID *id = ecs_field(it, SpatialGridID, 4);
BZ_UNUSED(velocity);
for (i32 i = 0; i < it->count; i++) {
Position pos = getBottomLeftPos(position[i], size[i]);
bzSpatialGridUpdate(game->entityGrid, id[i], pos.x, pos.y, size[i].x, size[i].y);
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);
}
}
@@ -225,12 +224,13 @@ void entityUpdateArms(ecs_iter_t *it) {
void renderColliders(ecs_iter_t *it) {
Position *pos = ecs_field(it, Position, 1);
Size *size = ecs_field(it, Size, 2);
HitBox *hitbox = ecs_field(it, HitBox , 2);
for (i32 i = 0; i < it->count; i++) {
f32 posX = pos[i].x - size[i].x * 0.5f;
f32 posY = pos[i].y - size[i].y * 0.5f;
DrawRectangleLines(posX, posY, size[i].x, size[i].y, RED);
HitBox hb = hitbox[i];
hb.x += pos[i].x;
hb.y += pos[i].y;
DrawRectangleLinesEx(hb, 1.0f, RED);
}
}

View File

@@ -16,8 +16,8 @@ void selectUnits(BzSpatialGrid *entityGrid, Rectangle area, Player player);
void addEntityToInspected(ecs_entity_t entity, Game *game);
static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos, Size *size));
static void iterRemovePaths(ecs_entity_t entity, Position *pos, Size *size);
static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos));
static void iterRemovePaths(ecs_entity_t entity, Position *pos);
void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 **outPlaces);
@@ -305,23 +305,27 @@ void drawPlayerInputUIGround() {
rlSetLineWidth(2.0f);
while (ecs_query_next(&it)) {
Position *pos = ecs_field(&it, Position, 1);
Size *size = ecs_field(&it, Size, 2);
HitBox *hitbox = ecs_field(&it, HitBox , 2);
for (i32 i = 0; i < it.count; i++) {
ecs_entity_t entity = it.entities[i];
f32 radius = BZ_MIN(size[i].x, size[i].y);
radius *= 0.5f;
f32 radius = BZ_MAX(hitbox[i].width, hitbox[i].height);
radius *= 0.8f;
const f32 lineThickness = 1.0f;
if (ecs_has(ECS, entity, Building)) {
const f32 padding = 2.0f;
Rectangle bounds = {
pos[i].x - size[i].x * 0.5f - padding,
pos[i].y - size[i].y * 0.5f - padding,
size[i].x + padding * 2,
size[i].y + padding * 2,
pos[i].x + hitbox[i].x - padding,
pos[i].y - hitbox[i].y - padding,
hitbox[i].width + padding * 2,
hitbox[i].height + padding * 2,
};
DrawRectangleLinesEx(bounds, lineThickness, GREEN);
} else {
DrawRing(pos[i], radius, radius + lineThickness, 0, 360, 12, GREEN);
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);
}
}
}
@@ -367,10 +371,10 @@ ecs_entity_t queryEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t
if (!ecs_has_id(ECS, entity, Selectable)) continue;
if (!ecs_has_id(ECS, entity, tag)) continue;
Vector2 pos;
Rectangle bounds;
if (!getEntityBounds(entity, &pos, NULL, &bounds)) continue;
Rectangle hitbox;
if (!getEntityHitBox(entity, &pos, &hitbox)) continue;
if (!CheckCollisionPointRec(point, bounds)) continue;
if (!CheckCollisionPointRec(point, hitbox)) continue;
f32 curDst = Vector2Distance(point, pos);
if (closestDst > curDst) {
@@ -405,10 +409,10 @@ void selectUnits(BzSpatialGrid *entityGrid, Rectangle area, Player player) {
if (owner.player != player) continue;
}
if (!ecs_has_id(ECS, entity, ecs_id(Unit))) continue;
Rectangle bounds;
if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue;
Rectangle hitbox;
if (!getEntityHitBox(entity, NULL, &hitbox)) continue;
if (!CheckCollisionRecs(area, bounds)) continue;
if (!CheckCollisionRecs(area, hitbox)) continue;
ecs_add(ECS, entity, Selected);
}
}
@@ -463,20 +467,19 @@ void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTil
}
}
static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos, Size *size)) {
static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos)) {
ecs_iter_t it = ecs_query_iter(ECS, query);
while (ecs_iter_next(&it)) {
Position *pos = ecs_field(&it, Position, 1);
Size *size = ecs_field(&it, Size, 2);
for (i32 i = 0; i < it.count; i++) {
ecs_entity_t entity = it.entities[i];
fn(entity, pos + i, size + i);
fn(entity, pos + i);
}
}
}
static void iterRemovePaths(ecs_entity_t entity, Position *pos, Size *size) {
static void iterRemovePaths(ecs_entity_t entity, Position *pos) {
ecs_remove(ECS, entity, Path);
}

View File

@@ -2,37 +2,25 @@
#include "../game_state.h"
Rectangle calculateEntityBounds(Position pos, Size size) {
return (Rectangle) {
pos.x - size.x * 0.5f,
pos.y - size.x * 0.5f,
size.x, size.y
};
}
bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Rectangle *outBounds) {
bool getEntityHitBox(ecs_entity_t entity, Position *outPos, Rectangle *outHitBox) {
if (!ecs_is_alive(ECS, entity))
return false;
const Position *pos = ecs_get(ECS, entity, Position);
if (!pos)
return false;
const Size *size = ecs_get(ECS, entity, Size);
if (!size)
return false;
if (outPos) {
if (outPos)
*outPos = *pos;
const HitBox *hitbox = ecs_get(ECS, entity, HitBox);
if (!hitbox)
return false;
if (outHitBox) {
*outHitBox = *hitbox;
outHitBox->x += pos->x;
outHitBox->y += pos->y;
}
if (outSize) {
*outSize = *size;
}
if (outBounds) {
*outBounds = (Rectangle) {
pos->x - size->x * 0.5f,
pos->y - size->y * 0.5f,
size->x, size->y
};
}
return true;
}
@@ -115,7 +103,7 @@ void setupSystems() {
ECS_OBSERVER(ECS, entityConsumePopCapacity, EcsOnSet, ConsumePopCapacity, Owner);
ECS_OBSERVER(ECS, entityUnConsumePopCapacity, EcsOnRemove, ConsumePopCapacity, Owner);
ECS_SYSTEM(ECS, entityUpdateSpatialID, EcsOnUpdate, Position, Size, Velocity, SpatialGridID);
ECS_SYSTEM(ECS, entityUpdateSpatialID, EcsOnUpdate, Position, HitBox, Velocity, SpatialGridID);
ECS_SYSTEM(ECS, entityUpdateKinematic, EcsOnUpdate, Position, Velocity, Steering, Unit);
ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Velocity, TargetPosition, Steering);
@@ -126,11 +114,11 @@ void setupSystems() {
ECS_SYSTEM(ECS, updateAnimationState, EcsOnUpdate, Animation, TextureRegion);
ECS_SYSTEM(ECS, updateAnimation, EcsOnUpdate, Animation, TextureRegion);
ECS_SYSTEM(ECS, updateEasingSystem, EcsOnUpdate, Easing, Position, Size, Rotation);
ECS_SYSTEM(ECS, updateEasingSystem, EcsOnUpdate, Easing, Position, HitBox, Rotation);
ECS_SYSTEM(ECS, renderDebugPath, EcsOnUpdate, Path);
ECS_SYSTEM(ECS, renderColliders, EcsOnUpdate, Position, Size);
ECS_SYSTEM(ECS, renderColliders, EcsOnUpdate, Position, HitBox);
ECS_SYSTEM(ECS, renderOrientationDirection, EcsOnUpdate, Position, Orientation);
ECS_SYSTEM(ECS, renderArmPosition, EcsOnUpdate, Position, Arm);

View File

@@ -91,7 +91,7 @@ void entityUnConsumePopCapacity(ecs_iter_t *it);
/*
* 0: Game (singleton) for entity map
* 1: Position
* 2: Size
* 2: HitBox
* 3: Velocity (only entities with velocity change position)
* 4: SpatialGridID
*/
@@ -132,7 +132,7 @@ void entityUpdateArms(ecs_iter_t *it);
/*
* 1: Position
* 2: Size
* 2: HitBox
*/
void renderColliders(ecs_iter_t *it);
@@ -199,8 +199,7 @@ void drawSettingsUI(Game *game, f32 dt);
* Utils
**********************************/
Rectangle calculateEntityBounds(Position pos, Size size);
bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Rectangle *outBounds);
bool getEntityHitBox(ecs_entity_t entity, Position *outPos, Rectangle *outHitBox);
/**********************************
* MISC