I can't find the problem in my script.

Hi, I’m working on a game similar to 3 stone match games. Mine is a little bit different. In this game, I have stones and birds. If a stone is colliding with 2 birds, those 3 objects gets destroyed and It’s not only just checking if it’s vertical or horizontal. It accepts both axis as long as a stone is colliding with 2 birds.

I have been working on this project for several weeks. I managed to overcome most of the issues I’ve faced (and managed to overcome some of them thanks to you guys.) Now there’s one more thing in my way and I can’t seem to find a way to deal with it.

When there are 2 stones that share the same birds like this :

Stones are brown, birds are blue

![Stones are brown, birds are blue][1]

4 objects gets deleted when only 3 of them are supposed to. I couldn’t find a single leak in my script and I have revised my script a thousand times. Here’s the script:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Stone2Birds : MonoBehaviour {

    bool access;
    List<GameObject> allObjs = new List<GameObject>();
    List<GameObject> allStones = new List<GameObject>();
    List<GameObject> stoneBirds = new List<GameObject>();

    void Permission(bool access)
    {
        this.access = access;
    }

    void Update()
    {
        if (access)
        {

            // ASSIGNS OBJECTS TO THEIR LISTS
            foreach (Collider col in Physics.OverlapSphere(new Vector3(2, 5, 0), 6.50f))
            {
                if (col.gameObject.tag == "Stone")
                {
                    allStones.Add(col.gameObject);
                }
            }

            // CHECKS EACH STONE
            for (int i = 0; i < allStones.Count; i++)
            {
                stoneBirds.Add(allStones*);*

for (int j = 0; j < allObjs.Count; j++)
{
if (allObjs[j].tag == “Bird”)
{
if (stoneBirds.Count < 3)
{
if (allObjs[j].transform.position.x - 1 == allStones_.transform.position.x && allObjs[j].transform.position.y == allStones*.transform.position.y)
{
stoneBirds.Add(allObjs[j]);
}*_

else if (allObjs[j].transform.position.x + 1 == allStones_.transform.position.x && allObjs[j].transform.position.y == allStones*.transform.position.y)
{
stoneBirds.Add(allObjs[j]);
}*_

else if (allObjs[j].transform.position.y - 1 == allStones_.transform.position.y && allObjs[j].transform.position.x == allStones*.transform.position.x)
{
stoneBirds.Add(allObjs[j]);
}*_

else if (allObjs[j].transform.position.y + 1 == allStones_.transform.position.y && allObjs[j].transform.position.x == allStones*.transform.position.x)
{
stoneBirds.Add(allObjs[j]);
}
}*_

* if (stoneBirds.Count == 3)*
* {*
* Destroy(stoneBirds[0]);*
* Destroy(stoneBirds[1]);*
* Destroy(stoneBirds[2]);*
* }*

}
}
stoneBirds.Clear();
}
allStones.Clear();
allObjs.Clear();
}
}
}
Thanks for reading.
[1]: http://i1063.photobucket.com/albums/t517/NikkiTheNikolai/image_zps5b6591c9.png?t=1391177608

Your problem is the following:

The script goes through all stones and for each stone it seeks two adjacent birds. Then it destroys all objects.

But be aware that the “Destroy” function just marks the objects for destruction, AFTER the whole script is through. This means that the script will continue for the second stone and all objects are still in place, so the second stone will also find two birds adjacent (there are in fact three, but your script stops after finding two), so these objects are also marked.

Result: After your script is done both stones and two birds are marked as destroyed.

Possible solution to the problem: Introduce a boolean variable (“destroyed”) initially set to false. After the first finding of a match set it to true and then use it to not look further (in the loop only check for birds if destroyed is false). This way you can be sure that you only destroy three objects and won’t look further.

First off, nice play on the old phrase! That’s pretty funny, makes me want to play it just because of that. Second, if you renamed stoneBirds to stonedBirds, that would also be funny.

But let’s get serious. :slight_smile: I think you need to remove the destroyed birds from stoneBirds when you destroy them, unless I’m missing something in the code. Also, or maybe the real problem, each list is of type List, so you may end up adding a stone twice or a bird twice to a list when you only want to add it once. You can use a HashSet instead that will ignore it if you call Add() with the same object, if it already exists in the set.

As requested, I’ve made this an answer!

if (stoneBirds.Count == 3){
    Destroy(stoneBirds[0]);
    Destroy(stoneBirds[1]);
    Destroy(stoneBirds[2]);
    break;
}

the break function stops the first encasing for loop, therefore only going through this if statement once (hopefully).

I’m still worried that it may be breaking something else as the break will also stop:

if (stoneBirds.Count < 3)

from being called. So make sure you do some testing before accepting my answer!

Also it may be that you have misunderstood @supernat’s answer. When you call

Destroy(stoneBirds[0]);

It doesn’t remove it from your list, it only destroys the object in game world. Therefore other stones can still be touching the ‘destroyed’ stoneBird. If you were to remove the stoneBird from the list when its destroyed then no further stones could be found to be adjacent to it, which feels like a ‘safer’ practice than my suggestion.

Anyway, good luck with your project!

Scribe