feat(entities): migrar la configuració del player a data/entities/player/player.yaml
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include "core/audio/audio.hpp"
|
||||
#include "core/defaults.hpp"
|
||||
@@ -20,27 +21,26 @@
|
||||
#include "core/types.hpp"
|
||||
#include "game/constants.hpp"
|
||||
|
||||
Ship::Ship(Rendering::Renderer* renderer, const char* shape_file)
|
||||
: Entity(renderer) {
|
||||
// Brightness específico para naves
|
||||
Ship::Ship(Rendering::Renderer* renderer, PlayerConfig config, const char* shape_override)
|
||||
: Entity(renderer),
|
||||
config_(std::move(config)) {
|
||||
brightness_ = Defaults::Brightness::NAU;
|
||||
|
||||
// Configuración del cuerpo físico
|
||||
body_.setMass(Defaults::Ship::MASS);
|
||||
body_.radius = Defaults::Entities::SHIP_RADIUS;
|
||||
body_.restitution = Defaults::Ship::RESTITUTION;
|
||||
body_.linear_damping = Defaults::Ship::LINEAR_DAMPING;
|
||||
body_.angular_damping = Defaults::Ship::ANGULAR_DAMPING;
|
||||
body_.setMass(config_.physics.mass);
|
||||
body_.radius = config_.physics.collision_radius;
|
||||
body_.restitution = config_.physics.restitution;
|
||||
body_.linear_damping = config_.physics.linear_damping;
|
||||
body_.angular_damping = config_.physics.angular_damping;
|
||||
|
||||
// Cargar shape compartida desde archivo
|
||||
shape_ = Graphics::ShapeLoader::load(shape_file);
|
||||
// El shape pot venir del YAML o ser overridden (ex: P2 amb "ship2.shp").
|
||||
const std::string SHAPE_PATH = (shape_override != nullptr) ? shape_override : config_.shape.path;
|
||||
shape_ = Graphics::ShapeLoader::load(SHAPE_PATH);
|
||||
if (!shape_ || !shape_->isValid()) {
|
||||
std::cerr << "[Ship] Error: no se ha podido cargar " << shape_file << '\n';
|
||||
std::cerr << "[Ship] Error: no se ha podido cargar " << SHAPE_PATH << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void Ship::init(const Vec2* spawn_point, bool activar_invulnerabilitat) {
|
||||
// Posición inicial
|
||||
if (spawn_point != nullptr) {
|
||||
center_ = *spawn_point;
|
||||
} else {
|
||||
@@ -50,34 +50,27 @@ void Ship::init(const Vec2* spawn_point, bool activar_invulnerabilitat) {
|
||||
center_ = {.x = center_x, .y = center_y};
|
||||
}
|
||||
|
||||
// Reset orientación
|
||||
angle_ = 0.0F;
|
||||
|
||||
// Sincronizar cuerpo físico con la posición/orientación inicial
|
||||
body_.position = center_;
|
||||
body_.angle = angle_;
|
||||
body_.velocity = Vec2{};
|
||||
body_.angular_velocity = 0.0F;
|
||||
body_.clearAccumulators();
|
||||
|
||||
// Activar invulnerabilidad solo si es respawn
|
||||
invulnerable_timer_ = activar_invulnerabilitat ? Defaults::Ship::INVULNERABILITY_DURATION : 0.0F;
|
||||
invulnerable_timer_ = activar_invulnerabilitat ? config_.invulnerability.duration : 0.0F;
|
||||
is_hit_ = false;
|
||||
hurt_timer_ = 0.0F;
|
||||
touching_enemy_prev_frame_ = false;
|
||||
}
|
||||
|
||||
void Ship::processInput(float delta_time, uint8_t player_id) {
|
||||
// Solo procesa input si la nave está viva
|
||||
if (is_hit_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* input = Input::get();
|
||||
|
||||
// Rotación: control directo del ángulo (no física, no inercial).
|
||||
// Se actualiza también body_.angle para que el dibujado tras
|
||||
// postUpdate refleje el cambio inmediatamente.
|
||||
const bool ROTATE_RIGHT = (player_id == 0)
|
||||
? input->checkActionPlayer1(InputAction::RIGHT, Input::ALLOW_REPEAT)
|
||||
: input->checkActionPlayer2(InputAction::RIGHT, Input::ALLOW_REPEAT);
|
||||
@@ -89,10 +82,10 @@ void Ship::processInput(float delta_time, uint8_t player_id) {
|
||||
: input->checkActionPlayer2(InputAction::THRUST, Input::ALLOW_REPEAT);
|
||||
|
||||
if (ROTATE_RIGHT) {
|
||||
body_.angle += Defaults::Physics::ROTATION_SPEED * delta_time;
|
||||
body_.angle += config_.physics.rotation_speed * delta_time;
|
||||
}
|
||||
if (ROTATE_LEFT) {
|
||||
body_.angle -= Defaults::Physics::ROTATION_SPEED * delta_time;
|
||||
body_.angle -= config_.physics.rotation_speed * delta_time;
|
||||
}
|
||||
|
||||
// Thrust: fuerza vectorial en la dirección de la nariz.
|
||||
@@ -100,44 +93,36 @@ void Ship::processInput(float delta_time, uint8_t player_id) {
|
||||
if (THRUST) {
|
||||
const float DIR_X = std::cos(body_.angle - (Constants::PI / 2.0F));
|
||||
const float DIR_Y = std::sin(body_.angle - (Constants::PI / 2.0F));
|
||||
// Fuerza = masa * aceleración: 10 kg * 400 px/s² = 4000 (unidades arcade)
|
||||
const float MAGNITUDE = body_.mass * Defaults::Physics::ACCELERATION;
|
||||
const float MAGNITUDE = body_.mass * config_.physics.acceleration;
|
||||
body_.applyForce(Vec2{.x = DIR_X * MAGNITUDE, .y = DIR_Y * MAGNITUDE});
|
||||
}
|
||||
}
|
||||
|
||||
void Ship::update(float delta_time) {
|
||||
// Solo update si la nave está viva
|
||||
if (is_hit_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Decrementar timer de invulnerabilidad
|
||||
if (invulnerable_timer_ > 0.0F) {
|
||||
invulnerable_timer_ -= delta_time;
|
||||
invulnerable_timer_ = std::max(invulnerable_timer_, 0.0F);
|
||||
}
|
||||
|
||||
// Decrementar timer d'estat HURT (a 0 → torna a normal sense efecte extern)
|
||||
if (hurt_timer_ > 0.0F) {
|
||||
hurt_timer_ -= delta_time;
|
||||
hurt_timer_ = std::max(hurt_timer_, 0.0F);
|
||||
}
|
||||
|
||||
// El movimiento real lo hace PhysicsWorld::update().
|
||||
// Aquí solo lógica de estado.
|
||||
|
||||
// Cap de velocidad: el thrust acumula fuerza sin límite; limitamos
|
||||
// la magnitud de body_.velocity tras aplicar fuerzas para preservar
|
||||
// el feel arcade del MAX_VELOCITY original.
|
||||
const float CURRENT_SPEED = body_.velocity.length();
|
||||
if (CURRENT_SPEED > Defaults::Physics::MAX_VELOCITY) {
|
||||
body_.velocity = body_.velocity * (Defaults::Physics::MAX_VELOCITY / CURRENT_SPEED);
|
||||
if (CURRENT_SPEED > config_.physics.max_velocity) {
|
||||
body_.velocity = body_.velocity * (config_.physics.max_velocity / CURRENT_SPEED);
|
||||
}
|
||||
}
|
||||
|
||||
void Ship::postUpdate(float /*delta_time*/) {
|
||||
// Sincronizar mirror desde body_ tras la integración del world.
|
||||
center_ = body_.position;
|
||||
angle_ = body_.angle;
|
||||
}
|
||||
@@ -147,11 +132,10 @@ void Ship::draw() const {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parpadeo si invulnerable
|
||||
if (isInvulnerable()) {
|
||||
const float BLINK_CYCLE = Defaults::Ship::BLINK_VISIBLE_TIME + Defaults::Ship::BLINK_INVISIBLE_TIME;
|
||||
const float BLINK_CYCLE = config_.invulnerability.blink_visible + config_.invulnerability.blink_invisible;
|
||||
const float TIME_IN_CYCLE = std::fmod(invulnerable_timer_, BLINK_CYCLE);
|
||||
if (TIME_IN_CYCLE < Defaults::Ship::BLINK_INVISIBLE_TIME) {
|
||||
if (TIME_IN_CYCLE < config_.invulnerability.blink_invisible) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -161,19 +145,17 @@ void Ship::draw() const {
|
||||
}
|
||||
|
||||
// Efecto visual de empuje: escala proporcional a la velocidad.
|
||||
// 0..200 px/s → escala 1.0..1.5 (manteniendo la sensación del Pascal original).
|
||||
const float SPEED = getSpeed();
|
||||
const float VISUAL_PUSH = SPEED / Defaults::Ship::VISUAL_PUSH_DIVISOR;
|
||||
const float SCALE = 1.0F + (VISUAL_PUSH / Defaults::Ship::VISUAL_SCALE_DIVISOR);
|
||||
const float VISUAL_PUSH = SPEED / config_.visual_thrust.push_divisor;
|
||||
const float SCALE = 1.0F + (VISUAL_PUSH / config_.visual_thrust.scale_divisor);
|
||||
|
||||
// Parpelleig daurat mentre està ferida: alterna color normal ↔ color hurt
|
||||
// a Hurt::BLINK_HZ (mateixa estètica que el wounded dels enemics).
|
||||
SDL_Color color = color_normal_;
|
||||
// Parpelleig daurat mentre està ferida: alterna color normal ↔ color hurt.
|
||||
SDL_Color color = config_.colors.normal;
|
||||
if (hurt_timer_ > 0.0F) {
|
||||
const float CYCLE = 1.0F / Defaults::Ship::Hurt::BLINK_HZ;
|
||||
const float CYCLE = 1.0F / config_.hurt.blink_hz;
|
||||
const float T = std::fmod(hurt_timer_, CYCLE);
|
||||
if (T < (CYCLE / 2.0F)) {
|
||||
color = color_hurt_;
|
||||
color = config_.colors.hurt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +163,6 @@ void Ship::draw() const {
|
||||
}
|
||||
|
||||
void Ship::hurt() {
|
||||
hurt_timer_ = Defaults::Ship::Hurt::DURATION;
|
||||
hurt_timer_ = config_.hurt.duration;
|
||||
Audio::get()->playSound(Defaults::Sound::HURT, Audio::Group::GAME);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user