I would like my camera to inherit the player in the hierarchy, and get closer when there is a wall or floor between the player and the camera.
Right now I am trying to raycast from the player to the desired position, and set the camera as close as possible to that desired position. But my camera is flicking all over the place.
Both of these scripts are attached to the player's camera, which inherits from the player.
.. RotateCamera adjusts x rotation of the camera with mouse movement, and sends the desired y-position to the FollowCamera script (y-position should shift to keep player in view). The way this is working is a little hacky, but I'd really like to first focus on the raycast situation before improving this code.
using UnityEngine;
public class RotateCamera : MonoBehaviour
{
[SerializeField] private float rotSpeed, downAngleLimit;
[Header("Up angle limit should be negative number")]
[SerializeField] private float upAngleLimit;
[SerializeField] private FollowCamera followCamera;
private Vector3 oglocpos;
private Transform tx;
void Start()
{
tx = transform;
oglocpos = tx.localPosition;
upAngleLimit += 360;
}
void Update()
{
GetInput();
}
private void LateUpdate()
{
ClampAngle();
}
void GetInput()
{
float mouseY = Input.GetAxis("Mouse Y");
Rotate(mouseY);
}
void Rotate(float degrees)
{
// Just takes care of up/down rotation
tx.Rotate(Vector3.left * (degrees * rotSpeed * Time.deltaTime));
ShiftCamera(tx.localEulerAngles.x);
}
void ShiftCamera(float degrees)
{
// Determines desired y-position by linear equation with current x-angle as variable
var pos = oglocpos;
if (degrees < upAngleLimit)
{
pos.y = .05f * degrees; // f(x) = .05x
}
else if (degrees > upAngleLimit)
{
pos.y = (.05f * degrees - 18); // f(x) = .05x - 18
}
// send this desired position (in local coordinates) to the raycasting script
followCamera.desiredPosition = pos;
}
void ClampAngle()
{
Vector3 eul = Vector3.zero;
var loceul = tx.localEulerAngles;
eul.x = loceul.x;
if (eul.x > upAngleLimit)
{
eul.x = Mathf.Clamp(eul.x, upAngleLimit, 360);
}
else if (eul.x < downAngleLimit)
{
eul.x = Mathf.Clamp(eul.x, 0, downAngleLimit);
}
tx.localEulerAngles = eul;
}
}
.. FollowCamera does the raycasting and actual camera adjustment. I'm sure the issue is in this second script, but I don't know how else to approach it.
using UnityEngine;
public class FollowCamera : MonoBehaviour
{
public Vector3 desiredPosition;
[SerializeField] private Transform ptx; // player transform
[SerializeField] private LayerMask layerMask;
void Update()
{
// Send raycast from player to camera's desired position (in world space)
if (Physics.Raycast(ptx.position, transform.TransformPoint(desiredPosition), out var hit, 6f, layerMask))
{
// turn that into a local coordinate and send the camera there
var lochitpos = transform.InverseTransformPoint(hit.point);
transform.localPosition = lochitpos;
}
else
{
transform.localPosition = desiredPosition;
}
}
}