using UnityEngine; using FSA = UnityEngine.Serialization.FormerlySerializedAsAttribute; namespace Lean.Common { /// This component will constrain the current transform.position to the specified box shape. /// NOTE: Unlike LeanConstrainToCollider, this component doesn't use the physics system, so it can avoid certain issues if your constrain shape moves. [DefaultExecutionOrder(200)] [HelpURL(LeanHelper.PlusHelpUrlPrefix + "LeanConstrainToBox")] [AddComponentMenu(LeanHelper.ComponentPathPrefix + "Constrain To Box")] public class LeanConstrainToBox : MonoBehaviour { /// The transform the constraint will be applied relative to. /// None/null = World space. public Transform RelativeTo { set { relativeTo = value; } get { return relativeTo; } } [FSA("RelativeTo")] [SerializeField] private Transform relativeTo; /// The size of the box relative to the current space. public Vector3 Size { set { size = value; } get { return size; } } [FSA("Size")] [SerializeField] private Vector3 size = Vector3.one; /// The center of the box relative to the current space. public Vector3 Center { set { center = value; } get { return center; } } [FSA("Center")] [SerializeField] private Vector3 center; protected virtual void LateUpdate() { var matrix = relativeTo != null ? relativeTo.localToWorldMatrix : Matrix4x4.identity; var oldPosition = transform.position; var local = matrix.MultiplyPoint(oldPosition); var min = center - size * 0.5f; var max = center + size * 0.5f; var set = false; if (local.x < min.x) { local.x = min.x; set = true; } if (local.y < min.y) { local.y = min.y; set = true; } if (local.z < min.z) { local.z = min.z; set = true; } if (local.x > max.x) { local.x = max.x; set = true; } if (local.y > max.y) { local.y = max.y; set = true; } if (local.z > max.z) { local.z = max.z; set = true; } if (set == true) { var newPosition = matrix.inverse.MultiplyPoint(local); if (Mathf.Approximately(oldPosition.x, newPosition.x) == false || Mathf.Approximately(oldPosition.y, newPosition.y) == false || Mathf.Approximately(oldPosition.z, newPosition.z) == false) { transform.position = newPosition; } } } protected virtual void OnDrawGizmosSelected() { Gizmos.matrix = relativeTo != null ? relativeTo.localToWorldMatrix : Matrix4x4.identity; Gizmos.DrawWireCube(center, size); } } } #if UNITY_EDITOR namespace Lean.Common.Editor { using TARGET = LeanConstrainToBox; [UnityEditor.CanEditMultipleObjects] [UnityEditor.CustomEditor(typeof(TARGET))] public class LeanConstrainToBox_Editor : LeanEditor { protected override void OnInspector() { TARGET tgt; TARGET[] tgts; GetTargets(out tgt, out tgts); Draw("relativeTo", "The transform the constraint will be applied relative to.\n\nNone/null = World space."); Draw("size", "The size of the box relative to the current space."); Draw("center", "The center of the box relative to the current space."); } } } #endif