What to do to prevent the camera from going through colliders with this script
I made this script that rotate the player and the camera and also to the camera it move it a little forward (lean forward) and a little down when looking down, and a little back and up when looking up, so I can make it more realistic. The problem is that if the player is facing a wall, or something with a collider, the camera is going through it. I have already tried this to fix and didn't worked: 1) Place a collider at the head/camera position. It don't work because between that collider and the body collider was a gap and the player could jump and stan in the air by standing over an edge of a mesh (is hanging by the "chin" collider, even with a sphere collider). 2) Tried to use rigidbody.moveposition and rigidbody.position and was just acting in another way that it was supposed to do.
using System.Collections; using UnityEngine;
public class Player_Rotation : MonoBehaviour {
[Range(1,10)]
public float lookSensitivity = 5;
private float yRotation, xRotation, currentYRotation, currentXRotation, yRotationV = 0.0f, xRotationV = 0.0f, peekingRotation = 0.0f;
[Range(0.00f,0.25f)]
public float lookSmoothDamp = 0.1f;
Transform camera, player;
Rigidbody rb;
bool rotate = true;
void Start (){camera = transform.GetChild (0).transform;player = this.transform;rb = camera.gameObject.GetComponent<Rigidbody> ();}
void Update ()
{
if (Input.GetKeyDown (KeyCode.F1))
rotate = !rotate;
if (!rotate)
return;
yRotation += Input.GetAxis("Mouse X") * lookSensitivity;
xRotation -= Input.GetAxis("Mouse Y") * lookSensitivity;
if (Input.GetKey (KeyCode.Q))
peekingRotation += lookSensitivity * 0.5f;
else if (Input.GetKey (KeyCode.E))
peekingRotation += -lookSensitivity * 0.5f;
else
if (peekingRotation > 0)
{
peekingRotation += -lookSensitivity * 1f;
peekingRotation = Mathf.Clamp (peekingRotation, 0, 45);
}
else if (peekingRotation < 0)
{
peekingRotation += lookSensitivity * 1f;
peekingRotation = Mathf.Clamp (peekingRotation, -45, 0);
}
peekingRotation = Mathf.Clamp (peekingRotation, -15, 15);
xRotation = Mathf.Clamp(xRotation, -90, 90);
currentXRotation = Mathf.SmoothDamp(currentXRotation, xRotation, ref xRotationV, lookSmoothDamp);
currentYRotation = Mathf.SmoothDamp(currentYRotation, yRotation, ref yRotationV, lookSmoothDamp);
camera.localRotation = Quaternion.Euler(currentXRotation, 0, Mathf.SmoothDamp(camera.localRotation.z, peekingRotation, ref yRotationV, lookSmoothDamp));
if (xRotation >= 0)
camera.localPosition = new Vector3 (-peekingRotation / 25f, 1.11f - xRotation/1000f, 0 + xRotation/100f);
else if(xRotation < 0)
camera.localPosition = new Vector3 (-peekingRotation / 25f, 1.11f - xRotation/2000f, 0 + xRotation/1000f);
player.rotation = Quaternion.Euler(0, currentYRotation, 0);
}
}
Answer by DreadKyller · Dec 23, 2017 at 01:19 AM
Your best bet may be to utilize Raycasting. you know your target camera location and your current camera location, what you can do is raycast in that direction with a max length of just farther than the distance you'll be moving, if the raycast hits, don't perform the movement.
Vector3 difference = (targetCameraPosition - currentCameraPosition);
Vector3 direction = difference.normalized;
if (!Physics.Raycast(currentCameraPosition, direction, difference.magnitude + padding))
{
//apply camera movement
}
Yeah, but what if I am already looking down and I move into a wall, the camera is already in that position. The camera movement is not like an animation to be one move and just not allow that move to happen, is calculated every frame, so as I said up, it will still be clipping being already in that position. I need something to act when I am clipping, something like limiting my angle of view downward until that angle after that the camera will be clipping. Do you have any solution for that?
On collision, if you take the vector of collisionPoint - playerHeadLocation
, and set the y to 0 to get a purely horizontal direction. Normalize that vector, and using the dot product of that vector and your players facing vector (forward) with the y as 0 again. Because both are unit vectors this will give you how much the collision direction projects onto your facing direction: Vector3.Dot(collisionVector, playerFacingVector)
If this number is less than or equal to 0 then the direction of collision doesn't collide in a direction that is in the same direction as your facing, you don't need to modify the camera, if it returns 1 then it's directly head-on. If the result from the dot product is positive, then pass it into the arc sine function $$anonymous$$athf.asin(value)
this will give you an angle in radians of how much to rotate your head
You'll need to detect if the collision was behind the player of in front, if behind the player you'll want to rotate downwards, if in front of the player you'll rotate downwards. By rotate I mean the same math you use to handle input control. You may need to adjust some values but in general this should be a system that moves your head into a location that doesn't intersect.
Another solution, is as you move in a direction, raycast in that direction from the camera, if the raycast hits over a really small distance then do essentially the same concept as above, only making the angle to rotate smaller the farther the distance is.