You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

逻辑说明

  1. 队列机制:不管用户点击速度多快,所有需要动画的线段都会加入队列,按顺序等待播放,不会出现动画重叠或乱序的问题。
  2. 状态控制isAnimating标记确保同一时间只有一个动画协程在运行,避免多个动画同时修改LineRenderer导致的混乱。
  3. 逐段生长:每一段动画只更新对应的LineRenderer位置,前一段的线段会保持固定,只有当前线段在生长,完美实现逐段播放的效果。
  4. 精度保障:动画结束后强制设置一次终点位置,避免因为Lerp的浮点精度问题导致线段没有完全到达目标点。

内容的提问来源于stack exchange,提问作者Saraphin34

火山引擎 最新活动