You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity双Line Renderer协程同时运行失效问题求助

Unity鼠标绘制线条异常:多线条同时消失问题及解决方法

我是编程新手,正在用C#开发Unity游戏,需求是实现鼠标绘制线条,线条会在1.5秒后从起点到终点逐步自动消失。脚本单独运行时功能正常,但当第一条线条正在消失过程中绘制第二条,两条线条会突然同时消失。

创建线条的核心代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Threading.Tasks;

public class LineDraw : MonoBehaviour
{
    public GameObject linePrefab;
    public GameObject currentLine;

    public LineRenderer lineRenderer;
    public EdgeCollider2D edgeCollider;
    public List<Vector2> fingerPositions;
    public List<GameObject> currentLines;

    public int testenum = 1;

    private IEnumerator coroutineErase;


    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            CreateLine();
        }
        if(Input.GetMouseButton(0))
        {
            Vector2 tempFingerPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            if(Vector2.Distance(tempFingerPos, fingerPositions[fingerPositions.Count - 1]) > .1f)
            {
                UpdateLine(tempFingerPos);
            }
        }
    }

    void CreateLine()
    {
        currentLine = Instantiate(linePrefab, Vector3.zero, Quaternion.identity);
        currentLine.name = "line number "+testnum;
        testnum++;

        lineRenderer = currentLine.GetComponent<LineRenderer>();
        edgeCollider = currentLine.GetComponent<EdgeCollider2D>();
        fingerPositions.Clear();
        fingerPositions.Add(Camera.main.ScreenToWorldPoint(Input.mousePosition));
        fingerPositions.Add(Camera.main.ScreenToWorldPoint(Input.mousePosition));
        lineRenderer.SetPosition(0, fingerPositions[0]);
        lineRenderer.SetPosition(1, fingerPositions[1]);
        edgeCollider.points = fingerPositions.ToArray();

        currentLines.Add(currentLine);
        int lineListPos = currentLines.IndexOf(currentLine);

        //Test with async function:
        //EraseLine2(fingerPositions, lineListPos);

        coroutineErase = EraseLine(fingerPositions, lineListPos);
        StartCoroutine(coroutineErase);

    }

    void UpdateLine(Vector2 newFingerPos)
    {
        fingerPositions.Add(newFingerPos);
        lineRenderer.positionCount++;
        lineRenderer.SetPosition(lineRenderer.positionCount - 1, newFingerPos);
        edgeCollider.points = fingerPositions.ToArray();
    }

[...]

}

尝试的两种线条擦除实现

协程版本

public IEnumerator EraseLine(List<Vector2> myPoints, int posListObj)
{
    
    yield return new WaitForSeconds(1.5f);
    LineRenderer line = currentLines[posListObj].GetComponent<LineRenderer>();
    EdgeCollider2D colisor = currentLines[posListObj].GetComponent<EdgeCollider2D>();
    int numPoints = myPoints.Count;
    while(true)
    {
       
        if(numPoints >= 1)
        {
            myPoints.RemoveAt(0);
            line.positionCount = myPoints.Count;
            for(int i = 0;i<myPoints.Count;i++){
                line.SetPosition(i,myPoints[i]); 
                colisor.points = myPoints.ToArray();   
            }

            numPoints = line.positionCount;
        }
        else
        {
            if (line != null)
            {
                line.positionCount = 0;
                Destroy(currentLines[posListObj]);
                //currentLines.RemoveAt(posListObj);
                StopCoroutine(coroutineErase);
            }
            
            
        }
        yield return new WaitForSeconds(0.02f);
    }
} 

异步版本

async void EraseLine2(List<Vector2> myPoints, int posListObj)
{
    CancellationTokenSource cancellationToken = new CancellationTokenSource();
    await Task.Delay(1500, cancellationToken.Token);

    try
    {
        LineRenderer line = currentLines[posListObj].GetComponent<LineRenderer>();
        EdgeCollider2D colisor = currentLines[posListObj].GetComponent<EdgeCollider2D>();
        int numPoints = myPoints.Count;
        while(true)
        {
       
            if(numPoints >= 1)
            {
                myPoints.RemoveAt(0);
                line.positionCount = myPoints.Count;
                for(int i = 0;i<myPoints.Count;i++){
                    line.SetPosition(i,myPoints[i]); 
                    colisor.points = myPoints.ToArray();   
                }

                numPoints = line.positionCount;
            }
            else
            {
                if (line != null)
                {
                    line.positionCount = 0;
                    Destroy(currentLines[posListObj]);
                    currentLines.RemoveAt(posListObj);
                }
            

                

            }
            await Task.Delay(20, cancellationToken.Token);
        }
    }
    catch
    {
        Debug.Log("Task was cancelled!");
        return;
    }
    finally
    {
        cancellationToken.Dispose();
        cancellationToken = null;
    }

}

我采用了线条列表并传入线条在列表中的位置,本以为能避免变量冲突,但问题仍未解决。我猜测问题出在擦除线条的代码中,求解决思路!


问题解决更新

在@derHugo的帮助下,我修改代码解决了问题。由于LineRenderer的GetPositions/SetPositions方法需要Vector3数组,而EdgeCollider2D的points属性是Vector2数组,因此需要同时处理两种类型的坐标列表,最终代码如下:

using System.Linq;

...

private IEnumerator EraseLine(LineRenderer line)
{   
    yield return new WaitForSeconds(1.5f);

    Vector3[] positionsv3 = new Vector3[line.positionCount];
    line.GetPositions(positionsv3);
    var pointsv3 = positionsv3.ToList(); 

    var positionsv2 = positionsv3.Select((v3) => (Vector2)v3).ToList();
    var pointsv2 = positionsv2.ToList(); 

    var colisor = line.GetComponent<EdgeCollider2D>();

    while(pointsv2.Count > 0)
    {   
        pointsv2.RemoveAt(0);
        pointsv3.RemoveAt(0);

        line.positionCount = pointsv2.Count;
        line.SetPositions(pointsv3.ToArray()); 
        colisor.points = pointsv2.ToArray();

        yield return new WaitForSeconds(0.02f); 
    }

    Destroy(line.gameObject);      
}

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 12:10:26