diff --git a/resources/config2/navigation3.json b/resources/config2/navigation3.json new file mode 100644 index 0000000..5db2650 --- /dev/null +++ b/resources/config2/navigation3.json @@ -0,0 +1,19 @@ +{ + "cellSize": 0.4, + "agentRadius": 0.45, + "floorY": 0.0, + "objectPadding": 0.25, + "areas": [ + { + "name": "main_corridor", + "available": true, + "polygon": [ + [26, 9.5], + [14, 9.5], + [14, -8.7], + [26, -8.7] + ] + } + ] + } + \ No newline at end of file diff --git a/src/Game.cpp b/src/Game.cpp index 6a7d2c8..b8e0607 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -246,11 +246,17 @@ namespace ZL menuManager.getState() == GameState::HelpScreen || menuManager.getState() == GameState::AboutMenu) { + // Normal UI: show cursor and release grab / relative mode SDL_ShowCursor(SDL_ENABLE); + SDL_SetRelativeMouseMode(SDL_FALSE); + if (Environment::window) SDL_SetWindowGrab(Environment::window, SDL_FALSE); } else if (menuManager.getState() == GameState::Gameplay) { + // Gameplay: hide cursor and enable relative mouse mode + window grab SDL_ShowCursor(SDL_DISABLE); + SDL_SetRelativeMouseMode(SDL_TRUE); + if (Environment::window) SDL_SetWindowGrab(Environment::window, SDL_TRUE); } if (menuManager.getState() != GameState::Gameplay) @@ -406,12 +412,15 @@ namespace ZL if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { if (menuManager.getState() == GameState::Gameplay) { SDL_SetRelativeMouseMode(SDL_TRUE); + if (Environment::window) SDL_SetWindowGrab(Environment::window, SDL_TRUE); } else { SDL_SetRelativeMouseMode(SDL_FALSE); + if (Environment::window) SDL_SetWindowGrab(Environment::window, SDL_FALSE); } } if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { SDL_SetRelativeMouseMode(SDL_FALSE); + if (Environment::window) SDL_SetWindowGrab(Environment::window, SDL_FALSE); } #ifdef __ANDROID__ diff --git a/src/Location.cpp b/src/Location.cpp index 3813c2e..886ae9b 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -12,7 +12,19 @@ #include #include "GameConstants.h" - +namespace { + Eigen::Matrix4f lookAt(const Eigen::Vector3f& eye, const Eigen::Vector3f& target, const Eigen::Vector3f& up) { + Eigen::Vector3f f = (target - eye).normalized(); + Eigen::Vector3f s = f.cross(up).normalized(); + Eigen::Vector3f u = s.cross(f); + Eigen::Matrix4f result; + result << s.x(), s.y(), s.z(), -s.dot(eye), + u.x(), u.y(), u.z(), -u.dot(eye), + -f.x(), -f.y(), -f.z(), f.dot(eye), + 0, 0, 0, 1; + return result; + } +} namespace ZL { @@ -270,6 +282,9 @@ void Location::setup() dialogueSystem.init(renderer, CONST_ZIP_FILE); dialogueSystem.loadDatabase("resources/dialogue/sample_dialogues.json"); + buildingFirstPersonZone = Eigen::AlignedBox(Eigen::Vector2f(14.0f, -8.7f), Eigen::Vector2f(26.0f, 9.5f)); + firstPersonMode = false; + std::cout << "[BARK] Setup complete, loaded " << gameObjects.size() << " models" << std::endl; } @@ -571,7 +586,7 @@ void Location::setup() Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); renderer.PushMatrix(); - renderer.LoadIdentity(); + /*renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix()); @@ -580,6 +595,36 @@ void Location::setup() renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() }); renderer.TranslateMatrix({ 0, -1.3f, 0 }); + */ + + if (firstPersonMode && !inCar && player) { + const float eyeHeight = 1.6f; + Eigen::Vector3f eye = player->position + Eigen::Vector3f(0.0f, eyeHeight, 0.0f); + + float yaw = cameraAzimuth; + float pitch = cameraInclination; + Eigen::Vector3f forward(std::sin(yaw), 0.0f, -std::cos(yaw)); + Eigen::Vector3f direction = Eigen::Quaternionf(Eigen::AngleAxisf(pitch, Eigen::Vector3f::UnitX())) * forward; + direction.normalize(); + + Eigen::Vector3f target = eye + direction; + Eigen::Vector3f up(0.0f, 1.0f, 0.0f); + + Eigen::Matrix4f view = lookAt(eye, target, up); + renderer.PushSpecialMatrix(view); // (2) добавляем матрицу первого лица в стек + } + else { + // Стандартная камера от третьего лица (без дополнительного Push) + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0, 0, -1.0f * Environment::zoom }); + renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix()); + renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix()); + Eigen::Vector3f camTarget = inCar ? carPosition : (player ? player->position : Eigen::Vector3f::Zero()); + renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() }); + const float cameraYOffset = firstPersonMode ? -0.2f : -1.3f; + renderer.TranslateMatrix({ 0, cameraYOffset, 0 }); + } + for (int i = -7; i <= 7; i++) { for (int j = -7; j <= 7; j++) @@ -661,7 +706,8 @@ void Location::setup() drawNpcCar(); - if (player && !inCar) player->draw(renderer); + // Don't draw the player mesh when in first-person mode + if (player && !inCar && !firstPersonMode) player->draw(renderer); if (girlfriend && !girlfriendInCar) { @@ -690,10 +736,19 @@ void Location::setup() drawDebugForbidden(); //#endif - renderer.PopMatrix(); + // renderer.PopMatrix(); + + // renderer.PopProjectionMatrix(); + + // renderer.shaderManager.PopShader(); + + // Восстанавливаем стек матриц + if (firstPersonMode && !inCar && player) { + renderer.PopMatrix(); // убираем (2) – матрицу первого лица + } + renderer.PopMatrix(); // убираем (1) – исходную матрицу renderer.PopProjectionMatrix(); - renderer.shaderManager.PopShader(); } @@ -762,7 +817,8 @@ void Location::setup() } // Draw characters (they handle their own skinning shader switch internally) - if (player) player->drawShadowDepth(renderer); + // Draw player shadow depth only if not in first-person (so depth won't be duplicated) + if (player && !firstPersonMode) player->drawShadowDepth(renderer); if (girlfriend && !girlfriendInCar) { @@ -816,13 +872,39 @@ void Location::setup() Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); renderer.PushMatrix(); - renderer.LoadIdentity(); + /*renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix()); renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix()); const Eigen::Vector3f& camTarget = player ? player->position : Eigen::Vector3f::Zero(); renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() }); + */ + + if (firstPersonMode && !inCar && player) { + const float eyeHeight = 1.6f; + Eigen::Vector3f eye = player->position + Eigen::Vector3f(0.0f, eyeHeight, 0.0f); + float yaw = cameraAzimuth; + float pitch = cameraInclination; + Eigen::Vector3f forward(std::sin(yaw), 0.0f, -std::cos(yaw)); + Eigen::Vector3f direction = Eigen::Quaternionf(Eigen::AngleAxisf(pitch, Eigen::Vector3f::UnitX())) * forward; + direction.normalize(); + Eigen::Vector3f target = eye + direction; + Eigen::Vector3f up(0.0f, 1.0f, 0.0f); + Eigen::Matrix4f view = lookAt(eye, target, up); + renderer.PushSpecialMatrix(view); // (2) + } + else { + // стандартная камера третьего лица + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0, 0, -1.0f * Environment::zoom }); + renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix()); + renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix()); + Eigen::Vector3f camTarget = inCar ? carPosition : (player ? player->position : Eigen::Vector3f::Zero()); + renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() }); + const float cameraYOffset = firstPersonMode ? -0.2f : -1.3f; + renderer.TranslateMatrix({ 0, cameraYOffset, 0 }); + } // Capture the camera view matrix and compute uLightFromCamera cameraViewMatrix = renderer.GetCurrentModelViewMatrix(); @@ -868,7 +950,8 @@ void Location::setup() // Characters use their own shadow-aware shaders CheckGlError(__FILE__, __LINE__); - if (player) player->drawWithShadow(renderer, lightFromCamera, shadowMap->getDepthTexture(), lightDirCamera); + // don't draw player with shadow shader if in first-person mode + if (player && !firstPersonMode) player->drawWithShadow(renderer, lightFromCamera, shadowMap->getDepthTexture(), lightDirCamera); CheckGlError(__FILE__, __LINE__); for (auto& npc : npcs) npc->drawWithShadow(renderer, lightFromCamera, shadowMap->getDepthTexture(), lightDirCamera); @@ -878,7 +961,16 @@ void Location::setup() drawDebugNavigation(); drawDebugForbidden(); - renderer.PopMatrix(); + // renderer.PopMatrix(); + // renderer.PopProjectionMatrix(); + // renderer.shaderManager.PopShader(); + + // Восстанавливаем стек + if (firstPersonMode && !inCar && player) { + renderer.PopMatrix(); // убираем (2) + } + renderer.PopMatrix(); // убираем (1) + renderer.PopProjectionMatrix(); renderer.shaderManager.PopShader(); } @@ -1056,6 +1148,30 @@ void Location::setup() const float maxHeightForHide = 3.0f; azsRoofVisible = !(insideAnyZone && player->position.y() < maxHeightForHide); } + + // --- first-person building zone detection --- + { + const Eigen::Vector2f p2d(player->position.x(), player->position.z()); + const bool insideBuilding = buildingFirstPersonZone.contains(p2d); + if (insideBuilding && !firstPersonMode) { + // Enter first-person + firstPersonMode = true; + savedCameraAzimuth = cameraAzimuth; + savedCameraInclination = cameraInclination; + // Align camera to player's facing so feel like first-person + cameraAzimuth = player->targetFacingAngle; + // a moderate inclination (slightly downwards) + cameraInclination = M_PI * 20.f / 180.f; + std::cout << "[FIRSTPERSON] Entered building zone, switching to first-person view" << std::endl; + } else if (!insideBuilding && firstPersonMode) { + // Exit first-person: restore camera + firstPersonMode = false; + cameraAzimuth = savedCameraAzimuth; + cameraInclination = savedCameraInclination; + std::cout << "[FIRSTPERSON] Exited building zone, restoring camera and third-person view" << std::endl; + } + } + // --- end first-person detection --- } if (girlfriend) diff --git a/src/Location.h b/src/Location.h index f0cb26c..7edf428 100644 --- a/src/Location.h +++ b/src/Location.h @@ -203,6 +203,13 @@ namespace ZL bool isPointInCarFootprint(const Eigen::Vector3f& point, const Eigen::Vector3f& center, float rotation) const; bool doesPlayerCarCollideWithNpcCar(const Eigen::Vector3f& center, float rotation) const; void pushOutOfNpcCarFootprint(Eigen::Vector3f& position) const; + + // --- FIRST PERSON BUILDING ZONE --- + bool firstPersonMode = false; + Eigen::AlignedBox buildingFirstPersonZone; // X,Z min/max + float savedCameraAzimuth = 0.f; + float savedCameraInclination = 0.f; + // ----------------------------------- }; } // namespace ZL \ No newline at end of file