Files
jaildoctors_dilemma/source/game/gameplay/tilemap_renderer.cpp

208 lines
6.7 KiB
C++

#include "tilemap_renderer.hpp"
#include "core/rendering/screen.hpp"
#include "core/rendering/surface.hpp"
#include "core/rendering/surface_sprite.hpp"
#ifdef _DEBUG
#include "core/system/debug.hpp"
#endif
#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()->isEnabled()) {
renderAnimatedTiles();
}
#else
renderAnimatedTiles();
#endif
}
#ifdef _DEBUG
// Redibuja el tilemap (para actualizar modo debug)
void TilemapRenderer::redrawMap(const CollisionMap* collision_map) {
fillMapTexture(collision_map);
}
#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;
#ifdef _DEBUG
if (!Debug::get()->isEnabled()) {
tileset_surface_->render(x * TILE_SIZE, y * TILE_SIZE, &clip);
}
#else
tileset_surface_->render(x * TILE_SIZE, y * TILE_SIZE, &clip);
#endif
}
}
}
#ifdef _DEBUG
// Pinta las superficies en el modo debug
if (Debug::get()->isEnabled()) {
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();
}
}