#include "game/entities/concrete/rolling_rock.hpp" #include #include "game/entities/entity_factory.hpp" #include "game/entities/event_bus.hpp" #include "game/entities/player.hpp" #include "game/map/map.hpp" namespace { // Tradueix la direcció inicial textual del YAML a un vector 2D. Valors // no reconeguts → sense moviment (útil per spawn estàtics a tests). void applyInitialDirection(const std::string& dir, DynamicHazard& rock) { if (dir == "right") { rock.setDirection(1.0F, 0.0F); } else if (dir == "left") { rock.setDirection(-1.0F, 0.0F); } else if (dir == "up") { rock.setDirection(0.0F, -1.0F); } else if (dir == "down") { rock.setDirection(0.0F, 1.0F); } else { rock.setDirection(0.0F, 0.0F); } } } // namespace RollingRock::RollingRock(const fkyaml::node& yaml) { name_ = yaml.contains("name") ? yaml["name"].get_value() : std::string("rolling_rock"); collides_ = true; interactable_ = false; if (yaml.contains("stats")) { const auto& s = yaml["stats"]; if (s.contains("speed")) { setSpeed(s["speed"].get_value()); } if (s.contains("damage")) { setDamage(s["damage"].get_value()); } } std::string initial = "right"; if (yaml.contains("ai") && yaml["ai"].contains("initial_direction")) { initial = yaml["ai"]["initial_direction"].get_value(); } applyInitialDirection(initial, *this); } void RollingRock::step(float delta_time) { const float DX = dir_x_ * speed_ * delta_time; const float DY = dir_y_ * speed_ * delta_time; if (DX == 0.0F && DY == 0.0F) { return; } auto candidate = getCollisionRect(); candidate.x += DX; candidate.y += DY; if (Map::insidePlayfield(candidate) && !Map::collides(candidate)) { pixel_rect_.x += DX; pixel_rect_.y += DY; return; } // Bloqueig: aturada definitiva (la roca no rebota). setDirection(0.0F, 0.0F); } void RollingRock::onPlayerContact(Player* player) { if (bus_ != nullptr) { bus_->publish(Event{ .name = "player_hit", .payload = getDamage(), .player_id = (player != nullptr) ? player->getId() : -1, }); } } REGISTER_ENTITY("rolling_rock", RollingRock)