c# - 为什么一遍又一遍地启动协程时出现 MissingReferenceException 异常?
问题描述
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateWalls : MonoBehaviour
{
public GameObject gameObjectToRaise;
public float duration;
public Vector3 raiseAmount;
public bool go = false;
public Color[] colors = new Color[4];
public bool randomColors = false;
private GameObject objtoraise;
private GameObject[] walls;
private bool scaleOver = false;
private void Start()
{
Init();
ColorWalls();
// The z Axis must be minimum 1 or any value above 0 could be also 0.1f
// but it's better to keep it minimum as 1 by default.
if (raiseAmount.z < 1)
{
raiseAmount.z = 1f;
}
if (go)
{
StartCoroutine(ScaleOverSeconds(objtoraise, new Vector3(raiseAmount.x, raiseAmount.y,
raiseAmount.z), duration));
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
//if (scaleOver)
//{
if (objtoraise != null)
{
if (raiseAmount.z < 1)
{
raiseAmount.z = 1f;
}
Destroy(objtoraise);
Init();
ColorWalls();
StartCoroutine(ScaleOverSeconds(objtoraise, new Vector3(raiseAmount.x, raiseAmount.y,
raiseAmount.z), duration));
scaleOver = false;
//}
}
}
}
private void Init()
{
objtoraise = Instantiate(gameObjectToRaise);
objtoraise.name = "Walls";
walls = GameObject.FindGameObjectsWithTag("Wall");
}
public IEnumerator ScaleOverSeconds(GameObject objectToScale, Vector3 scaleTo, float seconds)
{
float elapsedTime = 0;
Vector3 startingScale = objectToScale.transform.localScale;
while (elapsedTime < seconds)
{
objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
elapsedTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
objectToScale.transform.localScale = scaleTo;
scaleOver = true;
}
private void ColorWalls()
{
for (int i = 0; i < walls.Length; i++)
{
if (randomColors)
{
walls[i].transform.GetChild(0).GetComponent<Renderer>().material.color
= GetRandomColour32();
}
else
{
walls[i].transform.GetChild(0).GetComponent<Renderer>().material.color = colors[i];
}
}
}
private Color32 GetRandomColour32()
{
//using Color32
return new Color32(
(byte)UnityEngine.Random.Range(0, 255), //Red
(byte)UnityEngine.Random.Range(0, 255), //Green
(byte)UnityEngine.Random.Range(0, 255), //Blue
255 //Alpha (transparency)
);
}
}
在 Update() 内部,当我按下 R 键时,它会破坏实例化对象,然后再次实例化并再次启动协程。问题是当我在两次之后连续多次按下 R 键时,我在编辑器中收到 MissingReferenceException 异常:
MissingReferenceException:“GameObject”类型的对象已被销毁,但您仍在尝试访问它。您的脚本应该检查它是否为空,或者您不应该销毁该对象。GenerateWalls+d__12.MoveNext () (在 Assets/Scripts/GenerateWalls.cs:81)
第 81 行是:
objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
目标是能够在每次按下 R 时再次生成墙,它应该停止当前的协程并重新开始。
也许问题是它在协程的中间,因为旧的协程还没有停止,所以对象在中间丢失了,因为我破坏了它?
那我应该怎么做才能一遍又一遍地按 R ,它会一遍又一遍地启动协程?不是启动多个协程,而是每次重新启动协程。
解决方案
解决方案是在 Update() 中添加: StopCoroutine
这不是解决方案。我认为停止协程也会停止内部的while循环,但它没有。似乎在 while 循环中检查 null 解决了这个问题:
public IEnumerator ScaleOverSeconds(GameObject objectToScale, Vector3 scaleTo, float seconds)
{
if (objectToScale != null)
{
float elapsedTime = 0;
Vector3 startingScale = objectToScale.transform.localScale;
while (elapsedTime < seconds)
{
if (objectToScale == null)
{
yield return null;
}
else
{
objectToScale.transform.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
elapsedTime += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
}
objectToScale.transform.localScale = scaleTo;
scaleOver = true;
}
}
推荐阅读
- node.js - 如何使用 sendgrid 检查节点 js 中是否存在电子邮件
- sql - How to union a data set with a specific rule
- c++ - 结束迭代器在非连续 C++ 容器中指向哪里?
- rust - 在谓词失败后,在迭代器中获取一个额外元素的规范方法是什么?
- codenameone - 标签内的视频
- mysql - 如何对某类商品进行打折?
- javascript - Amplify 使“加载资源失败:服务器响应状态为 400”错误
- c# - EF Core 5 - 为每个标识列添加 Alter ColumnStatements 的新迁移
- python - 在 Python OpenCV 中访问 IP 摄像机 Teledye
- spring-boot - Spring Boot + gcp datastore + datastore 模拟器获取 INVALID_ARGUMENT 遇到“OR”/“IN”