Files
vibe3_physics/source/scene/scene_manager.cpp
Sergio c9bcce6f9b style: aplicar fixes de clang-tidy (todo excepto uppercase-literal-suffix)
Corregidos ~2570 issues automáticamente con clang-tidy --fix-errors
más ajustes manuales posteriores:

- modernize: designated-initializers, trailing-return-type, use-auto,
  avoid-c-arrays (→ std::array<>), use-ranges, use-emplace,
  deprecated-headers, use-equals-default, pass-by-value,
  return-braced-init-list, use-default-member-init
- readability: math-missing-parentheses, implicit-bool-conversion,
  braces-around-statements, isolate-declaration, use-std-min-max,
  identifier-naming, else-after-return, redundant-casting,
  convert-member-functions-to-static, make-member-function-const,
  static-accessed-through-instance
- performance: avoid-endl, unnecessary-value-param, type-promotion,
  inefficient-vector-operation
- dead code: XOR_KEY (orphan tras eliminar encryptData/decryptData),
  dead stores en engine.cpp y png_shape.cpp
- NOLINT justificado en 10 funciones con alta complejidad cognitiva
  (initialize, render, main, processEvents, update×3, performDemoAction,
  randomizeOnDemoStart, renderDebugHUD, AppLogo::update)

Compilación: gcc -Wall sin warnings. clang-tidy: 0 issues.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 10:52:07 +01:00

268 lines
8.6 KiB
C++

#include "scene_manager.hpp"
#include <cstdlib> // for rand
#include <utility>
#include "defines.hpp" // for BALL_COUNT_SCENARIOS, GRAVITY_MASS_MIN, etc
#include "external/texture.hpp" // for Texture
#include "theme_manager.hpp" // for ThemeManager
SceneManager::SceneManager(int screen_width, int screen_height)
: current_gravity_(GravityDirection::DOWN),
scenario_(0),
screen_width_(screen_width),
screen_height_(screen_height),
current_ball_size_(10),
texture_(nullptr),
theme_manager_(nullptr) {
}
void SceneManager::initialize(int scenario, std::shared_ptr<Texture> texture, ThemeManager* theme_manager) {
scenario_ = scenario;
texture_ = std::move(texture);
theme_manager_ = theme_manager;
current_ball_size_ = texture_->getWidth();
// Crear bolas iniciales (siempre en modo PHYSICS al inicio)
changeScenario(scenario_, SimulationMode::PHYSICS);
}
void SceneManager::update(float delta_time) {
// Actualizar física de todas las bolas
for (auto& ball : balls_) {
ball->update(delta_time);
}
}
void SceneManager::changeScenario(int scenario_id, SimulationMode mode) {
// Guardar escenario
scenario_ = scenario_id;
// Limpiar las bolas actuales
balls_.clear();
// Resetear gravedad al estado por defecto (DOWN) al cambiar escenario
changeGravityDirection(GravityDirection::DOWN);
// Crear las bolas según el escenario
int ball_count = (scenario_id == CUSTOM_SCENARIO_IDX)
? custom_ball_count_
: BALL_COUNT_SCENARIOS[scenario_id];
for (int i = 0; i < ball_count; ++i) {
float x;
float y;
float vx;
float vy;
// Inicialización según SimulationMode (RULES.md líneas 23-26)
switch (mode) {
case SimulationMode::PHYSICS: {
// PHYSICS: Parte superior, 75% distribución central en X
const int SIGN = ((rand() % 2) * 2) - 1;
const int MARGIN = static_cast<int>(screen_width_ * BALL_SPAWN_MARGIN);
const int SPAWN_ZONE_WIDTH = screen_width_ - (2 * MARGIN);
x = (rand() % SPAWN_ZONE_WIDTH) + MARGIN;
y = 0.0f; // Parte superior
vx = (((rand() % 20) + 10) * 0.1f) * SIGN;
vy = ((rand() % 60) - 30) * 0.1f;
break;
}
case SimulationMode::SHAPE: {
// SHAPE: Centro de pantalla, sin velocidad inicial
x = screen_width_ / 2.0f;
y = screen_height_ / 2.0f; // Centro vertical
vx = 0.0f;
vy = 0.0f;
break;
}
case SimulationMode::BOIDS: {
// BOIDS: Posiciones aleatorias, velocidades aleatorias
const int SIGN_X = ((rand() % 2) * 2) - 1;
const int SIGN_Y = ((rand() % 2) * 2) - 1;
x = static_cast<float>(rand() % screen_width_);
y = static_cast<float>(rand() % screen_height_); // Posición Y aleatoria
vx = (((rand() % 40) + 10) * 0.1f) * SIGN_X; // 1.0 - 5.0 px/frame
vy = (((rand() % 40) + 10) * 0.1f) * SIGN_Y;
break;
}
default:
// Fallback a PHYSICS por seguridad
const int SIGN = ((rand() % 2) * 2) - 1;
const int MARGIN = static_cast<int>(screen_width_ * BALL_SPAWN_MARGIN);
const int SPAWN_ZONE_WIDTH = screen_width_ - (2 * MARGIN);
x = (rand() % SPAWN_ZONE_WIDTH) + MARGIN;
y = 0.0f; // Parte superior
vx = (((rand() % 20) + 10) * 0.1f) * SIGN;
vy = ((rand() % 60) - 30) * 0.1f;
break;
}
// Seleccionar color de la paleta del tema actual (delegado a ThemeManager)
int random_index = rand();
Color color = theme_manager_->getInitialBallColor(random_index);
// Generar factor de masa aleatorio (0.7 = ligera, 1.3 = pesada)
float mass_factor = GRAVITY_MASS_MIN + ((rand() % 1000) / 1000.0f * (GRAVITY_MASS_MAX - GRAVITY_MASS_MIN));
balls_.emplace_back(std::make_unique<Ball>(
x,
y,
vx,
vy,
color,
texture_,
screen_width_,
screen_height_,
current_ball_size_,
current_gravity_,
mass_factor));
}
}
void SceneManager::updateBallTexture(std::shared_ptr<Texture> new_texture, int new_ball_size) {
if (balls_.empty()) {
return;
}
// Guardar tamaño antiguo
int old_size = current_ball_size_;
// Actualizar textura y tamaño
texture_ = std::move(new_texture);
current_ball_size_ = new_ball_size;
// Actualizar texturas de todas las pelotas
for (auto& ball : balls_) {
ball->setTexture(texture_);
}
// Ajustar posiciones según el cambio de tamaño
updateBallSizes(old_size, new_ball_size);
}
void SceneManager::pushBallsAwayFromGravity() {
for (auto& ball : balls_) {
const int SIGNO = ((rand() % 2) * 2) - 1;
const float LATERAL = (((rand() % 20) + 10) * 0.1f) * SIGNO;
const float MAIN = ((rand() % 40) * 0.1f) + 5;
float vx = 0;
float vy = 0;
switch (current_gravity_) {
case GravityDirection::DOWN: // Impulsar ARRIBA
vx = LATERAL;
vy = -MAIN;
break;
case GravityDirection::UP: // Impulsar ABAJO
vx = LATERAL;
vy = MAIN;
break;
case GravityDirection::LEFT: // Impulsar DERECHA
vx = MAIN;
vy = LATERAL;
break;
case GravityDirection::RIGHT: // Impulsar IZQUIERDA
vx = -MAIN;
vy = LATERAL;
break;
}
ball->modVel(vx, vy); // Modifica la velocidad según dirección de gravedad
}
}
void SceneManager::switchBallsGravity() {
for (auto& ball : balls_) {
ball->switchGravity();
}
}
void SceneManager::enableBallsGravityIfDisabled() {
for (auto& ball : balls_) {
ball->enableGravityIfDisabled();
}
}
void SceneManager::forceBallsGravityOn() {
for (auto& ball : balls_) {
ball->forceGravityOn();
}
}
void SceneManager::forceBallsGravityOff() {
// Contar cuántas pelotas están en superficie (suelo/techo/pared)
int balls_on_surface = 0;
for (const auto& ball : balls_) {
if (ball->isOnSurface()) {
balls_on_surface++;
}
}
// Si la mayoría (>50%) están en superficie, aplicar impulso para que se vea el efecto
float surface_ratio = static_cast<float>(balls_on_surface) / static_cast<float>(balls_.size());
if (surface_ratio > 0.5f) {
pushBallsAwayFromGravity(); // Dar impulso contrario a gravedad
}
// Desactivar gravedad
for (auto& ball : balls_) {
ball->forceGravityOff();
}
}
void SceneManager::changeGravityDirection(GravityDirection direction) {
current_gravity_ = direction;
for (auto& ball : balls_) {
ball->setGravityDirection(direction);
ball->applyRandomLateralPush(); // Aplicar empuje lateral aleatorio
}
}
void SceneManager::updateScreenSize(int width, int height) {
screen_width_ = width;
screen_height_ = height;
// NOTA: No actualizamos las bolas existentes, solo afecta a futuras creaciones
// Si se requiere reposicionar bolas existentes, implementar aquí
}
// === Métodos privados ===
void SceneManager::updateBallSizes(int old_size, int new_size) {
for (auto& ball : balls_) {
SDL_FRect pos = ball->getPosition();
// Ajustar posición para compensar cambio de tamaño
// Si aumenta tamaño, mover hacia centro; si disminuye, alejar del centro
float center_x = screen_width_ / 2.0f;
float center_y = screen_height_ / 2.0f;
float dx = pos.x - center_x;
float dy = pos.y - center_y;
// Ajustar proporcionalmente (evitar divisiones por cero)
if (old_size > 0) {
float scale_factor = static_cast<float>(new_size) / static_cast<float>(old_size);
pos.x = center_x + dx * scale_factor;
pos.y = center_y + dy * scale_factor;
}
// Actualizar tamaño del hitbox
ball->updateSize(new_size);
}
}
void SceneManager::enableShapeAttractionAll(bool enabled) {
for (auto& ball : balls_) {
ball->enableShapeAttraction(enabled);
}
}
void SceneManager::resetDepthScalesAll() {
for (auto& ball : balls_) {
ball->setDepthScale(1.0f);
}
}