Files
2026-02-21 16:45:37 +08:00

755 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace CurvedUI
{
[AddComponentMenu("CurvedUI/CurvedUISettings")]
[RequireComponent(typeof(Canvas))]
public class CurvedUISettings : MonoBehaviour
{
public enum CurvedUIShape
{
CYLINDER = 0,
RING = 1,
SPHERE = 2,
CYLINDER_VERTICAL = 3
}
[SerializeField]
private CurvedUIShape shape;
[SerializeField]
private float quality = 1f;
[SerializeField]
private bool interactable = true;
[SerializeField]
private bool blocksRaycasts = true;
[SerializeField]
private bool raycastMyLayerOnly = true;
[SerializeField]
private bool forceUseBoxCollider;
[SerializeField]
private int angle = 90;
[SerializeField]
private bool preserveAspect = true;
[SerializeField]
private int vertAngle = 90;
[SerializeField]
private float ringFill = 0.5f;
[SerializeField]
private int ringExternalDiamater = 1000;
[SerializeField]
private bool ringFlipVertical;
private int baseCircleSegments = 16;
private Vector2 savedRectSize;
private float savedRadius;
private Canvas myCanvas;
private RectTransform m_rectTransform;
private RectTransform RectTransform
{
get
{
if (m_rectTransform == null)
{
m_rectTransform = base.transform as RectTransform;
}
return m_rectTransform;
}
}
public int BaseCircleSegments
{
get
{
return baseCircleSegments;
}
}
public int Angle
{
get
{
return angle;
}
set
{
if (angle != value)
{
SetUIAngle(value);
}
}
}
public float Quality
{
get
{
return quality;
}
set
{
if (quality != value)
{
quality = value;
SetUIAngle(angle);
}
}
}
public CurvedUIShape Shape
{
get
{
return shape;
}
set
{
if (shape != value)
{
shape = value;
SetUIAngle(angle);
}
}
}
public int VerticalAngle
{
get
{
return vertAngle;
}
set
{
if (vertAngle != value)
{
vertAngle = value;
SetUIAngle(angle);
}
}
}
public float RingFill
{
get
{
return ringFill;
}
set
{
if (ringFill != value)
{
ringFill = value;
SetUIAngle(angle);
}
}
}
public float SavedRadius
{
get
{
if (savedRadius == 0f)
{
savedRadius = GetCyllinderRadiusInCanvasSpace();
}
return savedRadius;
}
}
public int RingExternalDiameter
{
get
{
return ringExternalDiamater;
}
set
{
if (ringExternalDiamater != value)
{
ringExternalDiamater = value;
SetUIAngle(angle);
}
}
}
public bool RingFlipVertical
{
get
{
return ringFlipVertical;
}
set
{
if (ringFlipVertical != value)
{
ringFlipVertical = value;
SetUIAngle(angle);
}
}
}
public bool PreserveAspect
{
get
{
return preserveAspect;
}
set
{
if (preserveAspect != value)
{
preserveAspect = value;
SetUIAngle(angle);
}
}
}
public bool Interactable
{
get
{
return interactable;
}
set
{
interactable = value;
}
}
public bool ForceUseBoxCollider
{
get
{
return forceUseBoxCollider;
}
set
{
forceUseBoxCollider = value;
}
}
public bool BlocksRaycasts
{
get
{
return blocksRaycasts;
}
set
{
if (blocksRaycasts != value)
{
blocksRaycasts = value;
if (Application.isPlaying && GetComponent<CurvedUIRaycaster>() != null)
{
GetComponent<CurvedUIRaycaster>().RebuildCollider();
}
}
}
}
public bool RaycastMyLayerOnly
{
get
{
return raycastMyLayerOnly;
}
set
{
raycastMyLayerOnly = value;
}
}
public bool PointingAtCanvas
{
get
{
if (GetComponent<CurvedUIRaycaster>() != null)
{
return GetComponent<CurvedUIRaycaster>().PointingAtCanvas;
}
Debug.LogWarning("CURVEDUI: Can't check if user is pointing at this canvas - No CurvedUIRaycaster is added to this canvas.");
return false;
}
}
public CurvedUIInputModule.CUIControlMethod ControlMethod
{
get
{
return CurvedUIInputModule.ControlMethod;
}
set
{
CurvedUIInputModule.ControlMethod = value;
}
}
public bool GazeUseTimedClick
{
get
{
return CurvedUIInputModule.Instance.GazeUseTimedClick;
}
set
{
CurvedUIInputModule.Instance.GazeUseTimedClick = value;
}
}
public float GazeClickTimer
{
get
{
return CurvedUIInputModule.Instance.GazeClickTimer;
}
set
{
CurvedUIInputModule.Instance.GazeClickTimer = value;
}
}
public float GazeClickTimerDelay
{
get
{
return CurvedUIInputModule.Instance.GazeClickTimerDelay;
}
set
{
CurvedUIInputModule.Instance.GazeClickTimerDelay = value;
}
}
public float GazeTimerProgress
{
get
{
return CurvedUIInputModule.Instance.GazeTimerProgress;
}
}
private void Awake()
{
if (RaycastMyLayerOnly && base.gameObject.layer == 0)
{
base.gameObject.layer = 5;
}
savedRectSize = RectTransform.rect.size;
}
private void Start()
{
if (Application.isPlaying)
{
GraphicRaycaster component = GetComponent<GraphicRaycaster>();
if (component != null)
{
if (!(component is CurvedUIRaycaster))
{
UnityEngine.Object.Destroy(component);
base.gameObject.AddComponent<CurvedUIRaycaster>();
}
}
else
{
base.gameObject.AddComponent<CurvedUIRaycaster>();
}
}
if (myCanvas == null)
{
myCanvas = GetComponent<Canvas>();
}
savedRadius = GetCyllinderRadiusInCanvasSpace();
}
private void OnEnable()
{
Graphic[] componentsInChildren = GetComponentsInChildren<Graphic>();
foreach (Graphic graphic in componentsInChildren)
{
graphic.SetAllDirty();
}
}
private void OnDisable()
{
Graphic[] componentsInChildren = GetComponentsInChildren<Graphic>();
foreach (Graphic graphic in componentsInChildren)
{
graphic.SetAllDirty();
}
}
private void Update()
{
if (RectTransform.rect.size != savedRectSize)
{
savedRectSize = RectTransform.rect.size;
SetUIAngle(angle);
}
if (savedRectSize.x == 0f || savedRectSize.y == 0f)
{
Debug.LogError("CurvedUI: Your Canvas size must be bigger than 0!");
}
}
private void SetUIAngle(int newAngle)
{
if (myCanvas == null)
{
myCanvas = GetComponent<Canvas>();
}
if (newAngle == 0)
{
newAngle = 1;
}
angle = newAngle;
savedRadius = GetCyllinderRadiusInCanvasSpace();
CurvedUIVertexEffect[] componentsInChildren = GetComponentsInChildren<CurvedUIVertexEffect>();
foreach (CurvedUIVertexEffect curvedUIVertexEffect in componentsInChildren)
{
curvedUIVertexEffect.SetDirty();
}
Graphic[] componentsInChildren2 = GetComponentsInChildren<Graphic>();
foreach (Graphic graphic in componentsInChildren2)
{
graphic.SetAllDirty();
}
if (Application.isPlaying && GetComponent<CurvedUIRaycaster>() != null)
{
GetComponent<CurvedUIRaycaster>().RebuildCollider();
}
}
private Vector3 CanvasToCyllinder(Vector3 pos)
{
float f = pos.x / savedRectSize.x * (float)Angle * ((float)Math.PI / 180f);
pos.x = Mathf.Sin(f) * (SavedRadius + pos.z);
pos.z += Mathf.Cos(f) * (SavedRadius + pos.z) - (SavedRadius + pos.z);
return pos;
}
private Vector3 CanvasToCyllinderVertical(Vector3 pos)
{
float f = pos.y / savedRectSize.y * (float)Angle * ((float)Math.PI / 180f);
pos.y = Mathf.Sin(f) * (SavedRadius + pos.z);
pos.z += Mathf.Cos(f) * (SavedRadius + pos.z) - (SavedRadius + pos.z);
return pos;
}
private Vector3 CanvasToRing(Vector3 pos)
{
float num = pos.y.Remap(savedRectSize.y * 0.5f * (float)(RingFlipVertical ? 1 : (-1)), (0f - savedRectSize.y) * 0.5f * (float)(RingFlipVertical ? 1 : (-1)), (float)RingExternalDiameter * (1f - RingFill) * 0.5f, (float)RingExternalDiameter * 0.5f);
float f = (pos.x / savedRectSize.x).Remap(-0.5f, 0.5f, (float)Math.PI / 2f, (float)angle * ((float)Math.PI / 180f) + (float)Math.PI / 2f);
pos.x = num * Mathf.Cos(f);
pos.y = num * Mathf.Sin(f);
return pos;
}
private Vector3 CanvasToSphere(Vector3 pos)
{
float num = SavedRadius;
float num2 = VerticalAngle;
if (PreserveAspect)
{
num2 = (float)angle * (savedRectSize.y / savedRectSize.x);
num += ((Angle <= 0) ? pos.z : (0f - pos.z));
}
else
{
num = savedRectSize.x / 2f + pos.z;
if (num2 == 0f)
{
return Vector3.zero;
}
}
float num3 = (pos.x / savedRectSize.x).Remap(-0.5f, 0.5f, (float)(180 - angle) / 2f - 90f, 180f - (float)(180 - angle) / 2f - 90f);
num3 *= (float)Math.PI / 180f;
float num4 = (pos.y / savedRectSize.y).Remap(-0.5f, 0.5f, (180f - num2) / 2f, 180f - (180f - num2) / 2f);
num4 *= (float)Math.PI / 180f;
pos.z = Mathf.Sin(num4) * Mathf.Cos(num3) * num;
pos.y = (0f - num) * Mathf.Cos(num4);
pos.x = Mathf.Sin(num4) * Mathf.Sin(num3) * num;
if (PreserveAspect)
{
pos.z -= num;
}
return pos;
}
public void AddEffectToChildren()
{
Graphic[] componentsInChildren = GetComponentsInChildren<Graphic>(true);
foreach (Graphic graphic in componentsInChildren)
{
if (graphic.GetComponent<CurvedUIVertexEffect>() == null)
{
graphic.gameObject.AddComponent<CurvedUIVertexEffect>();
graphic.SetAllDirty();
}
}
InputField[] componentsInChildren2 = GetComponentsInChildren<InputField>(true);
foreach (InputField inputField in componentsInChildren2)
{
if (inputField.GetComponent<CurvedUIInputFieldCaret>() == null)
{
inputField.gameObject.AddComponent<CurvedUIInputFieldCaret>();
}
}
}
public Vector3 VertexPositionToCurvedCanvas(Vector3 pos)
{
switch (Shape)
{
case CurvedUIShape.CYLINDER:
return CanvasToCyllinder(pos);
case CurvedUIShape.CYLINDER_VERTICAL:
return CanvasToCyllinderVertical(pos);
case CurvedUIShape.RING:
return CanvasToRing(pos);
case CurvedUIShape.SPHERE:
return CanvasToSphere(pos);
default:
return Vector3.zero;
}
}
public Vector3 CanvasToCurvedCanvas(Vector3 pos)
{
pos = VertexPositionToCurvedCanvas(pos);
if (float.IsNaN(pos.x) || float.IsInfinity(pos.x))
{
return Vector3.zero;
}
return base.transform.localToWorldMatrix.MultiplyPoint3x4(pos);
}
public Vector3 CanvasToCurvedCanvasNormal(Vector3 pos)
{
pos = VertexPositionToCurvedCanvas(pos);
switch (Shape)
{
case CurvedUIShape.CYLINDER:
return base.transform.localToWorldMatrix.MultiplyVector((pos - new Vector3(0f, 0f, 0f - GetCyllinderRadiusInCanvasSpace())).ModifyY(0f)).normalized;
case CurvedUIShape.CYLINDER_VERTICAL:
return base.transform.localToWorldMatrix.MultiplyVector((pos - new Vector3(0f, 0f, 0f - GetCyllinderRadiusInCanvasSpace())).ModifyX(0f)).normalized;
case CurvedUIShape.RING:
return -base.transform.forward;
case CurvedUIShape.SPHERE:
{
Vector3 vector = ((!PreserveAspect) ? Vector3.zero : new Vector3(0f, 0f, 0f - GetCyllinderRadiusInCanvasSpace()));
return base.transform.localToWorldMatrix.MultiplyVector(pos - vector).normalized;
}
default:
return Vector3.zero;
}
}
public bool RaycastToCanvasSpace(Ray ray, out Vector2 o_positionOnCanvas)
{
CurvedUIRaycaster component = GetComponent<CurvedUIRaycaster>();
o_positionOnCanvas = Vector2.zero;
switch (Shape)
{
case CurvedUIShape.CYLINDER:
return component.RaycastToCyllinderCanvas(ray, out o_positionOnCanvas, true);
case CurvedUIShape.CYLINDER_VERTICAL:
return component.RaycastToCyllinderVerticalCanvas(ray, out o_positionOnCanvas, true);
case CurvedUIShape.RING:
return component.RaycastToRingCanvas(ray, out o_positionOnCanvas, true);
case CurvedUIShape.SPHERE:
return component.RaycastToSphereCanvas(ray, out o_positionOnCanvas, true);
default:
return false;
}
}
public float GetCyllinderRadiusInCanvasSpace()
{
float num = ((!PreserveAspect) ? (RectTransform.rect.size.x * 0.5f / Mathf.Sin(Mathf.Clamp(angle, -180f, 180f) * 0.5f * ((float)Math.PI / 180f))) : ((shape != CurvedUIShape.CYLINDER_VERTICAL) ? (RectTransform.rect.size.x / ((float)Math.PI * 2f * ((float)angle / 360f))) : (RectTransform.rect.size.y / ((float)Math.PI * 2f * ((float)angle / 360f)))));
return (angle != 0) ? num : 0f;
}
public Vector2 GetTesslationSize(bool modifiedByQuality = true)
{
Vector2 size = RectTransform.rect.size;
if (Angle != 0 || (!PreserveAspect && vertAngle != 0))
{
switch (shape)
{
case CurvedUIShape.CYLINDER:
case CurvedUIShape.RING:
case CurvedUIShape.CYLINDER_VERTICAL:
size /= GetSegmentsByAngle(angle);
break;
case CurvedUIShape.SPHERE:
size.x /= GetSegmentsByAngle(angle);
if (PreserveAspect)
{
size.y = size.x * RectTransform.rect.size.y / RectTransform.rect.size.x;
}
else
{
size.y /= GetSegmentsByAngle(VerticalAngle);
}
break;
}
}
return size / ((!modifiedByQuality) ? 1f : Mathf.Clamp(Quality, 0.01f, 10f));
}
private float GetSegmentsByAngle(float angle)
{
if (angle.Abs() <= 1f)
{
return 1f;
}
if (angle.Abs() < 90f)
{
return (float)baseCircleSegments * Mathf.Abs(angle).Remap(0f, 90f, 0.01f, 0.5f);
}
return (float)baseCircleSegments * Mathf.Abs(angle).Remap(90f, 360f, 0.5f, 1f);
}
public void SetAllChildrenDirty(bool recalculateCurveOnly = false)
{
CurvedUIVertexEffect[] componentsInChildren = GetComponentsInChildren<CurvedUIVertexEffect>();
foreach (CurvedUIVertexEffect curvedUIVertexEffect in componentsInChildren)
{
if (recalculateCurveOnly)
{
curvedUIVertexEffect.SetDirty();
}
else
{
curvedUIVertexEffect.CurvingRequired = true;
}
}
}
public void Click()
{
if (GetComponent<CurvedUIRaycaster>() != null)
{
GetComponent<CurvedUIRaycaster>().Click();
}
}
public List<GameObject> GetObjectsUnderPointer()
{
if (GetComponent<CurvedUIRaycaster>() != null)
{
return GetComponent<CurvedUIRaycaster>().GetObjectsUnderPointer();
}
return new List<GameObject>();
}
public List<GameObject> GetObjectsUnderScreenPos(Vector2 pos, Camera eventCamera = null)
{
if (eventCamera == null)
{
eventCamera = myCanvas.worldCamera;
}
if (GetComponent<CurvedUIRaycaster>() != null)
{
return GetComponent<CurvedUIRaycaster>().GetObjectsUnderScreenPos(pos, eventCamera);
}
return new List<GameObject>();
}
public List<GameObject> GetObjectsHitByRay(Ray ray)
{
if (GetComponent<CurvedUIRaycaster>() != null)
{
return GetComponent<CurvedUIRaycaster>().GetObjectsHitByRay(ray);
}
return new List<GameObject>();
}
public void ActivateCurvedUIComponents(bool activate)
{
List<CurvedUITMP> list = new List<CurvedUITMP>();
list.AddRange(GetComponentsInChildren<CurvedUITMP>(true));
for (int i = 0; i < list.Count; i++)
{
list[i].enabled = activate;
}
List<CurvedUITMPSubmesh> list2 = new List<CurvedUITMPSubmesh>();
list2.AddRange(GetComponentsInChildren<CurvedUITMPSubmesh>(true));
for (int j = 0; j < list2.Count; j++)
{
list2[j].enabled = activate;
}
List<CurvedUIVertexEffect> list3 = new List<CurvedUIVertexEffect>();
list3.AddRange(GetComponentsInChildren<CurvedUIVertexEffect>(true));
for (int k = 0; k < list3.Count; k++)
{
if (list3[k].GetComponent<Graphic>() != null)
{
list3[k].GetComponent<Graphic>().SetAllDirty();
}
list3[k].enabled = activate;
}
List<CurvedUIRaycaster> list4 = new List<CurvedUIRaycaster>();
list4.AddRange(GetComponents<CurvedUIRaycaster>());
for (int l = 0; l < list4.Count; l++)
{
list4[l].enabled = activate;
}
base.enabled = activate;
}
public void RemoveCurvedUIComponents()
{
List<CurvedUITMP> list = new List<CurvedUITMP>();
list.AddRange(GetComponentsInChildren<CurvedUITMP>(true));
for (int i = 0; i < list.Count; i++)
{
UnityEngine.Object.DestroyImmediate(list[i]);
}
List<CurvedUITMPSubmesh> list2 = new List<CurvedUITMPSubmesh>();
list2.AddRange(GetComponentsInChildren<CurvedUITMPSubmesh>(true));
for (int j = 0; j < list2.Count; j++)
{
UnityEngine.Object.DestroyImmediate(list2[j]);
}
List<CurvedUIVertexEffect> list3 = new List<CurvedUIVertexEffect>();
list3.AddRange(GetComponentsInChildren<CurvedUIVertexEffect>(true));
for (int k = 0; k < list3.Count; k++)
{
if (list3[k].GetComponent<Graphic>() != null)
{
list3[k].GetComponent<Graphic>().SetAllDirty();
}
UnityEngine.Object.DestroyImmediate(list3[k]);
}
List<CurvedUIRaycaster> list4 = new List<CurvedUIRaycaster>();
list4.AddRange(GetComponents<CurvedUIRaycaster>());
for (int l = 0; l < list4.Count; l++)
{
UnityEngine.Object.DestroyImmediate(list4[l]);
}
UnityEngine.Object.DestroyImmediate(this);
}
}
}