我正在尝试销毁许多对象,这些对象也需要销毁。
public class Ball : MonoBehaviour
{
List<Transform> collidesColor = new List<Transform>();
//is Colding?
void OnCollisionEnter(Collision c)
{
if (c.transform.GetComponent<Renderer>() && c.transform.GetComponent<Renderer>().material.color == GetComponent<Renderer>().material.color)
{
collidesColor.Add(c.transform);
}
}
void OnCollisionExit(Collision c)
{
collidesColor.Remove(c.transform);
}
//gave stack overflow errors
//is mostly deleted
/*void DestroySameColor()
{
foreach (Transform t in collides)
{
if (t != null && t.GetComponent<Renderer>() && t.GetComponent<Renderer>().material.color == GetComponent<Renderer>().material.color)
{
t.SendMessage("DestroySameColor");
}
}
Destroy(gameObject);
}*/
//froze unity
/*IEnumerator*/ void OnMouseDown()
{
//Instantiate(ball, new Vector3Int(Random.Range(-6, 6), 75, Random.Range(1, 13)), Quaternion.identity);
for (var j = 0; j < collidesColor.Count; j++)
{
for (var i = 0; i < collidesColor[j].GetComponent<Ball>().collidesColor.Count; i++)
{
if (collidesColor[j].GetComponent<Ball>().collidesColor[i]==null || collidesColor.Contains(collidesColor[j].GetComponent<Ball>().collidesColor[i]))
{
collidesColor[j].GetComponent<Ball>().collidesColor.RemoveAt(i);
i--;
}
//yield return null;
}
collidesColor.AddRange(collidesColor[j].GetComponent<Ball>().collidesColor);
Destroy(collidesColor[j].gameObject);
j--;
//yield return null;
}
Destroy(gameObject);
}
}
我已经尝试过递归算法,但是出现堆栈溢出错误。 DestroySameColors()是残缺的部分。我还尝试获取每个对象列表并将其添加到一个巨大的列表中,但是这冻结了团结并使其成为无法生存的选择
我不确定其算法或编程执行是否错误。他们都可能有缺陷
我也很确定此算法有一个魔术关键字或名称,它将在Google上解锁许多答案,但我不知道这些答案是什么
我将如何删除列表中包含需要销毁更多对象的许多对象?
答案 0 :(得分:2)
问题是您的Ball
对象彼此碰撞
=>所以Ball1
在Ball2
的列表中,反之亦然
=>因此消息DestroySameColor
在它们之间来回ping通,因为它们运行的是foreach,其中包括最初产生整个调用的组件……直到到达StackOverflow。
首先,我实际上会向enum
组件本身添加一个适当的Ball
颜色字段,并且从一开始就只收集那些具有相同颜色的碰撞,例如
//all the colours you have
public enum BallColor
{
Blue,
Red,
// ...
}
public class Ball: MonoBehaviour
{
// set this in the inspector or while instantiating etc
public BallColor color;
//...
}
那么您现在就可以做
void OnCollisionEnter(Collision c)
{
var ball = c.gameObject.GetComponent<Ball>();
// if no Ball component or different color ignore
if (!ball || ball.color != color) return;
// skip if already contains this ball
if(collidingBalls.Contains(ball)) return;
// ad to list
collidingBalls.Add(ball);
}
void OnCollisionExit(Collision c)
{
var ball = c.gameObject.GetComponent<Ball>();
// if no Ball component ignore
if (!ball) return;
// if not contains ignore
if(!collidingBalls.Contains(ball)) return;
// remove from the list
collidingBalls.Remove(ball);
}
然后到破坏部分
DestroySameColorColliding
被一个球调用!总共是这样的
public class Ball: MonoBehaviour
{
//all the colors you have
public enum BallColor
{
Blue,
Red,
// ...
}
private readonly List<Ball> _collidingBalls = new List<Ball>();
// set this in the inspector or while instantiating etc
public BallColor Color;
private IEnumerable<Ball> GatherSubcollidingBalls(List<Ball> ignoreThose)
{
var output = new List<Ball>();
// add yourself to the ignored list
var newIgnoreThose = ignoreThose;
newIgnoreThose.Add(this);
// filter out only references that are not in ignoreThose
var withoutIgnored = _collidingBalls.Except(ignoreThose);
// add the filtered references to the output
output.AddRange(withoutIgnored);
// iterate your collidingBalls but ignore the once from ignoreThose
foreach (var ball in _collidingBalls.Except(ignoreThose))
{
// get this balls collisions ignoring the newIgnoreThose
var coll = ball.GatherSubcollidingBalls(newIgnoreThose);
// filter out only Ball references that are not in output already
var filtered = coll.Except(output).ToList();
// especially remove this reference which is the main object of the call
if (filtered.Contains(this)) filtered.Remove(this);
// add the filtered objects
output.AddRange(filtered);
}
return output;
}
private void OnCollisionEnter(Collision c)
{
var ball = c.gameObject.GetComponent<Ball>();
// if no Ball component or different color ignore
if (!ball || ball.Color != Color) return;
// skip if already contains this ball
if (_collidingBalls.Contains(ball)) return;
// ad to list
_collidingBalls.Add(ball);
}
private void OnCollisionExit(Collision c)
{
var ball = c.gameObject.GetComponent<Ball>();
// if no Ball component ignore
if (!ball) return;
// if not contains ignore
if (!_collidingBalls.Contains(ball)) return;
// remove from the list
_collidingBalls.Remove(ball);
}
public void DestroySameColorColliding()
{
// get all collisions ignoring yourself
var toDestroy = GatherSubcollidingBalls(new List<Ball> { this });
// destroy all other objects of the same color and in same collision chain
foreach (var ball in toDestroy)
{
Destroy(ball.gameObject);
}
// finally destroy yourself
Destroy(gameObject);
}
}