Unity中按顺序点击多点时Line Renderer逐段动画的实现问题咨询
解决方案:逐段依次播放连线动画(支持点击排队)
看起来你现在的核心问题是连线动画没办法按顺序逐段播放,而且用户点击速度快的时候会出现动画混乱对吧?我帮你调整代码逻辑,核心思路是用动画任务队列+状态标记来控制每一段动画的执行顺序,确保前一段播放完成后才会启动下一段。
核心修改点
- 新增动画队列,存储所有等待播放的线段(起点+终点)
- 用
isAnimating标记当前是否有动画在运行,避免同时执行多个动画 - 重写动画逻辑,每次从队列取一段播放,完成后再处理下一段
- 调整LineRenderer的更新方式,只更新当前动画的线段位置,实现逐段生长
修改后的完整代码
首先添加需要的变量:
[SerializeField] private float animationDuration = 3f; private LineRenderer lineRenderer; public Transform lastPoints; public List<Transform> points = new List<Transform>(); // 新增:动画任务队列,存储每一段需要动画的线段(起点坐标+终点坐标) private Queue<(Vector3 start, Vector3 end)> lineAnimationQueue = new Queue<(Vector3, Vector3)>(); // 新增:标记当前是否有动画在播放,避免同时执行多个协程 private bool isAnimating = false;
然后修改MakeLine方法,负责添加点并将新线段加入队列:
private void Awake() { lineRenderer = GetComponent<LineRenderer>(); // 初始化LineRenderer状态 lineRenderer.enabled = false; lineRenderer.positionCount = 0; } public void MakeLine(Transform finalPoint) { if (lastPoints == null) { // 处理第一个点 lastPoints = finalPoint; points.Add(lastPoints); lineRenderer.enabled = true; lineRenderer.positionCount = 1; lineRenderer.SetPosition(0, lastPoints.position); } else { // 添加新点到列表 points.Add(finalPoint); // 更新LineRenderer的总点数,先把终点的最终位置设置好 lineRenderer.positionCount = points.Count; lineRenderer.SetPosition(points.Count - 1, finalPoint.position); // 将这段新的线段(上一个点到当前点)加入动画队列 lineAnimationQueue.Enqueue((lastPoints.position, finalPoint.position)); lastPoints = finalPoint; // 如果当前没有动画在播放,启动队列处理协程 if (!isAnimating) { StartCoroutine(ProcessAnimationQueue()); } } }
重写动画协程,改成逐段处理队列的版本:
// 处理动画队列的协程,逐段播放线段动画 private IEnumerator ProcessAnimationQueue() { isAnimating = true; // 只要队列里有任务,就循环处理 while (lineAnimationQueue.Count > 0) { var currentSegment = lineAnimationQueue.Dequeue(); Vector3 startPos = currentSegment.start; Vector3 endPos = currentSegment.end; float startTime = Time.time; // 计算当前要更新的LineRenderer位置索引(当前线段的终点索引) int targetIndex = points.Count - lineAnimationQueue.Count - 1; // 播放当前线段的生长动画 while (Time.time - startTime < animationDuration) { float t = (Time.time - startTime) / animationDuration; Vector3 currentPos = Vector3.Lerp(startPos, endPos, t); // 只更新当前线段的终点位置,实现逐段生长 lineRenderer.SetPosition(targetIndex, currentPos); yield return null; } // 动画结束后,强制设置到准确的终点位置,避免插值精度问题 lineRenderer.SetPosition(targetIndex, endPos); } // 所有动画完成后,标记为未在动画状态 isAnimating = false; }
你的点击处理逻辑可以保留,只要确保选中正确的点后调用MakeLine即可:
// 处理鼠标点击的相关代码 private void CheckClickDownEvent() { if (Input.GetMouseButtonDown(0)) { var selectedObject = RaycastObject(); if(selectedObject != null) { OnObjectSelect?.Invoke(selectedObject); } } } private void HandlePointSelect(GameObject selectedPoint) { if (spawner.points.IndexOf(selectedPoint) == 0) { selectedPoint.GetComponent<PointScript>().SelectPoint(); spawner.points.Remove(selectedPoint); lineAnimator.MakeLine(selectedPoint.transform); } }
逻辑说明
- 队列机制:不管用户点击速度多快,所有需要动画的线段都会加入队列,按顺序等待播放,不会出现动画重叠或乱序的问题。
- 状态控制:
isAnimating标记确保同一时间只有一个动画协程在运行,避免多个动画同时修改LineRenderer导致的混乱。 - 逐段生长:每一段动画只更新对应的LineRenderer位置,前一段的线段会保持固定,只有当前线段在生长,完美实现逐段播放的效果。
- 精度保障:动画结束后强制设置一次终点位置,避免因为Lerp的浮点精度问题导致线段没有完全到达目标点。
内容的提问来源于stack exchange,提问作者Saraphin34




