Add tower firing
This commit is contained in:
@@ -176,9 +176,9 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type,
|
|||||||
.range = 46.0f,
|
.range = 46.0f,
|
||||||
.minDamage = 40.0f,
|
.minDamage = 40.0f,
|
||||||
.maxDamage = 80.0f,
|
.maxDamage = 80.0f,
|
||||||
.damageFalloff = 8.0f,
|
.projectileSpeed = 100.0f,
|
||||||
.damageRadius = 28.0f,
|
.projectileRadius = 4.0f,
|
||||||
.projectileSpeed = 10.0f,
|
.projectileDamageCount = 3,
|
||||||
.fireCooldown = 1.2f,
|
.fireCooldown = 1.2f,
|
||||||
.fireElapsed = 0.0f,
|
.fireElapsed = 0.0f,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ ECS_COMPONENT_DECLARE(Worker);
|
|||||||
ECS_COMPONENT_DECLARE(Building);
|
ECS_COMPONENT_DECLARE(Building);
|
||||||
ECS_COMPONENT_DECLARE(Unit);
|
ECS_COMPONENT_DECLARE(Unit);
|
||||||
ECS_COMPONENT_DECLARE(Tower);
|
ECS_COMPONENT_DECLARE(Tower);
|
||||||
|
ECS_COMPONENT_DECLARE(Projectile);
|
||||||
ECS_COMPONENT_DECLARE(BuildingRecruitInfo);
|
ECS_COMPONENT_DECLARE(BuildingRecruitInfo);
|
||||||
ECS_COMPONENT_DECLARE(Storage);
|
ECS_COMPONENT_DECLARE(Storage);
|
||||||
ECS_COMPONENT_DECLARE(Harvestable);
|
ECS_COMPONENT_DECLARE(Harvestable);
|
||||||
@@ -96,6 +97,7 @@ void initComponentIDs(ecs_world_t *ecs) {
|
|||||||
ECS_COMPONENT_DEFINE(ecs, Building);
|
ECS_COMPONENT_DEFINE(ecs, Building);
|
||||||
ECS_COMPONENT_DEFINE(ecs, Unit);
|
ECS_COMPONENT_DEFINE(ecs, Unit);
|
||||||
ECS_COMPONENT_DEFINE(ecs, Tower);
|
ECS_COMPONENT_DEFINE(ecs, Tower);
|
||||||
|
ECS_COMPONENT_DEFINE(ecs, Projectile);
|
||||||
ECS_COMPONENT_DEFINE(ecs, BuildingRecruitInfo);
|
ECS_COMPONENT_DEFINE(ecs, BuildingRecruitInfo);
|
||||||
ECS_COMPONENT_DEFINE(ecs, Storage);
|
ECS_COMPONENT_DEFINE(ecs, Storage);
|
||||||
ECS_COMPONENT_DEFINE(ecs, Harvestable);
|
ECS_COMPONENT_DEFINE(ecs, Harvestable);
|
||||||
|
|||||||
@@ -280,14 +280,23 @@ typedef struct Tower {
|
|||||||
f32 range;
|
f32 range;
|
||||||
f32 minDamage;
|
f32 minDamage;
|
||||||
f32 maxDamage;
|
f32 maxDamage;
|
||||||
f32 damageFalloff;
|
|
||||||
f32 damageRadius;
|
|
||||||
f32 projectileSpeed;
|
f32 projectileSpeed;
|
||||||
|
f32 projectileRadius;
|
||||||
|
i32 projectileDamageCount;
|
||||||
f32 fireCooldown;
|
f32 fireCooldown;
|
||||||
f32 fireElapsed;
|
f32 fireElapsed;
|
||||||
} Tower;
|
} Tower;
|
||||||
extern ECS_COMPONENT_DECLARE(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
|
#define BUILDING_MAX_RECRUIT_SLOTS 4
|
||||||
typedef struct BuildingRecruitSlot {
|
typedef struct BuildingRecruitSlot {
|
||||||
EntityType entityType;
|
EntityType entityType;
|
||||||
|
|||||||
@@ -337,8 +337,7 @@ void updateTower(ecs_iter_t *it) {
|
|||||||
Rectangle bounds = {
|
Rectangle bounds = {
|
||||||
center.x - range,
|
center.x - range,
|
||||||
center.y - range,
|
center.y - range,
|
||||||
range * 2,
|
range * 2.0f, range * 2.0f
|
||||||
range * 2,
|
|
||||||
};
|
};
|
||||||
BzSpatialGridIter spatialIt = bzSpatialGridIter(game->entityGrid,
|
BzSpatialGridIter spatialIt = bzSpatialGridIter(game->entityGrid,
|
||||||
bounds.x, bounds.y,
|
bounds.x, bounds.y,
|
||||||
@@ -361,7 +360,7 @@ void updateTower(ecs_iter_t *it) {
|
|||||||
continue;
|
continue;
|
||||||
Vector2 otherCenter = {
|
Vector2 otherCenter = {
|
||||||
otherBounds.x + otherBounds.width * 0.5f,
|
otherBounds.x + otherBounds.width * 0.5f,
|
||||||
otherBounds.y - otherBounds.height * 0.5f
|
otherBounds.y + otherBounds.height * 0.5f
|
||||||
};
|
};
|
||||||
f32 dst = Vector2Distance(center, otherCenter);
|
f32 dst = Vector2Distance(center, otherCenter);
|
||||||
if (dst > range)
|
if (dst > range)
|
||||||
@@ -375,14 +374,96 @@ void updateTower(ecs_iter_t *it) {
|
|||||||
|
|
||||||
if (target == 0) continue;
|
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;
|
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) {
|
void renderHealthBar(ecs_iter_t *it) {
|
||||||
Position *pos = ecs_field(it, Position, 1);
|
Position *pos = ecs_field(it, Position, 1);
|
||||||
|
|||||||
@@ -44,17 +44,22 @@ ecs_entity_t renderDebugPathSystem;
|
|||||||
|
|
||||||
ECS_DTOR(SpatialGridID, gridID, {
|
ECS_DTOR(SpatialGridID, gridID, {
|
||||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
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, {
|
ECS_MOVE(SpatialGridID, dst, src, {
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
*src = 0;
|
*src = -1;
|
||||||
})
|
})
|
||||||
void spatialIDRemoved(ecs_iter_t *it) {
|
void spatialIDRemoved(ecs_iter_t *it) {
|
||||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
SpatialGridID *spatialID = ecs_field(it, SpatialGridID, 1);
|
SpatialGridID *spatialID = ecs_field(it, SpatialGridID, 1);
|
||||||
for (int i = 0; i < it->count; i++) {
|
for (int i = 0; i < it->count; i++) {
|
||||||
|
if (spatialID[i] == -1) continue;
|
||||||
bzSpatialGridRemove(game->entityGrid, spatialID[i]);
|
bzSpatialGridRemove(game->entityGrid, spatialID[i]);
|
||||||
|
spatialID[i] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ECS_DTOR(Path, path, {
|
ECS_DTOR(Path, path, {
|
||||||
@@ -184,6 +189,7 @@ void setupSystems() {
|
|||||||
ECS_SYSTEM(ECS, updateAISystem, EcsOnUpdate, BzBTState);
|
ECS_SYSTEM(ECS, updateAISystem, EcsOnUpdate, BzBTState);
|
||||||
|
|
||||||
ECS_SYSTEM(ECS, updateTower, EcsOnUpdate, Owner, Tower, Position, Size);
|
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, updateAnimationState, EcsOnUpdate, Animation, TextureRegion);
|
||||||
ECS_SYSTEM(ECS, updateAnimation, 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);
|
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
|
* 1: Position
|
||||||
* 2: HitBox
|
* 2: HitBox
|
||||||
|
|||||||
Reference in New Issue
Block a user