using UnityEngine; using UnityEngine.Assertions; namespace Rokid.UXR.Interaction { public class CylinderProximityField : MonoBehaviour, IProximityField, ICurvedPlane { [SerializeField] private Cylinder _cylinder; [SerializeField] private float _rotation = 0f; [SerializeField, Range(0f, 360f)] private float _arcDegrees = 360; [SerializeField] private float _bottom = -1f; [SerializeField] private float _top = 1f; /// /// 提供一个ICurvePlane复写本地的属性 /// [Tooltip("Providing an ICurvedPlane here will " + "override all other local properties")] [SerializeField, Optional, Interface(typeof(ICurvedPlane))] private MonoBehaviour _curvedPlane; private ICurvedPlane CurvedPlane; public Cylinder Cylinder => _cylinder; public float ArcDegrees { get => _arcDegrees; set => _arcDegrees = value; } public float Rotation { get => _rotation; set => _rotation = value; } public float Bottom { get => _bottom; set => _bottom = value; } public float Top { get => _top; set => _top = value; } protected virtual void Awake() { CurvedPlane = _curvedPlane != null ? _curvedPlane as ICurvedPlane : this; } protected virtual void Start() { Assert.IsNotNull(CurvedPlane); Assert.IsNotNull(CurvedPlane.Cylinder); } public Vector3 ComputeClosestPoint(Vector3 point) { return ComputeClosestPoint(CurvedPlane, point); } /// /// 最近点的计算 /// /// /// /// private static Vector3 ComputeClosestPoint(ICurvedPlane curvedPlane, Vector3 point) { RKLog.Debug($"CylinderProximityField ComputeClosestPoint"); Vector3 localPoint = curvedPlane.Cylinder.transform.InverseTransformPoint(point); if (curvedPlane.Top > curvedPlane.Bottom) { localPoint.y = Mathf.Clamp(localPoint.y, curvedPlane.Bottom, curvedPlane.Top); } if (curvedPlane.ArcDegrees < 360) { float angle = Mathf.Atan2(localPoint.x, localPoint.z) * Mathf.Rad2Deg % 360; float rotation = curvedPlane.Rotation % 360; if (angle > rotation + 180) { angle -= 360; } else if (angle < rotation - 180) { angle += 360; } angle = Mathf.Clamp(angle, rotation - curvedPlane.ArcDegrees / 2f, rotation + curvedPlane.ArcDegrees / 2f); localPoint.x = Mathf.Sin(angle * Mathf.Deg2Rad) * curvedPlane.Cylinder.Radius; localPoint.z = Mathf.Cos(angle * Mathf.Deg2Rad) * curvedPlane.Cylinder.Radius; } else { Vector3 nearestPointOnCenterAxis = new Vector3(0f, localPoint.y, 0f); float distanceFromCenterAxis = Vector3.Distance(localPoint, nearestPointOnCenterAxis); localPoint = Vector3.MoveTowards(localPoint, nearestPointOnCenterAxis, distanceFromCenterAxis - curvedPlane.Cylinder.Radius); } return curvedPlane.Cylinder.transform.TransformPoint(localPoint); } } }