// enemy_ai.hpp - Sistema declaratiu d'IA per a enemics // © 2026 JailDesigner // // Cada enemic declara al seu YAML quin movement primitiu fa servir i, opcional- // ment, una llista d'accions periòdiques (tick). El motor només dispatcha; el // comportament viu a les dades. Patró paral·lel al d'events declaratius // (enemy_event.hpp). #pragma once #include #include #include // Primitiva de moviment activa per a un enemic. Substitueix el switch // hardcoded sobre EnemyType. enum class MovementType : uint8_t { ZIGZAG, // Canvi de direcció probabilístic agressiu (Pentagon/Star) TRACKING, // LERP discret cap al ship cada N segons (Square) RECTILINEAR_PROXIMITY, // Rectilini + boost rotació visual prop del ship (Pinwheel) WANDER, // Canvi de direcció probabilístic suau, sense target CHASE, // Steering continu cap al ship més proper FLEE, // Steering continu allunyant-se del ship més proper }; // Accions que s'executen periòdicament (un timer per acció). Futur (Fase C): // SHOOT amb aim_mode/jitter/bullet config. enum class AiActionType : uint8_t { SHOOT, }; enum class AimMode : uint8_t { RANDOM, // Angle uniformement aleatori AIMED, // atan2(nearest_ship - center) + soroll gaussià (jitter_rad) }; // Camps de tots els movements; només el subset rellevant per al type actiu // s'usa. Els altres queden a 0.0F. Mateixa filosofia que la BehaviorCfg // llegacy però amb el type explícit dins. struct MovementConfig { MovementType type{MovementType::ZIGZAG}; // ZIGZAG i WANDER (canvi de direcció probabilístic; comparteixen camps). float angle_change_max{0.0F}; float zigzag_prob_per_second{0.0F}; // TRACKING float tracking_strength{0.0F}; float tracking_interval{0.0F}; // RECTILINEAR_PROXIMITY float rotation_proximity_multiplier{0.0F}; float proximity_distance{0.0F}; // CHASE / FLEE: força del steering per segon (LERP velocity ↔ direcció ideal). // 1.0 = en ~1s la velocitat queda totalment realineada cap al target. float chase_strength{0.0F}; float flee_strength{0.0F}; }; // Acció periòdica. interval = segons entre disparades; el dispatcher manté un // timer per acció (paral·lel a aquesta llista) i dispara quan arriba a 0. struct AiTickAction { AiActionType type{AiActionType::SHOOT}; float interval{1.0F}; AimMode aim_mode{AimMode::RANDOM}; float jitter_rad{0.0F}; float bullet_speed{200.0F}; // px/s; la magnitud la decideix l'enemic, no el bullet config std::string bullet_config_name; // bullet config a usar (lazy-load des de BulletRegistry) }; struct EnemyAiConfig { MovementConfig movement; std::vector tick; }; // Estat per-instància que la primitiva de moviment manté entre frames (timers // d'interval, contadors de canvi de direcció...). Es viu dins de Enemy i el // sistema d'IA hi escriu via getAiState(). struct EnemyAiState { float direction_change_timer{0.0F}; // ZIGZAG float tracking_timer{0.0F}; // TRACKING float tracking_strength{0.0F}; // TRACKING (cau de cfg, mutable per dificultat) };