Files
WordConnect/Assets/WordConnectGameToolkit/Scripts/Gameplay/VirtualMouseUI.cs

214 lines
8.7 KiB
C#

// // ©2015 - 2025 Candy Smith
// // All rights reserved
// // Redistribution of this software is strictly not allowed.
// // Copy of this software can be obtained from unity asset store only.
// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// // FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// // THE SOFTWARE.
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.UI;
using UnityEngine.UI;
namespace WordsToolkit.Scripts.Gameplay
{
public class VirtualMouse : MonoBehaviour
{
private VirtualMouseInput virtualMouseInput;
private bool isInitialized = false;
[SerializeField]
private Canvas canvas;
private RectTransform canvasRectTransform;
private Camera uiCamera;
[SerializeField]
private float cursorHideDelay = 1.0f; // Time in seconds before hiding cursor
[SerializeField]
private float fadeSpeed = 3.0f; // How fast the cursor fades in/out
[SerializeField]
private float minCursorAlpha = 0f; // Minimum alpha when hidden
[SerializeField]
private float maxCursorAlpha = .5f; // Maximum alpha when visible
private float idleTimer = 0f;
private Vector2 lastPosition;
public Image cursorImage; // Reference to cursor image
private bool isCursorVisible = true;
private float targetAlpha;
private float currentAlpha;
private void Awake()
{
virtualMouseInput = GetComponent<VirtualMouseInput>();
if (virtualMouseInput == null)
{
Debug.LogError("VirtualMouseInput component not found! Please add it to the same GameObject.");
return;
}
canvasRectTransform = canvas.GetComponent<RectTransform>();
if (canvas.renderMode == RenderMode.ScreenSpaceCamera || canvas.renderMode == RenderMode.WorldSpace)
{
uiCamera = canvas.worldCamera;
}
targetAlpha = maxCursorAlpha;
currentAlpha = maxCursorAlpha;
}
private void Start()
{
StartCoroutine(WaitForVirtualMouseInitialization());
}
private IEnumerator WaitForVirtualMouseInitialization()
{
float timeout = 2.0f;
float timer = 0f;
while (timer < timeout)
{
if (virtualMouseInput != null && virtualMouseInput.virtualMouse != null)
{
lastPosition = virtualMouseInput.virtualMouse.position.value;
isInitialized = true;
Debug.Log("Virtual mouse initialized successfully.");
yield break;
}
timer += 0.1f;
yield return new WaitForSeconds(0.1f);
}
Debug.LogError("Failed to initialize virtualMouse within timeout period.");
}
private void Update()
{
if (!isInitialized || virtualMouseInput == null || virtualMouseInput.virtualMouse == null)
{
return; // Skip if not initialized
}
transform.SetAsLastSibling();
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay ||
canvas.renderMode == RenderMode.ScreenSpaceCamera)
{
transform.localScale = new Vector3(1f / canvas.scaleFactor, 1f / canvas.scaleFactor, 1f);
}
// Check if cursor moved - with null checks
try
{
Vector2 currentPosition = virtualMouseInput.virtualMouse.position.value;
if (Vector2.Distance(currentPosition, lastPosition) > 0.5f) // Small threshold to detect real movement
{
idleTimer = 0f;
targetAlpha = maxCursorAlpha; // Set target to maximum alpha rather than 1.0
lastPosition = currentPosition;
}
else
{
// No movement, increment timer
idleTimer += Time.deltaTime;
// Start fading cursor after delay
if (idleTimer >= cursorHideDelay)
{
targetAlpha = minCursorAlpha; // Set target to minimum alpha
}
}
// Smoothly fade the cursor
if (cursorImage != null)
{
// Gradually interpolate current alpha toward target alpha
currentAlpha = Mathf.Lerp(currentAlpha, targetAlpha, Time.deltaTime * fadeSpeed);
// Apply the alpha to the cursor image
Color cursorColor = cursorImage.color;
cursorColor.a = currentAlpha;
cursorImage.color = cursorColor;
}
}
catch (Exception e)
{
Debug.LogWarning("Error accessing virtual mouse position: " + e.Message);
}
}
private void LateUpdate()
{
if (!isInitialized || virtualMouseInput == null || virtualMouseInput.virtualMouse == null)
{
return; // Skip if not initialized
}
try
{
// Get the current virtual mouse position
var virtualMousePosition = virtualMouseInput.virtualMouse.position.value;
// Clamp to screen boundaries
virtualMousePosition.x = Mathf.Clamp(virtualMousePosition.x, 0, Screen.width);
virtualMousePosition.y = Mathf.Clamp(virtualMousePosition.y, 0, Screen.height);
if (canvas != null)
{
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay)
{
float scaleFactor = canvas.scaleFactor;
Rect canvasRect = canvasRectTransform.rect;
float canvasWidth = canvasRect.width * scaleFactor;
float canvasHeight = canvasRect.height * scaleFactor;
float xOffset = (Screen.width - canvasWidth) / 2;
float yOffset = (Screen.height - canvasHeight) / 2;
virtualMousePosition.x = Mathf.Clamp(virtualMousePosition.x, xOffset, xOffset + canvasWidth);
virtualMousePosition.y = Mathf.Clamp(virtualMousePosition.y, yOffset, yOffset + canvasHeight);
}
else if (canvas.renderMode == RenderMode.ScreenSpaceCamera && uiCamera != null)
{
Vector3[] corners = new Vector3[4];
canvasRectTransform.GetWorldCorners(corners);
Vector2 min = new Vector2(float.MaxValue, float.MaxValue);
Vector2 max = new Vector2(float.MinValue, float.MinValue);
for (int i = 0; i < 4; i++)
{
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, corners[i]);
min.x = Mathf.Min(min.x, screenPos.x);
min.y = Mathf.Min(min.y, screenPos.y);
max.x = Mathf.Max(max.x, screenPos.x);
max.y = Mathf.Max(max.y, screenPos.y);
}
virtualMousePosition.x = Mathf.Clamp(virtualMousePosition.x, min.x, max.x);
virtualMousePosition.y = Mathf.Clamp(virtualMousePosition.y, min.y, max.y);
}
}
InputState.Change(virtualMouseInput.virtualMouse.position, virtualMousePosition);
}
catch (Exception e)
{
Debug.LogWarning("Error in virtual mouse LateUpdate: " + e.Message);
}
}
}
}