Hi, I’ve been stuck with trying to get the standard First person controller (fpc) to a target. My camera is a child of the the main game object arranged like so:
When I try to force the fpc to look at a gameobject, it works fine but it messes up the cameras relative rotation to the parent and walking around becomes really disorienting.
My code for looking at an object
using UnityEngine;
public class LookAtTarget : MonoBehaviour
{
public GameObject targetObj;
public int speed = 3;
public bool focus;
public bool player = false;
public Transform childObjectWithCamera;
public bool Focus
{
get => focus;
set => focus = value;
}
// Update is called once per frame
void Update()
{
if (!focus) return;
var targetRotation = Quaternion.LookRotation(targetObj.transform.position - transform.position);
if (player)
{
Vector3 eulers = targetRotation.eulerAngles;
Vector3 parentTarget = new Vector3(0, eulers.y, 0f);
Vector3 childTarget = new Vector3(eulers.x,0,0 );
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(parentTarget),
speed * Time.deltaTime);
childObjectWithCamera.rotation = Quaternion.Slerp(childObjectWithCamera.rotation,
Quaternion.Euler(childTarget), speed * Time.deltaTime);
}
else
{
// transform.LookAt(targetObj.transform);
// var angles = targetRotation.eulerAngles;
// angles.x = 0;
// Smoothly rotate towards the target point.
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
}
}
}
If anyone knows how to properly rotate the first person controller I would appreciate the help!
These can be finicky… you might want to consider putting extra Transforms into the hierarchy between the main controller and the camera, and then modify those for “gaze.” When you’re not gazing, then you can slerp them back to identity rotation.
Though I’m not so sure this solution has the desired functionality I want since from how you put it, there would need to be some fade to black or jerk back to original rotation before the “gazing” started and I would like to avoid any sort of transition back to the pre gaze state if that make sense.
You’d have to calculate the heading and azimuth yourself for the gaze, gradually bring them on, then gradually take them off… it’s not hard really:
Turret aiming/rotating:
The biggest thing to note would be to base it not on an identity rotation (like the above code) but base it on relative to which way the player is standing, which is just one more step.
Yes, assuming no other parent object rotations. Once rotations start to cascade into each other, it becomes possible to have gimbal lock, where an axis is insufficient to control what you want.
I tried to take the hints from your code but it seems in the lerp for my parent object that the x and z rotations also get affected. Is there a way to just lerp the y component? Also here’s my updated code, and hierarchy.
public class LookAtTarget : MonoBehaviour
{
public GameObject targetObj;
public int speed = 3;
public bool focus;
public bool player = false;
public Transform childObjectWithCamera;
private float DesiredTraverse, DesiredElevation;
private Vector3 DeltaToTarget;
public bool Focus
{
get => focus;
set => focus = value;
}
// Update is called once per frame
void Update()
{
if (!focus) return;
if (player)
{
DeltaToTarget = targetObj.transform.position - transform.position;
DesiredTraverse = Mathf.Atan2(DeltaToTarget.x, DeltaToTarget.z) * Mathf.Rad2Deg;
float range = Mathf.Sqrt(DeltaToTarget.x * DeltaToTarget.x + DeltaToTarget.z * DeltaToTarget.z);
DesiredElevation = Mathf.Atan2(-DeltaToTarget.y, range) * Mathf.Rad2Deg;
Quaternion trav = Quaternion.Euler( 0, DesiredTraverse, 0);
Quaternion elev = Quaternion.Euler( DesiredElevation, 0, 0);
transform.localRotation = Quaternion.Lerp(transform.localRotation, trav,
speed * Time.deltaTime);
childObjectWithCamera.localRotation = Quaternion.Lerp(childObjectWithCamera.localRotation,
elev, speed * Time.deltaTime);
}
else
{
var targetRotation = Quaternion.LookRotation(targetObj.transform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime);
}
}
}