parthip Posted September 18 Posted September 18 I have been making a first person controller and i am trying to clamp the camera movement in y direction so that it doesn't turn 360 degrees given below is the code how do i implement it and i a using unigine version 2.15 #include "movement.h" #include <UnigineGame.h> #include <UnigineEditor.h> REGISTER_COMPONENT(movement); // macro for component registration by the Component System void movement::init() { _playerManager = getComponent<playerManager>(node); Player = _playerManager->getPlayer(); } void movement::updatePhysics() { float speed = speedW; float ifps = Game::getIFps(); float mouse_delta_x = Input::getMouseCoordDelta().x; float mouse_delta_y = Input::getMouseCoordDelta().y; // Calculate the rotation based on mouse movement and sensitivity float rotation_x = mouse_delta_x * sensitivity * ifps; float rotation_y = mouse_delta_y * sensitivity * ifps; // Rotate the node on the X-axis (yaw) if (node) { quat current_node_rotation = node->getWorldRotation(); quat yaw_rotation = quat(Vec3_up, -rotation_x); quat new_node_rotation = yaw_rotation * current_node_rotation; node->setWorldRotation(new_node_rotation); } // Rotate the camera on the Y-axis (pitch) if (camera) { quat current_camera_rotation = camera->getWorldRotation(); Vec3 right_direction = current_camera_rotation * Vec3_right; quat pitch_rotation = quat(right_direction, -rotation_y); quat new_camera_rotation = pitch_rotation * current_camera_rotation; camera->setWorldRotation(new_camera_rotation); } currentState = _playerManager->getCurrentState(); currentPose = _playerManager->getCurrentPose(); if (currentPose == _playerManager->MOVEMENTPOSE::running) { speed = speedR; } else { speed = speedW; } switch (currentState) { case _playerManager->MOVEMENTSTATES::Forward: movementDirection = node->getWorldDirection(Unigine::Math::AXIS_Y); Player->addLinearImpulse(movementDirection*speed*ifps); break; case _playerManager->MOVEMENTSTATES::Backward: movementDirection = node->getWorldDirection(Unigine::Math::AXIS_NY); Player->addLinearImpulse(movementDirection*speed*ifps); break; case _playerManager->MOVEMENTSTATES::LeftStride: movementDirection = node->getWorldDirection(Unigine::Math::AXIS_NX); Player->addLinearImpulse(movementDirection*speed*ifps); break; case _playerManager->MOVEMENTSTATES::RightStride: movementDirection = node->getWorldDirection(Unigine::Math::AXIS_X); Player->addLinearImpulse(movementDirection*speed*ifps); break; case _playerManager->MOVEMENTSTATES::Jump: movementDirection = node->getWorldDirection(Unigine::Math::AXIS_Z); Player->addLinearImpulse(movementDirection*speed*ifps); break; default: break; } } 1
parthip Posted September 19 Author Posted September 19 The current code given above doesn't clamp the camera rotation vertically so can anyone help me with it ? Also the the fall of the character is slow after jumping, the acceleration of gravity is -9.8 . What should I do to rectify this problem?
cash-metall Posted September 20 Posted September 20 It's difficult to pinpoint the exact issue without all the source code and a clear understanding of the hierarchy between the Player and the Node. However, here are a few suggestions: The updatePhysics method is called at a framerate different from the game loop, so using Game::IFps in this function is incorrect, as is applying transformations to nodes directly within the physics update. It's better to move the code responsible for adjusting the camera position to the post_update method. It's also best not to mix the setTransform/Rotation approach with applying physics to the same object. Doing so can lead to issues with physics (such as preserving momentum, acceleration) due to the object constantly being "teleported" to another position. Currently, it's unclear whether the Player and Node are separate nodes and what their dependency is, but the "slowing" effect in physics is usually related to mixing these approaches. By separating direct transformations and physics operations, you'll likely avoid conflicts in behavior. 1
parthip Posted September 20 Author Posted September 20 Thank you @cash-metall for your suggestions. as you said I have separated rotation and physics into different component and the camera component as been added to the camera node, also i create node(dirNode) for getting the direction for the WASD movement ,now i am not rotating the player which is a rigid body instead the dirNode for the yaw and the camera for the pitch. // Rotate the node on the X-axis (yaw) if (dirNode) { quat current_node_rotation = dirNode->getWorldRotation(); quat yaw_rotation = quat(Vec3_up, -rotation_x); quat new_node_rotation = yaw_rotation * current_node_rotation; dirNode->setWorldRotation(new_node_rotation); } // Rotate the camera on the Y-axis (pitch) if (node) { quat current_camera_rotation = node->getWorldRotation(); Vec3 right_direction = current_camera_rotation * Vec3_right; quat pitch_rotation = quat(right_direction, -rotation_y); quat new_camera_rotation = pitch_rotation * current_camera_rotation; node->setWorldRotation(new_camera_rotation); } This the hierarchy for the player node But the rotation of the camera in the y-axis if not limited i.e. it rotates 360 degrees, how to stop that or clamp it?
mifril Posted September 23 Posted September 23 In this situation you should get the current pitch rotation angle, and do not add pitch_rotation if angle does not follow your limits. Or another way to implement camera movement for first person controller, store phi and theta angles and construct rotation of the camera in each frame void movement::init() { phi = 180.0f; theta = 90.0f; } void movement::postUpdate() { if (!App::isMouseGrab()) return; float ifps = Game::getIFps(); float mouse_delta_x = Input::getMouseCoordDelta().x; float mouse_delta_y = Input::getMouseCoordDelta().y; phi -= mouse_delta_x * 4.0f * ifps; // limits for phi if (phi < 0.0f) phi += 360.0f; if (phi > 360.0f) phi -= 360.0f; theta -= mouse_delta_y * 4.0f * ifps; // limits for theta theta = clamp(theta, 0.1f, 179.9f); node->setWorldRotation(quat(Vec3_up, phi) * quat(Vec3_right, theta)); } Also using this way you do not need to get the movement direction, because you already have camera rotation angles. That works according this image 2
parthip Posted September 23 Author Posted September 23 Thank you @mifril I was able to solve the problem using your answer. the camera controller component is given below: #pragma once #include <Unigine.h> #include <UnigineComponentSystem.h> using namespace Unigine; using namespace Math; class cameraController : public ComponentBase { public: // declare constructor and destructor for the Spinner class COMPONENT_DEFINE(cameraController, Unigine::ComponentBase); // declare methods to be called at the corresponding stages of the execution sequence COMPONENT_INIT(init); COMPONENT_POST_UPDATE(postUpdate); // parameters PROP_PARAM(Float, sensitivity, 0.1f); PROP_PARAM(Node, dirNode); protected: // world main loop void init(); void postUpdate(); private: float phi; float theta; }; #include "cameraController.h" #include <UnigineGame.h> #include <UnigineEditor.h> REGISTER_COMPONENT(cameraController); // macro for component registration by the Component System void cameraController::init() { phi = 180.0f; theta = 90.0f; } void cameraController::postUpdate() { float mouse_delta_x = Input::getMouseCoordDelta().x; float mouse_delta_y = Input::getMouseCoordDelta().y; float ifps = Game::getIFps(); // Calculate the rotation based on mouse movement and sensitivity phi -= mouse_delta_x * sensitivity; if (phi < 0.0f) phi += 360.0f; if (phi > 360.0f) phi -= 360.0f; theta -= mouse_delta_y * sensitivity; theta = clamp(theta, 0.1f, 179.9f); node->setWorldRotation(quat(Vec3_up, phi) * quat(Vec3_right, theta)); // Rotate the node on the X-axis (yaw) if (dirNode) { dirNode->setWorldRotation(quat(Vec3_up, phi)); } }
Recommended Posts