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
相关产品推荐
相关产品推荐

