存个档
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
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 float rotationSpeed = 360f; // 齿轮旋转速度(度/秒)
|
||||
public float smoothTime = 0.1f; // 平滑过渡时间
|
||||
public float edgeSmoothTime = 0.05f; // 边缘移动平滑时间
|
||||
public float edgeScaleFactor = 1.1f; // 边缘点采样放大倍数
|
||||
public Color normalColor = Color.white; // 正常状态颜色
|
||||
public Color tractionColor = Color.yellow; // 牵引状态颜色
|
||||
|
||||
private List<Vector2> edgePoints; // 边缘路径点
|
||||
private int currentEdgeIndex = 0; // 当前吸附边缘点索引
|
||||
private SpriteRenderer gearSpriteRenderer; // 齿轮的SpriteRenderer
|
||||
private Vector2 currentVelocity; // 用于平滑移动
|
||||
private float currentRotationVelocity; // 用于平滑旋转
|
||||
|
||||
private enum State { Follow, Traction }
|
||||
private State currentState = State.Follow;
|
||||
|
||||
private Camera mainCamera;
|
||||
|
||||
private Vector2 targetEdgePosition; // 目标边缘位置
|
||||
private float currentEdgeProgress; // 当前边缘移动进度
|
||||
|
||||
void Start()
|
||||
{
|
||||
mainCamera = Camera.main;
|
||||
gearSpriteRenderer = GetComponent<SpriteRenderer>();
|
||||
if (gearSpriteRenderer == null)
|
||||
{
|
||||
Debug.LogError("齿轮对象缺少SpriteRenderer组件");
|
||||
}
|
||||
LoadEdgePointsFromSprite();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
Vector2 mouseWorldPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
|
||||
|
||||
switch (currentState)
|
||||
{
|
||||
case State.Follow:
|
||||
UpdateFollowState(mouseWorldPos);
|
||||
break;
|
||||
case State.Traction:
|
||||
UpdateTractionState(mouseWorldPos);
|
||||
break;
|
||||
}
|
||||
|
||||
// 更新齿轮旋转
|
||||
UpdateGearRotation();
|
||||
// 更新视觉反馈
|
||||
UpdateVisualFeedback();
|
||||
}
|
||||
|
||||
// 更新齿轮旋转
|
||||
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 ? tractionColor : normalColor;
|
||||
}
|
||||
}
|
||||
|
||||
// 从Sprite的PhysicsShape获取边缘点,构成闭环路径
|
||||
private void LoadEdgePointsFromSprite()
|
||||
{
|
||||
edgePoints = new List<Vector2>();
|
||||
if (targetSpriteRenderer == null)
|
||||
{
|
||||
Debug.LogError("targetSpriteRenderer 为空");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Vector2> shapePoints = new List<Vector2>();
|
||||
targetSpriteRenderer.sprite.GetPhysicsShape(0, shapePoints);
|
||||
|
||||
if (shapePoints.Count == 0)
|
||||
{
|
||||
Debug.LogError("目标Sprite没有物理形状点");
|
||||
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);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 假设形状是闭合的,确保首尾连通
|
||||
if (edgePoints[0] != edgePoints[edgePoints.Count - 1])
|
||||
{
|
||||
edgePoints.Add(edgePoints[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// 跟随模式逻辑
|
||||
private void UpdateFollowState(Vector2 mousePos)
|
||||
{
|
||||
// 使用平滑移动
|
||||
transform.position = Vector2.SmoothDamp(transform.position, mousePos, ref currentVelocity, smoothTime);
|
||||
|
||||
// 检测距离最近边缘点是否在snapDistance内,进入牵引
|
||||
int nearestIndex = FindNearestEdgePointIndex(mousePos, out float dist);
|
||||
|
||||
if (dist < snapDistance)
|
||||
{
|
||||
currentEdgeIndex = nearestIndex;
|
||||
currentState = State.Traction;
|
||||
// 切换到牵引状态时,调整渲染顺序
|
||||
if (gearSpriteRenderer != null)
|
||||
{
|
||||
gearSpriteRenderer.sortingOrder = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 牵引模式逻辑
|
||||
private void UpdateTractionState(Vector2 mousePos)
|
||||
{
|
||||
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))
|
||||
{
|
||||
// 未按键,齿轮固定在边缘点
|
||||
transform.position = Vector2.SmoothDamp(transform.position, edgePoints[currentEdgeIndex], ref currentVelocity, smoothTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 按住左键,齿轮沿边缘点链移动
|
||||
MoveAlongEdge(mousePos);
|
||||
}
|
||||
}
|
||||
|
||||
// 沿边缘移动的逻辑
|
||||
private void MoveAlongEdge(Vector2 mousePos)
|
||||
{
|
||||
// 找到当前边缘点前后点索引,注意闭环处理
|
||||
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;
|
||||
|
||||
// 计算鼠标到当前点的向量
|
||||
Vector2 mouseToCurrent = mousePos - currPoint;
|
||||
|
||||
// 计算鼠标在前后方向上的投影
|
||||
float projToPrev = Vector2.Dot(mouseToCurrent, dirToPrev);
|
||||
float projToNext = Vector2.Dot(mouseToCurrent, dirToNext);
|
||||
|
||||
// 根据投影决定移动方向
|
||||
Vector2 targetDir;
|
||||
if (Mathf.Abs(projToPrev) > Mathf.Abs(projToNext))
|
||||
{
|
||||
targetDir = dirToPrev;
|
||||
currentEdgeIndex = prevIndex;
|
||||
targetEdgePosition = prevPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetDir = dirToNext;
|
||||
currentEdgeIndex = nextIndex;
|
||||
targetEdgePosition = nextPoint;
|
||||
}
|
||||
|
||||
// 计算目标位置(在边缘上)
|
||||
Vector2 currentPos = (Vector2)transform.position;
|
||||
Vector2 targetPos = Vector2.Lerp(currPoint, targetEdgePosition, currentEdgeProgress);
|
||||
|
||||
// 使用平滑移动
|
||||
transform.position = Vector2.SmoothDamp(currentPos, targetPos, ref currentVelocity, edgeSmoothTime);
|
||||
|
||||
// 更新边缘移动进度
|
||||
float moveDistance = tractionSpeed * Time.deltaTime;
|
||||
float totalDistance = Vector2.Distance(currPoint, targetEdgePosition);
|
||||
currentEdgeProgress += moveDistance / totalDistance;
|
||||
|
||||
// 如果到达目标点,重置进度
|
||||
if (currentEdgeProgress >= 1f)
|
||||
{
|
||||
currentEdgeProgress = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 找到距离pos最近的边缘点索引和距离
|
||||
private int FindNearestEdgePointIndex(Vector2 pos, 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07505bc4dd78e1e4c87141a1d061dd10
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user