mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-09-05 14:58:27 +00:00
test fix
This commit is contained in:
@@ -378,37 +378,63 @@ bool Strip::CheckRotation(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
LOG("Diff: x=%f, y=%f, z=%f", std::abs(Math::RadToDeg(diff.x)), std::abs(Math::RadToDeg(diff.y)), std::abs(Math::RadToDeg(diff.z)));
|
LOG("Diff: x=%f, y=%f, z=%f", std::abs(Math::RadToDeg(diff.x)), std::abs(Math::RadToDeg(diff.y)), std::abs(Math::RadToDeg(diff.z)));
|
||||||
LOG("Velocity: x=%f, y=%f, z=%f", Math::RadToDeg(getAngVel.angVelocity.x) * deltaTime, Math::RadToDeg(getAngVel.angVelocity.y) * deltaTime, Math::RadToDeg(getAngVel.angVelocity.z) * deltaTime);
|
LOG("Velocity: x=%f, y=%f, z=%f", Math::RadToDeg(getAngVel.angVelocity.x) * deltaTime, Math::RadToDeg(getAngVel.angVelocity.y) * deltaTime, Math::RadToDeg(getAngVel.angVelocity.z) * deltaTime);
|
||||||
m_PreviousFrameRotation = curRotation;
|
m_PreviousFrameRotation = curRotation;
|
||||||
auto angVel = diff;
|
|
||||||
angVel.x = std::abs(Math::RadToDeg(angVel.x));
|
// Convert frame delta (radians) to absolute degrees moved this frame per axis.
|
||||||
angVel.y = std::abs(Math::RadToDeg(angVel.y));
|
// Use the reported angular velocity (radians/sec) * deltaTime instead of extracting
|
||||||
angVel.z = std::abs(Math::RadToDeg(angVel.z));
|
// Euler angles from the quaternion difference. Extracting Euler angles from a
|
||||||
|
// combined-axis quaternion won't produce per-axis rotations when axes rotate
|
||||||
|
// simultaneously, which caused late stopping. Using angular velocity is consistent
|
||||||
|
// with how velocity is applied in SimplePhysicsComponent.
|
||||||
|
NiPoint3 angMovedDegrees = NiPoint3(std::abs(Math::RadToDeg(getAngVel.angVelocity.x) * deltaTime),
|
||||||
|
std::abs(Math::RadToDeg(getAngVel.angVelocity.y) * deltaTime),
|
||||||
|
std::abs(Math::RadToDeg(getAngVel.angVelocity.z) * deltaTime));
|
||||||
|
|
||||||
const auto [rotateX, rotateY, rotateZ] = m_InActionTranslation;
|
const auto [rotateX, rotateY, rotateZ] = m_InActionTranslation;
|
||||||
bool rotateFinished = true;
|
bool rotateFinished = true; // assume finished until an axis proves otherwise
|
||||||
NiPoint3 finalRotationAdjustment = NiPoint3Constant::ZERO;
|
NiPoint3 finalRotationAdjustment = NiPoint3Constant::ZERO;
|
||||||
|
|
||||||
|
// Use a small epsilon to avoid missing the exact-zero case due to floating point
|
||||||
|
constexpr float EPS_DEG = 1e-3f;
|
||||||
|
|
||||||
|
// Handle each axis independently so we can rotate on multiple axes at once.
|
||||||
if (rotateX != 0.0f) {
|
if (rotateX != 0.0f) {
|
||||||
m_InActionTranslation.x -= angVel.x;
|
m_InActionTranslation.x -= angMovedDegrees.x;
|
||||||
rotateFinished = std::signbit(m_InActionTranslation.x) != std::signbit(rotateX);
|
// Finished if we crossed zero or are within epsilon
|
||||||
|
if (std::signbit(m_InActionTranslation.x) != std::signbit(rotateX) || std::abs(m_InActionTranslation.x) <= EPS_DEG) {
|
||||||
finalRotationAdjustment.x = Math::DegToRad(m_InActionTranslation.x);
|
finalRotationAdjustment.x = Math::DegToRad(m_InActionTranslation.x);
|
||||||
} else if (rotateY != 0.0f) {
|
m_InActionTranslation.x = 0.0f;
|
||||||
m_InActionTranslation.y -= angVel.y;
|
} else {
|
||||||
rotateFinished = std::signbit(m_InActionTranslation.y) != std::signbit(rotateY);
|
rotateFinished = false;
|
||||||
finalRotationAdjustment.y = Math::DegToRad(m_InActionTranslation.y);
|
}
|
||||||
} else if (rotateZ != 0.0f) {
|
|
||||||
m_InActionTranslation.z -= angVel.z;
|
|
||||||
rotateFinished = std::signbit(m_InActionTranslation.z) != std::signbit(rotateZ);
|
|
||||||
finalRotationAdjustment.z = Math::DegToRad(m_InActionTranslation.z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rotateFinished && m_InActionTranslation != NiPoint3Constant::ZERO) {
|
if (rotateY != 0.0f) {
|
||||||
LOG("Rotation finished, zeroing angVel");
|
m_InActionTranslation.y -= angMovedDegrees.y;
|
||||||
|
if (std::signbit(m_InActionTranslation.y) != std::signbit(rotateY) || std::abs(m_InActionTranslation.y) <= EPS_DEG) {
|
||||||
|
finalRotationAdjustment.y = Math::DegToRad(m_InActionTranslation.y);
|
||||||
|
m_InActionTranslation.y = 0.0f;
|
||||||
|
} else {
|
||||||
|
rotateFinished = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
angVel.x = Math::DegToRad(angVel.x);
|
if (rotateZ != 0.0f) {
|
||||||
angVel.y = Math::DegToRad(angVel.y);
|
m_InActionTranslation.z -= angMovedDegrees.z;
|
||||||
angVel.z = Math::DegToRad(angVel.z);
|
if (std::signbit(m_InActionTranslation.z) != std::signbit(rotateZ) || std::abs(m_InActionTranslation.z) <= EPS_DEG) {
|
||||||
|
finalRotationAdjustment.z = Math::DegToRad(m_InActionTranslation.z);
|
||||||
|
m_InActionTranslation.z = 0.0f;
|
||||||
|
} else {
|
||||||
|
rotateFinished = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotateFinished && (finalRotationAdjustment != NiPoint3Constant::ZERO)) {
|
||||||
|
LOG("Rotation finished, zeroing angVel for finished axes");
|
||||||
|
|
||||||
|
// Zero only the angular velocity channels that have just finished.
|
||||||
if (rotateX != 0.0f) getAngVel.angVelocity.x = 0.0f;
|
if (rotateX != 0.0f) getAngVel.angVelocity.x = 0.0f;
|
||||||
else if (rotateY != 0.0f) getAngVel.angVelocity.y = 0.0f;
|
if (rotateY != 0.0f) getAngVel.angVelocity.y = 0.0f;
|
||||||
else if (rotateZ != 0.0f) getAngVel.angVelocity.z = 0.0f;
|
if (rotateZ != 0.0f) getAngVel.angVelocity.z = 0.0f;
|
||||||
|
|
||||||
GameMessages::SetAngularVelocity setAngVel{};
|
GameMessages::SetAngularVelocity setAngVel{};
|
||||||
setAngVel.target = modelComponent.GetParent()->GetObjectID();
|
setAngVel.target = modelComponent.GetParent()->GetObjectID();
|
||||||
@@ -422,9 +448,11 @@ bool Strip::CheckRotation(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
currentRot.Normalize();
|
currentRot.Normalize();
|
||||||
modelComponent.GetParent()->SetRotation(currentRot);
|
modelComponent.GetParent()->SetRotation(currentRot);
|
||||||
|
|
||||||
m_InActionTranslation = NiPoint3Constant::ZERO;
|
// If all axes are zeroed out then stop rotating
|
||||||
|
if (m_InActionTranslation == NiPoint3Constant::ZERO) {
|
||||||
m_IsRotating = false;
|
m_IsRotating = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOG("angVel: x=%f, y=%f, z=%f", m_InActionTranslation.x, m_InActionTranslation.y, m_InActionTranslation.z);
|
LOG("angVel: x=%f, y=%f, z=%f", m_InActionTranslation.x, m_InActionTranslation.y, m_InActionTranslation.z);
|
||||||
return rotateFinished;
|
return rotateFinished;
|
||||||
|
@@ -8,6 +8,9 @@ list(APPEND DGAMETEST_SOURCES ${DCOMPONENTS_TESTS})
|
|||||||
add_subdirectory(dGameMessagesTests)
|
add_subdirectory(dGameMessagesTests)
|
||||||
list(APPEND DGAMETEST_SOURCES ${DGAMEMESSAGES_TESTS})
|
list(APPEND DGAMETEST_SOURCES ${DGAMEMESSAGES_TESTS})
|
||||||
|
|
||||||
|
add_subdirectory(dPropertyBehaviorsTests)
|
||||||
|
list(APPEND DGAMETEST_SOURCES ${DPROPERTYBEHAVIORS_TESTS})
|
||||||
|
|
||||||
file(COPY ${GAMEMESSAGE_TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
file(COPY ${GAMEMESSAGE_TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
file(COPY ${COMPONENT_TEST_DATA} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
file(COPY ${COMPONENT_TEST_DATA} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
6
tests/dGameTests/dPropertyBehaviorsTests/CMakeLists.txt
Normal file
6
tests/dGameTests/dPropertyBehaviorsTests/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
set(DPROPERTYBEHAVIORS_TESTS
|
||||||
|
"dPropertyBehaviorsTests/StripRotationTest.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Expose variable to parent CMake
|
||||||
|
set(DPROPERTYBEHAVIORS_TESTS ${DPROPERTYBEHAVIORS_TESTS} PARENT_SCOPE)
|
@@ -0,0 +1,53 @@
|
|||||||
|
#include "GameDependencies.h"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "NiQuaternion.h"
|
||||||
|
#include "dMath.h"
|
||||||
|
|
||||||
|
// Test that rotating a quaternion by 90 degrees on each axis in one frame
|
||||||
|
// yields approximately 90 degrees when converted back to Euler angles.
|
||||||
|
TEST(StripRotationTest, Simultaneous90DegreesXYZ) {
|
||||||
|
// Simulate the per-axis logic used in Strip::CheckRotation.
|
||||||
|
// Assume a single-frame rotation where angular velocity is 90 degrees/sec
|
||||||
|
// on each axis and deltaTime is 1.0 seconds. The remaining rotation
|
||||||
|
// prior to the frame is 90 degrees on each axis.
|
||||||
|
NiPoint3 remainingRotationDeg(90.0f, 90.0f, 90.0f);
|
||||||
|
NiPoint3 angularVelocityDegPerSec(90.0f, 90.0f, 90.0f);
|
||||||
|
const float deltaTime = 1.0f;
|
||||||
|
|
||||||
|
// Compute degrees moved this frame per axis
|
||||||
|
NiPoint3 angMovedDegrees(std::abs(angularVelocityDegPerSec.x) * deltaTime,
|
||||||
|
std::abs(angularVelocityDegPerSec.y) * deltaTime,
|
||||||
|
std::abs(angularVelocityDegPerSec.z) * deltaTime);
|
||||||
|
|
||||||
|
// Subtract movement from remaining rotation per axis (mirrors Strip logic)
|
||||||
|
bool rotateFinished = true;
|
||||||
|
constexpr float EPS_DEG = 1e-3f;
|
||||||
|
|
||||||
|
// X
|
||||||
|
remainingRotationDeg.x -= angMovedDegrees.x;
|
||||||
|
if (std::signbit(remainingRotationDeg.x) != std::signbit(90.0f) || std::abs(remainingRotationDeg.x) <= EPS_DEG) {
|
||||||
|
remainingRotationDeg.x = 0.0f;
|
||||||
|
} else {
|
||||||
|
rotateFinished = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Y
|
||||||
|
remainingRotationDeg.y -= angMovedDegrees.y;
|
||||||
|
if (std::signbit(remainingRotationDeg.y) != std::signbit(90.0f) || std::abs(remainingRotationDeg.y) <= EPS_DEG) {
|
||||||
|
remainingRotationDeg.y = 0.0f;
|
||||||
|
} else {
|
||||||
|
rotateFinished = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Z
|
||||||
|
remainingRotationDeg.z -= angMovedDegrees.z;
|
||||||
|
if (std::signbit(remainingRotationDeg.z) != std::signbit(90.0f) || std::abs(remainingRotationDeg.z) <= EPS_DEG) {
|
||||||
|
remainingRotationDeg.z = 0.0f;
|
||||||
|
} else {
|
||||||
|
rotateFinished = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_TRUE(rotateFinished);
|
||||||
|
ASSERT_EQ(remainingRotationDeg, NiPoint3(0.0f, 0.0f, 0.0f));
|
||||||
|
}
|
Reference in New Issue
Block a user