using UnityEngine; namespace SC.XR.Unity.Module_Keyboard { public class KeyboardFollower : FollowerBase { [Header("Following Settings")] public bool LinearFollowing;//Whether is linear movement. public Vector2 border_x; //x-axis boundary public Vector2 border_y; //y-axis boundary private Transform _slamHead; Vector2 initViewPoint;//The midpoint of the camera frame, the coordinates are (0.5f, 0.5f). Vector3 viewPoint = Vector3.zero;// Panel coordinates are relative to the coordinates of the camera screen. private Vector3 velocity = Vector3.zero; bool isFollower = false; Vector3 originPos = Vector3.zero; Vector3 desPos = Vector3.zero; float journeyLength = 0f; Vector3 offsetPos; Quaternion offsetRotation; protected override void OnEnable() { base.OnEnable(); } private void Start() { InitTrans(); } protected override void LateUpdate() { if (StopFollower == false) { if (IsFollower()) { if (LinearFollowing) { LinearFollow(); } else { Follow(); } } } } void InitTrans() { if (!this.StopFollower && (Camera.main != null)) { _slamHead = Camera.main.transform; transform.position = CalculateWindowPosition(Camera.main.transform); transform.rotation = CalculateWindowRotation(Camera.main.transform); initViewPoint = Camera.main.WorldToViewportPoint(_slamHead.position + (_slamHead.forward * WindowDistance));//The coordinates of the midpoint of the camera screen. } } protected bool IsFollower() { if ( Camera.main == null) { return false; } viewPoint = Camera.main.WorldToViewportPoint(transform.position);// The coordinates of the panel on the camera screen. if (viewPoint.x > initViewPoint.x + border_x.x + CalculateWindowOffsetX() || viewPoint.x < initViewPoint.x + border_x.y + CalculateWindowOffsetX() || viewPoint.y < initViewPoint.y + border_y.y + CalculateWindowOffsetY() || viewPoint.y > initViewPoint.y + border_y.x + CalculateWindowOffsetY())// Boundary judgment { isFollower = true; } else if (Mathf.Abs(viewPoint.x - initViewPoint.x - CalculateWindowOffsetX()) < 0.05f && Mathf.Abs(viewPoint.y - initViewPoint.y - CalculateWindowOffsetY()) < 0.09f) { isFollower = false; } return isFollower; } //Nonlinear Following by default protected override void Follow() { transform.position = Vector3.Lerp(transform.position, CalculateWindowPosition(Camera.main.transform), WindowFollowSpeed * Time.deltaTime); //transform.position = Vector3.SmoothDamp(transform.position, CalculateWindowPosition(Camera.main.transform), ref velocity, WindowFollowSpeed); transform.rotation = Quaternion.Slerp(transform.rotation, CalculateWindowRotation(Camera.main.transform), WindowFollowSpeed * Time.deltaTime); } //For Linear Following, turn down the WindowFollowSpeed to around 0.5 at distance = 1 for best experience protected void LinearFollow() { originPos = transform.position; desPos = CalculateWindowPosition(Camera.main.transform); journeyLength = Vector3.Distance(originPos, desPos); transform.position = Vector3.Lerp(originPos, desPos, (Time.fixedDeltaTime) / journeyLength * WindowFollowSpeed); transform.rotation = Quaternion.Slerp(transform.rotation, CalculateWindowRotation(Camera.main.transform), (Time.fixedDeltaTime) / journeyLength * WindowFollowSpeed); } protected override Vector3 CalculateWindowPosition(Transform cameraTransform) { Vector3 position = cameraTransform.position + (Vector3.ProjectOnPlane(cameraTransform.forward, Vector3.up).normalized * WindowDistance); Vector3 horizontalOffset = cameraTransform.right * windowOffset.x; Vector3 verticalOffset = cameraTransform.up * windowOffset.y; switch (windowAnchor) { case TextAnchor.UpperLeft: position += verticalOffset - horizontalOffset; break; case TextAnchor.UpperCenter: position += verticalOffset; break; case TextAnchor.UpperRight: position += verticalOffset + horizontalOffset; break; case TextAnchor.MiddleLeft: position -= horizontalOffset; break; case TextAnchor.MiddleRight: position += horizontalOffset; break; case TextAnchor.MiddleCenter: position += horizontalOffset + verticalOffset; break; case TextAnchor.LowerLeft: position -= verticalOffset + horizontalOffset; break; case TextAnchor.LowerCenter: position -= verticalOffset; break; case TextAnchor.LowerRight: position -= verticalOffset - horizontalOffset; break; } return position; } protected override Quaternion CalculateWindowRotation(Transform cameraTransform) { Quaternion rotation = Quaternion.Euler(0, cameraTransform.rotation.eulerAngles.y, 0); switch (windowAnchor) { case TextAnchor.UpperLeft: rotation *= windowHorizontalRotationInverse * windowVerticalRotationInverse; break; case TextAnchor.UpperCenter: rotation *= windowHorizontalRotationInverse; break; case TextAnchor.UpperRight: rotation *= windowHorizontalRotationInverse * windowVerticalRotation; break; case TextAnchor.MiddleLeft: rotation *= windowVerticalRotationInverse; break; case TextAnchor.MiddleRight: rotation *= windowVerticalRotation; break; case TextAnchor.LowerLeft: rotation *= windowHorizontalRotation * windowVerticalRotationInverse; break; case TextAnchor.LowerCenter: rotation *= windowHorizontalRotation; break; case TextAnchor.LowerRight: rotation *= windowHorizontalRotation * windowVerticalRotation; break; } return rotation; } } }