diff --git a/proj-windows/CMakeLists.txt b/proj-windows/CMakeLists.txt index 774e1e0..dad2933 100644 --- a/proj-windows/CMakeLists.txt +++ b/proj-windows/CMakeLists.txt @@ -54,7 +54,7 @@ add_executable(space-game001 ../src/network/LocalClient.h ../src/network/LocalClient.cpp ../src/network/ClientState.h - ../src/network/RemotePlayer.h + ../src/network/ClientState.cpp ../src/network/WebSocketClient.h ../src/network/WebSocketClient.cpp ) diff --git a/src/Environment.cpp b/src/Environment.cpp index 7c6ab60..069971f 100644 --- a/src/Environment.cpp +++ b/src/Environment.cpp @@ -16,20 +16,12 @@ int Environment::height = 0; float Environment::zoom = 36.f; -bool Environment::leftPressed = false; -bool Environment::rightPressed = false; -bool Environment::upPressed = false; -bool Environment::downPressed = false; - -bool Environment::settings_inverseVertical = false; - SDL_Window* Environment::window = nullptr; bool Environment::showMouse = false; bool Environment::exitGameLoop = false; -Eigen::Matrix3f Environment::shipMatrix = Eigen::Matrix3f::Identity(); Eigen::Matrix3f Environment::inverseShipMatrix = Eigen::Matrix3f::Identity(); @@ -37,15 +29,7 @@ bool Environment::tapDownHold = false; Eigen::Vector2f Environment::tapDownStartPos = { 0, 0 }; Eigen::Vector2f Environment::tapDownCurrentPos = { 0, 0 }; -Eigen::Vector3f Environment::shipPosition = {0,0,45000.f}; - -float Environment::shipVelocity = 0.f; -int Environment::shipSelectedVelocity = 0; -Eigen::Vector3f Environment::currentAngularVelocity; - - -int Environment::lastSentAngle = -1; -float Environment::lastSentMagnitude = 0.0f; +ClientState Environment::shipState; const float Environment::CONST_Z_NEAR = 5.f; const float Environment::CONST_Z_FAR = 5000.f; diff --git a/src/Environment.h b/src/Environment.h index 6c52147..294ee8d 100644 --- a/src/Environment.h +++ b/src/Environment.h @@ -6,6 +6,7 @@ #include "render/OpenGlExtensions.h" #endif #include +#include "network/ClientState.h" namespace ZL { @@ -16,14 +17,6 @@ public: static int height; static float zoom; - static bool leftPressed; - static bool rightPressed; - static bool upPressed; - static bool downPressed; - - static bool settings_inverseVertical; - - static Eigen::Matrix3f shipMatrix; static Eigen::Matrix3f inverseShipMatrix; static SDL_Window* window; @@ -31,18 +24,11 @@ public: static bool showMouse; static bool exitGameLoop; - static bool tapDownHold; static Eigen::Vector2f tapDownStartPos; static Eigen::Vector2f tapDownCurrentPos; - static Eigen::Vector3f shipPosition; - static float shipVelocity; - static int shipSelectedVelocity; - static Eigen::Vector3f currentAngularVelocity; - - static int lastSentAngle; - static float lastSentMagnitude; + static ClientState shipState; static const float CONST_Z_NEAR; static const float CONST_Z_FAR; diff --git a/src/Game.cpp b/src/Game.cpp index d63b260..3fe95f0 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -19,8 +19,6 @@ #include "network/LocalClient.h" #endif -#include "network/RemotePlayer.h" - namespace ZL { #ifdef EMSCRIPTEN @@ -239,15 +237,8 @@ namespace ZL uiManager.setSliderCallback("velocitySlider", [this](const std::string& name, float value) { int newVel = roundf(value * 10); - if (newVel != Environment::shipSelectedVelocity) { + if (newVel != Environment::shipState.selectedVelocity) { newShipVelocity = newVel; - //Environment::shipSelectedVelocity = newVel; - /*auto now_ms = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch() - ).count(); - std::string msg = "VEL:" + std::to_string(now_ms) + ":" + std::to_string(Environment::shipSelectedVelocity); - msg = msg + ":" + formPingMessageContent(); - networkClient->Send(msg);*/ } }); @@ -358,7 +349,7 @@ namespace ZL // 1. Вектор направления от центра планеты к игроку (в мировых координатах) // Предполагаем, что планета в (0,0,0). Если нет, то (shipPosition - planetCenter) - Vector3f playerDirWorld = Environment::shipPosition.normalized(); + Vector3f playerDirWorld = Environment::shipState.position.normalized(); // 2. Направление света в мировом пространстве //Vector3f worldLightDir = Vector3f(1.0f, -1.0f, -1.0f).normalized(); @@ -470,7 +461,7 @@ namespace ZL renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipPosition); + renderer.TranslateMatrix(-Environment::shipState.position); renderer.TranslateMatrix({ 0.f, 0.f, 45000.f }); renderer.TranslateMatrix(boxCoordsArr[i].pos); renderer.RotateMatrix(boxCoordsArr[i].m); @@ -528,7 +519,7 @@ namespace ZL CheckGlError(); float skyPercent = 0.0; - float distance = planetObject.distanceToPlanetSurface(Environment::shipPosition); + float distance = planetObject.distanceToPlanetSurface(Environment::shipState.position); if (distance > 1500.f) { skyPercent = 0.0f; @@ -545,7 +536,7 @@ namespace ZL drawCubemap(skyPercent); planetObject.draw(renderer); - if (planetObject.distanceToPlanetSurface(Environment::shipPosition) > 100.f) + if (planetObject.distanceToPlanetSurface(Environment::shipState.position) > 100.f) { glClear(GL_DEPTH_BUFFER_BIT); } @@ -602,7 +593,7 @@ namespace ZL renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.TranslateMatrix({ 0, -6.f, 0 }); //Ship camera offset renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipPosition); + renderer.TranslateMatrix(-Environment::shipState.position); Eigen::Vector3f relativePos = playerState.position;// -Environment::shipPosition; @@ -654,22 +645,25 @@ namespace ZL static float pingTimer = 0.0f; pingTimer += delta; if (pingTimer >= 1000.0f) { - std::string pingMsg = "UPD:" + std::to_string(now_ms) + ":" + formPingMessageContent(); + std::string pingMsg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); networkClient->Send(pingMsg); std::cout << "Sending: " << pingMsg << std::endl; pingTimer = 0.0f; } - if (newShipVelocity != Environment::shipSelectedVelocity) - { - Environment::shipSelectedVelocity = newShipVelocity; + //Handle input: - std::string msg = "UPD:" + std::to_string(now_ms) + ":" + formPingMessageContent(); + if (newShipVelocity != Environment::shipState.selectedVelocity) + { + Environment::shipState.selectedVelocity = newShipVelocity; + + std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); networkClient->Send(msg); - //} } + float discreteMag; + int discreteAngle; if (Environment::tapDownHold) { float diffx = Environment::tapDownCurrentPos(0) - Environment::tapDownStartPos(0); @@ -681,140 +675,40 @@ namespace ZL if (rawMag > 10.0f) { // Мертвая зона // 1. Дискретизируем отклонение (0.0 - 1.0 с шагом 0.1) float normalizedMag = min(rawMag / maxRadius, 1.0f); - float discreteMag = std::round(normalizedMag * 10.0f) / 10.0f; + discreteMag = std::round(normalizedMag * 10.0f) / 10.0f; // 2. Дискретизируем угол (0-359 градусов) // atan2 возвращает радианы, переводим в градусы float radians = atan2f(diffy, diffx); - int discreteAngle = static_cast(radians * 180.0f / M_PI); + discreteAngle = static_cast(radians * 180.0f / M_PI); if (discreteAngle < 0) discreteAngle += 360; - - bool sendRotation = false; - - std::cout << "OUTPUT discreteAngle=" << discreteAngle << std::endl; - - // 3. Проверяем, изменились ли параметры значимо для отправки на сервер - if (discreteAngle != Environment::lastSentAngle || discreteMag != Environment::lastSentMagnitude) { - Environment::lastSentAngle = discreteAngle; - Environment::lastSentMagnitude = discreteMag; - - std::string msg = "UPD:" + std::to_string(now_ms) + ":" + formPingMessageContent(); - networkClient->Send(msg); - std::cout << "Sending: " << msg << std::endl; - } - - // 4. Логика вращения (угловое ускорение) - // Теперь используем discreteAngle и discreteMag как "цель" для набора угловой скорости - // ... (код интерполяции скорости к этой цели) - - // Вычисляем целевой вектор оси вращения из дискретного угла - // В 3D пространстве экранные X и Y преобразуются в оси вращения вокруг Y и X соответственно - float rad = static_cast(discreteAngle) * static_cast(M_PI) / 180.0f; - - // Целевая угловая скорость (дискретная сила определяет модуль вектора) - // Вектор {cos, sin, 0} дает нам направление отклонения джойстика - Eigen::Vector3f targetAngularVelDir(sinf(rad), cosf(rad), 0.0f); - Eigen::Vector3f targetAngularVelocity = targetAngularVelDir * discreteMag; - - Eigen::Vector3f diffVel = targetAngularVelocity - Environment::currentAngularVelocity; - float diffLen = diffVel.norm(); - - if (diffLen > 0.0001f) { - // Вычисляем, на сколько мы можем изменить скорость в этом кадре - float maxChange = ANGULAR_ACCEL * static_cast(delta); - - if (diffLen <= maxChange) { - // Если до цели осталось меньше, чем шаг ускорения — просто прыгаем в цель - Environment::currentAngularVelocity = targetAngularVelocity; - } - else { - // Линейно двигаемся в сторону целевого вектора - Environment::currentAngularVelocity += (diffVel / diffLen) * maxChange; - } - } - - // Применяем вращение к матрице корабля - float speedScale = Environment::currentAngularVelocity.norm(); - if (speedScale > 0.0001f) { - // Коэффициент чувствительности вращения - const float ROTATION_SENSITIVITY = 0.002f; - float deltaAlpha = speedScale * static_cast(delta) * ROTATION_SENSITIVITY; - - Eigen::Vector3f axis = Environment::currentAngularVelocity.normalized(); - Eigen::Quaternionf rotateQuat(Eigen::AngleAxisf(deltaAlpha, axis)); - - Environment::shipMatrix = Environment::shipMatrix * rotateQuat.toRotationMatrix(); - Environment::inverseShipMatrix = Environment::shipMatrix.inverse(); - } - } - } - else { - // Если джойстик не зажат — сбрасываем дискретные значения и плавно замедляем вращение - int discreteAngle = -1; - float discreteMag = 0.0f; - - if (discreteAngle != Environment::lastSentAngle || discreteMag != Environment::lastSentMagnitude) { - Environment::lastSentAngle = discreteAngle; - Environment::lastSentMagnitude = discreteMag; - - std::string msg = "UPD:" + std::to_string(now_ms) + ":" + formPingMessageContent(); - networkClient->Send(msg); - std::cout << "Sending: " << msg << std::endl; - } - - - float currentSpeed = Environment::currentAngularVelocity.norm(); - - if (currentSpeed > 0.0001f) { - float drop = ANGULAR_ACCEL * static_cast(delta); - if (currentSpeed <= drop) { - Environment::currentAngularVelocity = Eigen::Vector3f::Zero(); - } - else { - // Уменьшаем модуль вектора, сохраняя направление - Environment::currentAngularVelocity -= (Environment::currentAngularVelocity / currentSpeed) * drop; - } - } - - // Применяем остаточное вращение (инерция) - float speedScale = Environment::currentAngularVelocity.norm(); - if (speedScale > 0.0001f) { - float deltaAlpha = speedScale * static_cast(delta) * 0.002f; - Eigen::Quaternionf rotateQuat(Eigen::AngleAxisf(deltaAlpha, Environment::currentAngularVelocity.normalized())); - Environment::shipMatrix = Environment::shipMatrix * rotateQuat.toRotationMatrix(); - Environment::inverseShipMatrix = Environment::shipMatrix.inverse(); - } - } - - float shipDesiredVelocity = Environment::shipSelectedVelocity * 100.f; - - if (Environment::shipVelocity < shipDesiredVelocity) - { - Environment::shipVelocity += delta * SHIP_ACCEL; - if (Environment::shipVelocity > shipDesiredVelocity) + else { - Environment::shipVelocity = shipDesiredVelocity; + discreteAngle = -1; + discreteMag = 0.0f; } } - else if (Environment::shipVelocity > shipDesiredVelocity) + else { - Environment::shipVelocity -= delta * SHIP_ACCEL; - if (Environment::shipVelocity < shipDesiredVelocity) - { - Environment::shipVelocity = shipDesiredVelocity; - } + discreteAngle = -1; + discreteMag = 0.0f; } - // Движение вперед (существующая логика) - if (fabs(Environment::shipVelocity) > 0.01f) - { - Vector3f velocityDirection = { 0,0, -Environment::shipVelocity * delta / 1000.f }; - Vector3f velocityDirectionAdjusted = Environment::shipMatrix * velocityDirection; - Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted; + + if (discreteAngle != Environment::shipState.discreteAngle || discreteMag != Environment::shipState.discreteMag) { + Environment::shipState.discreteAngle = discreteAngle; + Environment::shipState.discreteMag = discreteMag; + + std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); + networkClient->Send(msg); + std::cout << "Sending: " << msg << std::endl; } + Environment::shipState.simulate_physics(delta); + Environment::inverseShipMatrix = Environment::shipState.rotation.inverse(); + for (auto& p : projectiles) { if (p && p->isActive()) { p->update(static_cast(delta), renderer); @@ -825,7 +719,7 @@ namespace ZL for (const auto& p : projectiles) { if (p && p->isActive()) { Vector3f worldPos = p->getPosition(); - Vector3f rel = worldPos - Environment::shipPosition; + Vector3f rel = worldPos - Environment::shipState.position; Vector3f camPos = Environment::inverseShipMatrix * rel; projCameraPoints.push_back(camPos); } @@ -852,16 +746,17 @@ namespace ZL explosionEmitter.update(static_cast(delta)); if (shipAlive) { - float distToSurface = planetObject.distanceToPlanetSurface(Environment::shipPosition); + float distToSurface = planetObject.distanceToPlanetSurface(Environment::shipState.position); if (distToSurface <= 0.0f) { + Vector3f localForward = { 0,0,-1 }; - Vector3f worldForward = (Environment::shipMatrix * localForward).normalized(); + Vector3f worldForward = (Environment::shipState.rotation * localForward).normalized(); const float backDistance = 400.0f; - Environment::shipPosition = Environment::shipPosition - worldForward * backDistance; + Environment::shipState.position = Environment::shipState.position - worldForward * backDistance; shipAlive = false; gameOver = true; - Environment::shipVelocity = 0.0f; + Environment::shipState.velocity = 0.0f; showExplosion = true; explosionEmitter.setUseWorldSpace(false); @@ -878,8 +773,8 @@ namespace ZL this->uiGameOverShown = false; this->showExplosion = false; this->explosionEmitter.setEmissionPoints(std::vector()); - Environment::shipPosition = Vector3f{ 0, 0, 45000.f }; - Environment::shipVelocity = 0.0f; + Environment::shipState.position = Vector3f{ 0, 0, 45000.f }; + Environment::shipState.velocity = 0.0f; uiManager.popMenu(); std::cerr << "Game restarted\n"; }); @@ -900,7 +795,7 @@ namespace ZL for (int i = 0; i < boxCoordsArr.size(); ++i) { if (!boxAlive[i]) continue; Vector3f boxWorld = boxCoordsArr[i].pos + Vector3f{ 0.0f, 0.0f, 45000.0f }; - Vector3f diff = Environment::shipPosition - boxWorld; + Vector3f diff = Environment::shipState.position - boxWorld; float thresh = shipCollisionRadius + boxCollisionRadius; if (diff.squaredNorm() <= thresh * thresh) { boxAlive[i] = false; @@ -911,7 +806,7 @@ namespace ZL boxRenderArr[i].texCoordVBO.reset(); showExplosion = true; - Vector3f rel = boxWorld - Environment::shipPosition; + Vector3f rel = boxWorld - Environment::shipState.position; Vector3f camPos = Environment::inverseShipMatrix * rel; explosionEmitter.setUseWorldSpace(true); explosionEmitter.setEmissionPoints(std::vector{ boxWorld }); @@ -936,11 +831,11 @@ namespace ZL const float size = 0.5f; Vector3f localForward = { 0,0,-1 }; - Vector3f worldForward = (Environment::shipMatrix * localForward).normalized(); + Vector3f worldForward = (Environment::shipState.rotation * localForward).normalized(); for (const auto& lo : localOffsets) { - Vector3f worldPos = Environment::shipPosition + Environment::shipMatrix * lo; - Vector3f worldVel = worldForward * (projectileSpeed + Environment::shipVelocity); + Vector3f worldPos = Environment::shipState.position + Environment::shipState.rotation * lo; + Vector3f worldVel = worldForward * (projectileSpeed + Environment::shipState.velocity); for (auto& p : projectiles) { if (!p->isActive()) { @@ -1097,6 +992,7 @@ namespace ZL } } + /* std::string Game::formPingMessageContent() { Eigen::Quaternionf q(Environment::shipMatrix); @@ -1117,7 +1013,7 @@ namespace ZL + std::to_string(Environment::lastSentAngle); return pingMsg; - } + }*/ } // namespace ZL diff --git a/src/Game.h b/src/Game.h index 37ec3a1..0c0d3df 100644 --- a/src/Game.h +++ b/src/Game.h @@ -51,8 +51,6 @@ namespace ZL { void handleUp(int mx, int my); void handleMotion(int mx, int my); - std::string formPingMessageContent(); - SDL_Window* window; SDL_GLContext glContext; diff --git a/src/SparkEmitter.cpp b/src/SparkEmitter.cpp index d162675..7d317bb 100644 --- a/src/SparkEmitter.cpp +++ b/src/SparkEmitter.cpp @@ -75,7 +75,7 @@ namespace ZL { if (particle.active) { Vector3f posCam; if (useWorldSpace) { - Vector3f rel = particle.position - Environment::shipPosition; + Vector3f rel = particle.position - Environment::shipState.position; posCam = Environment::inverseShipMatrix * rel; } else { @@ -94,7 +94,7 @@ namespace ZL { const auto& particle = *particlePtr; Vector3f posCam; if (useWorldSpace) { - Vector3f rel = particle.position - Environment::shipPosition; + Vector3f rel = particle.position - Environment::shipState.position; posCam = Environment::inverseShipMatrix * rel; } else { diff --git a/src/network/ClientState.cpp b/src/network/ClientState.cpp new file mode 100644 index 0000000..12438a1 --- /dev/null +++ b/src/network/ClientState.cpp @@ -0,0 +1,224 @@ +#include "ClientState.h" + + +void ClientState::simulate_physics(size_t delta) { + if (discreteMag > 0.01f) + { + float rad = static_cast(discreteAngle) * static_cast(M_PI) / 180.0f; + + // Целевая угловая скорость (дискретная сила определяет модуль вектора) + // Вектор {cos, sin, 0} дает нам направление отклонения джойстика + Eigen::Vector3f targetAngularVelDir(sinf(rad), cosf(rad), 0.0f); + Eigen::Vector3f targetAngularVelocity = targetAngularVelDir * discreteMag; + + Eigen::Vector3f diffVel = targetAngularVelocity - currentAngularVelocity; + float diffLen = diffVel.norm(); + + if (diffLen > 0.0001f) { + // Вычисляем, на сколько мы можем изменить скорость в этом кадре + float maxChange = ANGULAR_ACCEL * static_cast(delta); + + if (diffLen <= maxChange) { + // Если до цели осталось меньше, чем шаг ускорения — просто прыгаем в цель + currentAngularVelocity = targetAngularVelocity; + } + + else { + // Линейно двигаемся в сторону целевого вектора + currentAngularVelocity += (diffVel / diffLen) * maxChange; + } + } + } + else + { + float currentSpeed = currentAngularVelocity.norm(); + + if (currentSpeed > 0.0001f) { + float drop = ANGULAR_ACCEL * static_cast(delta); + if (currentSpeed <= drop) { + currentAngularVelocity = Eigen::Vector3f::Zero(); + } + else { + // Уменьшаем модуль вектора, сохраняя направление + currentAngularVelocity -= (currentAngularVelocity / currentSpeed) * drop; + } + } + } + + float speedScale = currentAngularVelocity.norm(); + if (speedScale > 0.0001f) { + // Коэффициент чувствительности вращения + + float deltaAlpha = speedScale * static_cast(delta) * ROTATION_SENSITIVITY; + + Eigen::Vector3f axis = currentAngularVelocity.normalized(); + Eigen::Quaternionf rotateQuat(Eigen::AngleAxisf(deltaAlpha, axis)); + + rotation = rotation * rotateQuat.toRotationMatrix(); + } + + + // 4. Линейное изменение линейной скорости + float shipDesiredVelocity = selectedVelocity * 100.f; + + if (velocity < shipDesiredVelocity) + { + velocity += delta * SHIP_ACCEL; + if (velocity > shipDesiredVelocity) + { + velocity = shipDesiredVelocity; + } + } + else if (velocity > shipDesiredVelocity) + { + velocity -= delta * SHIP_ACCEL; + if (velocity < shipDesiredVelocity) + { + velocity = shipDesiredVelocity; + } + } + + if (fabs(velocity) > 0.01f) + { + Eigen::Vector3f velocityDirection = { 0,0, -velocity * delta / 1000.f }; + Eigen::Vector3f velocityDirectionAdjusted = rotation * velocityDirection; + position = position + velocityDirectionAdjusted; + } +} + +void ClientState::apply_lag_compensation(std::chrono::system_clock::time_point nowTime) { + + // 2. Вычисляем задержку + long long deltaMs = 0; + if (nowTime > lastUpdateServerTime) { + deltaMs = std::chrono::duration_cast(nowTime - lastUpdateServerTime).count(); + } + + // 3. Защита от слишком больших скачков (Clamp) + // Если лаг более 500мс, ограничиваем его, чтобы избежать резких рывков + long long final_lag_ms = deltaMs;//min(deltaMs, 500ll); + + if (final_lag_ms > 0) { + // Доматываем симуляцию на величину задержки + // Мы предполагаем, что за это время параметры управления не менялись + simulate_physics(final_lag_ms); + } +} + +void ClientState::handle_full_sync(const std::vector& parts, int startFrom) { + // Позиция + position = { std::stof(parts[startFrom]), std::stof(parts[startFrom + 1]), std::stof(parts[startFrom + 2]) }; + + Eigen::Quaternionf q( + std::stof(parts[startFrom + 3]), + std::stof(parts[startFrom + 4]), + std::stof(parts[startFrom + 5]), + std::stof(parts[startFrom + 6])); + rotation = q.toRotationMatrix(); + + currentAngularVelocity = Eigen::Vector3f{ + std::stof(parts[startFrom + 7]), + std::stof(parts[startFrom + 8]), + std::stof(parts[startFrom + 9]) }; + velocity = std::stof(parts[startFrom + 10]); + selectedVelocity = std::stoi(parts[startFrom + 11]); + discreteMag = std::stof(parts[startFrom + 12]); + discreteAngle = std::stoi(parts[startFrom + 13]); +} + +std::string ClientState::formPingMessageContent() +{ + Eigen::Quaternionf q(rotation); + + std::string pingMsg = std::to_string(position.x()) + ":" + + std::to_string(position.y()) + ":" + + std::to_string(position.z()) + ":" + + std::to_string(q.w()) + ":" + + std::to_string(q.x()) + ":" + + std::to_string(q.y()) + ":" + + std::to_string(q.z()) + ":" + + std::to_string(currentAngularVelocity.x()) + ":" + + std::to_string(currentAngularVelocity.y()) + ":" + + std::to_string(currentAngularVelocity.z()) + ":" + + std::to_string(velocity) + ":" + + std::to_string(selectedVelocity) + ":" + + std::to_string(discreteMag) + ":" // Используем те же static переменные из блока ROT + + std::to_string(discreteAngle); + + return pingMsg; +} + + +void ClientStateInterval::add_state(const ClientState& state) +{ + auto nowTime = std::chrono::system_clock::now(); + + if (timedStates.size() > 0 && timedStates[timedStates.size() - 1].lastUpdateServerTime == state.lastUpdateServerTime) + { + timedStates[timedStates.size() - 1] = state; + } + else + { + timedStates.push_back(state); + } + + auto cutoff_time = nowTime - std::chrono::milliseconds(CUTOFF_TIME); + + while (timedStates.size() > 0 && timedStates[0].lastUpdateServerTime < cutoff_time) + { + timedStates.erase(timedStates.begin()); + } +} + +bool ClientStateInterval::canFetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const +{ + if (timedStates.empty()) + { + return false; + } + if (timedStates[0].lastUpdateServerTime > targetTime) + { + return false; + } + + return true; +} + +ClientState ClientStateInterval::fetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const { + + ClientState closestState; + + if (timedStates.empty()) + { + throw std::runtime_error("No timed client states available"); + return closestState; + } + if (timedStates[0].lastUpdateServerTime > targetTime) + { + throw std::runtime_error("Found time but it is in future"); + return closestState; + } + if (timedStates.size() == 1) + { + closestState = timedStates[0]; + closestState.apply_lag_compensation(targetTime); + return closestState; + } + + + for (size_t i = 0; i < timedStates.size() - 1; ++i) + { + const auto& earlierState = timedStates[i]; + const auto& laterState = timedStates[i + 1]; + if (earlierState.lastUpdateServerTime <= targetTime && laterState.lastUpdateServerTime >= targetTime) + { + closestState = earlierState; + closestState.apply_lag_compensation(targetTime); + return closestState; + } + } + + closestState = timedStates[timedStates.size() - 1]; + closestState.apply_lag_compensation(targetTime); + return closestState; +} diff --git a/src/network/ClientState.h b/src/network/ClientState.h index 711533d..ac28def 100644 --- a/src/network/ClientState.h +++ b/src/network/ClientState.h @@ -25,213 +25,28 @@ struct ClientState { float velocity = 0.0f; int selectedVelocity = 0; float discreteMag = 0; - int discreteAngle = -1; + int discreteAngle = -1; // Для расчета лага std::chrono::system_clock::time_point lastUpdateServerTime; - void simulate_physics(size_t delta) { - if (discreteMag > 0.01f) - { - float rad = static_cast(discreteAngle) * static_cast(M_PI) / 180.0f; + void simulate_physics(size_t delta); - // Целевая угловая скорость (дискретная сила определяет модуль вектора) - // Вектор {cos, sin, 0} дает нам направление отклонения джойстика - Eigen::Vector3f targetAngularVelDir(sinf(rad), cosf(rad), 0.0f); - Eigen::Vector3f targetAngularVelocity = targetAngularVelDir * discreteMag; + void apply_lag_compensation(std::chrono::system_clock::time_point nowTime); - Eigen::Vector3f diffVel = targetAngularVelocity - currentAngularVelocity; - float diffLen = diffVel.norm(); + void handle_full_sync(const std::vector& parts, int startFrom); - if (diffLen > 0.0001f) { - // Вычисляем, на сколько мы можем изменить скорость в этом кадре - float maxChange = ANGULAR_ACCEL * static_cast(delta); - - if (diffLen <= maxChange) { - // Если до цели осталось меньше, чем шаг ускорения — просто прыгаем в цель - currentAngularVelocity = targetAngularVelocity; - } - - else { - // Линейно двигаемся в сторону целевого вектора - currentAngularVelocity += (diffVel / diffLen) * maxChange; - } - } - } - else - { - float currentSpeed = currentAngularVelocity.norm(); - - if (currentSpeed > 0.0001f) { - float drop = ANGULAR_ACCEL * static_cast(delta); - if (currentSpeed <= drop) { - currentAngularVelocity = Eigen::Vector3f::Zero(); - } - else { - // Уменьшаем модуль вектора, сохраняя направление - currentAngularVelocity -= (currentAngularVelocity / currentSpeed) * drop; - } - } - } - - float speedScale = currentAngularVelocity.norm(); - if (speedScale > 0.0001f) { - // Коэффициент чувствительности вращения - - float deltaAlpha = speedScale * static_cast(delta) * ROTATION_SENSITIVITY; - - Eigen::Vector3f axis = currentAngularVelocity.normalized(); - Eigen::Quaternionf rotateQuat(Eigen::AngleAxisf(deltaAlpha, axis)); - - rotation = rotation * rotateQuat.toRotationMatrix(); - } - - - // 4. Линейное изменение линейной скорости - float shipDesiredVelocity = selectedVelocity * 100.f; - - if (velocity < shipDesiredVelocity) - { - velocity += delta * SHIP_ACCEL; - if (velocity > shipDesiredVelocity) - { - velocity = shipDesiredVelocity; - } - } - else if (velocity > shipDesiredVelocity) - { - velocity -= delta * SHIP_ACCEL; - if (velocity < shipDesiredVelocity) - { - velocity = shipDesiredVelocity; - } - } - - if (fabs(velocity) > 0.01f) - { - Eigen::Vector3f velocityDirection = { 0,0, -velocity * delta / 1000.f }; - Eigen::Vector3f velocityDirectionAdjusted = rotation * velocityDirection; - position = position + velocityDirectionAdjusted; - } - } - - void apply_lag_compensation(std::chrono::system_clock::time_point nowTime) { - - // 2. Вычисляем задержку - long long deltaMs = 0; - if (nowTime > lastUpdateServerTime) { - deltaMs = std::chrono::duration_cast(nowTime - lastUpdateServerTime).count(); - } - - // 3. Защита от слишком больших скачков (Clamp) - // Если лаг более 500мс, ограничиваем его, чтобы избежать резких рывков - long long final_lag_ms = deltaMs;//min(deltaMs, 500ll); - - if (final_lag_ms > 0) { - // Доматываем симуляцию на величину задержки - // Мы предполагаем, что за это время параметры управления не менялись - simulate_physics(final_lag_ms); - } - } - - void handle_full_sync(const std::vector& parts, int startFrom) { - // Позиция - position = { std::stof(parts[startFrom]), std::stof(parts[startFrom+1]), std::stof(parts[startFrom+2]) }; - - Eigen::Quaternionf q( - std::stof(parts[startFrom+3]), - std::stof(parts[startFrom+4]), - std::stof(parts[startFrom+5]), - std::stof(parts[startFrom+6])); - rotation = q.toRotationMatrix(); - - currentAngularVelocity = Eigen::Vector3f{ - std::stof(parts[startFrom+7]), - std::stof(parts[startFrom+8]), - std::stof(parts[startFrom+9]) }; - velocity = std::stof(parts[startFrom+10]); - selectedVelocity = std::stoi(parts[startFrom+11]); - discreteMag = std::stof(parts[startFrom+12]); - discreteAngle = std::stoi(parts[startFrom+13]); - } + std::string formPingMessageContent(); }; - struct ClientStateInterval { std::vector timedStates; - void add_state(const ClientState& state) - { - auto nowTime = std::chrono::system_clock::now(); + void add_state(const ClientState& state); - if (timedStates.size() > 0 && timedStates[timedStates.size() - 1].lastUpdateServerTime == state.lastUpdateServerTime) - { - timedStates[timedStates.size() - 1] = state; - } - else - { - timedStates.push_back(state); - } + bool canFetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const; - auto cutoff_time = nowTime - std::chrono::milliseconds(CUTOFF_TIME); - - while (timedStates.size() > 0 && timedStates[0].lastUpdateServerTime < cutoff_time) - { - timedStates.erase(timedStates.begin()); - } - } - - bool canFetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const - { - if (timedStates.empty()) - { - return false; - } - if (timedStates[0].lastUpdateServerTime > targetTime) - { - return false; - } - - return true; - } - - ClientState fetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const { - - ClientState closestState; - - if (timedStates.empty()) - { - throw std::runtime_error("No timed client states available"); - return closestState; - } - if (timedStates[0].lastUpdateServerTime > targetTime) - { - throw std::runtime_error("Found time but it is in future"); - return closestState; - } - if (timedStates.size() == 1) - { - closestState = timedStates[0]; - closestState.apply_lag_compensation(targetTime); - return closestState; - } - - - for (size_t i = 0; i < timedStates.size() - 1; ++i) - { - const auto& earlierState = timedStates[i]; - const auto& laterState = timedStates[i + 1]; - if (earlierState.lastUpdateServerTime <= targetTime && laterState.lastUpdateServerTime >= targetTime) - { - closestState = earlierState; - closestState.apply_lag_compensation(targetTime); - return closestState; - } - } - - closestState = timedStates[timedStates.size() - 1]; - closestState.apply_lag_compensation(targetTime); - return closestState; - } + ClientState fetchClientStateAtTime(std::chrono::system_clock::time_point targetTime) const; }; + diff --git a/src/network/NetworkInterface.h b/src/network/NetworkInterface.h index 03f93a5..4873f07 100644 --- a/src/network/NetworkInterface.h +++ b/src/network/NetworkInterface.h @@ -1,10 +1,10 @@ -#pragma once +#pragma once #include #include #include #include "ClientState.h" -// NetworkInterface.h - +// NetworkInterface.h - »нтерфейс дл¤ разных типов соединений namespace ZL { class INetworkClient { @@ -13,7 +13,7 @@ namespace ZL { virtual void Connect(const std::string& host, uint16_t port) = 0; virtual void Send(const std::string& message) = 0; virtual bool IsConnected() const = 0; - virtual void Poll() = 0; // + virtual void Poll() = 0; // ƒл¤ обработки вход¤щих пакетов virtual std::unordered_map getRemotePlayers() = 0; }; } diff --git a/src/network/RemotePlayer.h b/src/network/RemotePlayer.h deleted file mode 100644 index 5a1664d..0000000 --- a/src/network/RemotePlayer.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "ClientState.h" diff --git a/src/network/WebSocketClient.cpp b/src/network/WebSocketClient.cpp index f7a0790..e9d1789 100644 --- a/src/network/WebSocketClient.cpp +++ b/src/network/WebSocketClient.cpp @@ -1,9 +1,8 @@ -#include "WebSocketClient.h" +#include "WebSocketClient.h" #include #include -#include "RemotePlayer.h" -// split +// Вспомогательный split std::vector split(const std::string& s, char delimiter) { std::vector tokens; std::string token; @@ -23,13 +22,13 @@ namespace ZL { ws_ = std::make_unique>(ioc_); - // handshake + // Выполняем синхронный коннект и handshake для простоты старта boost::beast::get_lowest_layer(*ws_).connect(results); ws_->handshake(host, "/"); connected = true; - // TaskManager + // Запускаем асинхронное чтение в пуле потоков TaskManager startAsyncRead(); } @@ -53,12 +52,12 @@ namespace ZL { } void WebSocketClient::processIncomingMessage(const std::string& msg) { - // ... + // Логика парсинга... if (msg.rfind("ID:", 0) == 0) { clientId = std::stoi(msg.substr(3)); } - // + // Безопасно кладем в очередь для главного потока std::lock_guard lock(queueMutex); messageQueue.push(msg); } @@ -138,14 +137,14 @@ namespace ZL { std::lock_guard lock(writeMutex_); writeQueue_.push(ss); - // , + // Если сейчас ничего не записывается, инициируем первую запись if (!isWriting_) { doWrite(); } } void WebSocketClient::doWrite() { - // + // Эта функция всегда вызывается под мьютексом или из колбэка if (writeQueue_.empty()) { isWriting_ = false; return; @@ -154,7 +153,7 @@ namespace ZL { isWriting_ = true; auto message = writeQueue_.front(); - // self (shared_from_this), + // Захватываем self (shared_from_this), чтобы объект не удалился во время записи ws_->async_write( boost::asio::buffer(*message), [this, message](boost::beast::error_code ec, std::size_t) { @@ -164,8 +163,8 @@ namespace ZL { } std::lock_guard lock(writeMutex_); - writeQueue_.pop(); // - doWrite(); // + writeQueue_.pop(); // Удаляем отправленное сообщение + doWrite(); // Проверяем следующее } ); } diff --git a/src/network/WebSocketClient.h b/src/network/WebSocketClient.h index ee7d119..09d3616 100644 --- a/src/network/WebSocketClient.h +++ b/src/network/WebSocketClient.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once // WebSocketClient.h #include "NetworkInterface.h" @@ -12,19 +12,19 @@ namespace ZL { class WebSocketClient : public INetworkClient { private: - // io_context TaskManager + // Переиспользуем io_context из TaskManager boost::asio::io_context& ioc_; - // + // Объекты переехали в члены класса std::unique_ptr> ws_; boost::beast::flat_buffer buffer_; std::queue messageQueue; - std::mutex queueMutex; // messageQueue + std::mutex queueMutex; // Защита для messageQueue std::queue> writeQueue_; bool isWriting_ = false; - std::mutex writeMutex_; // + std::mutex writeMutex_; // Отдельный мьютекс для очереди записи bool connected = false; int clientId = -1; diff --git a/src/planet/PlanetData.cpp b/src/planet/PlanetData.cpp index d4f2f02..a1a1254 100644 --- a/src/planet/PlanetData.cpp +++ b/src/planet/PlanetData.cpp @@ -1,4 +1,4 @@ -#include "PlanetData.h" +#include "PlanetData.h" #include #include #include @@ -10,13 +10,13 @@ namespace ZL { const float PlanetData::PLANET_RADIUS = 20000.f; const Vector3f PlanetData::PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f }; - // --- ( PlanetObject.cpp) --- + // --- Константы диапазонов (перенесены из PlanetObject.cpp) --- VertexID generateEdgeID(const VertexID& id1, const VertexID& id2) { return id1 < id2 ? id1 + "_" + id2 : id2 + "_" + id1; } - // () + // Вспомогательная функция для проекции (локальная) static Vector3f projectPointOnPlane(const Vector3f& P, const Vector3f& A, const Vector3f& B, const Vector3f& C) { Vector3f AB = B + A * (-1.0f); Vector3f AC = C + A * (-1.0f); @@ -138,18 +138,18 @@ namespace ZL { std::vector PlanetData::getBestTriangleUnderCamera(const Vector3f& viewerPosition) { - const LodLevel& finalLod = planetMeshLods[currentLod]; // LOD + const LodLevel& finalLod = planetMeshLods[currentLod]; // Работаем с текущим активным LOD Vector3f targetDir = (viewerPosition - PLANET_CENTER_OFFSET).normalized(); int bestTriangle = -1; float maxDot = -1.0f; - // 1: "" - // , N- - // LOD0, . - // ( 5-6 ) + // Шаг 1: Быстрый поиск ближайшего треугольника по "центроиду" + // Чтобы не проверять все, можно проверять каждый N-й или использовать + // предварительно вычисленные центры для LOD0, чтобы сузить круг. + // Но для надежности пройдемся по массиву (для 5-6 подразделений это быстро) for (int i = 0; i < (int)finalLod.triangles.size(); ++i) { - // + // Вычисляем примерное направление на треугольник Vector3f triDir = (finalLod.triangles[i].data[0] + finalLod.triangles[i].data[1] + finalLod.triangles[i].data[2]).normalized(); @@ -172,22 +172,22 @@ namespace ZL { float currentDist = shipLocal.norm(); Vector3f targetDir = shipLocal.normalized(); - // ( / ) - // , . + // Желаемый радиус покрытия на поверхности планеты (в метрах/единицах движка) + // Подбери это значение так, чтобы камни вокруг корабля всегда были видны. const float desiredCoverageRadius = 3000.0f; - // . - // (currentDist ), - // , . + // Вычисляем порог косинуса на основе желаемого радиуса и текущего расстояния. + // Чем мы дальше (currentDist больше), тем меньше должен быть угол отклонения + // от нормали, чтобы захватить ту же площадь. float angle = atan2(desiredCoverageRadius, currentDist); float searchThreshold = cos(angle); - // , + // Ограничитель, чтобы не захватить всю планету или вообще ничего searchThreshold = std::clamp(searchThreshold, 0.90f, 0.9999f); std::vector result; for (int i = 0; i < (int)finalLod.triangles.size(); ++i) { - // ( LodLevel ) + // Используем центроид (можно кэшировать в LodLevel для скорости) Vector3f triDir = (finalLod.triangles[i].data[0] + finalLod.triangles[i].data[1] + finalLod.triangles[i].data[2]).normalized(); @@ -205,7 +205,7 @@ namespace ZL { std::vector output; for (const auto& t : input) { - // ID + // Вершины и их ID const Vector3f& a = t.data[0]; const Vector3f& b = t.data[1]; const Vector3f& c = t.data[2]; @@ -213,7 +213,7 @@ namespace ZL { const VertexID& id_b = t.ids[1]; const VertexID& id_c = t.ids[2]; - // 1. () + // 1. Вычисляем середины (координаты) Vector3f m_ab = ((a + b) * 0.5f).normalized(); Vector3f m_bc = ((b + c) * 0.5f).normalized(); Vector3f m_ac = ((a + c) * 0.5f).normalized(); @@ -226,12 +226,12 @@ namespace ZL { Vector3f pm_bc = m_bc; Vector3f pm_ac = m_ac; - // 2. ID + // 2. Вычисляем ID новых вершин VertexID id_mab = generateEdgeID(id_a, id_b); VertexID id_mbc = generateEdgeID(id_b, id_c); VertexID id_mac = generateEdgeID(id_a, id_c); - // 3. 4 + // 3. Формируем 4 новых треугольника output.emplace_back(Triangle{ {a, pm_ab, pm_ac}, {id_a, id_mab, id_mac} }); // 0 output.emplace_back(Triangle{ {pm_ab, b, pm_bc}, {id_mab, id_b, id_mbc} }); // 1 output.emplace_back(Triangle{ {pm_ac, pm_bc, c}, {id_mac, id_mbc, id_c} }); // 2 @@ -282,31 +282,31 @@ namespace ZL { Vector2f(1.0f, 0.0f) }; - const Vector3f colorPinkish = { 1.0f, 0.8f, 0.82f }; // - const Vector3f colorYellowish = { 1.0f, 1.0f, 0.75f }; // + const Vector3f colorPinkish = { 1.0f, 0.8f, 0.82f }; // Слегка розоватый + const Vector3f colorYellowish = { 1.0f, 1.0f, 0.75f }; // Слегка желтоватый - const float colorFrequency = 4.0f; // + const float colorFrequency = 4.0f; // Масштаб пятен for (const auto& t : lod.triangles) { - // --- ( GetRotationForTriangle) --- + // --- Вычисляем локальный базис треугольника (как в GetRotationForTriangle) --- Vector3f vA = t.data[0]; Vector3f vB = t.data[1]; Vector3f vC = t.data[2]; - Vector3f x_axis = (vC - vB).normalized(); // U + Vector3f x_axis = (vC - vB).normalized(); // Направление U Vector3f edge1 = vB - vA; Vector3f edge2 = vC - vA; - Vector3f z_axis = edge1.cross(edge2).normalized(); // + Vector3f z_axis = edge1.cross(edge2).normalized(); // Нормаль плоскости - // ( ) + // Проверка направления нормали наружу (от центра планеты) Vector3f centerToTri = (vA + vB + vC).normalized(); if (z_axis.dot(centerToTri) < 0) { z_axis = z_axis * -1.0f; } - Vector3f y_axis = z_axis.cross(x_axis).normalized(); // V + Vector3f y_axis = z_axis.cross(x_axis).normalized(); // Направление V for (int i = 0; i < 3; ++i) { lod.vertexData.PositionData.push_back(t.data[i]); @@ -315,7 +315,7 @@ namespace ZL { lod.vertexData.TangentData.push_back(x_axis); lod.vertexData.BinormalData.push_back(y_axis); - // + // Используем один шум для выбора между розовым и желтым Vector3f dir = t.data[i].normalized(); float blendFactor = colorPerlin.noise( dir(0) * colorFrequency, @@ -323,10 +323,10 @@ namespace ZL { dir(2) * colorFrequency ); - // [-1, 1] [0, 1] + // Приводим шум из диапазона [-1, 1] в [0, 1] blendFactor = blendFactor * 0.5f + 0.5f; - // + // Линейная интерполяция между двумя цветами Vector3f finalColor; finalColor = colorPinkish + blendFactor * (colorYellowish - colorPinkish); @@ -339,17 +339,17 @@ namespace ZL { LodLevel PlanetData::generateSphere(int subdivisions, float noiseCoeff) { const float t = (1.0f + std::sqrt(5.0f)) / 2.0f; - // 12 + // 12 базовых вершин икосаэдра std::vector icosaVertices = { {-1, t, 0}, { 1, t, 0}, {-1, -t, 0}, { 1, -t, 0}, { 0, -1, t}, { 0, 1, t}, { 0, -1, -t}, { 0, 1, -t}, { t, 0, -1}, { t, 0, 1}, {-t, 0, -1}, {-t, 0, 1} }; - // + // Нормализуем вершины for (auto& v : icosaVertices) v = v.normalized(); - // 20 + // 20 граней икосаэдра struct IndexedTri { int v1, v2, v3; }; std::vector faces = { {0, 11, 5}, {0, 5, 1}, {0, 1, 7}, {0, 7, 10}, {0, 10, 11}, @@ -365,7 +365,7 @@ namespace ZL { tri.data[1] = icosaVertices[f.v2]; tri.data[2] = icosaVertices[f.v3]; - // ID ( ) + // Генерируем ID для базовых вершин (можно использовать их координаты) for (int i = 0; i < 3; ++i) { tri.ids[i] = std::to_string(tri.data[i](0)) + "_" + std::to_string(tri.data[i](1)) + "_" + @@ -374,15 +374,15 @@ namespace ZL { geometry.push_back(tri); } - // 3. N + // 3. Разбиваем N раз for (int i = 0; i < subdivisions; i++) { - geometry = subdivideTriangles(geometry, 0.0f); // + geometry = subdivideTriangles(geometry, 0.0f); // Шум пока игнорируем } - // 4. LodLevel (v2tMap) + // 4. Создаем LodLevel и заполняем топологию (v2tMap) LodLevel lodLevel = createLodLevel(geometry); - // v2tMap ( ) + // Пересобираем v2tMap (она критична для релаксации) lodLevel.v2tMap.clear(); for (size_t i = 0; i < geometry.size(); ++i) { for (int j = 0; j < 3; ++j) { @@ -390,12 +390,12 @@ namespace ZL { } } - // 5. (Lloyd-like) - // 5-10 + // 5. Применяем итеративную релаксацию (Lloyd-like) + // 5-10 итераций достаточно для отличной сетки applySphericalRelaxation(lodLevel, 8); - // 6. - // ... ( Perlin) + // 6. Накладываем шум и обновляем атрибуты + // ... (твой код наложения шума через Perlin) recalculateMeshAttributes(lodLevel); return lodLevel; @@ -410,7 +410,7 @@ namespace ZL { for (auto const& [vID, connectedTris] : lod.v2tMap) { Vector3f centroid(0, 0, 0); - // + // Находим среднюю точку среди центров всех соседних треугольников for (int triIdx : connectedTris) { const auto& tri = lod.triangles[triIdx]; Vector3f faceCenter = (tri.data[0] + tri.data[1] + tri.data[2]) * (1.0f / 3.0f); @@ -419,11 +419,11 @@ namespace ZL { centroid = centroid * (1.0f / (float)connectedTris.size()); - // + // Проецируем обратно на единичную сферу newPositions[vID] = centroid.normalized(); } - // + // Синхронизируем данные в треугольниках for (auto& tri : lod.triangles) { for (int i = 0; i < 3; ++i) { tri.data[i] = newPositions[tri.ids[i]]; diff --git a/src/planet/PlanetData.h b/src/planet/PlanetData.h index 8c875da..9430239 100644 --- a/src/planet/PlanetData.h +++ b/src/planet/PlanetData.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "utils/Perlin.h" #include "render/Renderer.h" @@ -16,7 +16,7 @@ namespace ZL { struct Vector3fComparator { bool operator()(const Eigen::Vector3f& a, const Eigen::Vector3f& b) const { - // (x, y, z) + // Лексикографическое сравнение (x, затем y, затем z) if (a.x() != b.x()) return a.x() < b.x(); if (a.y() != b.y()) return a.y() < b.y(); return a.z() < b.z(); @@ -87,11 +87,11 @@ namespace ZL { std::array planetMeshLods; LodLevel planetAtmosphereLod; - int currentLod; // + int currentLod; // Логический текущий уровень детализации //std::map initialVertexMap; - // + // Внутренние методы генерации std::vector subdivideTriangles(const std::vector& inputTriangles, float noiseCoeff); LodLevel createLodLevel(const std::vector& triangles); void recalculateMeshAttributes(LodLevel& lod); @@ -101,17 +101,17 @@ namespace ZL { void init(); - // ( ) + // Методы доступа к данным (для рендерера) const LodLevel& getLodLevel(int level) const; const LodLevel& getAtmosphereLod() const; int getCurrentLodIndex() const; int getMaxLodIndex() const; - // + // Логика std::pair calculateZRange(float distanceToSurface); float distanceToPlanetSurfaceFast(const Vector3f& viewerPosition); - // , + // Возвращает индексы треугольников, видимых камерой std::vector getBestTriangleUnderCamera(const Vector3f& viewerPosition); std::vector getTrianglesUnderCameraNew2(const Vector3f& viewerPosition); diff --git a/src/planet/PlanetObject.cpp b/src/planet/PlanetObject.cpp index 9048b6c..1216607 100644 --- a/src/planet/PlanetObject.cpp +++ b/src/planet/PlanetObject.cpp @@ -101,15 +101,15 @@ namespace ZL { // 1. Проверка порога движения (оптимизация из текущего кода) float movementThreshold = 1.0f; - if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold + if ((Environment::shipState.position - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold && !triangleIndicesToDraw.empty()) { //processMainThreadTasks(); // Все равно обрабатываем очередь OpenGL задач return; } - lastUpdatePos = Environment::shipPosition; + lastUpdatePos = Environment::shipState.position; // 2. Получаем список видимых треугольников - auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipPosition); + auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipState.position); std::sort(newIndices.begin(), newIndices.end()); // 3. Анализируем, что нужно загрузить @@ -305,7 +305,7 @@ namespace ZL { renderer.EnableVertexAttribArray(vTexCoordName); - float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipPosition); + float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position); auto zRange = planetData.calculateZRange(dist); const float currentZNear = zRange.first; const float currentZFar = zRange.second; @@ -320,7 +320,7 @@ namespace ZL { renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipPosition); + renderer.TranslateMatrix(-Environment::shipState.position); const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix(); @@ -332,7 +332,7 @@ namespace ZL { Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании // Позиция камеры (корабля) в мире - renderer.RenderUniform3fv("uViewPos", Environment::shipPosition.data()); + renderer.RenderUniform3fv("uViewPos", Environment::shipState.position.data()); //renderer.RenderUniform1f("uHeightScale", 0.08f); renderer.RenderUniform1f("uHeightScale", 0.0f); @@ -345,7 +345,7 @@ namespace ZL { renderer.RenderUniform3fv("uLightDirWorld", sunDirWorld.data()); // Направление от центра планеты к игроку для расчета дня/ночи - Vector3f playerDirWorld = Environment::shipPosition.normalized(); + Vector3f playerDirWorld = Environment::shipState.position.normalized(); renderer.RenderUniform3fv("uPlayerDirWorld", playerDirWorld.data()); // Тот же фактор освещенности игрока @@ -394,7 +394,7 @@ namespace ZL { renderer.EnableVertexAttribArray(vTexCoordName); - float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipPosition); + float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position); auto zRange = planetData.calculateZRange(dist); const float currentZNear = zRange.first; const float currentZFar = zRange.second; @@ -409,17 +409,17 @@ namespace ZL { renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipPosition); + renderer.TranslateMatrix(-Environment::shipState.position); renderer.RenderUniform1f("uDistanceToPlanetSurface", dist); renderer.RenderUniform1f("uCurrentZFar", currentZFar); - renderer.RenderUniform3fv("uViewPos", Environment::shipPosition.data()); - //std::cout << "uViewPos" << Environment::shipPosition << std::endl; + renderer.RenderUniform3fv("uViewPos", Environment::shipState.position.data()); + //std::cout << "uViewPos" << Environment::shipState.position << std::endl; // PlanetObject.cpp, метод drawStones Vector3f sunDirWorld = Vector3f(1.0f, -1.0f, -1.0f).normalized(); renderer.RenderUniform3fv("uLightDirWorld", sunDirWorld.data()); - Vector3f playerDirWorld = Environment::shipPosition.normalized(); + Vector3f playerDirWorld = Environment::shipState.position.normalized(); float playerLightFactor = max(0.0f, (playerDirWorld.dot(-sunDirWorld) + 0.2f) / 1.2f); renderer.RenderUniform1f("uPlayerLightFactor", playerLightFactor); @@ -479,7 +479,7 @@ namespace ZL { renderer.EnableVertexAttribArray(vPositionName); renderer.EnableVertexAttribArray(vNormalName); - float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipPosition); + float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position); auto zRange = planetData.calculateZRange(dist); float currentZNear = zRange.first; float currentZFar = zRange.second; @@ -499,7 +499,7 @@ namespace ZL { renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipPosition); + renderer.TranslateMatrix(-Environment::shipState.position); const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix(); @@ -536,7 +536,7 @@ namespace ZL { renderer.RenderUniform3fv("uWorldLightDir", worldLightDir.data()); // 1. Рассчитываем uPlayerLightFactor (как в Game.cpp) - Vector3f playerDirWorld = Environment::shipPosition.normalized(); + Vector3f playerDirWorld = Environment::shipState.position.normalized(); Vector3f sunDirWorld = Vector3f(1.0f, -1.0f, -1.0f).normalized(); // Насколько игрок на свету @@ -549,7 +549,7 @@ namespace ZL { // 3. Убедитесь, что uSkyColor тоже передан (в коде выше его не было) renderer.RenderUniform3fv("uSkyColor", color.data()); - //Vector3f playerDirWorld = Environment::shipPosition.normalized(); + //Vector3f playerDirWorld = Environment::shipState.position.normalized(); renderer.RenderUniform3fv("uPlayerDirWorld", playerDirWorld.data()); glEnable(GL_BLEND); diff --git a/src/planet/StoneObject.h b/src/planet/StoneObject.h index a2218b4..6827a74 100644 --- a/src/planet/StoneObject.h +++ b/src/planet/StoneObject.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "render/Renderer.h" #include "PlanetData.h" @@ -6,11 +6,11 @@ namespace ZL { struct StoneParams { - static const float BASE_SCALE; // - static const float MIN_AXIS_SCALE; // / - static const float MAX_AXIS_SCALE; // / - static const float MIN_PERTURBATION; // - static const float MAX_PERTURBATION; // + static const float BASE_SCALE; // Общий размер камня + static const float MIN_AXIS_SCALE; // Минимальное растяжение/сжатие по оси + static const float MAX_AXIS_SCALE; // Максимальное растяжение/сжатие по оси + static const float MIN_PERTURBATION; // Минимальное радиальное возмущение вершины + static const float MAX_PERTURBATION; // Максимальное радиальное возмущение вершины static const int STONES_PER_TRIANGLE; }; @@ -23,19 +23,19 @@ namespace ZL { }; enum class ChunkStatus { - Empty, // - Generating, // TaskManager (CPU) - ReadyToUpload, // , - Live // GPU + Empty, // Данных нет + Generating, // Задача в TaskManager (CPU) + ReadyToUpload, // Данные в памяти, ждут очереди в главный поток + Live // Загружено в GPU и готово к отрисовке }; struct StoneGroup { - // mesh.PositionData inflate() + // mesh.PositionData и прочие будут заполняться в inflate() VertexDataStruct mesh; std::vector> allInstances; - // + // Очищает старую геометрию и генерирует новую для указанных индексов std::vector inflate(int count); VertexRenderStruct inflateOne(int index, float scaleModifier); @@ -43,13 +43,13 @@ namespace ZL { std::vector statuses; - // + // Инициализация статусов при создании группы void initStatuses() { statuses.assign(allInstances.size(), ChunkStatus::Empty); } }; - // , + // Теперь возвращает заготовку со всеми параметрами, но без тяжелого меша StoneGroup CreateStoneGroupData(uint64_t globalSeed, const LodLevel& lodLevel); Triangle createLocalTriangle(const Triangle& sampleTri);