基本交互和视觉效果确定

This commit is contained in:
2025-05-18 02:23:06 +08:00
parent 3ef8e4441d
commit de34465cdf
20 changed files with 13210 additions and 56 deletions
@@ -0,0 +1,118 @@
using System.Collections.Generic;
using UnityEngine;
public class CutLineManager : MonoBehaviour
{
[Header("切割线参数")]
public float cutLineWidth = 0.1f;
public float noiseAmount = 0.05f; // 毛刺偏移幅度
public float segmentDuration = 4f; // 线段持续时间
public float cutLineDelay = 3f; // 延迟几秒才显示轨迹点
public LineRenderer mainCutLineRenderer;
private List<TimedPoint> timedCutPoints = new List<TimedPoint>();
private bool isCutting = false;
public bool IsCutting => isCutting; // Public property to access isCutting state
private class TimedPoint
{
public Vector3 position;
public float timeAdded;
public TimedPoint(Vector3 pos, float time)
{
position = pos;
timeAdded = time;
}
}
private void Awake()
{
InitializeMainCutLine();
}
private void InitializeMainCutLine()
{
GameObject cutLineObj = new GameObject("MainCutLine");
cutLineObj.transform.parent = transform;
mainCutLineRenderer = cutLineObj.AddComponent<LineRenderer>();
mainCutLineRenderer.positionCount = 0;
mainCutLineRenderer.widthCurve = AnimationCurve.Constant(0, 1, cutLineWidth);
mainCutLineRenderer.material = new Material(Shader.Find("Sprites/Default"));
mainCutLineRenderer.numCapVertices = 0;
mainCutLineRenderer.sortingOrder = 1;
}
public void StartCutting()
{
isCutting = true;
timedCutPoints.Clear();
if (mainCutLineRenderer != null)
{
mainCutLineRenderer.positionCount = 0;
}
}
public void AddCutPoint(Vector3 point)
{
if (!isCutting) return;
if (timedCutPoints.Count == 0 || Vector3.Distance(timedCutPoints[timedCutPoints.Count - 1].position, point) > 0.05f)
{
timedCutPoints.Add(new TimedPoint(point, Time.time));
if (timedCutPoints.Count >= 2)
{
Vector3 prev = timedCutPoints[timedCutPoints.Count - 2].position;
Vector3 curr = timedCutPoints[timedCutPoints.Count - 1].position;
CreateSegment(prev, curr);
}
}
}
public void EndCutting()
{
isCutting = false;
}
private void Update()
{
UpdateCutLineRenderer();
}
private void UpdateCutLineRenderer()
{
if (mainCutLineRenderer == null) return;
float currentTime = Time.time;
List<Vector3> visiblePoints = new List<Vector3>();
foreach (var timedPoint in timedCutPoints)
{
if (currentTime - timedPoint.timeAdded >= cutLineDelay)
{
visiblePoints.Add(timedPoint.position);
}
}
mainCutLineRenderer.positionCount = visiblePoints.Count;
if (visiblePoints.Count > 0)
mainCutLineRenderer.SetPositions(visiblePoints.ToArray());
}
private void CreateSegment(Vector3 from, Vector3 to)
{
GameObject segObj = new GameObject("HeatLineSegment");
segObj.transform.parent = transform;
LineRenderer segLine = segObj.AddComponent<LineRenderer>();
segLine.positionCount = 2;
segLine.SetPosition(0, from);
segLine.SetPosition(1, to);
segLine.sortingOrder = 4;
segLine.material = new Material(Shader.Find("Sprites/Default"));
segLine.widthCurve = AnimationCurve.Constant(0, 1, cutLineWidth);
segLine.numCapVertices = 0;
var segmentController = segObj.AddComponent<HeatLineSegmentController>();
segmentController.duration = segmentDuration;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6fe8e1ba5a1fbed40b777c74953b13bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,198 @@
using UnityEngine;
using System.Collections.Generic;
public class CuttingSystem : MonoBehaviour
{
[Header("切割系统参数")]
public float snapDistance = 0.3f;
public float detachDistance = 1.0f;
public float directionSwitchCooldown = 0.2f;
private CutLineManager cutLineManager;
public float tractionSpeed = 2f;
[Header("测试")]
public SpriteRenderer TargetspriteRenderer;
private GearController gearController;
private Camera mainCamera;
private int currentEdgeIndex = 0;
private int tractionDirection = 1;
private float directionSwitchTimer = 0f;
private enum State { Follow, Traction }
private State currentState = State.Follow;
private List<Vector2> edgePoints;
private List<Vector2> originalEdgePoints;
private void Start()
{
mainCamera = Camera.main;
gearController = GetComponentInChildren<GearController>();
cutLineManager = GetComponentInChildren<CutLineManager>();
edgePoints = new List<Vector2>();
originalEdgePoints = new List<Vector2>();
if (TargetspriteRenderer != null)
{
InitializeCutting(TargetspriteRenderer);
}
else
{
Debug.LogError("TargetspriteRenderer is null!");
}
}
private void Update()
{
UpdateCutting();
}
public void InitializeCutting(SpriteRenderer targetSprite, float edgePointsScale = 1.2f)
{
if (targetSprite == null) return;
LoadEdgePointsFromSprite(targetSprite, edgePointsScale);
Debug.Log($"InitializeCutting: edgePoints count = {edgePoints.Count}");
}
public void UpdateCutting()
{
Vector2 mouseWorldPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
if (Input.GetMouseButton(0))
{
gearController.SetRotation(true);
}
else
{
gearController.SetRotation(false);
}
switch (currentState)
{
case State.Follow:
UpdateFollowState(mouseWorldPos);
break;
case State.Traction:
UpdateTractionState(mouseWorldPos);
break;
}
}
private void LoadEdgePointsFromSprite(SpriteRenderer targetSprite, float edgePointsScale)
{
var shapePoints = CuttingUtils.GetSpritePhysicsShapePoints(targetSprite);
if (shapePoints == null) return;
var (scaledPoints, originalPoints) = CuttingUtils.ProcessEdgePoints(shapePoints, targetSprite, edgePointsScale);
if (scaledPoints == null) return;
edgePoints = scaledPoints;
originalEdgePoints = originalPoints;
Debug.Log($"LoadEdgePointsFromSprite: edgePoints count = {edgePoints.Count}");
}
private void UpdateFollowState(Vector2 mousePos)
{
gearController.transform.position = mousePos;
int nearestIndex = CuttingUtils.FindNearestEdgePointIndex(mousePos, edgePoints, out float dist);
Debug.Log($"Distance to nearest point: {dist}, Snap distance: {snapDistance}");
if (dist < snapDistance)
{
currentEdgeIndex = nearestIndex;
Vector2 prev = edgePoints[CuttingUtils.WrapIndex(currentEdgeIndex - 1, edgePoints.Count)];
Vector2 next = edgePoints[CuttingUtils.WrapIndex(currentEdgeIndex + 1, edgePoints.Count)];
float distToPrev = Vector2.Distance(mousePos, prev);
float distToNext = Vector2.Distance(mousePos, next);
tractionDirection = (distToNext < distToPrev) ? 1 : -1;
gearController.transform.position = edgePoints[currentEdgeIndex];
currentState = State.Traction;
Debug.Log("Switched to Traction state");
}
}
private void UpdateTractionState(Vector2 mousePos)
{
Vector2 gearPos = transform.position;
if (Vector2.Distance(mousePos, gearPos) > detachDistance)
{
currentState = State.Follow;
cutLineManager.EndCutting();
return;
}
if (!Input.GetMouseButton(0))
{
cutLineManager.EndCutting();
return;
}
if (!cutLineManager.IsCutting)
{
cutLineManager.StartCutting();
}
int nextIndex = CuttingUtils.WrapIndex(currentEdgeIndex + tractionDirection, edgePoints.Count);
Vector2 from = edgePoints[currentEdgeIndex];
Vector2 to = edgePoints[nextIndex];
Vector2 forward = (to - from).normalized;
Vector2 toMouse = (mousePos - from).normalized;
float angle = Vector2.SignedAngle(forward, toMouse);
if (Mathf.Abs(angle) > 120f)
{
directionSwitchTimer += Time.deltaTime;
if (directionSwitchTimer > directionSwitchCooldown)
{
tractionDirection *= -1;
directionSwitchTimer = 0f;
nextIndex = CuttingUtils.WrapIndex(currentEdgeIndex + tractionDirection, edgePoints.Count);
from = edgePoints[currentEdgeIndex];
to = edgePoints[nextIndex];
forward = (to - from).normalized;
}
}
else
{
directionSwitchTimer = 0f;
}
Vector2 targetPoint = CuttingUtils.GetClosestPointOnSegment(from, to, mousePos);
Vector2 moveDir = (targetPoint - gearPos);
float distance = moveDir.magnitude;
float maxStep = tractionSpeed * Time.deltaTime;
if (distance <= maxStep)
{
gearController.transform.position = targetPoint;
if (Vector2.Distance(targetPoint, to) < 0.01f)
{
currentEdgeIndex = nextIndex;
}
}
else
{
gearController.transform.position += (Vector3)(moveDir.normalized * maxStep);
}
Vector2 originalFrom = originalEdgePoints[currentEdgeIndex];
Vector2 originalTo = originalEdgePoints[nextIndex];
Vector2 originalTargetPoint = CuttingUtils.GetClosestPointOnSegment(originalFrom, originalTo, transform.position);
Vector3 noisyPoint = originalTargetPoint;
noisyPoint.x += Random.Range(-cutLineManager.noiseAmount, cutLineManager.noiseAmount);
noisyPoint.y += Random.Range(-cutLineManager.noiseAmount, cutLineManager.noiseAmount);
cutLineManager.AddCutPoint(noisyPoint);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ee21f841c30549c43837ad222c4892b3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,102 @@
using UnityEngine;
using System.Collections.Generic;
public static class CuttingUtils
{
public static int FindNearestEdgePointIndex(Vector2 pos, List<Vector2> edgePoints, out float minDist)
{
int nearestIndex = 0;
minDist = float.MaxValue;
for (int i = 0; i < edgePoints.Count; i++)
{
float dist = Vector2.Distance(pos, edgePoints[i]);
if (dist < minDist)
{
minDist = dist;
nearestIndex = i;
}
}
return nearestIndex;
}
public static Vector2 GetClosestPointOnSegment(Vector2 a, Vector2 b, Vector2 p)
{
Vector2 ab = b - a;
float t = Vector2.Dot(p - a, ab) / ab.sqrMagnitude;
t = Mathf.Clamp01(t);
return a + ab * t;
}
public static int WrapIndex(int index, int count)
{
if (index < 0) return count - 2;
if (index >= count - 1) return 0;
return index;
}
public static List<Vector2> GetSpritePhysicsShapePoints(SpriteRenderer spriteRenderer)
{
List<Vector2> shapePoints = new List<Vector2>();
spriteRenderer.sprite.GetPhysicsShape(0, shapePoints);
if (shapePoints.Count == 0)
{
Debug.LogError("目标Sprite没有物理形状点");
return null;
}
return shapePoints;
}
public static (List<Vector2> scaledPoints, List<Vector2> originalPoints) ProcessEdgePoints(
List<Vector2> shapePoints,
SpriteRenderer spriteRenderer,
float edgePointsScale = 1.2f,
float desiredSegmentLength = 0.1f)
{
if (shapePoints == null || shapePoints.Count == 0) return (null, null);
List<Vector2> scaledPoints = new List<Vector2>();
List<Vector2> originalPoints = new List<Vector2>();
// 计算中心点
Vector2 center = Vector2.zero;
foreach (Vector2 point in shapePoints)
{
center += point;
}
center /= shapePoints.Count;
// 处理每个线段
for (int i = 0; i < shapePoints.Count; i++)
{
Vector2 p1 = spriteRenderer.transform.TransformPoint(shapePoints[i]);
Vector2 p2 = spriteRenderer.transform.TransformPoint(shapePoints[(i + 1) % shapePoints.Count]);
Vector2 scaledP1 = center + (p1 - center) * edgePointsScale;
Vector2 scaledP2 = center + (p2 - center) * edgePointsScale;
float segmentLength = Vector2.Distance(scaledP1, scaledP2);
int steps = Mathf.Max(1, Mathf.CeilToInt(segmentLength / desiredSegmentLength));
for (int s = 0; s < steps; s++)
{
float t = (float)s / steps;
Vector2 interpolated = Vector2.Lerp(scaledP1, scaledP2, t);
Vector2 originalInterpolated = Vector2.Lerp(p1, p2, t);
scaledPoints.Add(interpolated);
originalPoints.Add(originalInterpolated);
}
}
// 确保首尾相连
if ((scaledPoints[0] - scaledPoints[scaledPoints.Count - 1]).sqrMagnitude > 0.0001f)
{
scaledPoints.Add(scaledPoints[0]);
originalPoints.Add(originalPoints[0]);
}
return (scaledPoints, originalPoints);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6fd7ba5ee9e9b7a4ca602330a830ac95
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
using UnityEngine;
public class GearController : MonoBehaviour
{
[Header("齿轮参数")]
public float rotationSpeed = 360f;
public float snapDistance = 0.3f;
public float detachDistance = 10.0f;
private bool isRotating = false;
public void SetRotation(bool shouldRotate)
{
isRotating = shouldRotate;
}
private void Update()
{
if (isRotating)
{
transform.Rotate(Vector3.forward, -rotationSpeed * Time.deltaTime);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b570555589f44fb4889f5dd5712ced34
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using Shapes;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.VFX;
public class GearFollower : MonoBehaviour
{
@@ -13,12 +15,22 @@ public class GearFollower : MonoBehaviour
[Header("切割轨迹")]
public LineRenderer cutLineRenderer;
public float cutLineWidth = 0.1f;
public float noiseAmount = 0.05f; // 毛刺偏移幅度
public float segmentDuration = 4f; // 线段持续时间
[Header("震动与光照反馈")]
public Light2D cutLight; // 需要使用 Unity 的 2D 点光源(URP
public float lightPulseSpeed = 5f;
public float lightMaxIntensity = 1.5f;
public float shakeAmount = 0.05f;
[Header("VFX火花")]
public VisualEffect sparkVFX; // 关联Spark VFX Graph组件
public float maxEmissionRate = 50f; // 最大发射速率
public float emissionChangeSpeed = 100f; // 发射速率变化速度
private float currentEmissionRate = 0f;
private Vector3 originalLocalPosition;
private List<Vector2> edgePoints;
private List<Vector2> originalEdgePoints; // 存储原始边缘点
private int currentEdgeIndex = 0;
@@ -26,15 +38,10 @@ public class GearFollower : MonoBehaviour
private enum State { Follow, Traction }
private State currentState = State.Follow;
private Camera mainCamera;
private List<Vector3> cutLinePoints = new List<Vector3>();
private bool isCutting = false;
private float directionSwitchCooldown = 0.2f;
private float directionSwitchTimer = 0f;
private class TimedPoint
{
public Vector3 position;
@@ -45,25 +52,30 @@ public class GearFollower : MonoBehaviour
timeAdded = time;
}
}
private List<TimedPoint> timedCutPoints = new List<TimedPoint>();
public float cutLineDelay = 3f; // 延迟几秒才显示轨迹点
public float cutLineDelay = 3f;
private Vector3 shakeOffset = Vector3.zero;
private Vector3 targetPosition = Vector3.zero;
private bool isInTractionMode = false;
void Start()
{
mainCamera = Camera.main;
LoadEdgePointsFromSprite();
if (cutLineRenderer != null)
{
cutLineRenderer.positionCount = 0;
cutLineRenderer.widthCurve = AnimationCurve.Constant(0, 1, cutLineWidth);
cutLineRenderer.material = new Material(Shader.Find("Sprites/Default"));
cutLineRenderer.numCapVertices = 0; // 线头不圆滑,显锐利
cutLineRenderer.numCapVertices = 0;
cutLineRenderer.sortingOrder = 1;
}
if (cutLight != null)
{
cutLight.intensity = 0f;
cutLight.enabled = false;
}
}
void Update()
{
Vector2 mouseWorldPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
@@ -72,7 +84,6 @@ public class GearFollower : MonoBehaviour
{
transform.Rotate(Vector3.forward, -360f * Time.deltaTime);
}
switch (currentState)
{
case State.Follow:
@@ -83,18 +94,60 @@ public class GearFollower : MonoBehaviour
break;
}
UpdateCutLineRenderer();
UpdateVisualFeedback();
}
private void UpdateVisualFeedback()
{
if (isInTractionMode && isCutting)
{
// 原始小幅震动
Vector2 baseShake = Random.insideUnitCircle * shakeAmount;
shakeOffset = (Vector3)baseShake;
transform.position = targetPosition + shakeOffset;
// 根据震动幅度控制灯光强度
if (cutLight != null)
{
cutLight.enabled = true;
float intensity = shakeOffset.magnitude / shakeAmount; // 得到 [0,1] 比例
cutLight.intensity = intensity * lightMaxIntensity;
}
// if (sparkVFX != null)
// {
// sparkVFX.SendEvent("OnPlay"); // 这里的 "OnBurst" 是你在VFX Graph里定义的事件名,需要一致
// }
}
else
{
shakeOffset = Vector3.zero;
if (isInTractionMode)
{
transform.position = targetPosition;
}
if (cutLight != null)
{
cutLight.intensity = 0f;
cutLight.enabled = false;
}
// if (sparkVFX != null)
// {
// sparkVFX.SendEvent("OnStop"); // 这里的 "OnBurst" 是你在VFX Graph里定义的事件名,需要一致
// }
}
}
private void LoadEdgePointsFromSprite()
{
edgePoints = new List<Vector2>();
originalEdgePoints = new List<Vector2>(); // 初始化原始边缘点列表
originalEdgePoints = new List<Vector2>();
if (targetSpriteRenderer == null)
{
Debug.LogError("targetSpriteRenderer 为空");
return;
}
List<Vector2> shapePoints = new List<Vector2>();
targetSpriteRenderer.sprite.GetPhysicsShape(0, shapePoints);
@@ -103,32 +156,26 @@ public class GearFollower : MonoBehaviour
Debug.LogError("目标Sprite没有物理形状点");
return;
}
float desiredSegmentLength = 0.1f;
edgePoints.Clear();
originalEdgePoints.Clear();
// 计算中心点
Vector2 center = Vector2.zero;
foreach (Vector2 point in shapePoints)
{
center += point;
}
center /= shapePoints.Count;
for (int i = 0; i < shapePoints.Count; i++)
{
Vector2 p1 = targetSpriteRenderer.transform.TransformPoint(shapePoints[i]);
Vector2 p2 = targetSpriteRenderer.transform.TransformPoint(shapePoints[(i + 1) % shapePoints.Count]);
// 计算缩放后的点
Vector2 scaledP1 = center + (p1 - center) * edgePointsScale;
Vector2 scaledP2 = center + (p2 - center) * edgePointsScale;
float segmentLength = Vector2.Distance(scaledP1, scaledP2);
int steps = Mathf.Max(1, Mathf.CeilToInt(segmentLength / desiredSegmentLength));
for (int s = 0; s < steps; s++)
{
float t = (float)s / steps;
@@ -144,12 +191,11 @@ public class GearFollower : MonoBehaviour
edgePoints.Add(edgePoints[0]);
originalEdgePoints.Add(originalEdgePoints[0]);
}
Debug.Log($"边缘点数量:{edgePoints.Count}");
}
private void UpdateFollowState(Vector2 mousePos)
{
transform.position = mousePos;
isInTractionMode = false;
int nearestIndex = FindNearestEdgePointIndex(mousePos, out float dist);
if (dist < snapDistance)
@@ -164,27 +210,28 @@ public class GearFollower : MonoBehaviour
tractionDirection = (distToNext < distToPrev) ? 1 : -1;
transform.position = edgePoints[currentEdgeIndex];
targetPosition = edgePoints[currentEdgeIndex];
transform.position = targetPosition;
currentState = State.Traction;
isInTractionMode = true;
}
}
private void UpdateTractionState(Vector2 mousePos)
{
Vector2 gearPos = transform.position;
Vector2 gearPos = transform.position - shakeOffset;
if (Vector2.Distance(mousePos, gearPos) > detachDistance)
{
currentState = State.Follow;
isInTractionMode = false;
EndCutting();
return;
}
if (!Input.GetMouseButton(0))
{
EndCutting();
return;
}
if (!isCutting)
{
StartCutting();
@@ -225,7 +272,7 @@ public class GearFollower : MonoBehaviour
if (distance <= maxStep)
{
transform.position = targetPoint;
targetPosition = targetPoint;
if (Vector2.Distance(targetPoint, to) < 0.01f)
{
@@ -234,19 +281,36 @@ public class GearFollower : MonoBehaviour
}
else
{
transform.position += (Vector3)(moveDir.normalized * maxStep);
targetPosition = (Vector3)gearPos + (Vector3)(moveDir.normalized * maxStep);
}
transform.position = targetPosition + shakeOffset;
// 使用原始边缘点来记录切割线
Vector2 originalFrom = originalEdgePoints[currentEdgeIndex];
Vector2 originalTo = originalEdgePoints[nextIndex];
Vector2 originalTargetPoint = GetClosestPointOnSegment(originalFrom, originalTo, transform.position);
Vector2 originalTargetPoint = GetClosestPointOnSegment(originalFrom, originalTo, transform.position - shakeOffset);
// 记录切割点(带噪声模拟毛糙)
Vector3 noisyPoint = originalTargetPoint;
noisyPoint.x += Random.Range(-noiseAmount, noiseAmount);
noisyPoint.y += Random.Range(-noiseAmount, noiseAmount);
AddCutPoint(noisyPoint);
if (sparkVFX != null)
{
// 计算从切割点到目标精灵中心的向量
Vector2 center = targetSpriteRenderer.transform.position;
Vector2 toCenter = center - (Vector2)originalTargetPoint;
// 计算法线方向(垂直于切割方向)
Vector2 normal = Vector2.Perpendicular(moveDir.normalized);
// 根据切割方向决定法线方向
if (tractionDirection > 0)
{
normal = -normal;
}
Vector3 velocity = (Vector3)normal * 10f;
sparkVFX.SetVector3("Initial Velocity1", velocity);
}
}
private void StartCutting()
@@ -257,15 +321,27 @@ public class GearFollower : MonoBehaviour
{
cutLineRenderer.positionCount = 0;
}
if (sparkVFX != null)
{
sparkVFX.Play();
}
}
private void AddCutPoint(Vector3 point)
{
if (timedCutPoints.Count == 0 || Vector3.Distance(timedCutPoints[timedCutPoints.Count - 1].position, point) > 0.05f)
{
timedCutPoints.Add(new TimedPoint(point, Time.time));
// 立即创建片段
// 更新光照位置到最新切点
if (cutLight != null)
{
cutLight.transform.position = point;
}
// 把火花特效位置设置到当前切割点
if (sparkVFX != null)
{
sparkVFX.transform.position = point;
}
if (timedCutPoints.Count >= 2)
{
Vector3 prev = timedCutPoints[timedCutPoints.Count - 2].position;
@@ -289,7 +365,6 @@ public class GearFollower : MonoBehaviour
}
else
{
// 这里的点还没到延迟时间,不显示
}
}
@@ -301,7 +376,11 @@ public class GearFollower : MonoBehaviour
private void EndCutting()
{
isCutting = false;
// 这里可以添加切割结束后的淡出效果等
if (sparkVFX != null)
{
sparkVFX.Stop();
}
}
private int FindNearestEdgePointIndex(Vector2 pos, out float minDist)
{
@@ -319,7 +398,6 @@ public class GearFollower : MonoBehaviour
}
return nearestIndex;
}
private Vector2 GetClosestPointOnSegment(Vector2 a, Vector2 b, Vector2 p)
{
Vector2 ab = b - a;