feat(enemy): migrar el moviment dels enemics a un sistema d'IA declaratiu

This commit is contained in:
2026-05-25 17:45:30 +02:00
parent 410955de3c
commit 61e40e88f4
8 changed files with 379 additions and 95 deletions
+6 -84
View File
@@ -28,14 +28,6 @@ namespace {
};
}
// Recupera el "ángulo equivalente" de un body en movimiento (para zigzag).
auto velocityToAngle(const Vec2& velocity) -> float {
if (velocity.lengthSquared() < 0.0001F) {
return 0.0F;
}
return std::atan2(velocity.y, velocity.x) + (Constants::PI / 2.0F);
}
// Random float [0..1).
auto randFloat01() -> float {
return static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
@@ -62,10 +54,8 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
config_ = &EnemyRegistry::get(type);
const EnemyConfig& cfg = *config_;
if (type_ == EnemyType::SQUARE) {
tracking_timer_ = 0.0F;
tracking_strength_ = cfg.behavior.tracking_strength;
}
ai_state_ = EnemyAiState{};
ai_state_.tracking_strength = cfg.ai.movement.tracking_strength;
shape_ = Graphics::ShapeLoader::load(cfg.shape.path);
if (!shape_ || !shape_->isValid()) {
@@ -136,8 +126,6 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
invulnerability_timer_ = cfg.spawn.invulnerability_duration;
brightness_ = cfg.spawn.invulnerability_brightness_start;
direction_change_timer_ = 0.0F;
is_active_ = true;
}
@@ -167,22 +155,9 @@ void Enemy::update(float delta_time) {
brightness_ = START + ((END - START) * SMOOTH_T);
}
if (!isWounded()) {
switch (type_) {
case EnemyType::PENTAGON:
case EnemyType::STAR:
// STAR reusa el zigzag esquivador de Pentagon. Si en el futur
// vol comportament propi, separa-li el cas.
behaviorPentagon(delta_time);
break;
case EnemyType::SQUARE:
behaviorSquare(delta_time);
break;
case EnemyType::PINWHEEL:
behaviorPinwheel(delta_time);
break;
}
}
// El moviment es delega a Systems::EnemyAi::tick, invocat des de l'scene
// ABANS d'aquest update (manté l'ordre: AI escriu velocity/rotation_delta,
// després animation pot modular rotation_delta via rotation_accel).
updateAnimation(delta_time);
@@ -246,59 +221,6 @@ void Enemy::setVelocityFromAngle(float angle_movement, float speed) {
body_.velocity = angleToDirection(angle_movement) * speed;
}
// PENTAGON: zigzag esquivador. Canvis de direcció periòdics (probabilístics)
// en lloc de detectar parets; el rebot contra murs el fa PhysicsWorld.
void Enemy::behaviorPentagon(float delta_time) {
direction_change_timer_ += delta_time;
if (randFloat01() < config_->behavior.zigzag_prob_per_second * delta_time) {
const float CURRENT_ANGLE = velocityToAngle(body_.velocity);
const float DELTA = randFloat01() * config_->behavior.angle_change_max;
const float NEW_ANGLE = CURRENT_ANGLE + ((std::rand() % 2 == 0) ? DELTA : -DELTA);
const float SPEED = body_.velocity.length();
setVelocityFromAngle(NEW_ANGLE, SPEED);
direction_change_timer_ = 0.0F;
}
}
// SQUARE: tracking discret cap a la nau cada N segons.
void Enemy::behaviorSquare(float delta_time) {
tracking_timer_ += delta_time;
if (tracking_timer_ >= config_->behavior.tracking_interval && ship_position_ != nullptr) {
tracking_timer_ = 0.0F;
const Vec2 TO_SHIP = *ship_position_ - center_;
const float DIST = TO_SHIP.length();
if (DIST > 0.0F) {
const Vec2 DESIRED_DIR = TO_SHIP / DIST;
const float SPEED = body_.velocity.length();
const Vec2 DESIRED_VEL = DESIRED_DIR * SPEED;
body_.velocity = (body_.velocity * (1.0F - tracking_strength_)) +
(DESIRED_VEL * tracking_strength_);
const float NEW_SPEED = body_.velocity.length();
if (NEW_SPEED > 0.0F) {
body_.velocity = body_.velocity * (SPEED / NEW_SPEED);
}
}
}
}
// PINWHEEL: movement rectilini + boost de rotació visual prop del ship.
void Enemy::behaviorPinwheel(float /*delta_time*/) {
if (ship_position_ != nullptr) {
const Vec2 TO_SHIP = *ship_position_ - center_;
const float DIST = TO_SHIP.length();
if (DIST < config_->behavior.proximity_distance) {
rotation_delta_ = animation_.rotation_delta_base * config_->behavior.rotation_proximity_multiplier;
} else {
rotation_delta_ = animation_.rotation_delta_base;
}
}
}
void Enemy::updateAnimation(float delta_time) {
updatePulse(delta_time);
updateRotationAcceleration(delta_time);
@@ -373,7 +295,7 @@ auto Enemy::getBaseRotation() const -> float {
void Enemy::setTrackingStrength(float strength) {
if (type_ == EnemyType::SQUARE) {
tracking_strength_ = strength;
ai_state_.tracking_strength = strength;
}
}