Dictionary with Vector3 as key cannot be child gameobjects

It appears that there are weird rounding errors if there is a dictionary with keys being Vector3 representing positions of gameobjects that are children of another gameobject.

For such a situation, when you need to check if a hit gameobject is in the dictionary (by position), is there another solution other than to de-parent?


Steps:

  1. Create some pooled gameobjects that are children of a parent object.
  2. Loop through parent transform GetChild to get child objects, and assign each child objet’s position as key to the dictionary
  3. Try a raycasthit on any of the child gameobject positions, to see if they are in the dictionary. None will show up!

But, the above works as expected if they are not parented.

if you are in situation where you need a dictionary with Keys as Vector3

then, you can create a dictionary with a custom IEqualityComparer:

class Vector3CoordComparer : IEqualityComparer<Vector3> {
    public bool Equals(Vector3 a, Vector3 b) {
       if (Mathf.Abs(a.x - b.x) > 0.001) return false;
       if (Mathf.Abs(a.y - b.y) > 0.001) return false;
       if (Mathf.Abs(a.z - b.z) > 0.001) return false;

        return true; //indeed, very close
    }

    public int GetHashCode(Vector3 obj) {
        //a cruder than default comparison, allows to compare very close-vector3's into same hash-code.
        return Math.Round(obj.x, 3).GetHashCode() 
             ^ Math.Round(obj.y, 3).GetHashCode() << 2 
             ^ Math.Round(obj.z, 3).GetHashCode() >> 2;
    }

}

public static Vector3CoordComparer  _customComparer = new Vector3CoordComparer ();
public Dictionary<Vector3, someValues> coord_to_values = new Dictionary(_customComparer); //notice, the argument

I guess the problem might be related to float numbers rounding, e.g. the Vector3 which is a key might be (1,1,1), while the vector you’re using to retrieve value might be (1,1,0.99999999999999999). When checking for existence of key (dic.ContainsKey(key)), or when retrieving value by key (dic[key]), Equals(object) method is used, which checks if x, y, and z are exactly the same.

Depending on the number of children, you can try iterating through dictionary, checking keys for equality using == operator. This operator for Vector3 is overloaded, so if two vectors differs slightly, they are treated as equal.