Decoupling one component from another

I’m having a lot of trouble understanding how components should speak to each other given that they know nothing about each other.

Here’s a simple example of something I’m trying to do. I have two classes:

  • DrawableTexture, which contains a Texture and lets the player draw on the texture.

  • Canvas, which is where the texture will be placed. A Canvas has a width and height.
    The texture is created at runtime, based on the size of the Canvas. If the classes know nothing of each other, how is the Texture supposed to be created?

My coupled solution is for DrawableTexture to have a public reference to the Canvas and its dimensions. This seems sloppy and maintaining so many drag and drop references in Unity seems like a nightmare. Now DrawableTexture depends on Canvas.

One alternative is that the Canvas creates the texture. But, the Canvas is just a Canvas - its job is not to create textures for other objects.

Does anyone have ideas about how I could do this? It’s a simple problem but I think it’s at the root of what I’m having trouble understanding.

I’ve been learning about design patterns for the past week, but then I got back to Unity and I’m realizing that Unity’s component paradigm doesn’t make any of these patterns easy to implement.

Think of a script or component as having a single responsibility. Internally a class should be abstracted to receive an input, which is doesn’t know or care about, then operate on this and produce a result. In your case you’ve got that.

Decoupling then means not having hard-coded references or heavy composition. Just because you have a drag and drop reference between your texture script and canvas is not a problem. They need to know about each other, they just don’t need to know anything other than that. So I’d argue you’ve got the right architecture and it sounds like this matches Unity’s component pattern already.

Another way to do it is to use Singletons as an easy way in code to get a reference to another object, if there is only one of something. This way you don`t have to create public variables to hold objects you want to talk to, drag them in the editor, get the script component from them on start. You just call them directly from anywhere.

public class SomeClass : MonoBehaviour
{
	public static SomeClass Instance;

	void Awake()
	{
		Instance = this;
	}
	
	public void DoSomething()
	{
	...
	}	
}

	...
	// Somewhere in another script
	SomeClass.Instance.DoSomething()
	...

Another option would be to have the Texture script take an input for it’s size, then use another script to link the 2. Then the texture script never knows about anything and can be used in any program. You just need to give it input (like any function)