我对编码还很陌生,我正在用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;
}
}
我选择了行列表(并将该行在列表中的位置传递给函数),因为我认为该函数可能会尝试访问已被第一行元素占用的变量,但它没有解决不了问题。 :(
我猜问题出在擦除该行的代码中,但我无法解决它。有谁知道我如何让它发挥作用?
谢谢!!!
您的问题是,
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));