协程不能同时在两个线渲染器上工作

问题描述 投票:0回答:1

我对编码还很陌生,我正在用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;
    }

}

我选择了行列表(并将该行在列表中的位置传递给函数),因为我认为该函数可能会尝试访问已被第一行元素占用的变量,但它没有解决不了问题。 :(

我猜问题出在擦除该行的代码中,但我无法解决它。有谁知道我如何让它发挥作用?

谢谢!!!

c# unity-game-engine asynchronous coroutine unity3d-2dtools
1个回答
0
投票

您的问题是,

fingerPositions
列表对于您的所有线路来说似乎都是相同的实例。

此外,您使用传递的索引也有缺陷,因为在协同程序的一次执行过程中,列表的长度可能会在许多点发生变化。

相反,我会将所有相关信息作为参数传递到协程中,以便协程的一个实例处理与一行相关的所有内容。

例如

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

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

    while(points.Count > 0)
    {   
        points.RemoveAt(0);

        var pointsArray = points.ToArray();

        line.positionCount = points.Count;
        line.SetPositions(pointsArray); 
        colisor.points = pointsArray;  

        yield return new WaitForSeconds(0.02f); 
    }

    Destroy(line.gameObject);      
}

然后你只需传入

StartCoroutine(EraseLine(lineRenderer));
© www.soinside.com 2019 - 2024. All rights reserved.