feat(orb): contra-atac amb bullet_double dirigida al jugador en rebre impacte
This commit is contained in:
@@ -3,13 +3,19 @@
|
||||
|
||||
#include "game/systems/enemy_event_dispatcher.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
#include "game/entities/bullet.hpp"
|
||||
#include "game/entities/bullet_config.hpp"
|
||||
#include "game/entities/bullet_registry.hpp"
|
||||
#include "game/entities/enemy_ai.hpp"
|
||||
#include "game/entities/enemy_config.hpp"
|
||||
#include "game/entities/ship.hpp"
|
||||
|
||||
namespace Systems::EnemyEvents {
|
||||
|
||||
@@ -72,6 +78,87 @@ namespace Systems::EnemyEvents {
|
||||
(bullet->getBody().mass * bullet->getConfig().physics.impact_momentum_factor);
|
||||
enemy.applyImpulse(IMPULSE);
|
||||
}
|
||||
|
||||
auto randFloat01() -> float {
|
||||
return static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
|
||||
}
|
||||
|
||||
// Còpia local de la mateixa primitiva que viu a enemy_ai_system.cpp.
|
||||
// No s'ha extret a un header compartit perquè és l'únic punt de
|
||||
// duplicació; si apareix un tercer consumidor, refactoritzar.
|
||||
auto findNearestShipPosition(const Enemy& enemy) -> const Vec2* {
|
||||
const Vec2& self = enemy.getCenter();
|
||||
const Vec2* best = nullptr;
|
||||
float best_dist_sq = 0.0F;
|
||||
for (const Ship* ship : enemy.getShips()) {
|
||||
if (ship == nullptr || !ship->isActive()) {
|
||||
continue;
|
||||
}
|
||||
const Vec2& pos = ship->getCenter();
|
||||
const Vec2 DELTA = pos - self;
|
||||
const float DIST_SQ = DELTA.lengthSquared();
|
||||
if (best == nullptr || DIST_SQ < best_dist_sq) {
|
||||
best = &pos;
|
||||
best_dist_sq = DIST_SQ;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
// FIRE_BULLET: paral·lel a doShoot() d'enemy_ai_system.cpp, però disparat
|
||||
// per esdeveniment (típicament on_hit per a contra-atacs) en lloc de
|
||||
// periòdicament. owner_id es deriva de l'índex dins ctx.enemies via
|
||||
// aritmètica de punters (l'array és contigu).
|
||||
void doFireBullet(Systems::Collision::Context& ctx, const Enemy& enemy, const EnemyAction& action) {
|
||||
if (action.bullet_config_name.empty()) {
|
||||
return;
|
||||
}
|
||||
const BulletConfig* cfg = BulletRegistry::get(action.bullet_config_name);
|
||||
if (cfg == nullptr) {
|
||||
return;
|
||||
}
|
||||
Bullet* slot = nullptr;
|
||||
constexpr std::size_t START = Defaults::Entities::ENEMY_BULLET_START_IDX;
|
||||
constexpr std::size_t END = START + Defaults::Entities::MAX_ENEMY_BULLETS;
|
||||
for (std::size_t i = START; i < END; ++i) {
|
||||
if (!ctx.bullets[i].isActive()) {
|
||||
slot = &ctx.bullets[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (slot == nullptr) {
|
||||
return; // pool d'enemic ple
|
||||
}
|
||||
|
||||
float angle = 0.0F;
|
||||
if (action.aim_mode == AimMode::AIMED) {
|
||||
const Vec2* target = findNearestShipPosition(enemy);
|
||||
if (target == nullptr) {
|
||||
angle = randFloat01() * 2.0F * Constants::PI;
|
||||
} else {
|
||||
const Vec2 TO = *target - enemy.getCenter();
|
||||
angle = std::atan2(TO.y, TO.x) + (Constants::PI / 2.0F);
|
||||
}
|
||||
} else {
|
||||
angle = randFloat01() * 2.0F * Constants::PI;
|
||||
}
|
||||
if (action.jitter_rad > 0.0F) {
|
||||
angle += (randFloat01() - 0.5F) * 2.0F * action.jitter_rad;
|
||||
}
|
||||
|
||||
// Localitzem l'índex de l'enemic per construir l'owner_id. Evitem
|
||||
// aritmètica de punters sobre Enemy (tipus polimòrfic — UB si la
|
||||
// jerarquia canvia); cerca lineal a l'array (mida petita, no és hot path).
|
||||
std::size_t enemy_index = 0;
|
||||
for (std::size_t i = 0; i < ctx.enemies.size(); ++i) {
|
||||
if (&ctx.enemies[i] == &enemy) {
|
||||
enemy_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto OWNER = static_cast<uint8_t>(Defaults::Entities::ENEMY_OWNER_BASE + enemy_index);
|
||||
slot->fire(enemy.getCenter(), angle, OWNER, action.bullet_speed, cfg);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void dispatchEvent(Systems::Collision::Context& ctx, Enemy& enemy, EnemyEventType event, uint8_t shooter_id, const Bullet* bullet) {
|
||||
@@ -153,6 +240,9 @@ namespace Systems::EnemyEvents {
|
||||
case EnemyActionType::FLASH:
|
||||
enemy.triggerFlash();
|
||||
break;
|
||||
case EnemyActionType::FIRE_BULLET:
|
||||
doFireBullet(ctx, enemy, action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user