feat(enemy): sistema d'events declaratius via YAML
This commit is contained in:
1 parent
9b3da3a6e7
commit
9c0502eefb
10 files changed
+299
-71
No files matched your search
@@ -9,61 +9,11 @@
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
#include "game/entities/bullet_config.hpp"
|
||||
#include "game/entities/enemy_config.hpp"
|
||||
#include "game/systems/enemy_event_dispatcher.hpp"
|
||||
|
||||
namespace Systems::Collision {
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t NO_SHOOTER = 0xFF;
|
||||
|
||||
// Mata al enemy con explosión: floating score, debris con velocity heredada,
|
||||
// sonido. Si shooter_id ≠ NO_SHOOTER, suma puntos a ese jugador.
|
||||
// CRUCIAL: leer velocity/datos ANTES de destruir() (que zera la velocity).
|
||||
void explodeNow(Context& ctx, Enemy& enemy, uint8_t shooter_id) {
|
||||
const Vec2 ENEMY_POS = enemy.getCenter();
|
||||
const Vec2 ENEMY_VEL = enemy.getVelocityVector();
|
||||
const float BRIGHTNESS = enemy.getBrightness();
|
||||
const auto SHAPE = enemy.getShape();
|
||||
|
||||
const int POINTS = enemy.getConfig().score;
|
||||
const SDL_Color COLOR = enemy.getConfig().colors.normal;
|
||||
const SDL_Color WOUNDED_COLOR = enemy.getConfig().colors.wounded;
|
||||
|
||||
if (shooter_id != NO_SHOOTER) {
|
||||
ctx.score_per_player[shooter_id] += POINTS;
|
||||
}
|
||||
ctx.floating_score_manager.crear(POINTS, ENEMY_POS);
|
||||
|
||||
enemy.destroy();
|
||||
|
||||
constexpr float SPEED_EXPLOSIO = 80.0F; // px/s (explosión suave)
|
||||
const Vec2 INHERITED_VEL = ENEMY_VEL * Defaults::Physics::Debris::ENEMY_VELOCITY_INHERITANCE;
|
||||
ctx.debris_manager.explode(
|
||||
SHAPE,
|
||||
ENEMY_POS,
|
||||
0.0F, // angle (rotación interna del enemy)
|
||||
1.0F, // escala
|
||||
SPEED_EXPLOSIO,
|
||||
BRIGHTNESS,
|
||||
INHERITED_VEL,
|
||||
0.0F, // sense herència angular: evita que els 5 trossos curvin en bloc
|
||||
0.0F, // sin herencia visual
|
||||
Defaults::Sound::EXPLOSION,
|
||||
COLOR,
|
||||
Defaults::Physics::Debris::ENEMY_LIFETIME,
|
||||
Defaults::Physics::Debris::ENEMY_FRICTION,
|
||||
Defaults::Physics::Debris::ENEMY_SEGMENT_MULTIPLIER);
|
||||
|
||||
// Firework burst radial des del centro de l'enemic (efecte adicional al debris).
|
||||
// Línia blanca + halo daurat (WOUNDED) per a feel d'espurnes.
|
||||
ctx.firework_manager.spawn(ENEMY_POS,
|
||||
Defaults::FX::Firework::DEFAULT_COLOR,
|
||||
Defaults::FX::Firework::SPEED,
|
||||
Defaults::FX::Firework::N_POINTS,
|
||||
Defaults::FX::Firework::INITIAL_BRIGHTNESS,
|
||||
/*glow=*/true,
|
||||
WOUNDED_COLOR);
|
||||
}
|
||||
|
||||
// Trenca una bala en debris (8 fragments de l'octàgon) + so HIT + desactiva.
|
||||
// S'invoca des de qualsevol desactivació de bala (impacte amb enemic, amb jugador,
|
||||
@@ -102,26 +52,11 @@ namespace Systems::Collision {
|
||||
}
|
||||
|
||||
// *** COLISIÓN bullet → enemy ***
|
||||
// Empuje físico cuasi-realista: el impulse és el moment de la bala
|
||||
// (m·v) multiplicat pel factor de transferència. Direcció = vector
|
||||
// velocity de la bala (cap a on viatjava).
|
||||
const Vec2 IMPULSE = bullet.getBody().velocity *
|
||||
(bullet.getBody().mass * bullet.getConfig().physics.impact_momentum_factor);
|
||||
enemy.applyImpulse(IMPULSE);
|
||||
|
||||
const uint8_t SHOOTER = bullet.getOwnerId();
|
||||
|
||||
if (enemy.isWounded()) {
|
||||
// Segundo impacto sobre enemy ya herido → muerte instantánea,
|
||||
// puntos al nuevo shooter.
|
||||
explodeNow(ctx, enemy, SHOOTER);
|
||||
} else {
|
||||
// Primer impacto → entra en estado herido (explosión diferida).
|
||||
enemy.hurt(SHOOTER);
|
||||
}
|
||||
|
||||
// La cadena d'efectes (impulse, hurt, destroy, debris, score...) viu
|
||||
// al YAML de l'enemic via la secció `events:`. Aquí només dispatchem.
|
||||
Systems::EnemyEvents::dispatchEvent(ctx, enemy, EnemyEventType::ON_HIT, bullet.getOwnerId(), &bullet);
|
||||
breakBullet(ctx.debris_manager, bullet);
|
||||
break; // Una bala impacta a un enemy y muere
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +67,7 @@ namespace Systems::Collision {
|
||||
continue;
|
||||
}
|
||||
enemy.consumeWoundExpired();
|
||||
explodeNow(ctx, enemy, enemy.getLastHitBy());
|
||||
Systems::EnemyEvents::dispatchEvent(ctx, enemy, EnemyEventType::ON_HURT_END, enemy.getLastHitBy());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// enemy_event_dispatcher.cpp - Implementació del dispatcher d'events d'enemic
|
||||
// © 2026 JailDesigner
|
||||
|
||||
#include "game/systems/enemy_event_dispatcher.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/types.hpp"
|
||||
#include "game/entities/bullet.hpp"
|
||||
#include "game/entities/bullet_config.hpp"
|
||||
#include "game/entities/enemy_config.hpp"
|
||||
|
||||
namespace Systems::EnemyEvents {
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t NO_SHOOTER = 0xFF;
|
||||
|
||||
void doAddScore(Systems::Collision::Context& ctx, const Enemy& enemy, uint8_t shooter) {
|
||||
const int POINTS = enemy.getConfig().score;
|
||||
if (shooter != NO_SHOOTER) {
|
||||
ctx.score_per_player[shooter] += POINTS;
|
||||
}
|
||||
ctx.floating_score_manager.crear(POINTS, enemy.getCenter());
|
||||
}
|
||||
|
||||
void doCreateDebris(Systems::Collision::Context& ctx, const Enemy& enemy) {
|
||||
constexpr float SPEED_EXPLOSIO = 80.0F;
|
||||
const Vec2 INHERITED_VEL = enemy.getVelocityVector() *
|
||||
Defaults::Physics::Debris::ENEMY_VELOCITY_INHERITANCE;
|
||||
ctx.debris_manager.explode(
|
||||
enemy.getShape(),
|
||||
enemy.getCenter(),
|
||||
0.0F,
|
||||
1.0F,
|
||||
SPEED_EXPLOSIO,
|
||||
enemy.getBrightness(),
|
||||
INHERITED_VEL,
|
||||
0.0F,
|
||||
0.0F,
|
||||
Defaults::Sound::EXPLOSION,
|
||||
enemy.getConfig().colors.normal,
|
||||
Defaults::Physics::Debris::ENEMY_LIFETIME,
|
||||
Defaults::Physics::Debris::ENEMY_FRICTION,
|
||||
Defaults::Physics::Debris::ENEMY_SEGMENT_MULTIPLIER);
|
||||
}
|
||||
|
||||
void doCreateFireworks(Systems::Collision::Context& ctx, const Enemy& enemy) {
|
||||
ctx.firework_manager.spawn(enemy.getCenter(),
|
||||
Defaults::FX::Firework::DEFAULT_COLOR,
|
||||
Defaults::FX::Firework::SPEED,
|
||||
Defaults::FX::Firework::N_POINTS,
|
||||
Defaults::FX::Firework::INITIAL_BRIGHTNESS,
|
||||
/*glow=*/true,
|
||||
enemy.getConfig().colors.wounded);
|
||||
}
|
||||
|
||||
void doApplyImpulse(Enemy& enemy, const Bullet* bullet) {
|
||||
if (bullet == nullptr) {
|
||||
return;
|
||||
}
|
||||
const Vec2 IMPULSE = bullet->getBody().velocity *
|
||||
(bullet->getBody().mass * bullet->getConfig().physics.impact_momentum_factor);
|
||||
enemy.applyImpulse(IMPULSE);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void dispatchEvent(Systems::Collision::Context& ctx, Enemy& enemy, EnemyEventType event, uint8_t shooter_id, const Bullet* bullet) {
|
||||
const auto& actions = enemy.getConfig().events.getActions(event);
|
||||
for (const auto& action : actions) {
|
||||
switch (action.type) {
|
||||
case EnemyActionType::SET_HURT:
|
||||
if (enemy.isWounded()) {
|
||||
// Segon hit sobre wounded → mort immediata (regla 2-hits).
|
||||
dispatchEvent(ctx, enemy, EnemyEventType::ON_DESTROY, shooter_id, bullet);
|
||||
enemy.destroy();
|
||||
} else {
|
||||
enemy.hurt(shooter_id);
|
||||
}
|
||||
break;
|
||||
case EnemyActionType::DESTROY:
|
||||
dispatchEvent(ctx, enemy, EnemyEventType::ON_DESTROY, shooter_id, bullet);
|
||||
enemy.destroy();
|
||||
break;
|
||||
case EnemyActionType::ADD_SCORE:
|
||||
doAddScore(ctx, enemy, shooter_id);
|
||||
break;
|
||||
case EnemyActionType::CREATE_DEBRIS:
|
||||
doCreateDebris(ctx, enemy);
|
||||
break;
|
||||
case EnemyActionType::CREATE_FIREWORKS:
|
||||
doCreateFireworks(ctx, enemy);
|
||||
break;
|
||||
case EnemyActionType::APPLY_IMPULSE:
|
||||
doApplyImpulse(enemy, bullet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Systems::EnemyEvents
|
||||
@@ -0,0 +1,23 @@
|
||||
// enemy_event_dispatcher.hpp - Executa les accions YAML d'un event d'enemic
|
||||
// © 2026 JailDesigner
|
||||
//
|
||||
// Mira la llista d'EnemyAction associada a l'event al config de l'enemic i les
|
||||
// executa una per una. L'acció DESTROY dispara recursivament ON_DESTROY abans
|
||||
// de desactivar físicament l'enemic (el parser garanteix que ON_DESTROY no
|
||||
// conté DESTROY, evitant recursió infinita).
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "game/entities/enemy_event.hpp"
|
||||
#include "game/systems/collision_system.hpp"
|
||||
|
||||
namespace Systems::EnemyEvents {
|
||||
|
||||
// shooter_id: id del jugador que ha disparat (0xFF = sense atribució).
|
||||
// bullet: punter opcional a la bala que ha causat l'event (usat per APPLY_IMPULSE);
|
||||
// nullptr per a events no derivats d'una bala (on_hurt_end).
|
||||
void dispatchEvent(Systems::Collision::Context& ctx, Enemy& enemy, EnemyEventType event, uint8_t shooter_id, const Bullet* bullet = nullptr);
|
||||
|
||||
} // namespace Systems::EnemyEvents
|
||||
Reference in new issue
Block a user