237 lines
7.7 KiB
C#
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
|