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键时,它正在破坏Instantiated对象,然后再次Instantiate is并再次启动协程。问题是,当我连续两次按下R键多次后,我在编辑器中得到MissingReferenceException异常:
MissingReferenceException:类型为"GameObject"的对象已被销毁,但您仍试图访问它。您的脚本应该检查它是否为空,或者您不应该销毁该对象。GenerateWalls + d__12。MoveNext () (at 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;
}
}