Unity Уничтожающие объекты и их списки объектов - PullRequest
0 голосов
/ 26 февраля 2019

Я пытаюсь уничтожить многие объекты со списками объектов, которые тоже нужно уничтожить

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, но я не имею ни малейшего понятия, что это будет за

как бы удалить много объектов со списками, которые содержат больше объектов, которые нужно уничтожить?

1 Ответ

0 голосов
/ 26 февраля 2019

Проблема в том, что ваши Ball объекты сталкиваются друг с другом

=> поэтому Ball1 находится в списке Ball2, а наоборот

=> таксообщение DestroySameColor перебрасывается между ними, потому что они запускают 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);
}

Затем в часть уничтожения

  1. Сделать весь процесс уничтожения обработанным только одним единственным объектом.Поэтому убедитесь, что DestroySameColorColliding вызывается только одним мячом!
  2. Перед тем, как что-либо уничтожить, соберите все объекты, которые нужно уничтожить, в один список, чтобы убедиться, что нет двойников или неожиданностей - особенно убедитесь, что один главныйобъекта нет в списке
  3. уничтожить все объекты в списке
  4. уничтожить основной объект как последний

В целом что-то вроде этого

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);
    }
}
...