Is it advisable to use a component within a GameObject to store references to other components on the same object? Rather than components having references to each other ad-hoc. This could simplify inter-object communication via ‘GetComponent’ and potentially mitigate circular dependencies as component count grows. Any thoughts or alternative approaches? Am I setting myself up for future problems with this method? Thanks very much.
It does not solve circular dependencies, it only hides them behind another layer of indirection. If component A has a reference to B and B has one to A it does not matter whether they have corresponding fields in their scripts or whether they get these references through the „ComponentReferenceStore“ class. It is still a circular dependency.
If you need this many component references on a single object that you consider a reference store class then this seems like a code smell to begin with that isn‘t solved by storing the references elsewhere. On the scene/global level it may start to make sense though. Especially when you can specify whether requesting a reference can or must not return null, or run some default code like creating an object, instantiating a prefab or adding a component if it does not yet exist.
You’ve made that much clearer for me, thank you. I understand your point about circular dependencies but in terms of inter-object communication I’m trying to get around the problem of object A needing access to two or more different components on object B.
For example, on collision, A needs to know what state B is in and then call B’s RemoveHealthPoints() method accordingly. State is managed in one component, and Health in another. I’m guessing that calling GetComponent twice would be silly? Especially when 100 object could be colliding regularly. Is this where your suggestion of tying things together at the scene level comes in?
What exactly are we talking about? Your first post made it seem like you are talking about permanent connections, like a car having a reference to its wheels. In your second post you talk about collisions, in which case you simply dynamically get the components you are interrested in. Calling GetComponent twice is not silly, if you need two components from the collision. It’s not that slow. If you are worried about performance, make a simple stress test to see if an actual issue exists or not. I highly doubt the GetComponent calls would be the bottleneck tho.
Hi Yoreki, thank you, I should have been clearer. My question about inter-object communication refered to dynamically getting components as you say. It wasn’t so much a performance worry as much as a concern about implementing something properly now to lessen future headaches.
I’ll take on board what you say about there being no problem in using GetComponent twice.
Personally I think whatever object you have should have “it’s script”. And any other references to components on that object should be cached in that main class, as you would do for renderer, collider, transform, etc…
I think this is situation where following the Tell-Don’t-Ask principle could be a good idea.
Instead of object A directly examining the state of object B and accessing multiple members on multiple components on it, it would just call one method on one component - e.g. OnCollision(ICollider collider).
This way the class responsible for handling the collision can be kept much simpler, and doesn’t need to know the implementation details of object B, and your classes can be more decoupled.
You can also use an interface for further decoupling.
public interface ICollidable
{
void OnCollision(ICollider collider)
}
And you can use GetComponents/GetComponentsInChildren to allow multiple components to react to the collision, making the system potentially more flexible and reusable.
foreach(var collidable in collision.GetComponentsInChildren<ICollidable>())
{
collidable.OnCollision(this);
}