Enemy swarm movement
This commit is contained in:
@@ -256,6 +256,110 @@ void entityMoveToTarget(ecs_iter_t *it) {
|
||||
}
|
||||
}
|
||||
|
||||
void entityMoveSwarm(ecs_iter_t *it) {
|
||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||
Position *pos = ecs_field(it, Position, 1);
|
||||
Velocity *vel = ecs_field(it, Velocity, 2);
|
||||
HitBox *hb = ecs_field(it, HitBox, 3);
|
||||
Swarm *swarm = ecs_field(it, Swarm, 4);
|
||||
Owner *owner = ecs_field(it, Owner, 5);
|
||||
Steering *steer = ecs_field(it, Steering, 6);
|
||||
|
||||
for (i32 i = 0; i < it->count; i++) {
|
||||
|
||||
// Vector2 align = Vector2Zero(); // Alignment (match velocity)
|
||||
Vector2 avoid = Vector2Zero(); // Separation
|
||||
Vector2 target = Vector2Zero();
|
||||
Vector2 cohesion = Vector2Zero(); // Cohesion (move towards center)
|
||||
|
||||
const f32 FRIEND_RADIUS = 22.0f;
|
||||
const f32 ENEMY_RADIUS = 52.0f;
|
||||
|
||||
const Vector2 center = entityGetCenter(pos[i], hb[i]);
|
||||
|
||||
const f32 RANGE = BZ_MAX(FRIEND_RADIUS, ENEMY_RADIUS);
|
||||
BzSpatialGridIter spatialIt = bzSpatialGridIter(game->entityGrid,
|
||||
center.x - RANGE, center.y - RANGE,
|
||||
RANGE * 2.0f, RANGE * 2.0f);
|
||||
|
||||
i32 numFriends = 0;
|
||||
while (bzSpatialGridQueryNext(&spatialIt)) {
|
||||
ecs_entity_t other = *(ecs_entity_t *) spatialIt.data;
|
||||
if (!ecs_has(ECS, other, Owner))
|
||||
continue;
|
||||
Owner otherOwner = *ecs_get(ECS, other, Owner);
|
||||
bool isFriend = owner[i].player == otherOwner.player;
|
||||
|
||||
if (!ecs_has(ECS, other, Position) || !ecs_has(ECS, other, HitBox))
|
||||
continue;
|
||||
Position otherPos = *ecs_get(ECS, other, Position);
|
||||
Rectangle otherHB = *ecs_get(ECS, other, HitBox);;
|
||||
Vector2 otherCenter = entityGetCenter(otherPos, otherHB);
|
||||
f32 dst = Vector2Distance(center, otherCenter);
|
||||
const f32 MIN_AVOID_DST = 18.0f;
|
||||
const f32 MIN_ENEMY_DST = ENEMY_RADIUS;
|
||||
if (isFriend) {
|
||||
if (dst < MIN_AVOID_DST) {
|
||||
Vector2 dif = Vector2Subtract(center, otherCenter);
|
||||
dif = Vector2Scale(Vector2Normalize(dif), MIN_AVOID_DST - dst);
|
||||
avoid = Vector2Add(avoid, dif);
|
||||
}
|
||||
Vector2Add(cohesion, otherCenter);
|
||||
numFriends++;
|
||||
} else {
|
||||
if (dst < MIN_ENEMY_DST) {
|
||||
//DrawCircleV(otherCenter, 2.0f, RED);
|
||||
Vector2 dif = Vector2Subtract(otherCenter, center);
|
||||
dif = Vector2Scale(Vector2Normalize(dif), MIN_ENEMY_DST - dst);
|
||||
target = Vector2Add(target, dif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numFriends > 0) {
|
||||
cohesion = Vector2Divide(cohesion, (Vector2) { numFriends, numFriends });
|
||||
cohesion = Vector2Subtract(cohesion, center);
|
||||
}
|
||||
|
||||
|
||||
//bzLogInfo("%d %d", numFriends, numEnemies);
|
||||
|
||||
const f32 noiseRange = 10.0f;
|
||||
Vector2 noise = {
|
||||
randFloatRange(-noiseRange, noiseRange),
|
||||
randFloatRange(-noiseRange, noiseRange)
|
||||
};
|
||||
Vector2 followWaypoint = Vector2Zero();
|
||||
if (swarm[i].currWaypoint < game->swamNumWaypoints) {
|
||||
Vector2 waypoint = game->swarmWaypoints[swarm[i].currWaypoint];
|
||||
Vector2 waypointDir = Vector2Subtract(waypoint, center);
|
||||
followWaypoint = waypointDir;
|
||||
|
||||
f32 dst = Vector2Distance(center, waypoint);
|
||||
const f32 WAYPOINT_THRESHOLD = 54.0f;
|
||||
if (dst < WAYPOINT_THRESHOLD) {
|
||||
swarm[i].currWaypoint++;
|
||||
}
|
||||
}
|
||||
const f32 AVOID_FACTOR = 1.0f;
|
||||
const f32 TARGET_FACTOR = 2.2f;
|
||||
const f32 COHESION_FACTOR = 0.10f;
|
||||
const f32 WAYPOINT_FACTOR = 0.45f;
|
||||
const f32 NOISE_FACTOR = 0.2f;
|
||||
Vector2 move = Vector2Zero();
|
||||
move = Vector2Add(move, Vector2Scale(avoid, AVOID_FACTOR));
|
||||
move = Vector2Add(move, Vector2Scale(target, TARGET_FACTOR));
|
||||
//move = Vector2Add(move, Vector2Scale(cohesion, COHESION_FACTOR));
|
||||
move = Vector2Add(move, Vector2Scale(followWaypoint, WAYPOINT_FACTOR));
|
||||
move = Vector2Add(move, Vector2Scale(noise, NOISE_FACTOR));
|
||||
|
||||
//bzLogInfo("%.2f %.2f", move.x, move.y);
|
||||
//DrawLineV(center, Vector2Add(center, Vector2Scale(Vector2Normalize(avoid), 100)), ORANGE);
|
||||
|
||||
steer[i] = move;
|
||||
}
|
||||
}
|
||||
|
||||
void entityFollowPath(ecs_iter_t *it) {
|
||||
const Game *game = ecs_singleton_get(ECS, Game);
|
||||
|
||||
@@ -307,7 +411,7 @@ void updateBuildingRecruitment(ecs_iter_t *it) {
|
||||
slot->elapsed = 0;
|
||||
PlayerResources *playerRes = &game->playerResources[player];
|
||||
playerRes->pop--;
|
||||
entityRecruit(slot->entityType, placePos, player, game);
|
||||
entityCreate(slot->entityType, placePos, player, game);
|
||||
slot->numRecruiting--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,8 +391,8 @@ void drawMainMenuUI(Game *game, f32 dt) {
|
||||
//loadMap(game, "assets/maps/tree_test.tmj");
|
||||
//loadMap(game, "assets/maps/entity_test.tmj");
|
||||
//loadMap(game, "assets/maps/worker_test.tmj");
|
||||
loadMap(game, "assets/maps/battle_test.tmj");
|
||||
//loadMap(game, "assets/maps/map_01.tmj");
|
||||
//loadMap(game, "assets/maps/battle_test.tmj");
|
||||
loadMap(game, "assets/maps/map_01.tmj");
|
||||
}
|
||||
if (uiMainMenuButton("Settings", true)) {
|
||||
setScreen(game, SCREEN_SETTINGS);
|
||||
|
||||
@@ -181,6 +181,7 @@ void setupSystems() {
|
||||
ECS_SYSTEM(ECS, entityUpdate, EcsOnUpdate, Position, HitBox, Velocity, Unit, Owner, SpatialGridID);
|
||||
|
||||
ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Velocity, TargetPosition, Steering);
|
||||
ECS_SYSTEM(ECS, entityMoveSwarm, EcsOnUpdate, Position, Velocity, HitBox, Swarm, Owner, Steering);
|
||||
ECS_SYSTEM(ECS, entityFollowPath, EcsOnUpdate, Path);
|
||||
|
||||
ECS_SYSTEM(ECS, updateBuildingRecruitment, EcsOnUpdate, Owner, Building, BuildingRecruitInfo);
|
||||
|
||||
@@ -143,6 +143,17 @@ void entityUpdate(ecs_iter_t *it);
|
||||
*/
|
||||
void entityMoveToTarget(ecs_iter_t *it);
|
||||
|
||||
/*
|
||||
* 0: Game (singleton for waypoints)
|
||||
* 1: Position
|
||||
* 2: Velocity
|
||||
* 3: HitBox
|
||||
* 4: Swarm
|
||||
* 5: Owner
|
||||
* 6: Steering
|
||||
*/
|
||||
void entityMoveSwarm(ecs_iter_t *it);
|
||||
|
||||
/*
|
||||
* 0: Game (singleton) for object pool
|
||||
* 1: Path
|
||||
|
||||
Reference in New Issue
Block a user