- Home /
How to clamp player to viewport constraints when rotating
Hi,
I am trying to clamp my Player's movements to so that he stays within a certain viewport area when rotating. I am using Bunny83's solution,(here) but am using a plane and Plane.Raycast to find the point where the ray intersects the plane and then position (lerp) the Player to this position. I have created the viewport bounds (leftBottom and rightTop) to act as the min and max range in the Mathf.clamp functions for the X and Y axes. The Player is a child of the MainCamera and the Player can be dragged around and faced the correct direction, however the clamping no longer works. I don't think the bounds are moving with the camera?
Can anyone point me in the right direction here?
Thanks
void Update()
{
// Variable to represent the camera
Camera myCamera = Camera.main;
float dist = myCamera.transform.InverseTransformPoint(transform.position).z;
Vector3 localPos = myCamera.transform.InverseTransformPoint(Player.position);
// Create a plane with normal in the opposite direction to where the Player is facing, and with a
// fixed position which is set distance from the camera.
Plane plane = new Plane(-Player.forward, myCamera.transform.position + myCamera.transform.forward * DesiredPlayerDistanceFromCam);
// Create a ray to hold the information when the mouse is clicked on the screen.
// Returns a ray going from camera through a screen point.
// Resulting ray is in world space, starting on the near plane of the camera and going through position's
// (x,y) pixel coordinates on the screen (position.z is ignored)
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// If the ray intersects the plane..
if (plane.Raycast(ray, out dist))
{
// Find the position on the plane and store in variable pos
Vector3 pos = ray.GetPoint(dist);
// Debug.Log("dist = " + dist);
pos2 = pos;
}
// Set the player position to that position on the plane (move the player there)
Player.position = Vector3.Lerp(Player.position, pos2, Time.deltaTime * Smooth);
leftBottom = myCamera.ViewportToWorldPoint(new Vector3(0, 0, dist));
rightTop = myCamera.ViewportToWorldPoint(new Vector3(1, 1, dist));
leftBottom = myCamera.transform.InverseTransformPoint(leftBottom);
Debug.Log("leftBottom = " + leftBottom);
rightTop = myCamera.transform.InverseTransformPoint(rightTop);
Debug.Log("rightTop = " + rightTop);
float x = Mathf.Clamp(localPos.x, leftBottom.x, rightTop.x);
float y = Mathf.Clamp(localPos.y, leftBottom.y, rightTop.y);
// Player.position = myCamera.transform.TransformPoint(new Vector3(x, y, localPos.z));
}
Answer by fafase · Dec 17, 2012 at 06:25 PM
I am not totally sure of the principle but I give it a try.
You could use the camera position to which you add/subtract the width and height you need.
Then you clamp the position of your guy from those values.
As the camera moves the max positions are also updated so it should work... In pseudocode, that'd go:
Transform camera;
float height;
float width;
float maxY = camera.position.y + height/2;
float minY = camera.position.y - height/2;;
float maxX = camera.position.x + width/2;
float minX = camera.position.x - width/2;;
float myPosY = Mathf.Clamp(Player.position.y, minY, maxY);
float myPosX = Mathf.Clamp(Player.position.x, minX, maxX);
One thing also:
if (Player.position.y <= bottomBorderWorld || Player.position.y >= topBorderWorld){
float myPosY = Mathf.Clamp(Player.position.y, bottomBorderWorld, topBorderWorld);
Player.position = new Vector3(Player.position.x, myPosY, Player.position.z);
Debug.Log("posX = " + posX);
}
The if statement can be removed since clamp does inside what your if does.
Thanks for that - I'll give that a shot and see how it turns out.
For now though I would like to keep dist constant as the clamping works whilst moving forward. I would like to see if I can get it to work while rotating.
Now, as camera rotation is not taken into account during the calculation of the bounds in world space, I'm not completely sure when this should be applied. For instance:
leftBorderWorld = Camera.main.ViewportToWorldPoint(new Vector3(0, 0, dist)).x + playerRadius;
Ok in this case you would need to define the clamp values in local transform of the camera and then convert them to world position. Actually you could even have four empty game object attached to the camera and simply comparing their position to the player position using only the appropriate position.
I see what you mean.
I have updated my code above to show what I have so far. The Player now rotates with the camera and points in the correct direction when moving. However, the clamping is no longer working, as I don't think the bounds are moving with the camera?
$$anonymous$$uch thanks for the guidance, fafase - I figured it out and it now works great with rotations and all.
$$anonymous$$ay you have a $$anonymous$$erry $$anonymous$$ and a Happy New Year! :D