Add tower firing

This commit is contained in:
2024-02-10 11:25:02 +01:00
parent e654c47446
commit 1c6fab51c6
6 changed files with 119 additions and 12 deletions

View File

@@ -176,9 +176,9 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type,
.range = 46.0f,
.minDamage = 40.0f,
.maxDamage = 80.0f,
.damageFalloff = 8.0f,
.damageRadius = 28.0f,
.projectileSpeed = 10.0f,
.projectileSpeed = 100.0f,
.projectileRadius = 4.0f,
.projectileDamageCount = 3,
.fireCooldown = 1.2f,
.fireElapsed = 0.0f,
});

View File

@@ -43,6 +43,7 @@ ECS_COMPONENT_DECLARE(Worker);
ECS_COMPONENT_DECLARE(Building);
ECS_COMPONENT_DECLARE(Unit);
ECS_COMPONENT_DECLARE(Tower);
ECS_COMPONENT_DECLARE(Projectile);
ECS_COMPONENT_DECLARE(BuildingRecruitInfo);
ECS_COMPONENT_DECLARE(Storage);
ECS_COMPONENT_DECLARE(Harvestable);
@@ -96,6 +97,7 @@ void initComponentIDs(ecs_world_t *ecs) {
ECS_COMPONENT_DEFINE(ecs, Building);
ECS_COMPONENT_DEFINE(ecs, Unit);
ECS_COMPONENT_DEFINE(ecs, Tower);
ECS_COMPONENT_DEFINE(ecs, Projectile);
ECS_COMPONENT_DEFINE(ecs, BuildingRecruitInfo);
ECS_COMPONENT_DEFINE(ecs, Storage);
ECS_COMPONENT_DEFINE(ecs, Harvestable);

View File

@@ -280,14 +280,23 @@ typedef struct Tower {
f32 range;
f32 minDamage;
f32 maxDamage;
f32 damageFalloff;
f32 damageRadius;
f32 projectileSpeed;
f32 projectileRadius;
i32 projectileDamageCount;
f32 fireCooldown;
f32 fireElapsed;
} Tower;
extern ECS_COMPONENT_DECLARE(Tower);
typedef struct Projectile {
Vector2 target;
f32 radius;
f32 damage;
ecs_entity_t lastDamaged;
i32 damageCount;
} Projectile;
extern ECS_COMPONENT_DECLARE(Projectile);
#define BUILDING_MAX_RECRUIT_SLOTS 4
typedef struct BuildingRecruitSlot {
EntityType entityType;

View File

@@ -337,8 +337,7 @@ void updateTower(ecs_iter_t *it) {
Rectangle bounds = {
center.x - range,
center.y - range,
range * 2,
range * 2,
range * 2.0f, range * 2.0f
};
BzSpatialGridIter spatialIt = bzSpatialGridIter(game->entityGrid,
bounds.x, bounds.y,
@@ -361,7 +360,7 @@ void updateTower(ecs_iter_t *it) {
continue;
Vector2 otherCenter = {
otherBounds.x + otherBounds.width * 0.5f,
otherBounds.y - otherBounds.height * 0.5f
otherBounds.y + otherBounds.height * 0.5f
};
f32 dst = Vector2Distance(center, otherCenter);
if (dst > range)
@@ -375,14 +374,96 @@ void updateTower(ecs_iter_t *it) {
if (target == 0) continue;
Vector2 dir = Vector2Subtract(targetPos, center);
dir = Vector2Normalize(dir);
dir = Vector2Scale(dir, tower[i].projectileSpeed);
ecs_entity_t proj = entityCreateEmpty();
ecs_set(ECS, proj, Position, { center.x, center.y });
ecs_set(ECS, proj, Velocity, { dir.x, dir.y });
ecs_set(ECS, proj, Projectile, {
.damage = randFloatRange(tower[i].minDamage, tower[i].maxDamage),
.target = targetPos,
.radius = tower[i].projectileRadius,
.damageCount = tower[i].projectileDamageCount
});
ecs_set(ECS, proj, Owner, { owner[i].player });
tower[i].fireElapsed = 0.0f;
bzLogInfo("FIRE!");
}
}
void updateProjectile(ecs_iter_t *it) {
Game *game = ecs_singleton_get_mut(ECS, Game);
Owner *owner = ecs_field(it, Owner, 1);
Projectile *proj = ecs_field(it, Projectile, 2);
Position *pos = ecs_field(it, Position, 3);
Velocity *vel = ecs_field(it, Velocity, 4);
f32 dt = GetFrameTime();
for (i32 i = 0; i < it->count; i++) {
const f32 radius = proj[i].radius;
const f32 hRadius = radius * 0.5f;
const Rectangle bounds = {
pos[i].x - hRadius,
pos[i].y + hRadius,
radius, radius
};
BzSpatialGridIter spatialIt = bzSpatialGridIter(game->entityGrid,
bounds.x, bounds.y,
bounds.width, bounds.height);
while (bzSpatialGridQueryNext(&spatialIt)) {
ecs_entity_t other = *(ecs_entity_t *) spatialIt.data;
if (proj[i].lastDamaged == other)
continue;
if (!ecs_has(ECS, other, Owner))
continue;
Owner otherOwner = *ecs_get(ECS, other, Owner);
if (otherOwner.player == owner[i].player)
continue;
if (!ecs_has(ECS, other, Health))
continue;
Vector2 otherPos;
Rectangle otherHB;
if (!entityGetHitBox(other, &otherPos, &otherHB))
continue;
if (!CheckCollisionRecs(bounds, otherHB))
continue;
damageEvent(other, (DamageEvent) {
.amount = proj[i].damage,
.hitbox = otherHB
});
proj[i].lastDamaged = other;
proj[i].damageCount--;
break;
}
if (proj[i].damageCount <= 0) {
ecs_delete(ECS, it->entities[i]);
continue;
}
DrawRectangleV((Vector2) {bounds.x, bounds.y}, (Vector2) {bounds.width, bounds.height},
RED);
pos[i] = Vector2Add(pos[i], Vector2Scale(vel[i], dt));
if (pos[i].x < 0.0f || pos[i].y < 0.0f ||
pos[i].x >= game->map.width * game->map.tileWidth ||
pos[i].y >= game->map.height * game->map.tileHeight) {
ecs_delete(ECS, it->entities[i]);
}
}
}
void renderHealthBar(ecs_iter_t *it) {
Position *pos = ecs_field(it, Position, 1);

View File

@@ -44,17 +44,22 @@ ecs_entity_t renderDebugPathSystem;
ECS_DTOR(SpatialGridID, gridID, {
Game *game = ecs_singleton_get_mut(ECS, Game);
bzSpatialGridRemove(game->entityGrid, *gridID);
if (*gridID != -1) {
bzSpatialGridRemove(game->entityGrid, *gridID);
*gridID = -1;
}
})
ECS_MOVE(SpatialGridID, dst, src, {
*dst = *src;
*src = 0;
*src = -1;
})
void spatialIDRemoved(ecs_iter_t *it) {
Game *game = ecs_singleton_get_mut(ECS, Game);
SpatialGridID *spatialID = ecs_field(it, SpatialGridID, 1);
for (int i = 0; i < it->count; i++) {
if (spatialID[i] == -1) continue;
bzSpatialGridRemove(game->entityGrid, spatialID[i]);
spatialID[i] = -1;
}
}
ECS_DTOR(Path, path, {
@@ -184,6 +189,7 @@ void setupSystems() {
ECS_SYSTEM(ECS, updateAISystem, EcsOnUpdate, BzBTState);
ECS_SYSTEM(ECS, updateTower, EcsOnUpdate, Owner, Tower, Position, Size);
ECS_SYSTEM(ECS, updateProjectile, EcsOnUpdate, Owner, Projectile, Position, Velocity);
ECS_SYSTEM(ECS, updateAnimationState, EcsOnUpdate, Animation, TextureRegion);
ECS_SYSTEM(ECS, updateAnimation, EcsOnUpdate, Animation, TextureRegion);

View File

@@ -166,6 +166,15 @@ void updateBuildingRecruitment(ecs_iter_t *it);
*/
void updateTower(ecs_iter_t *it);
/*
* 0: Game (singleton for querying entities)
* 1: Owner
* 2 Projectile
* 3: Position
* 4: Velocity
*/
void updateProjectile(ecs_iter_t *it);
/*
* 1: Position
* 2: HitBox