Modernizar convenciones de código C++ aplicando las siguientes directivas:
## Cambios principales
**1. Renombrar headers (.h → .hpp)**
- 36 archivos renombrados a extensión .hpp (estándar C++)
- Mantenidos como .h: stb_image.h, stb_image_resize2.h (librerías C externas)
**2. Modernizar include guards (#ifndef → #pragma once)**
- resource_manager.hpp: #ifndef RESOURCE_MANAGER_H → #pragma once
- resource_pack.hpp: #ifndef RESOURCE_PACK_H → #pragma once
- spatial_grid.hpp: #ifndef SPATIAL_GRID_H → #pragma once
**3. Sistema de includes desde raíz del proyecto**
- CMakeLists.txt: añadido include_directories(${CMAKE_SOURCE_DIR}/source)
- Eliminadas rutas relativas (../) en todos los includes
- Includes ahora usan rutas absolutas desde source/
**Antes:**
```cpp
#include "../defines.h"
#include "../text/textrenderer.h"
```
**Ahora:**
```cpp
#include "defines.hpp"
#include "text/textrenderer.hpp"
```
## Archivos afectados
- 1 archivo CMakeLists.txt modificado
- 36 archivos renombrados (.h → .hpp)
- 32 archivos .cpp actualizados (includes)
- 36 archivos .hpp actualizados (includes + guards)
- 1 archivo tools/ actualizado
**Total: 70 archivos modificados**
## Verificación
✅ Proyecto compila sin errores
✅ Todas las rutas de includes correctas
✅ Include guards modernizados
✅ Librerías externas C mantienen extensión .h
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
239 lines
8.0 KiB
C++
239 lines
8.0 KiB
C++
#include "scene_manager.hpp"
|
|
|
|
#include <cstdlib> // for rand
|
|
|
|
#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_ = 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
|
|
for (int i = 0; i < BALL_COUNT_SCENARIOS[scenario_id]; ++i) {
|
|
float X, Y, VX, 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_ = 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, 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);
|
|
}
|
|
}
|