dezhou_client/wb_unity_pro/Assets/Scripts/LuaHelper/SmoothTrajectorySystem.cs

466 lines
16 KiB
C#
Raw Normal View History

2025-12-17 21:08:27 +08:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
[System.Serializable]
public class TrajectoryPoint
{
public int index;
public RectTransform pointTransform;
public Button pointButton;
public Vector2 initialPosition; // 初始位置
public Vector2 currentPosition; // 当前位置
public TrajectoryPoint(int idx, RectTransform transform, Button button, Vector2 initPos)
{
index = idx;
pointTransform = transform;
pointButton = button;
initialPosition = initPos;
currentPosition = initPos;
}
}
public class SmoothTrajectorySystem : MonoBehaviour
{
[SerializeField]
RectTransform[] points;
[Header("Movement Settings")]
[SerializeField] float movementDuration = 1f;
[SerializeField] float curveHeight = 50f;
[SerializeField] AnimationCurve movementCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
[Header("Debug")]
[SerializeField] bool enableDebug = true;
private List<TrajectoryPoint> trajectoryPoints = new List<TrajectoryPoint>();
private bool isMoving = false;
private Vector2 fixedTargetPosition; // 固定的目标位置0号位置的初始位置
void Start()
{
InitializePoints();
}
void InitializePoints()
{
trajectoryPoints.Clear();
if (points == null || points.Length == 0)
{
Debug.LogError("Points array is empty!");
return;
}
// 设置固定的目标位置0号位置的初始位置
if (points[0] != null)
{
fixedTargetPosition = points[0].anchoredPosition;
if (enableDebug) Debug.Log($"Fixed target position (index 0 initial): {fixedTargetPosition}");
}
// 初始化所有点
for (int i = 0; i < points.Length; i++)
{
if (points[i] == null) continue;
Button button = null;
// 尝试获取按钮(可能在点本身或其子对象上)
if (points[i].GetComponent<Button>() != null)
{
button = points[i].GetComponent<Button>();
}
else if (points[i].childCount > 0 && points[i].GetChild(0).GetComponent<Button>() != null)
{
button = points[i].GetChild(0).GetComponent<Button>();
}
Vector2 initialPosition = points[i].anchoredPosition;
TrajectoryPoint trajectoryPoint = new TrajectoryPoint(i, points[i], button, initialPosition);
trajectoryPoints.Add(trajectoryPoint);
// 设置按钮事件
if (button != null)
{
int index = i;
button.onClick.RemoveAllListeners();
button.onClick.AddListener(() => OnClickItem(index));
if (enableDebug) Debug.Log($"Button event added to point {i}: {points[i].name}, Initial Position: {initialPosition}");
}
else
{
Debug.LogWarning($"Point {i} ({points[i].name}) has no Button component!");
}
}
if (enableDebug) Debug.Log($"Initialized {trajectoryPoints.Count} trajectory points with fixed target position");
}
void OnClickItem(int clickedIndex)
{
if (enableDebug) Debug.Log($"Clicked point index: {clickedIndex}");
if (isMoving)
{
if (enableDebug) Debug.Log("Movement in progress, ignoring click");
return;
}
// 检查点击的点是否已经在目标位置(基于实际位置,不是索引)
if (IsPointAtTargetPosition(clickedIndex))
{
if (enableDebug) Debug.Log("Clicked point is already at target position, no movement needed");
return;
}
StartCoroutine(SequentialMovePointsCoroutine(clickedIndex));
}
bool IsPointAtTargetPosition(int pointIndex)
{
// 检查点是否在固定的目标位置(基于实际坐标位置)
TrajectoryPoint point = trajectoryPoints[pointIndex];
bool isAtTarget = Vector2.Distance(point.currentPosition, fixedTargetPosition) < 0.1f;
if (enableDebug)
{
Debug.Log($"Point {pointIndex} at target position: {isAtTarget} " +
$"(Current: {point.currentPosition}, Target: {fixedTargetPosition}, " +
$"Distance: {Vector2.Distance(point.currentPosition, fixedTargetPosition)})");
}
return isAtTarget;
}
IEnumerator SequentialMovePointsCoroutine(int clickedIndex)
{
isMoving = true;
if (enableDebug) Debug.Log($"Starting sequential movement for point {clickedIndex} to fixed target position");
// 计算移动方向(基于中间点数量)
MovementDirection direction = CalculateMovementDirectionByIntermediatePoints(clickedIndex);
if (enableDebug) Debug.Log($"Movement direction: {direction}");
// 计算每个点的最终目标位置索引
int[] targetIndices = CalculateTargetIndices(clickedIndex, direction);
if (enableDebug)
{
Debug.Log("Target indices:");
for (int i = 0; i < targetIndices.Length; i++)
{
Debug.Log($" Point {i} -> Target index {targetIndices[i]} " +
$"(Position: {trajectoryPoints[targetIndices[i]].initialPosition})");
}
}
// 计算每个点的移动路径
List<Vector2>[] movePaths = new List<Vector2>[trajectoryPoints.Count];
for (int i = 0; i < trajectoryPoints.Count; i++)
{
movePaths[i] = CalculateMovePath(i, targetIndices[i]);
if (enableDebug)
{
Debug.Log($"Point {i} path: {movePaths[i].Count} steps " +
$"(Start: {movePaths[i][0]}, End: {movePaths[i][movePaths[i].Count - 1]})");
}
}
// 按步骤顺序移动
int maxPathLength = 0;
for (int i = 0; i < trajectoryPoints.Count; i++)
{
if (movePaths[i].Count > maxPathLength)
maxPathLength = movePaths[i].Count;
}
// 执行顺序移动
for (int step = 0; step < maxPathLength; step++)
{
if (enableDebug) Debug.Log($"=== Step {step + 1}/{maxPathLength} ===");
bool anyPointMoved = false;
List<Coroutine> moveCoroutines = new List<Coroutine>();
// 移动所有在这一步有目标位置的点
for (int i = 0; i < trajectoryPoints.Count; i++)
{
if (step < movePaths[i].Count - 1) // -1 因为第一个位置是当前位置
{
TrajectoryPoint point = trajectoryPoints[i];
Vector2 startPos = (step == 0) ? point.pointTransform.anchoredPosition : movePaths[i][step];
Vector2 targetPos = movePaths[i][step + 1];
if (Vector2.Distance(startPos, targetPos) > 0.1f)
{
if (enableDebug) Debug.Log($"Moving point {i} from {startPos} to {targetPos}");
Coroutine coroutine = StartCoroutine(MoveSinglePoint(point, startPos, targetPos, i));
moveCoroutines.Add(coroutine);
anyPointMoved = true;
}
else
{
if (enableDebug) Debug.Log($"Point {i} already at target position, skipping move");
}
}
}
// 等待所有移动完成
foreach (Coroutine coroutine in moveCoroutines)
{
yield return coroutine;
}
if (anyPointMoved)
{
// 等待一小段时间让移动更明显
yield return new WaitForSeconds(0.1f);
}
}
// 更新所有点的当前位置记录
UpdatePointsCurrentPositions();
if (enableDebug)
{
Debug.Log("Sequential movement completed");
LogCurrentPositions();
}
isMoving = false;
}
IEnumerator MoveSinglePoint(TrajectoryPoint point, Vector2 startPos, Vector2 targetPos, int pointIndex)
{
float elapsedTime = 0f;
while (elapsedTime < movementDuration)
{
elapsedTime += Time.deltaTime;
float t = movementCurve.Evaluate(elapsedTime / movementDuration);
Vector2 newPosition = CalculateSmoothPosition(
startPos,
targetPos,
t,
pointIndex,
trajectoryPoints.Count
);
point.pointTransform.anchoredPosition = newPosition;
yield return null;
}
// 确保最终位置准确
point.pointTransform.anchoredPosition = targetPos;
}
MovementDirection CalculateMovementDirectionByIntermediatePoints(int clickedIndex)
{
if (trajectoryPoints.Count <= 2) return MovementDirection.Clockwise;
// 计算顺时针方向的中间点数量从点击点到0号位置的路径
int clockwiseIntermediatePoints = clickedIndex - 1;
if (clockwiseIntermediatePoints < 0) clockwiseIntermediatePoints = 0;
// 计算逆时针方向的中间点数量从点击点到0号位置的路径
int counterClockwiseIntermediatePoints = trajectoryPoints.Count - clickedIndex - 1;
if (counterClockwiseIntermediatePoints < 0) counterClockwiseIntermediatePoints = 0;
if (enableDebug) Debug.Log($"Clockwise intermediate points: {clockwiseIntermediatePoints}, CounterClockwise: {counterClockwiseIntermediatePoints}");
// 优选顺时针,中间点数量相同时选择顺时针
if (clockwiseIntermediatePoints <= counterClockwiseIntermediatePoints)
return MovementDirection.Clockwise;
else
return MovementDirection.CounterClockwise;
}
int[] CalculateTargetIndices(int clickedIndex, MovementDirection direction)
{
int[] targetIndices = new int[trajectoryPoints.Count];
int pointCount = trajectoryPoints.Count;
for (int i = 0; i < pointCount; i++)
{
if (direction == MovementDirection.Clockwise)
{
// 顺时针移动所有点向前移动clickedIndex个位置
// 点击的点会移动到0号位置
targetIndices[i] = (i - clickedIndex + pointCount) % pointCount;
}
else
{
// 逆时针移动:所有点向后移动(pointCount - clickedIndex)个位置
// 点击的点会移动到0号位置
targetIndices[i] = (i + (pointCount - clickedIndex)) % pointCount;
}
}
return targetIndices;
}
List<Vector2> CalculateMovePath(int currentIndex, int targetIndex)
{
List<Vector2> path = new List<Vector2>();
// 起始位置(当前位置)
path.Add(trajectoryPoints[currentIndex].currentPosition);
// 如果已经在目标位置,直接返回
if (currentIndex == targetIndex &&
Vector2.Distance(trajectoryPoints[currentIndex].currentPosition, trajectoryPoints[targetIndex].initialPosition) < 0.1f)
{
return path;
}
// 目标位置(使用对应索引的初始位置)
Vector2 targetPosition = trajectoryPoints[targetIndex].initialPosition;
path.Add(targetPosition);
return path;
}
Vector2 CalculateSmoothPosition(Vector2 start, Vector2 end, float t, int pointIndex, int totalPoints)
{
// 基础线性插值
Vector2 basePosition = Vector2.Lerp(start, end, t);
// 添加弧度效果
if (curveHeight > 0)
{
float arcFactor = Mathf.Sin(t * Mathf.PI) * curveHeight;
// 根据点在序列中的位置调整弧线方向
float pointWeight = (float)pointIndex / totalPoints;
Vector2 arcDirection = (end - start).normalized;
// 计算垂直方向(确保有弧度效果)
Vector2 perpendicular = new Vector2(-arcDirection.y, arcDirection.x);
// 应用弧线偏移
Vector2 arcOffset = perpendicular * arcFactor * pointWeight;
return basePosition + arcOffset;
}
return basePosition;
}
void UpdatePointsCurrentPositions()
{
foreach (TrajectoryPoint point in trajectoryPoints)
{
point.currentPosition = point.pointTransform.anchoredPosition;
}
}
void LogCurrentPositions()
{
Debug.Log("Current positions:");
foreach (TrajectoryPoint point in trajectoryPoints)
{
bool atTarget = Vector2.Distance(point.currentPosition, fixedTargetPosition) < 0.1f;
Debug.Log($" Point {point.index}: {point.currentPosition} (Initial: {point.initialPosition}) [At Target: {atTarget}]");
}
Debug.Log($"Fixed target position: {fixedTargetPosition}");
}
[ContextMenu("Refresh Points")]
void RefreshPoints()
{
// 获取所有直接子对象
List<RectTransform> tempList = new List<RectTransform>();
foreach (Transform child in transform)
{
RectTransform rt = child.GetComponent<RectTransform>();
if (rt != null)
{
tempList.Add(rt);
}
}
points = tempList.ToArray();
InitializePoints();
Debug.Log($"Refreshed points: found {trajectoryPoints.Count} trajectory points");
}
[ContextMenu("Reset to Initial Positions")]
void ResetToInitialPositions()
{
if (isMoving) return;
foreach (TrajectoryPoint point in trajectoryPoints)
{
if (point.pointTransform != null)
{
point.pointTransform.anchoredPosition = point.initialPosition;
point.currentPosition = point.initialPosition;
}
}
Debug.Log("Reset all points to initial positions");
}
[ContextMenu("Move Point 0 Away From Target")]
void MovePoint0AwayFromTarget()
{
if (trajectoryPoints.Count > 0 && !isMoving)
{
// 将0号点移动到远离目标位置的位置用于测试
Vector2 newPosition = trajectoryPoints[0].currentPosition + new Vector2(100, 100);
trajectoryPoints[0].pointTransform.anchoredPosition = newPosition;
trajectoryPoints[0].currentPosition = newPosition;
Debug.Log($"Moved point 0 away from target: {newPosition}");
}
}
[ContextMenu("Test Movement - Point 0")]
void TestMovement0()
{
if (!isMoving && trajectoryPoints.Count > 0)
{
OnClickItem(0);
}
}
[ContextMenu("Test Movement - Point 1")]
void TestMovement1()
{
if (!isMoving && trajectoryPoints.Count > 1)
{
OnClickItem(1);
}
}
[ContextMenu("Test Movement - Last Point")]
void TestMovementLast()
{
if (!isMoving && trajectoryPoints.Count > 1)
{
OnClickItem(trajectoryPoints.Count - 1);
}
}
[ContextMenu("Check All Points Target Status")]
void CheckAllPointsTargetStatus()
{
Debug.Log("=== All Points Target Status ===");
for (int i = 0; i < trajectoryPoints.Count; i++)
{
bool atTarget = IsPointAtTargetPosition(i);
Debug.Log($"Point {i}: At Target = {atTarget}, Position = {trajectoryPoints[i].currentPosition}");
}
}
enum MovementDirection
{
Clockwise,
CounterClockwise
}
}