Better formation placement

This commit is contained in:
2024-02-09 09:46:36 +01:00
parent 8056fda650
commit ea738270a0
9 changed files with 4673 additions and 267 deletions

View File

@@ -8,6 +8,7 @@
#include <rlImGui.h>
#include <raymath.h>
#include <rlgl.h>
#include <stdlib.h>
ecs_entity_t queryEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag);
@@ -21,7 +22,7 @@ void addEntityToInspected(ecs_entity_t entity, Game *game);
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);
i32 placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 *outPlaces);
void resetInputState(InputState *input) {
input->cursor = CURSOR_NONE;
@@ -73,6 +74,28 @@ void inputPrimaryAction(Game *game, InputState *input) {
if (selectedCount == 0)
resetInputState(input);
}
typedef struct EntityPosPair {
ecs_entity_t entity;
Vector2 pos;
} EntityPosPair;
static int vec2CmpZero(const void *lhsData, const void *rhsData) {
const Vector2 *lhs = lhsData;
const Vector2 *rhs = rhsData;
f32 dstL = Vector2DistanceSqr(Vector2Zero(), *lhs);
f32 dstR = Vector2DistanceSqr(Vector2Zero(), *rhs);
if (dstL < dstR) return -1;
if (dstL > dstR) return 1;
return 0;
}
static int entityPosPairCmpZero(const void *lhsData, const void *rhsData) {
const EntityPosPair *lhs = lhsData;
const EntityPosPair *rhs = rhsData;
return vec2CmpZero(&lhs->pos, &rhs->pos);
}
void inputUnitAction(Game *game, InputState *input) {
ecs_query_t *query = input->queries.selected;
BzTileMap *map = &game->map;
@@ -155,35 +178,58 @@ void inputUnitAction(Game *game, InputState *input) {
return;
}
if (isInputBtnJustUp(input, actionBtn)) {
// Unit place position
Vector2 *positions = bzStackAlloc(&game->stackAlloc, sizeof(*positions) * numUnits);
Vector2 start = Vector2Zero();
Vector2 end = Vector2Zero();
if (isInputBtnDragged(input, actionBtn) || isInputBtnJustDragged(input, actionBtn)) {
start = input->mouseDownWorld;
end = input->mouseWorld;
} else {
start = end = input->mouseWorld;
f32 displace = 8 * numUnits;
displace = BZ_MIN(displace, 50.0f);
start.x -= displace;
end.x += displace + 2;
}
i32 placedUnits = placeUnits(numUnits, 6.0f, start, end, map, positions);
input->numUnits = placedUnits;
input->unitPlacePos = positions;
if (IsMouseButtonReleased(actionBtn)) {
// Note: We mustn't use ecs ecs_remove_all since this will also
// remove ongoing paths that are not part of this query.
ecs_defer_begin(ECS);
iterateSelectedUnits(query, iterRemovePaths);
ecs_defer_end(ECS);
const Position target = input->mouseWorld;
EntityPosPair *entities = bzStackAlloc(&game->stackAlloc, sizeof(*entities) * input->numUnits);
ecs_iter_t it = ecs_query_iter(ECS, query);
ecs_defer_begin(ECS);
i32 unitIdx = 0;
while (ecs_iter_next(&it)) {
for (i32 i = 0; i < it.count; i++) {
if (unitIdx >= input->numUnits)
break;
const ecs_entity_t entity = it.entities[i];
setAIBehaviour(entity, game->BTs.moveTo, &(AIBlackboard) {
.moveToPos = target,
.proximity = 6.0f,
});
/*
clearActions(entity, game);
addAction(entity, game, &(const Action) {
.type = ACTION_MOVE_TO,
.as.moveTo.target = target,
.as.moveTo.proximityThreshold = 6.0f,
});
*/
if (!ecs_has(ECS, entity, Position)) continue;
entities[unitIdx++] = (EntityPosPair) {
.entity = entity,
.pos = *ecs_get(ECS, entity, Position)
};
}
}
ecs_defer_end(ECS);
qsort(entities, unitIdx, sizeof(*entities), entityPosPairCmpZero);
qsort(input->unitPlacePos, unitIdx, sizeof(*input->unitPlacePos), vec2CmpZero);
for (i32 i = 0; i < unitIdx; i++) {
ecs_entity_t entity = entities[i].entity;
setAIBehaviour(entity, game->BTs.moveTo, &(AIBlackboard) {
.moveToPos = positions[i],
.proximity = 1.0f,
});
}
}
}
@@ -194,6 +240,9 @@ void updatePlayerInput() {
Game *game = ecs_singleton_get_mut(ECS, Game);
InputState *input = ecs_singleton_get_mut(ECS, InputState);
input->numUnits = 0;
input->unitPlacePos = NULL;
const f32 maxZoom = 4.5f;
const f32 minZoom = 0.9f;
if (input->canUseKeyboard) {
@@ -370,6 +419,12 @@ void drawPlayerInputUIGround() {
}
}
if (input->unitPlacePos) {
for (i32 i = 0; i < input->numUnits; i++) {
DrawCircleV(input->unitPlacePos[i], 2.0f, RED);
}
}
}
void drawPlayerInputUI() {
@@ -512,8 +567,14 @@ static bool canPlaceUnit(Vector2 pos, f32 space, BzTileMap *map) {
return true;
}
static bool unitWithinMap(Vector2 pos, BzTileMap *map) {
f32 x = pos.x / map->tileWidth;
f32 y = pos.y / map->tileHeight;
void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 **outPlaces) {
return !(x < 0 || y < 0 || x >= map->width || y >= map->height);
}
i32 placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 *outPlaces) {
i32 outIdx = 0;
f32 angle = Vector2Angle(start, end);
f32 lineLength = Vector2Distance(start, end);
@@ -527,13 +588,15 @@ void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTil
pos.y += unitSpacing * 2.0f;
}
Vector2 unitPos = Vector2Add(start, Vector2Rotate(pos, angle));
if (!canPlaceUnit(unitPos, 4.0f, map)) {
bool withinMap = unitWithinMap(unitPos, map);
if (canPlaceUnit(unitPos, 4.0f, map) && withinMap) {
outPlaces[outIdx++] = unitPos;
} else if (withinMap) {
i--;
} else {
bzArrayPush(*outPlaces, unitPos);
}
pos.x += unitSpacing * 2.0f;
}
return outIdx;
}
static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos)) {