using UnityEngine; public class AxisConstrainedLookAt : MonoBehaviour { public Transform target; public enum LocalAxis { X, Y, Z } public enum RotationAxis { X, Y, Z } [Header("Which local axis should point at the target?")] public LocalAxis lookAxis = LocalAxis.Z; [Header("Allow rotation only around this world axis")] public RotationAxis allowedRotationAxis = RotationAxis.Y; void Update() { if (target == null) return; Vector3 toTarget = target.position - transform.position; if (toTarget.sqrMagnitude < 0.0001f) return; // Project direction onto the allowed rotation plane Vector3 projectedDirection = ProjectDirection(toTarget.normalized, allowedRotationAxis); if (projectedDirection.sqrMagnitude < 0.0001f) return; // Get the desired rotation to look at the projected target direction Quaternion targetRotation = Quaternion.LookRotation(projectedDirection, Vector3.up); // Adjust rotation so the selected local axis is pointing in that direction Quaternion localAxisRotation = GetLocalAxisRotation(lookAxis); // Apply final rotation transform.rotation = targetRotation * Quaternion.Inverse(localAxisRotation); } private Vector3 ProjectDirection(Vector3 direction, RotationAxis axis) { switch (axis) { case RotationAxis.X: return Vector3.ProjectOnPlane(direction, Vector3.right); case RotationAxis.Y: return Vector3.ProjectOnPlane(direction, Vector3.up); case RotationAxis.Z: return Vector3.ProjectOnPlane(direction, Vector3.forward); default: return direction; } } private Quaternion GetLocalAxisRotation(LocalAxis axis) { switch (axis) { case LocalAxis.X: return Quaternion.LookRotation(Vector3.right, Vector3.up); case LocalAxis.Y: return Quaternion.LookRotation(Vector3.up, Vector3.forward); // alternative up case LocalAxis.Z: return Quaternion.LookRotation(Vector3.forward, Vector3.up); default: return Quaternion.identity; } } }