边缘
This commit is contained in:
@@ -4,7 +4,6 @@ using AibisDream.Framework;
|
||||
using AibisDream.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace AibisDream.FixSystem
|
||||
{
|
||||
@@ -23,14 +22,15 @@ namespace AibisDream.FixSystem
|
||||
|
||||
private SpriteRenderer _targetSpriteRenderer; // 目标的 SpriteRenderer
|
||||
|
||||
private LineRenderer _dotLine;
|
||||
private LineRenderer _cutLine;
|
||||
private CutLine _cutLine;
|
||||
|
||||
#endregion
|
||||
|
||||
// 模块基本数据
|
||||
[SerializeField] public BodyModuleData data;
|
||||
public float clickRadius = 0.5f;
|
||||
private bool _available = true;
|
||||
private bool _cutting;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -49,6 +49,14 @@ namespace AibisDream.FixSystem
|
||||
_alarmMaterial = Resources.Load<Material>("Materials/AlarmMaterial");
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_cutting && Input.GetMouseButtonDown(0))
|
||||
{
|
||||
OnCut();
|
||||
}
|
||||
}
|
||||
|
||||
#region 插槽功能
|
||||
|
||||
public bool IsAvailable()
|
||||
@@ -104,35 +112,37 @@ namespace AibisDream.FixSystem
|
||||
|
||||
public void EnableCut()
|
||||
{
|
||||
// 显示虚线
|
||||
var dotLine = GetOrCreateDotLine();
|
||||
// 指针转为锯片
|
||||
// 打开或获取CutLine
|
||||
ShowCutLine();
|
||||
_cutting = true;
|
||||
}
|
||||
|
||||
private void OnCut()
|
||||
{
|
||||
//
|
||||
Vector2 mousePos = CommonUtil.GetMouseWorldPos(Input.mousePosition);
|
||||
_cutLine.DetectLineClick(mousePos, clickRadius);
|
||||
}
|
||||
|
||||
private LineRenderer GetOrCreateDotLine()
|
||||
private void ShowCutLine()
|
||||
{
|
||||
if (_dotLine != null)
|
||||
// 切割线不存在,就新建一个
|
||||
if (_cutLine == null)
|
||||
{
|
||||
return _dotLine;
|
||||
var prefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.CutLinePrefabName);
|
||||
var cutLineObj = Instantiate(prefab, transform);
|
||||
_cutLine = cutLineObj.GetComponent<CutLine>();
|
||||
}
|
||||
|
||||
var dotLine = new GameObject("Dot Line").AddComponent<LineRenderer>();
|
||||
// 设置Line的参数
|
||||
dotLine.sortingLayerName = ConstRef.FixMiddleLayer;
|
||||
dotLine.sortingOrder = 4;
|
||||
dotLine.materials = new[] { ResourceKit.LoadAssetSync<Material>(ConstRef.DotLineMaterialName) };
|
||||
dotLine.textureMode = LineTextureMode.Tile;
|
||||
dotLine.loop = true;
|
||||
|
||||
// 设置line的周长
|
||||
_targetSpriteRenderer.sprite.GetPhysicsShape(0, new List<Vector2>());
|
||||
// 对切割线进行初始化
|
||||
var shapePoints = new List<Vector2>();
|
||||
_targetSpriteRenderer.sprite.GetPhysicsShape(0, shapePoints);
|
||||
if (shapePoints.Count <= 0)
|
||||
{
|
||||
Debug.LogWarning($"{name} has no shape");
|
||||
return;
|
||||
}
|
||||
|
||||
return dotLine;
|
||||
_cutLine.Init(shapePoints, clickRadius);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class CutLine : MonoBehaviour
|
||||
{
|
||||
private LineRenderer _lineRenderer;
|
||||
|
||||
private Vector2[] _linePoints;
|
||||
private float[] _normalizedLinePoints;
|
||||
private Bounds _bounds;
|
||||
private List<Vector2> _recordedRanges = new();
|
||||
|
||||
#region 初始化
|
||||
|
||||
public void Init(List<Vector2> shapePoints, float clickRadius)
|
||||
{
|
||||
_lineRenderer = GetComponent<LineRenderer>();
|
||||
|
||||
// 按照新点位重绘线条
|
||||
RedrawLine(shapePoints);
|
||||
// 生成归一化点
|
||||
NormalizePoints(shapePoints);
|
||||
// 生成基本的包围盒
|
||||
GeneBoundingBox(clickRadius);
|
||||
|
||||
ClearRecordedRanges();
|
||||
}
|
||||
|
||||
private void RedrawLine(List<Vector2> shapePoints)
|
||||
{
|
||||
var linePoints = shapePoints.Select(item => new Vector3(item.x, item.y, 0)).ToArray();
|
||||
_lineRenderer.SetPositions(linePoints);
|
||||
}
|
||||
|
||||
private void NormalizePoints(List<Vector2> shapePoints)
|
||||
{
|
||||
// 先生成首尾相连的点,默认Loop
|
||||
shapePoints.Add(shapePoints[0]);
|
||||
_linePoints = shapePoints.ToArray();
|
||||
|
||||
float totalLength = 0f;
|
||||
var segmentLengths = new List<float>();
|
||||
|
||||
// 计算总长度和各段长度
|
||||
for (var i = 1; i < _linePoints.Length; i++)
|
||||
{
|
||||
var segmentLength = Vector2.Distance(_linePoints[i - 1], _linePoints[i]);
|
||||
segmentLengths.Add(segmentLength);
|
||||
totalLength += segmentLength;
|
||||
}
|
||||
|
||||
// 计算每个点的归一化位置
|
||||
var normalizedLinePoints = new float[segmentLengths.Count + 1];
|
||||
normalizedLinePoints[0] = 0f;
|
||||
var accumulatedLength = 0f;
|
||||
|
||||
for (var i = 0; i < segmentLengths.Count; i++)
|
||||
{
|
||||
accumulatedLength += segmentLengths[i];
|
||||
normalizedLinePoints[i + 1] = accumulatedLength / totalLength;
|
||||
}
|
||||
}
|
||||
|
||||
private void GeneBoundingBox(float clickRadius)
|
||||
{
|
||||
_bounds = new Bounds();
|
||||
foreach (var point in _linePoints)
|
||||
{
|
||||
_bounds.Encapsulate(point);
|
||||
}
|
||||
|
||||
_bounds.Expand(clickRadius * 2);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 切割检测
|
||||
|
||||
public void DetectLineClick(Vector2 clickPosition, float clickRadius)
|
||||
{
|
||||
// 先进行包围盒检测,不在包围盒直接返回
|
||||
if (!_bounds.Contains(clickPosition))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<Vector2> newRanges = new List<Vector2>();
|
||||
|
||||
// 检查每条线段
|
||||
for (int i = 1; i < _linePoints.Length; i++)
|
||||
{
|
||||
Vector2 start = _linePoints[i - 1];
|
||||
Vector2 end = _linePoints[i];
|
||||
|
||||
// 计算点到线段的距离
|
||||
float distance = DistanceToSegment(clickPosition, start, end);
|
||||
|
||||
if (distance <= clickRadius)
|
||||
{
|
||||
// 计算点击影响的范围
|
||||
float normalizedStart = _normalizedLinePoints[i - 1];
|
||||
float normalizedEnd = _normalizedLinePoints[i];
|
||||
|
||||
// 计算实际影响的范围(考虑点击半径)
|
||||
float segmentLength = Vector2.Distance(start, end);
|
||||
float radiusRatio = clickRadius / segmentLength;
|
||||
|
||||
float rangeStart = Mathf.Clamp01(normalizedStart - radiusRatio);
|
||||
float rangeEnd = Mathf.Clamp01(normalizedEnd + radiusRatio);
|
||||
|
||||
newRanges.Add(new Vector2(rangeStart, rangeEnd));
|
||||
}
|
||||
}
|
||||
|
||||
// 合并新检测到的区间
|
||||
foreach (Vector2 range in newRanges)
|
||||
{
|
||||
_recordedRanges.Add(range);
|
||||
}
|
||||
|
||||
// 合并所有重叠区间
|
||||
MergeRanges();
|
||||
|
||||
// 打印当前所有区间(调试用)
|
||||
Debug.Log("Current recorded ranges:");
|
||||
foreach (Vector2 range in _recordedRanges)
|
||||
{
|
||||
Debug.Log($"Range: {range.x} - {range.y}");
|
||||
}
|
||||
}
|
||||
|
||||
private float DistanceToSegment(Vector2 point, Vector2 segmentStart, Vector2 segmentEnd)
|
||||
{
|
||||
Vector2 segment = segmentEnd - segmentStart;
|
||||
Vector2 pointToStart = point - segmentStart;
|
||||
|
||||
float dotProduct = Vector2.Dot(pointToStart, segment);
|
||||
|
||||
// 检查点是否在线段的投影范围内
|
||||
if (dotProduct <= 0)
|
||||
{
|
||||
return Vector2.Distance(point, segmentStart);
|
||||
}
|
||||
|
||||
float segmentLengthSquared = segment.sqrMagnitude;
|
||||
if (dotProduct >= segmentLengthSquared)
|
||||
{
|
||||
return Vector2.Distance(point, segmentEnd);
|
||||
}
|
||||
|
||||
// 计算垂直距离
|
||||
return Mathf.Abs(segmentStart.y * segmentEnd.x - segmentStart.x * segmentEnd.y +
|
||||
point.x * (segmentStart.y - segmentEnd.y) +
|
||||
point.y * (segmentEnd.x - segmentStart.x)) /
|
||||
Mathf.Sqrt(segmentLengthSquared);
|
||||
}
|
||||
|
||||
private void MergeRanges()
|
||||
{
|
||||
if (_recordedRanges.Count <= 1) return;
|
||||
|
||||
// 先按起始位置排序
|
||||
_recordedRanges.Sort((a, b) => a.x.CompareTo(b.x));
|
||||
|
||||
List<Vector2> mergedRanges = new List<Vector2>();
|
||||
Vector2 currentRange = _recordedRanges[0];
|
||||
|
||||
for (int i = 1; i < _recordedRanges.Count; i++)
|
||||
{
|
||||
Vector2 nextRange = _recordedRanges[i];
|
||||
|
||||
// 检查是否有重叠或相邻
|
||||
if (nextRange.x <= currentRange.y)
|
||||
{
|
||||
// 合并区间
|
||||
currentRange.y = Mathf.Max(currentRange.y, nextRange.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
mergedRanges.Add(currentRange);
|
||||
currentRange = nextRange;
|
||||
}
|
||||
}
|
||||
|
||||
mergedRanges.Add(currentRange);
|
||||
_recordedRanges = mergedRanges;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// 获取当前所有记录的范围(0-1之间的值)
|
||||
public List<Vector2> GetRecordedRanges()
|
||||
{
|
||||
return new List<Vector2>(_recordedRanges);
|
||||
}
|
||||
|
||||
// 清除所有记录的范围
|
||||
public void ClearRecordedRanges()
|
||||
{
|
||||
_recordedRanges.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5842a5c9314449c8a972472b796da927
|
||||
timeCreated: 1745912339
|
||||
Reference in New Issue
Block a user