Accessing instances of a component efficiently

Issue:

I’d like to have a static field inside a component. I’m trying to figure out if this is going to come back to bite me.

The use case is that I have a component, called Graspable, and a related component called Grasper. Each Graspable instance has a field for a Collider, which I assign in the editor.

Instances of Grasper monitor the collision system by calling Physics.OverlapSphere. When a Grasper detects a Collider nearby, I want it to find the Graspable instance (if any) which is associated with that Collider.

It occurred to me I could maintain a static associative table in Graspable, with Colliders as keys and Graspables as values. Graspable objects can add themselves to the table, and Graspers can use the table to find the Graspable associated with any given Collider. This method would allow me to relate any Graspable to any Collider. I could potentially use a data structure like a hash table to make these lookups efficient.

I am clueless about what problems this is going to create. I just know that using static fields is tricky. Can anybody help me understand whether this is a good idea, and whether I have any other options? I haven’t found another solution that doesn’t involve some sort of static or singleton entity, and this seems to be the most elegant solution I’ve found.

Why I don’t want to use GetComponent:

Here is an example of a reason I don’t want to use GetComponent. The GetComponent family of functions can only obtain components on the same GameObject, or on children or parents of that GameObject. I want to be able to make objects with this structure in the transform hierarchy:

GameObject parent(Graspable, Transform, etc.)
    GameObject child1(Collider, Transform)
    GameObject child2(Collider, Transform)
    GameObject child3(Collider, Transform)

I only want one of the Colliders on the children to be associated with the Graspable component on the parent. To achieve this with GetComponent, I will need to search up the tree with GetComponentInParent, then check the collider field in the Graspable component to see if it matches the collider I’m checking. This means that if there are lots of colliders in close proximity I will be calling GetComponentInParent several times. I don’t want to waste time searching through trees that don’t contain Graspables, which is why I want the relation between a Collider and a Graspable to be efficiently queriable. While I might be able to solve this problem using layer masks, there are a limited number of layers available and I could imagine needing many different systems using this type of functionality.

While I’m unclear on a few points, I’m certain there are several options to consider, and using a Dictionary isn’t a bad one. I sense another is slightly better, but that requires a few assumptions about those points on which I’m not entirely clear.


One point I’m not certain about is why only one child collider is to be associated with the parent Graspable, when the hierarchy you list shows a Graspable with three child GameObjects each with a collider component. OverlapSphere will return possibly all 3 of these children, or whatever combination fits in or on the sphere, and perhaps what you require is that only 1 notification is processed on the parent Graspable. Still, for a Dictionary, it would seem to me that all 3 must be keyed (lest two colliders would never be found on lookup). As I said, this is a point upon which I’m unclear, but that may not matter if the following is applicable to you.


The collider(s) given from a call to OverlapSphere each have a gameObject property, from which the transform provides the parent property, which should provide the GameObect instance owning the Graspable component (given the hierarchy you’ve illustrated), from which you could call GetComponent for the Graspable Monobehaviour derivative that parent owns. While that plan does utilize GetComponent, it is directly on the owning GameObject and therefore doesn’t search far and wide through a hierarchy. For example (exaggerated pseudo code):

foreach( Collider c in colliders_from_overlap_sphere )
  {
   GameObject obj_child = c.gameObject;
   Transform obj_child_transform = obj_child.transform;
   GameObject parent_owning_graspable = obj_child_transform.parent;

   Graspable g = parent_owning_graspable.GetComponent< Graspable >() as Graspable;

   /* use g */
  }

The point here is to illustrate that from c, the Collider, to parent_owning_graspable are fairly quick reference ‘jumps’ (a pointer to a pointer to a pointer). These are fast, given what they are, relative to something like a find or a GetComponentInParent. One might say they are ‘direct’ accesses.


The parent_owning_graspable GameObject, therefore, may use a call to GetComponent<> as a rather ‘direct’ means of finding the component, in that it is the parent that owns the component (unless I misunderstand the implications of your hierarchy). There is a search performed by GetComponent, but that is relative to the volume of components on the object.


Now, compare the alternative. If one forms a Dictionary (implemented as a hash table under the hood) to store keyed data, I assume the purpose is to look up a collider in the list from OverlapSphere, and find from that a reference to the Graspable component. The question (which you may have in mind as a theory, hinted from your post) is will this be faster or slower than the approach above. Since the only search performed in that plan is within GetComponent, this becomes a comparison of the performance between that search and the search performed within Dictionary to find the match. Certainly it is logically direct, a collider returns a Graspable by key. Searching for a hash, however, is not exactly low cost or cost free (and it can depend on the cost of the hash function).


One key to prediction is to know the likely number of components that might be attached to the parent GameObject owning a Graspable, and the number of colliders in the Dictionary. Searches are quite fast, so volumes under 10 are likely comparable in both case, as much about overhead to perform the search as the search itself. However, it is not likely the parent owning the Graspable would have more than 10 attached components to search through, and perhaps you could contrive a means of making sure the volume is small, but only you know how many entries may ultimately be in the Dictionary. As that volume grows, the lookup will take a bit longer, to an extent that it may well take longer than the approach I’ve outlined above (using collider’s gameObject.transform.parent.GetComponent() approach ). That, of course, assumes I correctly understand the implications of your hierarchy.


Now, if you do choose a Dictionary, implemented as a static member, there are no serious problems beyond the standard caveats. Those start with the general warning about avoiding global data unless it is genuinely global, and initialization must be controlled well (which is to say, only once). Beyond that, if there are threads which can conflict, they must be coordinated (often with locks, hopefully with lock free methods where applicable). From what I understand of your stated intent, a static Dictionary is a good fit. The Start or Awake in Graspable would call a static method which conditionally initializes a new Dictionary if required (lazy initialization avoids order of execution issues), but otherwise ‘registers’ the collider/Graspable keys as part of that initialization (which can involve the costly searching and getting required, but then only once at initialization). That can be on the occasion that new objects are instantiated during the game.

Why are you using Physics.SphereOverlap if you can use Triggers. Attach sphere collider of desired radius on your Grasper objects and make it a trigger. Then you can use simple unity callback OnTriggerEnter