This screenshot is when running the game, the head and the body both facing forward direction fine :
And this screenshot is after moving the mouse and rotating the head, the head is facing backward while the body is facing forward :
What I want is using a script to clamp and limit the head rotation to the most human head rotation when looking around. It can be a bit to the backward but not like in the second screenshot.
This is the script I’m using it’s attached to the player root object :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Interactable : MonoBehaviour
{
public Transform objToRotateLookAT;
public Transform body;
public float lookAtSpeed;
public float originalLookSpeed;
public float rotationSpeed;
public float distanceToInteract;
public Animator anim;
public GameObject text;
private bool raycastSucceed;
private Vector3 originalRotation;
private bool originalRotFlag = true;
private bool isInstant = false;
// Start is called before the first frame update
void Start()
{
Cursor.visible = false;
originalRotation = objToRotateLookAT.position;
if (anim == null)
{
anim = GetComponent<Animator>();
}
}
void FixedUpdate()
{
int layerMask = 1 << 8;
RaycastHit hit;
// Does the ray intersect any objects excluding the player layer
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, Mathf.Infinity, layerMask))
{
if (!raycastSucceed)
Debug.Log("Did Hit");
raycastSucceed = true;
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.red);
text.SetActive(true);
if (Vector3.Distance(transform.position, hit.transform.position) <= distanceToInteract)
{
anim.SetBool("Pickup Item", true);
}
}
else
{
if (raycastSucceed)
Debug.Log("Did not Hit");
raycastSucceed = false;
Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * 1000, Color.yellow);
text.SetActive(false);
if (originalRotFlag == false)
{
}
else
{
}
}
}
private void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Quaternion targetRotation = Quaternion.LookRotation(ray.direction);
targetRotation.y = Mathf.Clamp(targetRotation.y, -90f, 90f);
if (isInstant)
{
objToRotateLookAT.rotation = targetRotation;
}
else
{
Quaternion currentRotation = objToRotateLookAT.rotation;
float angularDifference = Quaternion.Angle(currentRotation, targetRotation);
// will always be positive (or zero)
if (angularDifference > 0) objToRotateLookAT.rotation = Quaternion.Slerp(
currentRotation,
targetRotation,
(rotationSpeed * 180 * Time.deltaTime) / angularDifference
);
else objToRotateLookAT.rotation = targetRotation;
}
}
}
The part for rotating the head with the mouse is in the Update section.
This screenshot is the editor hierarchy and the inspector of the script attached to the player.
I attached it to the empty GameObject but it can be attached any child or the root.
The reason for this empty GameObject is to allow me to rotate the empty GameObject instead the head since the root player object have Animator.
I thought also to try to use the IK solution but my player don’t have the HumanBodyBones.Head I tried this script but getting null on the chest so I returned to my original script trying to figure out how to clamp the head rotation :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyLookAt : MonoBehaviour
{
public Transform target;
public Vector3 offset;
public Animator anim;
Transform chest;
// Start is called before the first frame update
void Start()
{
chest = anim.GetBoneTransform(HumanBodyBones.Head);
}
// Update is called once per frame
void LateUpdate()
{
chest.LookAt(target.position);
chest.rotation = chest.rotation * Quaternion.Euler(offset);
}
}