## 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>
194 lines
6.4 KiB
C++
194 lines
6.4 KiB
C++
#include "tilemap_renderer.hpp"
|
|
|
|
#include "core/rendering/screen.hpp"
|
|
#include "core/rendering/surface.hpp"
|
|
#include "core/rendering/surface_sprite.hpp"
|
|
#include "core/system/debug.hpp"
|
|
#include "game/gameplay/collision_map.hpp"
|
|
#include "utils/utils.hpp"
|
|
|
|
// Constructor
|
|
TilemapRenderer::TilemapRenderer(std::vector<int> tile_map, int tile_set_width,
|
|
std::shared_ptr<Surface> tileset_surface, std::string bg_color,
|
|
int conveyor_belt_direction)
|
|
: tile_map_(std::move(tile_map)),
|
|
tile_set_width_(tile_set_width),
|
|
tileset_surface_(std::move(tileset_surface)),
|
|
bg_color_(std::move(bg_color)),
|
|
conveyor_belt_direction_(conveyor_belt_direction) {
|
|
// Crear la surface del mapa
|
|
map_surface_ = std::make_shared<Surface>(PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT);
|
|
}
|
|
|
|
// Inicializa el renderizador
|
|
void TilemapRenderer::initialize(const CollisionMap* collision_map) {
|
|
setAnimatedTiles(collision_map);
|
|
fillMapTexture(collision_map);
|
|
}
|
|
|
|
// Actualiza las animaciones de tiles
|
|
void TilemapRenderer::update(float delta_time) {
|
|
if (is_paused_) {
|
|
return;
|
|
}
|
|
|
|
// Actualiza el acumulador de tiempo
|
|
time_accumulator_ += delta_time;
|
|
|
|
// Actualiza los tiles animados
|
|
updateAnimatedTiles();
|
|
}
|
|
|
|
// Renderiza el mapa completo en pantalla
|
|
void TilemapRenderer::render() {
|
|
// 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
|
|
}
|
|
|
|
// Pinta el mapa estático y debug lines
|
|
void TilemapRenderer::fillMapTexture(const CollisionMap* collision_map) {
|
|
const Uint8 COLOR = stringToColor(bg_color_);
|
|
auto previous_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;
|
|
tileset_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(previous_renderer);
|
|
}
|
|
|
|
// Localiza todos los tiles animados
|
|
void TilemapRenderer::setAnimatedTiles(const CollisionMap* collision_map) {
|
|
// Recorre la habitación entera por filas buscando tiles de tipo t_animated
|
|
for (int i = 0; i < (int)tile_map_.size(); ++i) {
|
|
const auto TILE_TYPE = collision_map->getTile(i);
|
|
if (TILE_TYPE == CollisionMap::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>(tileset_surface_, X, Y, 8, 8);
|
|
at.sprite->setClip(XC, YC, 8, 8);
|
|
at.x_orig = XC;
|
|
animated_tiles_.push_back(at);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Actualiza tiles animados
|
|
void TilemapRenderer::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);
|
|
}
|
|
}
|
|
|
|
// Renderiza tiles animados
|
|
void TilemapRenderer::renderAnimatedTiles() {
|
|
for (const auto& a : animated_tiles_) {
|
|
a.sprite->render();
|
|
}
|
|
}
|