1

I made a script that makes an array of all the cubes in the current scene:

public GameObject[] allCubes; 

void Awake()
{
    allCubes = GameObject.FindGameObjectsWithTag("cube");
}

The problem is that the array looks like this in the inspector:

https://i.gyazo.com/69f2f844183fe6e592e61c1517267da1.png

I already try to do this:

public GameObject[] allCubes; 

void Awake()
{
    allCubes = GameObject.FindGameObjectsWithTag("cube");
    Array.Sort (allCubes);
}

However, this gives me an error:

InvalidOperationException: No IComparable or IComparable<UnityEngine.GameObject> interface found.
System.Array.compare[GameObject] (UnityEngine.GameObject value1, UnityEngine.GameObject value2, IComparer`1 comparer) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Array.cs:1756)
System.Array.qsort[GameObject,GameObject] (UnityEngine.GameObject[] keys, UnityEngine.GameObject[] items, Int32 low0, Int32 high0, IComparer`1 comparer) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/Array.cs:1722)
System.Array.Sort[GameObject,GameObject] (UnityEngine.GameObject[] keys, UnityEngine.GameObject[] items, Int32 index, Int32 length, IComparer`1 comparer) (at

What should I do?

Programmer
  • 121,791
  • 22
  • 236
  • 328
J.K. Harthoorn
  • 218
  • 1
  • 3
  • 19

2 Answers2

0

You don't say wich parameter you want to use to sort cubes

this the code to compare by name using Array.Sort:

class GameObjectComparerByName : IComparer<GameObject> {
 int IComparer<GameObject>.Compare(GameObject x, GameObject y)
{
     return string.Compare(x.name, y.name);  
} 

And use anywhere:

Array.Sort(allCubes,new GameObjectComparer ());

Explanation:

To the Array.Sort method works it must implement the IComparable<UnityEngine.GameObject> interface C# compiler dosen't know whow to compare two cubes object that are instance of GameObject and throw the exception.

Example:

   class Testy {
    private int bla;        
    public int Bla
    {
        get { return bla; }
        set { bla = value; }
    }
    public Testy(int bla )
    {
        this.bla = bla;
    }
}

The compiler dosen't know how to interpret x>y or x<=y etc... when x,y are two object of the example class Testy, but you implement the interface of IComparer

class TestyComparer : IComparer<Testy> {


    int IComparer<Testy>.Compare(Testy x, Testy y)
    {
        if (x.Bla == y.Bla)
        {
            return 0;
        }
        else if (x.Bla > y.Bla)
        {
            return 1;
        }
        else // (x.Bla < y.Bla)
        {
            return -1;
        }
        //all lines works equals than:
        //return x.Bla < y.Bla
    }
}

and now you can use Array.Sort(testyArray, new TestyComparer());

In your case implements

 class GameObjectComparer : IComparer<GameObject> {
     int IComparer<GameObject>.Compare(GameObject x, GameObject y)
    {
       //Compare the two cubes here
       //By the parameter you want to use to sor them (volume, proximity etc..)
         /*
            return <=-1;//Less
            return 0;//Equals
            return >=1;//Greather
         */        
    }

and do

Array.Sort(allCubes,new GameObjectComparer ());

If you use .Net 4.5 or add extra classes you can use a lambda for the Comparer interface see this post Using lambda expression in place of IComparer argument

Rolando Corratge Nieves
  • 1,233
  • 2
  • 10
  • 25
0

From the screenshot you provided, the string contains int values too. You need an alphanumeric sort. There is AlphanumComparatorFast made by dotnetperls that I use and recommend. See below for the slightly modified version that can be used for this.

public GameObject[] allCubes;

void Awake()
{
    allCubes = GameObject.FindGameObjectsWithTag("cube");
    allCubes = allCubes.OrderBy(obj => obj.name, new AlphanumComparatorFast()).ToArray();
}

Here is the modified version of the AlphanumComparatorFast class:

public class AlphanumComparatorFast : IComparer<string>
{
    public int Compare(string x, string y)
    {
        string s1 = x as string;
        if (s1 == null)
        {
            return 0;
        }
        string s2 = y as string;
        if (s2 == null)
        {
            return 0;
        }

        int len1 = s1.Length;
        int len2 = s2.Length;
        int marker1 = 0;
        int marker2 = 0;

        // Walk through two the strings with two markers.
        while (marker1 < len1 && marker2 < len2)
        {
            char ch1 = s1[marker1];
            char ch2 = s2[marker2];

            // Some buffers we can build up characters in for each chunk.
            char[] space1 = new char[len1];
            int loc1 = 0;
            char[] space2 = new char[len2];
            int loc2 = 0;

            // Walk through all following characters that are digits or
            // characters in BOTH strings starting at the appropriate marker.
            // Collect char arrays.
            do
            {
                space1[loc1++] = ch1;
                marker1++;

                if (marker1 < len1)
                {
                    ch1 = s1[marker1];
                }
                else
                {
                    break;
                }
            } while (char.IsDigit(ch1) == char.IsDigit(space1[0]));

            do
            {
                space2[loc2++] = ch2;
                marker2++;

                if (marker2 < len2)
                {
                    ch2 = s2[marker2];
                }
                else
                {
                    break;
                }
            } while (char.IsDigit(ch2) == char.IsDigit(space2[0]));

            // If we have collected numbers, compare them numerically.
            // Otherwise, if we have strings, compare them alphabetically.
            string str1 = new string(space1);
            string str2 = new string(space2);

            int result;

            if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
            {
                int thisNumericChunk = int.Parse(str1);
                int thatNumericChunk = int.Parse(str2);
                result = thisNumericChunk.CompareTo(thatNumericChunk);
            }
            else
            {
                result = str1.CompareTo(str2);
            }

            if (result != 0)
            {
                return result;
            }
        }
        return len1 - len2;
    }
}

Don't forget to import System.Linq; with using System.Linq;


For sorting strings without numerals you can just simply use:

public GameObject[] allCubes;

void Awake()
{
    allCubes = GameObject.FindGameObjectsWithTag("cube").OrderBy(go => go.name).ToArray();
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Wow that is some complicated stuff, but thanks a lot, it works perfectly! – J.K. Harthoorn Jul 25 '17 at 10:57
  • little question: is there a way to find out at what number the current object in the array is? I added this script to all the cubes, so is there a way that if I put some code in the script it will return the position of that gameobject in the array list? For example if I debug Cube5, it will return: "My position in the array is 4'' (as you can see in this picture: https://i.gyazo.com/0dd2c9fdf8e07f9f971cd074695fc061.png) – J.K. Harthoorn Jul 25 '17 at 14:09
  • It's a long function but possible do to. Create a new question with what you have tried and I will provide an answer. – Programmer Jul 25 '17 at 14:13