198 lines
4.9 KiB
C#
198 lines
4.9 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace BlockSpace.Voxels
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public sealed class BrowserButton : MonoBehaviour
|
|
{
|
|
private const float ButtonPressCooldown = 0.2f;
|
|
|
|
private const float ButtonShrinkDuration = 0.08f;
|
|
|
|
private const float ButtonSettleDuration = 0.12f;
|
|
|
|
private const float ButtonPressedScale = 0.84f;
|
|
|
|
private const float ButtonOvershootScale = 1.04f;
|
|
|
|
private const string ButtonThockResourcePath = "Thock";
|
|
|
|
[Header("Button")]
|
|
[SerializeField]
|
|
private Collider buttonCollider;
|
|
|
|
[SerializeField]
|
|
private VRVoxelBrush voxelBrush;
|
|
|
|
[Header("Browser Login")]
|
|
[SerializeField]
|
|
private string loginUrl = "https://example.com/login";
|
|
|
|
[Header("Audio")]
|
|
[SerializeField]
|
|
private AudioClip buttonThockClip;
|
|
|
|
private readonly Dictionary<Transform, Vector3> buttonBaseScales = new Dictionary<Transform, Vector3>();
|
|
|
|
private readonly Dictionary<Transform, Coroutine> buttonAnimationCoroutines = new Dictionary<Transform, Coroutine>();
|
|
|
|
private bool insidePrevious;
|
|
|
|
private float nextButtonPressTime;
|
|
|
|
private void Awake()
|
|
{
|
|
ResolveReferences();
|
|
EnsureButtonAudioAssigned();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
StopAllCoroutines();
|
|
ResetAllButtonScales();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
ResolveReferences();
|
|
HandleButton();
|
|
}
|
|
|
|
private void ResolveReferences()
|
|
{
|
|
if (buttonCollider == null)
|
|
{
|
|
buttonCollider = GetComponent<Collider>();
|
|
}
|
|
if (voxelBrush == null)
|
|
{
|
|
voxelBrush = ((VRVoxelBrush.Instance != null) ? VRVoxelBrush.Instance : Object.FindObjectOfType<VRVoxelBrush>());
|
|
}
|
|
}
|
|
|
|
private void HandleButton()
|
|
{
|
|
bool flag = IsHandInside(buttonCollider, (voxelBrush != null) ? voxelBrush.LeftHandAnchor : null) || IsHandInside(buttonCollider, (voxelBrush != null) ? voxelBrush.RightHandAnchor : null);
|
|
if (flag && !insidePrevious)
|
|
{
|
|
PlayButtonEnterAnimation(buttonCollider);
|
|
if (Time.unscaledTime >= nextButtonPressTime)
|
|
{
|
|
nextButtonPressTime = Time.unscaledTime + 0.2f;
|
|
PlayButtonClickFeedback(buttonCollider);
|
|
OpenLoginUrl();
|
|
}
|
|
}
|
|
insidePrevious = flag;
|
|
}
|
|
|
|
private void OpenLoginUrl()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(loginUrl))
|
|
{
|
|
Debug.LogWarning("[BrowserLoginButton] Login URL is empty.");
|
|
}
|
|
else
|
|
{
|
|
Application.OpenURL(loginUrl);
|
|
}
|
|
}
|
|
|
|
private void PlayButtonEnterAnimation(Collider button)
|
|
{
|
|
if (!(button == null))
|
|
{
|
|
Transform transform = button.transform;
|
|
if (!buttonBaseScales.TryGetValue(transform, out var value))
|
|
{
|
|
value = transform.localScale;
|
|
buttonBaseScales.Add(transform, value);
|
|
}
|
|
if (buttonAnimationCoroutines.TryGetValue(transform, out var value2) && value2 != null)
|
|
{
|
|
StopCoroutine(value2);
|
|
}
|
|
transform.localScale = value;
|
|
buttonAnimationCoroutines[transform] = StartCoroutine(AnimateButtonScale(transform, value));
|
|
}
|
|
}
|
|
|
|
private void PlayButtonClickFeedback(Collider button)
|
|
{
|
|
if (!(buttonThockClip == null) && !(button == null))
|
|
{
|
|
AudioSource.PlayClipAtPoint(buttonThockClip, button.bounds.center, 1f);
|
|
}
|
|
}
|
|
|
|
private IEnumerator AnimateButtonScale(Transform buttonTransform, Vector3 baseScale)
|
|
{
|
|
Vector3 pressedScale = baseScale * 0.84f;
|
|
Vector3 overshootScale = baseScale * 1.04f;
|
|
float elapsed = 0f;
|
|
while (elapsed < 0.08f)
|
|
{
|
|
if (buttonTransform == null)
|
|
{
|
|
yield break;
|
|
}
|
|
elapsed += Time.unscaledDeltaTime;
|
|
float t = Mathf.Clamp01(elapsed / 0.08f);
|
|
buttonTransform.localScale = Vector3.LerpUnclamped(baseScale, pressedScale, t);
|
|
yield return null;
|
|
}
|
|
elapsed = 0f;
|
|
while (elapsed < 0.12f)
|
|
{
|
|
if (buttonTransform == null)
|
|
{
|
|
yield break;
|
|
}
|
|
elapsed += Time.unscaledDeltaTime;
|
|
float num = Mathf.Clamp01(elapsed / 0.12f);
|
|
float num2 = num * num * (3f - 2f * num);
|
|
Vector3 localScale = ((num2 < 0.5f) ? Vector3.LerpUnclamped(pressedScale, overshootScale, num2 / 0.5f) : Vector3.LerpUnclamped(overshootScale, baseScale, (num2 - 0.5f) / 0.5f));
|
|
buttonTransform.localScale = localScale;
|
|
yield return null;
|
|
}
|
|
if (buttonTransform != null)
|
|
{
|
|
buttonTransform.localScale = baseScale;
|
|
buttonAnimationCoroutines[buttonTransform] = null;
|
|
}
|
|
}
|
|
|
|
private void ResetAllButtonScales()
|
|
{
|
|
foreach (KeyValuePair<Transform, Vector3> buttonBaseScale in buttonBaseScales)
|
|
{
|
|
if (buttonBaseScale.Key != null)
|
|
{
|
|
buttonBaseScale.Key.localScale = buttonBaseScale.Value;
|
|
}
|
|
}
|
|
buttonAnimationCoroutines.Clear();
|
|
}
|
|
|
|
private void EnsureButtonAudioAssigned()
|
|
{
|
|
if (buttonThockClip == null)
|
|
{
|
|
buttonThockClip = Resources.Load<AudioClip>("Thock");
|
|
}
|
|
}
|
|
|
|
private static bool IsHandInside(Collider button, Transform handAnchor)
|
|
{
|
|
if (button == null || handAnchor == null)
|
|
{
|
|
return false;
|
|
}
|
|
Vector3 position = handAnchor.position;
|
|
return (button.ClosestPoint(position) - position).sqrMagnitude <= 1E-06f;
|
|
}
|
|
}
|
|
}
|