Polish up AI
This commit is contained in:
@@ -15,6 +15,8 @@ float shortestArc(float a, float b) {
|
||||
}
|
||||
|
||||
BzBTStatus aiMoveTo(AIBlackboard *data, f32 dt) {
|
||||
if (!data->shouldMoveTo)
|
||||
return BZ_BT_FAIL;
|
||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||
const Vector2 pos = *ecs_get(ECS, data->entity, Position);
|
||||
const HitBox hb = *ecs_get(ECS, data->entity, HitBox);
|
||||
@@ -23,12 +25,15 @@ BzBTStatus aiMoveTo(AIBlackboard *data, f32 dt) {
|
||||
f32 dst = Vector2Distance(center, target);
|
||||
if (dst < data->proximity) {
|
||||
ecs_remove(ECS, data->entity, Path);
|
||||
data->shouldMoveTo = false;
|
||||
return BZ_BT_SUCCESS;
|
||||
}
|
||||
if (!ecs_has(ECS, data->entity, Path)) {
|
||||
bool pathfindSuccessful = entitySetPath(data->entity, target, game);
|
||||
if (!pathfindSuccessful)
|
||||
if (!pathfindSuccessful) {
|
||||
data->shouldMoveTo = false;
|
||||
return BZ_BT_FAIL;
|
||||
}
|
||||
}
|
||||
if (ecs_has(ECS, data->entity, Orientation)) {
|
||||
Orientation *orientation = ecs_get_mut(ECS, data->entity, Orientation);
|
||||
@@ -47,18 +52,21 @@ BzBTStatus aiResetElapsed(AIBlackboard *data, f32 dt) {
|
||||
return BZ_BT_SUCCESS;
|
||||
}
|
||||
|
||||
#define ENEMY_NEARBY_DST 26.0f
|
||||
#define ENEMY_NEARBY_DST 30.0f
|
||||
#define ENEMY_CHASE_THRESH 25.0f
|
||||
#define ENEMY_EVADE_THRESH 30.0f
|
||||
|
||||
BzBTStatus aiIsEnemyNearby(AIBlackboard *data, f32 dt) {
|
||||
if (data->seenEnemy && ecs_is_alive(ECS, data->seenEnemy)) {
|
||||
Position enemyPos = *ecs_get(ECS, data->seenEnemy, Position);
|
||||
Position pos = *ecs_get(ECS, data->entity, Position);
|
||||
|
||||
if (Vector2Distance(enemyPos, pos) > ENEMY_NEARBY_DST)
|
||||
if (Vector2Distance(enemyPos, pos) < ENEMY_NEARBY_DST)
|
||||
return BZ_BT_SUCCESS;
|
||||
data->seenEnemy = 0;
|
||||
}
|
||||
|
||||
const f32 range = 20.0f;
|
||||
const f32 range = 30.0f;
|
||||
Position pos = *ecs_get(ECS, data->entity, Position);
|
||||
HitBox hb = *ecs_get(ECS, data->entity, HitBox);
|
||||
Vector2 center = entityGetCenter(pos, hb);
|
||||
@@ -109,6 +117,10 @@ BzBTStatus aiAttackEnemy(AIBlackboard *data, f32 dt) {
|
||||
Position enemyPos = *ecs_get(ECS, data->seenEnemy, Position);
|
||||
Position pos = *ecs_get(ECS, data->entity, Position);
|
||||
|
||||
f32 dst = Vector2Distance(pos, enemyPos);
|
||||
if (dst > ENEMY_CHASE_THRESH)
|
||||
return BZ_BT_FAIL;
|
||||
|
||||
Vector2 dif = Vector2Subtract(enemyPos, pos);
|
||||
// Overload steering
|
||||
Steering *steering = ecs_get_mut(ECS, data->entity, Steering);
|
||||
@@ -124,6 +136,10 @@ BzBTStatus aiEvadeEnemy(AIBlackboard *data, f32 dt) {
|
||||
Position enemyPos = *ecs_get(ECS, data->seenEnemy, Position);
|
||||
Position pos = *ecs_get(ECS, data->entity, Position);
|
||||
|
||||
f32 dst = Vector2Distance(pos, enemyPos);
|
||||
if (dst > ENEMY_EVADE_THRESH)
|
||||
return BZ_BT_FAIL;
|
||||
|
||||
Vector2 dif = Vector2Subtract(pos, enemyPos);
|
||||
// Overload steering
|
||||
Steering *steering = ecs_get_mut(ECS, data->entity, Steering);
|
||||
@@ -141,6 +157,7 @@ BzBTStatus aiFindNextHarvestable(AIBlackboard *data, f32 dt) {
|
||||
if (harvestable.harvestCount < harvestable.harvestLimit) {
|
||||
// Target still alive, no need to find next harvestable
|
||||
data->moveToPos = data->as.worker.harvestPos;
|
||||
data->shouldMoveTo = true;
|
||||
return BZ_BT_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -191,6 +208,7 @@ BzBTStatus aiFindNextHarvestable(AIBlackboard *data, f32 dt) {
|
||||
data->as.worker.harvestTarget = closest;
|
||||
data->as.worker.harvestPos = closestPos;
|
||||
data->moveToPos = closestPos;
|
||||
data->shouldMoveTo = true;
|
||||
return BZ_BT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -233,6 +251,7 @@ BzBTStatus aiFindNearestStorage(AIBlackboard *data, f32 dt) {
|
||||
|
||||
data->as.worker.depositTarget = closest;
|
||||
data->moveToPos = getPositionNearBuilding(closest, pos);
|
||||
data->shouldMoveTo = true;
|
||||
|
||||
return BZ_BT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ typedef struct AIBlackboard {
|
||||
ecs_entity_t entity;
|
||||
|
||||
ecs_entity_t seenEnemy;
|
||||
bool shouldMoveTo;
|
||||
Vector2 moveToPos;
|
||||
|
||||
union {
|
||||
|
||||
@@ -90,9 +90,7 @@ ecs_entity_t entityCreateSoldier(const Position position, Player player, Game *g
|
||||
unit.maxDamage = 10.0f;
|
||||
unit.attackCooldown = 1.0f;
|
||||
ecs_set_ptr(ECS, e, Unit, &unit);
|
||||
setAIBehaviour(e, game->BTs.unit, &(AIBlackboard) {
|
||||
.moveToPos = position,
|
||||
});
|
||||
setAIBehaviour(e, game->BTs.unit, NULL);
|
||||
return e;
|
||||
}
|
||||
ecs_entity_t entityCreateWarrior(const Position position, Player player, Game *game) {
|
||||
@@ -107,9 +105,7 @@ ecs_entity_t entityCreateWarrior(const Position position, Player player, Game *g
|
||||
unit.maxDamage = 22.0f;
|
||||
unit.attackCooldown = 1.8f;
|
||||
ecs_set_ptr(ECS, e, Unit, &unit);
|
||||
setAIBehaviour(e, game->BTs.unit, &(AIBlackboard) {
|
||||
.moveToPos = position,
|
||||
});
|
||||
setAIBehaviour(e, game->BTs.unit, NULL);
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -128,9 +124,7 @@ ecs_entity_t entityCreateWorker(const Position position, Player player, Game *ga
|
||||
.lastChanged = -1000.0f
|
||||
});
|
||||
|
||||
setAIBehaviour(e, game->BTs.unit, &(AIBlackboard) {
|
||||
.moveToPos = position,
|
||||
});
|
||||
setAIBehaviour(e, game->BTs.unitEvasive, NULL);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
12
game/main.c
12
game/main.c
@@ -274,6 +274,8 @@ bool init(void *userData) {
|
||||
game->BTs.unit = root;
|
||||
|
||||
BzBTNode *sel = bzBTCompSelector(nodePool, root);
|
||||
node = bzBTAction(nodePool, sel, (BzBTActionFn) aiMoveTo);
|
||||
bzBTNodeSetName(node, "moveTo");
|
||||
BzBTNode *attackSeq = bzBTCompSequence(nodePool, sel);
|
||||
{
|
||||
node = bzBTAction(nodePool, attackSeq, (BzBTActionFn) aiIsEnemyNearby);
|
||||
@@ -282,9 +284,7 @@ bool init(void *userData) {
|
||||
node = bzBTAction(nodePool, attackSeq, (BzBTActionFn) aiAttackEnemy);
|
||||
bzBTNodeSetName(node, "attackEnemy");
|
||||
}
|
||||
node = bzBTAction(nodePool, sel, (BzBTActionFn) aiMoveTo);
|
||||
bzBTNodeSetName(node, "moveTo");
|
||||
bzBTDecorDelay(nodePool, sel, 2.0f);
|
||||
bzBTDecorDelay(nodePool, sel, 0.2f);
|
||||
}
|
||||
// Unit (evasive)
|
||||
{
|
||||
@@ -294,6 +294,9 @@ bool init(void *userData) {
|
||||
game->BTs.unitEvasive = root;
|
||||
|
||||
BzBTNode *sel = bzBTCompSelector(nodePool, root);
|
||||
node = bzBTAction(nodePool, sel, (BzBTActionFn) aiMoveTo);
|
||||
bzBTNodeSetName(node, "moveTo");
|
||||
//bzBTDecorDelay(nodePool, sel, 0.2f);
|
||||
BzBTNode *evadeSeq = bzBTCompSequence(nodePool, sel);
|
||||
{
|
||||
node = bzBTAction(nodePool, evadeSeq, (BzBTActionFn) aiIsEnemyNearby);
|
||||
@@ -302,9 +305,6 @@ bool init(void *userData) {
|
||||
node = bzBTAction(nodePool, evadeSeq, (BzBTActionFn) aiEvadeEnemy);
|
||||
bzBTNodeSetName(node, "evadeEnemy");
|
||||
}
|
||||
node = bzBTAction(nodePool, sel, (BzBTActionFn) aiMoveTo);
|
||||
bzBTNodeSetName(node, "moveTo");
|
||||
bzBTDecorDelay(nodePool, sel, 2.0f);
|
||||
}
|
||||
// evade
|
||||
BzBTNode *evade = NULL;
|
||||
|
||||
@@ -263,8 +263,12 @@ void inputUnitAction(Game *game, InputState *input) {
|
||||
|
||||
for (i32 i = 0; i < unitIdx; i++) {
|
||||
ecs_entity_t entity = entities[i].entity;
|
||||
setAIBehaviour(entity, game->BTs.unit, &(AIBlackboard) {
|
||||
BzBTNode *BT = game->BTs.unit;
|
||||
if (ecs_has(ECS, entity, Worker))
|
||||
BT = game->BTs.unitEvasive;
|
||||
setAIBehaviour(entity, BT, &(AIBlackboard) {
|
||||
.moveToPos = positions[i],
|
||||
.shouldMoveTo = true,
|
||||
.proximity = 1.0f,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -406,11 +406,11 @@ void drawMainMenuUI(Game *game, f32 dt) {
|
||||
if (uiMainMenuButton("Play", true)) {
|
||||
setScreen(game, SCREEN_GAME);
|
||||
unloadMap(game);
|
||||
loadMap(game, "assets/maps/tree_test.tmj", false);
|
||||
//loadMap(game, "assets/maps/tree_test.tmj", false);
|
||||
//loadMap(game, "assets/maps/entity_test.tmj", false);
|
||||
//loadMap(game, "assets/maps/worker_test.tmj", false);
|
||||
//loadMap(game, "assets/maps/battle_test.tmj", false);
|
||||
//loadMap(game, "assets/maps/map_01.tmj", false);
|
||||
loadMap(game, "assets/maps/map_01.tmj", false);
|
||||
}
|
||||
if (uiMainMenuButton("Settings", true)) {
|
||||
setScreen(game, SCREEN_SETTINGS);
|
||||
|
||||
Reference in New Issue
Block a user