Jump to content

[SOLVED] clamping the camera y movement


photo

Recommended Posts

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;
    }

    	
}

 

  • Thanks 1
Link to comment

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?

Link to comment

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.

  • Thanks 1
Link to comment

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);
    
    }

image.png.87a03281f63e83020c36246e1af31691.png 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?

 

 

Link to comment

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 Coordinate Systems – XFdtd – Remcom Support

  • Like 2
Link to comment

 

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));
    }

	
}

 

Link to comment
  • silent changed the title to [SOLVED] clamping the camera y movement
×
×
  • Create New...