Add tower firing
This commit is contained in:
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user