Fase 3: Refactorización de Room - Extracción del sistema de renderizado de tilemap

## Cambios principales

### Nuevo componente: TilemapRenderer
- **tilemap_renderer.hpp/cpp**: Nueva clase que encapsula el renderizado del mapa de tiles
- Responsabilidades extraídas de Room:
  - Renderizado del tilemap estático
  - Gestión de tiles animados (conveyor belts)
  - Actualización de animaciones basadas en tiempo
  - Debug visualization de colisiones (en modo DEBUG)
  - Gestión de map_surface y time_accumulator

### Modificaciones en Room
- **room.hpp**:
  - Añadido TilemapRenderer como miembro (unique_ptr)
  - Removida estructura AnimatedTile (ahora privada en TilemapRenderer)
  - Removidos: map_surface_, animated_tiles_, time_accumulator_, CONVEYOR_FRAME_DURATION
  - Removidos 4 métodos privados de renderizado: fillMapTexture, setAnimatedTiles, updateAnimatedTiles, renderAnimatedTiles

- **room.cpp**:
  - Constructor: Inicializa TilemapRenderer con tile_map, tile_set_width, surface, bg_color, conveyor_belt_direction
  - Constructor: Llama a tilemap_renderer_->initialize(collision_map_)
  - Delegación: renderMap() llama a tilemap_renderer_->render()
  - Delegación: update() llama a tilemap_renderer_->update(delta_time)
  - Delegación: setPaused() llama a tilemap_renderer_->setPaused(value)
  - Removida inicialización de time_accumulator_
  - Eliminados ~95 líneas de código de renderizado (incluyendo debug lines)

### Mejoras en CollisionMap
- **collision_map.hpp/cpp**:
  - Marcados getTile(SDL_FPoint) y getTile(int) como const (const correctness)
  - Permite uso desde TilemapRenderer con puntero const

### Build system
- **CMakeLists.txt**: Añadido tilemap_renderer.cpp a las fuentes del proyecto

## Métricas
- **Código eliminado de Room**: ~95 líneas de lógica de renderizado de tilemap
- **Nuevo TilemapRenderer**: 208 líneas (tilemap_renderer.cpp)
- **Reducción en room.cpp**: Continúa la mejora en cohesión y separación de responsabilidades

## Verificación
-  Compilación exitosa sin errores
-  Juego inicia y renderiza correctamente
-  clang-tidy: 1 warning (naming style) corregido
-  cppcheck: 1 suggestion (const correctness) aplicado
-  Const correctness mejorada en CollisionMap

## Próximos pasos
- Fase 4: Extracción del parseo de archivos (RoomLoader)
- Fase 5: Limpieza final y reducción de Room a coordinador ligero

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-13 09:09:51 +01:00
parent c5ad8041e8
commit 5365d62abc
7 changed files with 334 additions and 191 deletions

View File

@@ -18,6 +18,7 @@
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
#include "game/gameplay/item_manager.hpp" // Para ItemManager
#include "game/gameplay/item_tracker.hpp" // Para ItemTracker
#include "game/gameplay/tilemap_renderer.hpp" // Para TilemapRenderer
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
#include "game/options.hpp" // Para Options, OptionsStats, options
#include "utils/defines.hpp" // Para BLOCK, PLAY_AREA_HEIGHT, PLAY_AREA_WIDTH
@@ -37,11 +38,14 @@ Room::Room(const std::string& room_path, std::shared_ptr<Scoreboard::Data> data)
// Crea el mapa de colisiones (necesita tile_map_, tile_set_width_, conveyor_belt_direction_)
collision_map_ = std::make_unique<CollisionMap>(tile_map_, tile_set_width_, conveyor_belt_direction_);
openTheJail(); // Abre la Jail si se da el caso
setAnimatedTiles(); // Busca los tiles animados
map_surface_ = std::make_shared<Surface>(PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT); // Crea la textura para el mapa de tiles de la habitación
fillMapTexture(); // Pinta el mapa de la habitación en la textura
Screen::get()->setBorderColor(stringToColor(border_color_)); // Establece el color del borde
openTheJail(); // Abre la Jail si se da el caso
// Crea el renderizador del tilemap (necesita tile_map_, tile_set_width_, surface_, bg_color_, conveyor_belt_direction_)
tilemap_renderer_ = std::make_unique<TilemapRenderer>(tile_map_, tile_set_width_, surface_, bg_color_,
conveyor_belt_direction_);
tilemap_renderer_->initialize(collision_map_.get()); // Inicializa (crea map_surface, pinta tiles, busca animados)
Screen::get()->setBorderColor(stringToColor(border_color_)); // Establece el color del borde
}
// Destructor
@@ -66,7 +70,6 @@ void Room::initializeRoom(const Data& room) {
surface_ = Resource::Cache::get()->getSurface(room.tile_set_file);
tile_set_width_ = surface_->getWidth() / TILE_SIZE;
is_paused_ = false;
time_accumulator_ = 0.0F;
// Crear los enemigos usando el manager
for (const auto& enemy_data : room.enemies) {
@@ -109,105 +112,9 @@ void Room::openTheJail() {
}
}
// Crea la textura con el mapeado de la habitación
void Room::fillMapTexture() {
const Uint8 COLOR = stringToColor(bg_color_);
auto previuos_renderer = Screen::get()->getRendererSurface();
Screen::get()->setRendererSurface(map_surface_);
map_surface_->clear(COLOR);
// Los tileSetFiles son de 20x20 tiles. El primer tile es el 0. Cuentan hacia la derecha y hacia abajo
SDL_FRect clip = {0, 0, TILE_SIZE, TILE_SIZE};
for (int y = 0; y < MAP_HEIGHT; ++y) {
for (int x = 0; x < MAP_WIDTH; ++x) {
// Tiled pone los tiles vacios del mapa como cero y empieza a contar de 1 a n.
// Al cargar el mapa en memoria, se resta uno, por tanto los tiles vacios son -1
// Tampoco hay que dibujar los tiles animados que estan en la fila 19 (indices)
const int INDEX = (y * MAP_WIDTH) + x;
const bool A = (tile_map_[INDEX] >= 18 * tile_set_width_) && (tile_map_[INDEX] < 19 * tile_set_width_);
const bool B = tile_map_[INDEX] > -1;
if (B && !A) {
clip.x = (tile_map_[INDEX] % tile_set_width_) * TILE_SIZE;
clip.y = (tile_map_[INDEX] / tile_set_width_) * TILE_SIZE;
surface_->render(x * TILE_SIZE, y * TILE_SIZE, &clip);
}
}
}
#ifdef _DEBUG
if (Debug::get()->getEnabled()) {
auto surface = Screen::get()->getRendererSurface();
// BottomSurfaces
{
for (auto l : collision_map_->getBottomFloors()) {
surface->drawLine(l.x1, l.y, l.x2, l.y, static_cast<Uint8>(PaletteColor::BLUE));
}
}
// TopSurfaces
{
for (auto l : collision_map_->getTopFloors()) {
surface->drawLine(l.x1, l.y, l.x2, l.y, static_cast<Uint8>(PaletteColor::RED));
}
}
// LeftSurfaces
{
for (auto l : collision_map_->getLeftWalls()) {
surface->drawLine(l.x, l.y1, l.x, l.y2, static_cast<Uint8>(PaletteColor::GREEN));
}
}
// RightSurfaces
{
for (auto l : collision_map_->getRightWalls()) {
surface->drawLine(l.x, l.y1, l.x, l.y2, static_cast<Uint8>(PaletteColor::MAGENTA));
}
}
// LeftSlopes
{
for (auto l : collision_map_->getLeftSlopes()) {
surface->drawLine(l.x1, l.y1, l.x2, l.y2, static_cast<Uint8>(PaletteColor::CYAN));
}
}
// RightSlopes
{
for (auto l : collision_map_->getRightSlopes()) {
surface->drawLine(l.x1, l.y1, l.x2, l.y2, static_cast<Uint8>(PaletteColor::YELLOW));
}
}
// AutoSurfaces
{
for (auto l : collision_map_->getConveyorBeltFloors()) {
surface->drawLine(l.x1, l.y, l.x2, l.y, static_cast<Uint8>(PaletteColor::WHITE));
}
}
}
#endif // _DEBUG
Screen::get()->setRendererSurface(previuos_renderer);
}
// Dibuja el mapa en pantalla
void Room::renderMap() {
// Dibuja la textura con el mapa en pantalla
SDL_FRect dest = {0, 0, PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT};
map_surface_->render(nullptr, &dest);
// Dibuja los tiles animados
#ifdef _DEBUG
if (!Debug::get()->getEnabled()) {
renderAnimatedTiles();
}
#else
renderAnimatedTiles();
#endif
tilemap_renderer_->render();
}
// Dibuja los enemigos en pantalla
@@ -227,11 +134,8 @@ void Room::update(float delta_time) {
return;
}
// Actualiza el acumulador de tiempo
time_accumulator_ += delta_time;
// Actualiza los tiles animados
updateAnimatedTiles();
// Actualiza los tiles animados usando el renderer
tilemap_renderer_->update(delta_time);
// Actualiza los enemigos usando el manager
enemy_manager_->update(delta_time);
@@ -243,60 +147,10 @@ void Room::update(float delta_time) {
// Pone el mapa en modo pausa
void Room::setPaused(bool value) {
is_paused_ = value;
tilemap_renderer_->setPaused(value);
item_manager_->setPaused(value);
}
// Localiza todos los tiles animados de la habitación
void Room::setAnimatedTiles() {
// Recorre la habitación entera por filas buscando tiles de tipo t_animated
for (int i = 0; i < (int)tile_map_.size(); ++i) {
if (getTile(i) == Tile::ANIMATED) {
// La i es la ubicación
const int X = (i % MAP_WIDTH) * TILE_SIZE;
const int Y = (i / MAP_WIDTH) * TILE_SIZE;
// TileMap[i] es el tile a poner
const int XC = (tile_map_[i] % tile_set_width_) * TILE_SIZE;
const int YC = (tile_map_[i] / tile_set_width_) * TILE_SIZE;
AnimatedTile at;
at.sprite = std::make_shared<SurfaceSprite>(surface_, X, Y, 8, 8);
at.sprite->setClip(XC, YC, 8, 8);
at.x_orig = XC;
animated_tiles_.push_back(at);
}
}
}
// Actualiza los tiles animados
void Room::updateAnimatedTiles() {
const int NUM_FRAMES = 4;
// Calcular frame actual basado en tiempo
const int CURRENT_FRAME = static_cast<int>(time_accumulator_ / CONVEYOR_FRAME_DURATION) % NUM_FRAMES;
// Calcular offset basado en dirección
int offset = 0;
if (conveyor_belt_direction_ == -1) {
offset = CURRENT_FRAME * TILE_SIZE;
} else {
offset = (NUM_FRAMES - 1 - CURRENT_FRAME) * TILE_SIZE;
}
for (auto& a : animated_tiles_) {
SDL_FRect rect = a.sprite->getClip();
rect.x = a.x_orig + offset;
a.sprite->setClip(rect);
}
}
// Pinta los tiles animados en pantalla
void Room::renderAnimatedTiles() {
for (const auto& a : animated_tiles_) {
a.sprite->render();
}
}
// Devuelve la cadena del fichero de la habitación contigua segun el borde
auto Room::getRoom(Border border) -> std::string {
switch (border) {