还可以的效果
This commit is contained in:
@@ -5,13 +5,14 @@ using UnityEngine;
|
||||
public class GearFollower : MonoBehaviour
|
||||
{
|
||||
[Header("参数")]
|
||||
public SpriteRenderer targetSpriteRenderer; // 目标图片
|
||||
public float snapDistance = 0.3f; // 距离边缘多少时吸附
|
||||
public float detachDistance = 1.0f; // 超过多少距离脱离牵引
|
||||
public float tractionSpeed = 2f; // 牵引时沿边缘移动速度
|
||||
public SpriteRenderer targetSpriteRenderer;
|
||||
public float snapDistance = 0.3f;
|
||||
public float detachDistance = 1.0f;
|
||||
public float tractionSpeed = 2f;
|
||||
|
||||
private List<Vector2> edgePoints; // 边缘路径点
|
||||
private int currentEdgeIndex = 0; // 当前吸附边缘点索引
|
||||
private List<Vector2> edgePoints;
|
||||
private int currentEdgeIndex = 0;
|
||||
private int tractionDirection = 1;
|
||||
|
||||
private enum State { Follow, Traction }
|
||||
private State currentState = State.Follow;
|
||||
@@ -28,6 +29,11 @@ public class GearFollower : MonoBehaviour
|
||||
{
|
||||
Vector2 mouseWorldPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
|
||||
|
||||
if (Input.GetMouseButton(0))
|
||||
{
|
||||
transform.Rotate(Vector3.forward, -360f * Time.deltaTime);
|
||||
}
|
||||
|
||||
switch (currentState)
|
||||
{
|
||||
case State.Follow:
|
||||
@@ -39,7 +45,6 @@ public class GearFollower : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// 从Sprite的PhysicsShape获取边缘点,构成闭环路径
|
||||
private void LoadEdgePointsFromSprite()
|
||||
{
|
||||
edgePoints = new List<Vector2>();
|
||||
@@ -58,96 +63,92 @@ public class GearFollower : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
// 转换为世界坐标
|
||||
edgePoints = shapePoints
|
||||
.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.Traction;
|
||||
|
||||
// 吸附齿轮到边缘点位置
|
||||
// 判断应该向前还是向后吸附
|
||||
Vector2 prev = edgePoints[WrapIndex(currentEdgeIndex - 1)];
|
||||
Vector2 next = edgePoints[WrapIndex(currentEdgeIndex + 1)];
|
||||
|
||||
float distToPrev = Vector2.Distance(mousePos, prev);
|
||||
float distToNext = Vector2.Distance(mousePos, next);
|
||||
|
||||
tractionDirection = (distToNext < distToPrev) ? 1 : -1;
|
||||
|
||||
transform.position = edgePoints[currentEdgeIndex];
|
||||
currentState = State.Traction;
|
||||
}
|
||||
}
|
||||
|
||||
// 牵引模式逻辑
|
||||
private void UpdateTractionState(Vector2 mousePos)
|
||||
{
|
||||
Vector2 gearPos = (Vector2)transform.position;
|
||||
Vector2 gearPos = transform.position;
|
||||
|
||||
// 计算鼠标和齿轮距离,超过detachDistance则脱离牵引
|
||||
if (Vector2.Distance(mousePos, gearPos) > detachDistance)
|
||||
{
|
||||
currentState = State.Follow;
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断是否按住左键
|
||||
if (!Input.GetMouseButton(0))
|
||||
{
|
||||
// 未按键,齿轮固定在边缘点
|
||||
transform.position = edgePoints[currentEdgeIndex];
|
||||
// 不按左键不移动
|
||||
return;
|
||||
}
|
||||
|
||||
int nextIndex = WrapIndex(currentEdgeIndex + tractionDirection);
|
||||
Vector2 from = edgePoints[currentEdgeIndex];
|
||||
Vector2 to = edgePoints[nextIndex];
|
||||
|
||||
// 判断鼠标是否在当前前进方向上,否则允许换方向
|
||||
float forwardDot = Vector2.Dot((to - from).normalized, (mousePos - from).normalized);
|
||||
if (forwardDot < 0) // 鼠标在反方向
|
||||
{
|
||||
// 允许方向切换
|
||||
tractionDirection *= -1;
|
||||
nextIndex = WrapIndex(currentEdgeIndex + tractionDirection);
|
||||
from = edgePoints[currentEdgeIndex];
|
||||
to = edgePoints[nextIndex];
|
||||
}
|
||||
|
||||
Vector2 targetPoint = GetClosestPointOnSegment(from, to, mousePos);
|
||||
Vector2 moveDir = (targetPoint - gearPos);
|
||||
float distance = moveDir.magnitude;
|
||||
|
||||
float maxStep = tractionSpeed * Time.deltaTime;
|
||||
|
||||
if (distance <= maxStep)
|
||||
{
|
||||
transform.position = targetPoint;
|
||||
|
||||
// 如果到达段末,前进一段
|
||||
if (Vector2.Distance(targetPoint, to) < 0.01f)
|
||||
{
|
||||
currentEdgeIndex = nextIndex;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
transform.position += (Vector3)(moveDir.normalized * maxStep);
|
||||
}
|
||||
}
|
||||
|
||||
// 找到距离pos最近的边缘点索引和距离
|
||||
private int FindNearestEdgePointIndex(Vector2 pos, out float minDist)
|
||||
{
|
||||
int nearestIndex = 0;
|
||||
@@ -164,4 +165,19 @@ public class GearFollower : MonoBehaviour
|
||||
}
|
||||
return nearestIndex;
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private int WrapIndex(int index)
|
||||
{
|
||||
if (index < 0) return edgePoints.Count - 2;
|
||||
if (index >= edgePoints.Count - 1) return 0;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user