#include "camera_service.h" #include "../../render/gl/camera.h" #include "../core/component.h" #include "../core/entity.h" #include "../core/world.h" #include "../game_config.h" #include "camera_controller.h" #include "camera_follow_system.h" #include "selection_system.h" #include "units/spawn_type.h" #include #include #include #include namespace Game::Systems { CameraService::CameraService() : m_controller(std::make_unique()), m_followSystem(std::make_unique()) {} CameraService::~CameraService() = default; void CameraService::move(Render::GL::Camera &camera, float dx, float dz) { float const dist = camera.get_distance(); float const scale = std::max(0.12F, dist * 0.05F); m_controller->move(camera, dx * scale, dz * scale); } void CameraService::elevate(Render::GL::Camera &camera, float dy) { float const distance = camera.get_distance(); float const scale = std::clamp(distance * 0.05F, 0.1F, 5.0F); m_controller->move_up(camera, dy * scale); } void CameraService::zoom(Render::GL::Camera &camera, float delta) { m_controller->zoom_distance(camera, delta); } auto CameraService::get_distance(const Render::GL::Camera &camera) -> float { return camera.get_distance(); } void CameraService::yaw(Render::GL::Camera &camera, float degrees) { m_controller->yaw(camera, degrees); } void CameraService::orbit(Render::GL::Camera &camera, float yaw_deg, float pitch_deg) { if (!std::isfinite(yaw_deg) || !std::isfinite(pitch_deg)) { return; } m_controller->orbit(camera, yaw_deg, pitch_deg); } void CameraService::orbit_direction(Render::GL::Camera &camera, int direction, bool shift) { const auto &cam_config = Game::GameConfig::instance().camera(); float const step = shift ? cam_config.orbit_step_shift : cam_config.orbit_step_normal; float const pitch = step * float(direction); orbit(camera, 0.0F, pitch); } void CameraService::follow_selection(Render::GL::Camera &camera, Engine::Core::World &world, bool enable) { m_controller->set_follow_enabled(camera, enable); if (enable) { if (auto *selection_system = world.get_system()) { m_followSystem->snap_to_selection(world, *selection_system, camera); } } else { auto pos = camera.get_position(); auto tgt = camera.get_target(); camera.look_at(pos, tgt, QVector3D(0, 1, 0)); } } void CameraService::set_follow_lerp(Render::GL::Camera &camera, float alpha) { float const a = std::clamp(alpha, 0.0F, 1.0F); m_controller->set_follow_lerp(camera, a); } void CameraService::reset_camera(Render::GL::Camera &camera, Engine::Core::World &world, int local_owner_id, unsigned int player_unit_id) { Engine::Core::Entity *focus_entity = nullptr; for (auto *e : world.get_entities_with()) { if (e == nullptr) { continue; } auto *u = e->get_component(); if (u == nullptr) { continue; } if (u->spawn_type == Game::Units::SpawnType::Barracks && u->owner_id == local_owner_id && u->health > 0) { focus_entity = e; break; } } if ((focus_entity == nullptr) && player_unit_id != 0U) { focus_entity = world.get_entity(player_unit_id); } if (focus_entity != nullptr) { snap_to_entity(camera, *focus_entity); } } void CameraService::snap_to_entity(Render::GL::Camera &camera, Engine::Core::Entity &entity) { if (auto *t = entity.get_component()) { QVector3D const center(t->position.x, t->position.y, t->position.z); const auto &cam_config = Game::GameConfig::instance().camera(); camera.set_rts_view(center, cam_config.default_distance, cam_config.default_pitch, cam_config.default_yaw); } } void CameraService::update_follow(Render::GL::Camera &camera, Engine::Core::World &world, bool follow_enabled) { if (follow_enabled) { if (auto *selection_system = world.get_system()) { m_followSystem->update(world, *selection_system, camera); } } } } // namespace Game::Systems