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

466 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}
}