Files
back_cantanBuilding/Assets/Scripts/UI/ScratchTicket/EditablePolygon.cs
2026-05-26 16:15:54 +08:00

237 lines
7.7 KiB
C#

using GameCore;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace game
{
[RequireComponent(typeof(PolygonCollider2D))]
[RequireComponent(typeof(Image))]
public class EditablePolygon : MonoBehaviour
{
public Color polygonColor = new Color(0.5f, 0.5f, 1f, 0.5f);
public Vector2[] points = new Vector2[]
{
new Vector2(0, 0),
new Vector2(100, 50),
new Vector2(50, 100),
new Vector2(-50, 50)
};
private PolygonCollider2D polygonCollider;
private Image image;
void OnValidate()
{
UpdatePolygon();
}
void Awake()
{
UpdatePolygon();
}
public void UpdatePolygon()
{
if (polygonCollider == null) polygonCollider = GetComponent<PolygonCollider2D>();
if (image == null) image = GetComponent<Image>();
polygonCollider.points = points;
image.color = polygonColor;
}
public bool IsDown()
{
if (EventSystem.current == null)
{
return true;
}
PointerEventData pointerEventData = new PointerEventData(EventSystem.current)
{
position = Input.mousePosition
};
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerEventData, results);
if (results.Count > 0 && results[0].gameObject == gameObject)
{
return true;
}
return false;
}
public bool ContainsPoint(Vector2 position)
{
if (!IsDown())
{
return false;
}
RectTransformUtility.ScreenPointToLocalPointInRectangle(
transform as RectTransform,
position,
UIManager.Instance.UICanvas.worldCamera,
out Vector2 localPoint);
//bool flag = polygonCollider.OverlapPoint(localPoint);
//if (IsPointInPolygon(localPoint, polygonCollider.points))
//{
// Debug.LogError("点在多边形内");
//}
//else
//{
// Debug.LogError("点不在多边形内");
//}
return IsPointInPolygon(localPoint, points);
}
bool IsPointInPolygon(Vector2 point, Vector2[] polygon)
{
int polygonLength = polygon.Length;
bool inside = false;
// 从点向右发射水平射线
for (int i = 0, j = polygonLength - 1; i < polygonLength; j = i++)
{
Vector2 pi = polygon[i];
Vector2 pj = polygon[j];
// 检查点是否在顶点上
if (Mathf.Approximately(point.x, pi.x) && Mathf.Approximately(point.y, pi.y))
return true;
// 检查边是否与射线相交
if (((pi.y > point.y) != (pj.y > point.y)) &&
(point.x < (pj.x - pi.x) * (point.y - pi.y) / (pj.y - pi.y) + pi.x))
{
inside = !inside;
}
}
return inside;
}
}
}
#if UNITY_EDITOR
namespace game
{
using UnityEditor;
[CustomEditor(typeof(EditablePolygon))]
public class EditablePolygonEditor : Editor
{
private EditablePolygon polygon;
private SerializedProperty pointsProperty;
private SerializedProperty colorProperty;
private const float handleSize = 10f;
private int selectedIndex = -1;
void OnEnable()
{
polygon = (EditablePolygon)target;
pointsProperty = serializedObject.FindProperty("points");
colorProperty = serializedObject.FindProperty("polygonColor");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(colorProperty);
EditorGUILayout.LabelField("多边形顶点", EditorStyles.boldLabel);
for (int i = 0; i < pointsProperty.arraySize; i++)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(pointsProperty.GetArrayElementAtIndex(i),
new GUIContent("顶点 " + i));
if (GUILayout.Button("删除", GUILayout.Width(50)))
{
pointsProperty.DeleteArrayElementAtIndex(i);
serializedObject.ApplyModifiedProperties();
polygon.UpdatePolygon();
return;
}
EditorGUILayout.EndHorizontal();
}
if (GUILayout.Button("添加顶点"))
{
pointsProperty.arraySize++;
serializedObject.ApplyModifiedProperties();
polygon.UpdatePolygon();
}
serializedObject.ApplyModifiedProperties();
}
void OnSceneGUI()
{
RectTransform rectTransform = polygon.GetComponent<RectTransform>();
for (int i = 0; i < polygon.points.Length; i++)
{
Vector2 point = polygon.points[i];
Vector3 worldPoint = rectTransform.TransformPoint(point);
Handles.color = i == selectedIndex ? Color.red : Color.green;
// 绘制可拖拽的handle
EditorGUI.BeginChangeCheck();
var fmh_147_21_638823244657839550 = Quaternion.identity; Vector3 newWorldPoint = Handles.FreeMoveHandle(
worldPoint,
handleSize,
Vector3.zero,
Handles.CircleHandleCap);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(polygon, "Move Polygon Point");
polygon.points[i] = rectTransform.InverseTransformPoint(newWorldPoint);
polygon.UpdatePolygon();
}
// 检查点击选择
if (Event.current.type == EventType.MouseDown &&
Event.current.button == 0 &&
Vector2.Distance(HandleUtility.WorldToGUIPoint(worldPoint),
Event.current.mousePosition) < handleSize)
{
selectedIndex = i;
Event.current.Use();
}
}
// 绘制多边形线框
Handles.color = polygon.polygonColor;
Vector3[] worldPoints = new Vector3[polygon.points.Length + 1];
for (int i = 0; i < polygon.points.Length; i++)
{
worldPoints[i] = rectTransform.TransformPoint(polygon.points[i]);
}
worldPoints[worldPoints.Length - 1] = worldPoints[0];
Handles.DrawPolyLine(worldPoints);
// 删除选中的顶点
if (selectedIndex != -1 && Event.current.type == EventType.KeyDown &&
Event.current.keyCode == KeyCode.Delete)
{
Undo.RecordObject(polygon, "Delete Polygon Point");
var newPoints = new Vector2[polygon.points.Length - 1];
for (int i = 0, j = 0; i < polygon.points.Length; i++)
{
if (i != selectedIndex) newPoints[j++] = polygon.points[i];
}
polygon.points = newPoints;
selectedIndex = -1;
polygon.UpdatePolygon();
Event.current.Use();
}
}
}
}
#endif