Hello all. I’m trying to develop a Ranger Aiming System in my game, and I’m currently on the final step of trying to get the player to rotate, before he enters the Ranger Aiming State (my architecture follows the State Machine model, for context), to wherever the Cinemachine FreeLook camera is pointing at. The goal is to get the player to rotate in direction of wherever the Cinemachine FreeLook Camera is pointing at in my game scene, when we are about to access the Ranger Aiming State, but right now whilst it’s not random, it’s not working as expected at all, and I’m guessing it’s a mathematical issue…
I asked ChatGPT for a little bit of help, and whilst we got somewhat better results, I feel like sometimes it’s still random, so we developed 2 checks, one where the camera finds something by hitting a Raycast (where the player is expected to rotate to whatever the camera hit), and one where the camera can’t find anything 100 meters from where it started (in this case, the player points at wherever the camera’s forward is), but still… it’s a little random (again, it’s a Cinemachine FreeLook Camera)
Can someone kindly guide me through this problem? Here’s what I developed so far:
// TEST - Player Ranger Aiming State:
private void InputReader_HandleRangerAimingEvent()
{
if (stateMachine.Fighter.GetCurrentWeaponConfig().GetIsRangerAimWeapon())
{
RotatePlayerToCameraDirection();
stateMachine.SwitchState(new PlayerRangerAimingState(stateMachine));
}
}
// TEST - Rotating the Player before entering the Ranger Aiming Phase:
private void RotatePlayerToCameraDirection()
{
if (stateMachine.MainFreeLookCamera != null)
{
Vector3 rayOrigin = stateMachine.MainFreeLookCamera.transform.position;
Vector3 rayDirection = stateMachine.MainFreeLookCamera.transform.forward;
Ray ray = new Ray(rayOrigin, rayDirection);
if (Physics.Raycast(ray, out RaycastHit hit)) // if the camera fired a raycast that hit something, point the player to it
{
Vector3 targetDirection = (hit.point - stateMachine.transform.position).normalized; // (Player) --> (hit.point), literally
targetDirection.y = 0;
targetDirection = -targetDirection;
Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
targetRotation = NormalizeRotation(targetRotation);
stateMachine.transform.rotation = targetRotation;
Debug.Log($"Rotating player to match the Raycast Direction: {targetDirection}");
}
else // if the camera fired a raycast that hit nothing, set the player's rotation to match that of the camera
{
Vector3 fallbackDirection = stateMachine.MainFreeLookCamera.transform.forward; // direction of the camera, forward
fallbackDirection.y = 0;
fallbackDirection = -fallbackDirection;
Quaternion fallbackRotation = Quaternion.LookRotation(fallbackDirection, Vector3.up);
fallbackRotation = NormalizeRotation(fallbackRotation);
stateMachine.transform.rotation = fallbackRotation;
Debug.Log($"Rotating player to match the fallback camera direction: {fallbackDirection}");
}
}
else Debug.Log($"MainFreeLookCamera is not assigned in PlayerStateMachine");
}
private Quaternion NormalizeRotation(Quaternion rotation)
{
Vector3 euler = rotation.eulerAngles;
euler.x = NormalizeAngle(euler.x);
euler.y = NormalizeAngle(euler.y);
euler.z = NormalizeAngle(euler.z);
return Quaternion.Euler(euler);
}
private float NormalizeAngle(float angle)
{
if (angle > 180) angle -= 360;
if (angle < -180) angle += 360;
return angle;
}
I also introduced a Normalizer to deal with Unity’s Internal workings with Euler Angles, but that wasn’t enough. Please send help
(and yes, the logic can be wrong. I’m not sure at this point in time, to be honest)