diff --git a/Assets/Scripts/FixSystemNew/BodyModule/GearFollower.cs b/Assets/Scripts/FixSystemNew/BodyModule/GearFollower.cs index 9395e45bd..97b2d6cd8 100644 --- a/Assets/Scripts/FixSystemNew/BodyModule/GearFollower.cs +++ b/Assets/Scripts/FixSystemNew/BodyModule/GearFollower.cs @@ -2,69 +2,26 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -[RequireComponent(typeof(LineRenderer))] -public class GearFollowerWithVisualCut : MonoBehaviour +public class GearFollower : MonoBehaviour { [Header("参数")] - public SpriteRenderer targetSpriteRenderer; - public float snapDistance = 0.3f; - public float detachDistance = 1.0f; - public float tractionSpeed = 2f; - public float rotationSpeed = 360f; - public float edgeScaleFactor = 1.1f; + public SpriteRenderer targetSpriteRenderer; // 目标图片 + public float snapDistance = 0.3f; // 距离边缘多少时吸附 + public float detachDistance = 1.0f; // 超过多少距离脱离牵引 + public float tractionSpeed = 2f; // 牵引时沿边缘移动速度 - public Color normalEdgeColor = Color.white; - public Color cutEdgeColor = Color.yellow; + private List edgePoints; // 边缘路径点 + private int currentEdgeIndex = 0; // 当前吸附边缘点索引 - private List edgePoints; - private int currentEdgeIndex = 0; - private SpriteRenderer gearSpriteRenderer; - private Camera mainCamera; - - private enum State { Follow, Attract, Traction } + private enum State { Follow, Traction } private State currentState = State.Follow; - private bool[] cutSegments; - - private LineRenderer edgeLineRenderer; // 绘制全部边缘 - private LineRenderer cutLineRenderer; // 绘制切割线段 + private Camera mainCamera; void Start() { mainCamera = Camera.main; - gearSpriteRenderer = GetComponent(); LoadEdgePointsFromSprite(); - - cutSegments = new bool[edgePoints.Count - 1]; - - // 设置主边缘线条渲染器 - edgeLineRenderer = GetComponent(); - edgeLineRenderer.positionCount = edgePoints.Count; - edgeLineRenderer.loop = false; - edgeLineRenderer.startWidth = 0.05f; - edgeLineRenderer.endWidth = 0.05f; - edgeLineRenderer.material = new Material(Shader.Find("Sprites/Default")); - edgeLineRenderer.startColor = normalEdgeColor; - edgeLineRenderer.endColor = normalEdgeColor; - edgeLineRenderer.sortingOrder = 3; - - for (int i = 0; i < edgePoints.Count; i++) - { - edgeLineRenderer.SetPosition(i, edgePoints[i]); - } - - // 创建用于切割线段的LineRenderer - GameObject cutLineObj = new GameObject("CutLineRenderer"); - cutLineObj.transform.parent = this.transform; - cutLineRenderer = cutLineObj.AddComponent(); - cutLineRenderer.positionCount = 0; - cutLineRenderer.loop = false; - cutLineRenderer.startWidth = 0.07f; - cutLineRenderer.endWidth = 0.07f; - cutLineRenderer.material = new Material(Shader.Find("Sprites/Default")); - cutLineRenderer.startColor = cutEdgeColor; - cutLineRenderer.endColor = cutEdgeColor; - cutLineRenderer.sortingOrder = 4; } void Update() @@ -76,36 +33,13 @@ public class GearFollowerWithVisualCut : MonoBehaviour case State.Follow: UpdateFollowState(mouseWorldPos); break; - case State.Attract: - UpdateAttractState(mouseWorldPos); - break; case State.Traction: UpdateTractionState(mouseWorldPos); break; } - - UpdateGearRotation(); - UpdateVisualFeedback(); - UpdateCutLineRenderer(); - CheckAllSegmentsCut(); - } - - private void UpdateGearRotation() - { - if (currentState == State.Traction && Input.GetMouseButton(0)) - { - transform.Rotate(0, 0, rotationSpeed * Time.deltaTime); - } - } - - private void UpdateVisualFeedback() - { - if (gearSpriteRenderer != null) - { - gearSpriteRenderer.color = (currentState == State.Traction || currentState == State.Attract) ? cutEdgeColor : normalEdgeColor; - } } + // 从Sprite的PhysicsShape获取边缘点,构成闭环路径 private void LoadEdgePointsFromSprite() { edgePoints = new List(); @@ -124,138 +58,96 @@ public class GearFollowerWithVisualCut : MonoBehaviour return; } - Vector2 center = Vector2.zero; - foreach (Vector2 point in shapePoints) - { - center += point; - } - center /= shapePoints.Count; - + // 转换为世界坐标 edgePoints = shapePoints - .Select(p => - { - Vector2 dirFromCenter = p - center; - Vector2 scaledPoint = center + dirFromCenter * edgeScaleFactor; - return (Vector2)targetSpriteRenderer.transform.TransformPoint(scaledPoint); - }) + .Select(p => (Vector2)targetSpriteRenderer.transform.TransformPoint(p)) .ToList(); + // 假设形状是闭合的,确保首尾连通 if (edgePoints[0] != edgePoints[edgePoints.Count - 1]) { edgePoints.Add(edgePoints[0]); } } + // 跟随模式逻辑 private void UpdateFollowState(Vector2 mousePos) { transform.position = mousePos; + // 检测距离最近边缘点是否在snapDistance内,进入牵引 int nearestIndex = FindNearestEdgePointIndex(mousePos, out float dist); if (dist < snapDistance) { currentEdgeIndex = nearestIndex; - currentState = State.Attract; - if (gearSpriteRenderer != null) - gearSpriteRenderer.sortingOrder = 1; - } - } - - private void UpdateAttractState(Vector2 mousePos) - { - Vector2 closestPoint = Vector2.zero; - float closestDist = float.MaxValue; - int closestSegmentStartIndex = 0; - - for (int i = 0; i < edgePoints.Count - 1; i++) - { - Vector2 a = edgePoints[i]; - Vector2 b = edgePoints[i + 1]; - Vector2 projected = ProjectPointOnSegment(mousePos, a, b); - float dist = Vector2.Distance(mousePos, projected); - - if (dist < closestDist) - { - closestDist = dist; - closestPoint = projected; - closestSegmentStartIndex = i; - } - } - - transform.position = closestPoint; - currentEdgeIndex = closestSegmentStartIndex; - - if (Vector2.Distance(mousePos, closestPoint) > detachDistance) - { - currentState = State.Follow; - if (gearSpriteRenderer != null) - gearSpriteRenderer.sortingOrder = 5; - return; - } - - if (Input.GetMouseButton(0)) - { currentState = State.Traction; + + // 吸附齿轮到边缘点位置 + transform.position = edgePoints[currentEdgeIndex]; } } + // 牵引模式逻辑 private void UpdateTractionState(Vector2 mousePos) { - if (Vector2.Distance(mousePos, transform.position) > detachDistance) + Vector2 gearPos = (Vector2)transform.position; + + // 计算鼠标和齿轮距离,超过detachDistance则脱离牵引 + if (Vector2.Distance(mousePos, gearPos) > detachDistance) { currentState = State.Follow; - if (gearSpriteRenderer != null) - gearSpriteRenderer.sortingOrder = 5; return; } - if (Input.GetMouseButton(0)) + // 判断是否按住左键 + if (!Input.GetMouseButton(0)) { - MoveAlongEdge(mousePos); + // 未按键,齿轮固定在边缘点 + transform.position = edgePoints[currentEdgeIndex]; + } + else + { + // 按住左键,齿轮沿边缘点链移动 + + // 找到当前边缘点前后点索引,注意闭环处理 + int prevIndex = (currentEdgeIndex - 1 + edgePoints.Count) % edgePoints.Count; + int nextIndex = (currentEdgeIndex + 1) % edgePoints.Count; + + Vector2 prevPoint = edgePoints[prevIndex]; + Vector2 currPoint = edgePoints[currentEdgeIndex]; + Vector2 nextPoint = edgePoints[nextIndex]; + + // 计算向前和向后移动方向 + Vector2 dirToPrev = (prevPoint - currPoint).normalized; + Vector2 dirToNext = (nextPoint - currPoint).normalized; + + // 预测如果沿前后方向移动一个小步长后到鼠标的距离 + float stepDistance = tractionSpeed * Time.deltaTime; + + Vector2 posIfMovePrev = currPoint + dirToPrev * stepDistance; + Vector2 posIfMoveNext = currPoint + dirToNext * stepDistance; + + float distPrev = Vector2.Distance(posIfMovePrev, mousePos); + float distNext = Vector2.Distance(posIfMoveNext, mousePos); + + // 选择距离鼠标更近的方向前进 + if (distPrev < distNext) + { + // 向前移动 + currentEdgeIndex = prevIndex; + transform.position = prevPoint; + } + else + { + // 向后移动 + currentEdgeIndex = nextIndex; + transform.position = nextPoint; + } } } - private void MoveAlongEdge(Vector2 mousePos) -{ - // 当前段的两个点 - Vector2 a = edgePoints[currentEdgeIndex]; - Vector2 b = edgePoints[currentEdgeIndex + 1]; - - // 投影鼠标位置到当前段 - Vector2 projected = ProjectPointOnSegment(mousePos, a, b); - - // 鼠标离齿轮足够远才移动(模拟牵引力) - float tractionThreshold = 0.1f; - float distToMouse = Vector2.Distance(transform.position, mousePos); - if (distToMouse < tractionThreshold) - return; - - // 移动齿轮朝向投影点 - transform.position = Vector2.MoveTowards(transform.position, projected, tractionSpeed * Time.deltaTime); - - // 标记切割 - if (!cutSegments[currentEdgeIndex]) - { - cutSegments[currentEdgeIndex] = true; - Debug.Log($"切割线段 {currentEdgeIndex} ({a}->{b})"); - } - - // 判断是否前进或后退段 - float switchThreshold = 0.05f; - - // 往前走(靠近 b 点且还有下一段) - if (Vector2.Distance(projected, b) < switchThreshold && currentEdgeIndex < edgePoints.Count - 2) - { - currentEdgeIndex++; - } - // 往后退(靠近 a 点且还有上一段) - else if (Vector2.Distance(projected, a) < switchThreshold && currentEdgeIndex > 0) - { - currentEdgeIndex--; - } -} - - + // 找到距离pos最近的边缘点索引和距离 private int FindNearestEdgePointIndex(Vector2 pos, out float minDist) { int nearestIndex = 0; @@ -272,51 +164,4 @@ public class GearFollowerWithVisualCut : MonoBehaviour } return nearestIndex; } - - private Vector2 ProjectPointOnSegment(Vector2 point, Vector2 a, Vector2 b) - { - Vector2 ab = b - a; - float abLengthSquared = ab.sqrMagnitude; - if (abLengthSquared == 0f) return a; - - float t = Vector2.Dot(point - a, ab) / abLengthSquared; - t = Mathf.Clamp01(t); - return a + t * ab; - } - - private void UpdateCutLineRenderer() - { - // 统计所有已切割线段点数 = 2*切割线段数(start和end) - int count = cutSegments.Count(cut => cut); - if (count == 0) - { - cutLineRenderer.positionCount = 0; - return; - } - - // 每个切割线段2个点 - cutLineRenderer.positionCount = count * 2; - - int index = 0; - for (int i = 0; i < cutSegments.Length; i++) - { - if (cutSegments[i]) - { - cutLineRenderer.SetPosition(index, edgePoints[i]); - cutLineRenderer.SetPosition(index + 1, edgePoints[i + 1]); - index += 2; - } - } - } - - private void CheckAllSegmentsCut() - { - if (cutSegments == null) return; - - if (System.Array.TrueForAll(cutSegments, cut => cut)) - { - Debug.Log("所有边缘线段都已经切割完成!"); - enabled = false; - } - } }