diff --git a/src/Game.cpp b/src/Game.cpp index bf44c38..29d765e 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -687,48 +687,78 @@ namespace ZL bool joystickActive = isUsingJoystick && joystick && joystick->isActive; if (joystickActive) { - float joyX = -joystick->getDirectionX(); // -1..1 - float joyY = joystick->getDirectionY(); // -1..1 (вверх обычно отрицательный) + float joyX = joystick->getDirectionX(); // <-- оставляем инверсию X + float joyY = joystick->getDirectionY(); float magnitude = joystick->getMagnitude(); const float deadzone = 0.1f; + + Vector3f newMoveDir = Vector3f::Zero(); + float newMag = 0.0f; + if (magnitude > deadzone) { - // forward/right из ТЕКУЩЕГО camYaw (без lock) - Vector3f forward(-sinf(camYaw), 0.0f, -cosf(camYaw)); - Vector3f right(cosf(camYaw), 0.0f, -sinf(camYaw)); + // Берём ориентацию камеры из view matrix: + // view = World -> View, значит Rcw = (Rwv)^T = View -> World + Matrix4f viewM = camera.getViewMatrix(); + Matrix3f Rwv = viewM.block<3, 3>(0, 0); + Matrix3f Rcw = Rwv.transpose(); - // joyY: если вверх = отрицательный, то "- forward * joyY" даёт движение вперёд при joyY<0 - Vector3f worldMove = right * joyX - forward * joyY; + Vector3f camRight = (Rcw * Vector3f(1, 0, 0)); + Vector3f camForward = (Rcw * Vector3f(0, 0, -1)); // куда смотрит камера в мире + + if (camRight.squaredNorm() > 1e-6f) camRight.normalize(); + if (camForward.squaredNorm() > 1e-6f) camForward.normalize(); + + // joystick: X = вправо/влево, Y = вверх/вниз + // joyY обычно отрицательный при "вверх", поэтому "- camForward * joyY" даёт "вперёд" + Vector3f worldMove = camRight * joyX - camForward * joyY; if (worldMove.squaredNorm() > 1e-6f) { - worldMove.normalize(); - - float ang = atan2f(worldMove.x(), worldMove.z()); // 0 -> +Z - int a = (int)std::round(ang * 180.0f / (float)M_PI); - if (a < 0) a += 360; - a %= 360; - - discreteAngle = a; - - discreteMag = (std::min)(magnitude, 1.0f); - discreteMag = std::round(discreteMag * 10.0f) / 10.0f; + newMoveDir = worldMove.normalized(); + newMag = (std::min)(magnitude, 1.0f); + newMag = std::round(newMag * 10.0f) / 10.0f; } } + + // Применяем в shipState + bool changed = false; + + if ((Environment::shipState.currentAngularVelocity - newMoveDir).norm() > 0.001f) { + Environment::shipState.currentAngularVelocity = newMoveDir; // <-- теперь это "moveDirWorld" + changed = true; + } + + if (fabs(Environment::shipState.discreteMag - newMag) > 0.001f) { + Environment::shipState.discreteMag = newMag; // throttle + changed = true; + } + + // discreteAngle больше не нужен для движения (можешь оставить -1) + if (Environment::shipState.discreteAngle != -1) { + Environment::shipState.discreteAngle = -1; + changed = true; + } + + if (changed) { + std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); + networkClient->Send(msg); + } + } // Network Update - bool changed = false; + //bool changed = false; - if (discreteAngle != Environment::shipState.discreteAngle) { - Environment::shipState.discreteAngle = discreteAngle; - changed = true; - } - if (discreteMag != Environment::shipState.discreteMag) { - Environment::shipState.discreteMag = discreteMag; - changed = true; - } + //if (discreteAngle != Environment::shipState.discreteAngle) { + // Environment::shipState.discreteAngle = discreteAngle; + // changed = true; + //} + //if (discreteMag != Environment::shipState.discreteMag) { + // Environment::shipState.discreteMag = discreteMag; + // changed = true; + //} // slider value применяем здесь (ты раньше только newShipVelocity менял) //int newVelInt = (int)newShipVelocity; @@ -737,9 +767,27 @@ namespace ZL // changed = true; //} - if (changed) { - std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); - networkClient->Send(msg); + //if (changed) { + // std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); + // networkClient->Send(msg); + //} + // Network Update (только если НЕ используем джойстик) + if (!joystickActive) { + bool changed2 = false; + + if (discreteAngle != Environment::shipState.discreteAngle) { + Environment::shipState.discreteAngle = discreteAngle; + changed2 = true; + } + if (discreteMag != Environment::shipState.discreteMag) { + Environment::shipState.discreteMag = discreteMag; + changed2 = true; + } + + if (changed2) { + std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); + networkClient->Send(msg); + } } diff --git a/src/network/ClientState.cpp b/src/network/ClientState.cpp index 60bd1e0..1d312b6 100644 --- a/src/network/ClientState.cpp +++ b/src/network/ClientState.cpp @@ -46,11 +46,8 @@ void ClientState::simulate_physics(size_t deltaMs) const float ROT_T = std::clamp(ROTATION_SENSITIVITY * static_cast(deltaMs), 0.0f, 1.0f); // ------------------------------------------- - // We keep this for protocol compatibility, but it no longer affects anything. - currentAngularVelocity = Eigen::Vector3f::Zero(); - // Input validity - const bool hasInput = (discreteAngle >= 0) && (discreteMag > 0.01f); + const bool hasInput = (discreteMag > 0.01f) && (currentAngularVelocity.squaredNorm() > 1e-6f); // Speed command: // - Prefer discreteMag (joystick magnitude) @@ -75,37 +72,47 @@ void ClientState::simulate_physics(size_t deltaMs) // ang = atan2(worldMove.x, worldMove.z) // So we reconstruct as: // x = sin(rad), z = cos(rad) - const float rad = DegToRad(static_cast(discreteAngle)); + Eigen::Vector3f moveDirWorld = currentAngularVelocity.normalized(); + + + Eigen::Vector3f veccc(0.0f, 0.0f, -1.0f); + + Eigen::Vector3f veccc_rotated = rotation * veccc; - Eigen::Vector3f moveDirWorld( - sinf(rad), - 0.0f, - cosf(rad) - ); - if (moveDirWorld.squaredNorm() > 1e-6f) { - moveDirWorld.normalize(); - } - else { - return; - } // Move in world - position += moveDirWorld * (velocity * dt); + //position += moveDirWorld * (velocity * dt); + position += veccc_rotated * (velocity * dt); // Rotate ship to face movement direction (optional). // Ship local forward is (0,0,-1) (as in your fireProjectiles). // We need yaw so that rotation * (0,0,-1) == moveDirWorld. // That yaw is: yaw = atan2(-dir.x, -dir.z) { - float desiredYaw = atan2f(-moveDirWorld.x(), -moveDirWorld.z()); + Eigen::Vector3f worldUp(0.0f, 1.0f, 0.0f); + + // local forward = (0,0,-1) => значит Z-ось мира должна смотреть в -moveDirWorld + Eigen::Vector3f zAxis = -moveDirWorld; + Eigen::Vector3f xAxis = worldUp.cross(zAxis); + + if (xAxis.squaredNorm() < 1e-6f) xAxis = Eigen::Vector3f(1, 0, 0); + xAxis.normalize(); + + Eigen::Vector3f yAxis = zAxis.cross(xAxis).normalized(); + + Eigen::Matrix3f R; + R.col(0) = xAxis; + R.col(1) = yAxis; + R.col(2) = zAxis; Eigen::Quaternionf qCur(rotation); - Eigen::Quaternionf qTar(Eigen::AngleAxisf(desiredYaw, Eigen::Vector3f::UnitY())); + Eigen::Quaternionf qTar(R); Eigen::Quaternionf qNew = qCur.slerp(ROT_T, qTar).normalized(); rotation = qNew.toRotationMatrix(); } + } void ClientState::apply_lag_compensation(std::chrono::system_clock::time_point nowTime)