using System; using UnityEngine; namespace VRC.SDK3.ClientSim { /// /// This system is responsible for displaying the Reticle in the center of the screen /// and for displaying the mouse UI pointer if there is a UI Shape under the mouse. /// /// /// Listens to Events: /// - ClientSimMouseReleasedEvent /// - ClientSimRaycastHitResultsEvent /// [AddComponentMenu("")] public class ClientSimReticle : ClientSimBehaviour, IDisposable { [SerializeField] private Texture2D reticle; [SerializeField] private Texture2D uiShapeHoverIcon; private IClientSimEventDispatcher _eventDispatcher; private ClientSimSettings _settings; private IClientSimMousePositionProvider _mousePositionProvider; private bool _mouseReleased = false; private int _lastUiShapeHoveredFrame = -1; public void Initialize( IClientSimEventDispatcher eventDispatcher, ClientSimSettings settings, IClientSimMousePositionProvider mousePositionProvider) { _settings = settings; _eventDispatcher = eventDispatcher; _mousePositionProvider = mousePositionProvider; _eventDispatcher.Subscribe(MouseReleasedEvent); _eventDispatcher.Subscribe(OnRaycastHit); } private void OnDestroy() { Dispose(); } public void Dispose() { _eventDispatcher?.Unsubscribe(MouseReleasedEvent); _eventDispatcher?.Unsubscribe(OnRaycastHit); } #region ClientSim Events private void MouseReleasedEvent(ClientSimMouseReleasedEvent mouseReleasedEvent) { _mouseReleased = mouseReleasedEvent.isReleased; } private void OnRaycastHit(ClientSimRaycastHitResultsEvent hitEvent) { if (hitEvent.raycastResults?.uiShape != null) { _lastUiShapeHoveredFrame = Time.frameCount; } } #endregion private bool ShouldShowReticle() { return _settings.showDesktopReticle && !_mouseReleased; } private bool ShouldShowUiShapeHoverIcon() { return _lastUiShapeHoveredFrame == Time.frameCount; } private void OnGUI() { if (ShouldShowReticle()) { Vector2 center = ClientSimBaseInput.GetScreenCenter(); Vector2 size = new Vector2(reticle.width, reticle.height); Rect position = new Rect(center - size * 0.5f, size); GUI.DrawTexture(position, reticle); } if (ShouldShowUiShapeHoverIcon()) { Vector2 mousePos = _mousePositionProvider.GetMousePosition(); // GUI draws with inverted y mousePos.y = Screen.height - mousePos.y; Vector2 size = new Vector2(uiShapeHoverIcon.width, uiShapeHoverIcon.height); Rect position = new Rect(mousePos - new Vector2(8, 8), size); GUI.DrawTexture(position, uiShapeHoverIcon); } } } }