Architecture & Tight Coupling #1

I’d like to get some input from you on a common practice in Unity.

This being wiring things up in the Editor. When I first started using Unity I thought it was quite empowering the way we can easily drag n drop references from one component to another.

However, in the back of my mind I had this nagging thought that I was doing something I really shouldn’t be doing… basically hard-wiring dependencies. The only difference is I was doing it visually instead of programmatically.

I think we all know that too much of this kind of thing causes problems down the road.

I think the visual nature of the process makes it so many people don’t consider it the same as if they were hard-wiring inside their code. Kind of the same way many people use the common pattern of setting up a Delegate / EventHandler in code and then use the .SomeEventSubscriptionMethod += SendEventNotificationsToThisMethod pattern thinking they are actually making their code more loosely coupled when in reality this is not loosely coupled. How can it be? This pattern has one class explicitly registering itself to an Event on another class and to do that it must first have a reference to the other class. There is some flexibility in the pattern in that multiple classes can register and receive the notifications but that is another story. The proper way to decouple it IMO is to just create a completely separate EventManager class and have all publishers and subscribers use that one class. Now there is a single explicit connection used by all other classes. Of course, in Unity I suppose the SendMessage may be ideal for decoupling.

Anyway, I digress…

Let’s use a basic example of setting a camera to follow a player. Making the camera a child of the player works. But that is too simple so let’s say the camera is following a pinball. Can’t simply be a child because the camera would roll as the ball rolls.

There are always a number of different ways to do things and there are alternatives to wiring things up in the Editor.

One way would be to simply use GameObject.Find(“Player”).GetComponent in a Camera script to automatically find and set the reference of the player’s transform.

Another (kind of insane) way would be for the Camera script to have a public method that accepts a transform and in a script on the player have it locate the camera, get a reference to the attached camera script and then call the method to pass over the player’s transform. The camera script receives the transform and stores it.

The Unity messaging system could be used in the same way to allow a player script to send its transform over to the Camera.

A custom Notification Class could be used to do the same thing.

And so forth. Many different ways. With pros and cons to each. For Unity I think a good way is probably the first approach described above… simply make use of the Find() method in a camera script. However, it is obviously not completely decoupled. There is a dependency. A requirement. Simply changing the name of the GameObject from Player to Hero would cause the code to fail and the reference would not be set. Same for passing to a camera where the camera name has changed.

So, in this case relying on some kind of Messaging / Notification system OR simply wiring it up in the Editor actually are the more robust solutions. The issue I see with hard-wiring up references in the Editor is it can turn a project into a mess of spaghetti where you end up looking around… “where in hell is this set up?!” Is it in the code? Is it in the Editor? This is particularly a pain point when dealing with projects someone else created such as Assets from the store.

Reason for all of this is that I plan on very slowly getting back into Unity and focusing on each thing like this one at a time to find a best pattern before going forward. I already did that a lot previously but I will revisit and evaluate the options just to be sure.

So this all leads me to my question…

How do the rest of you feel about such things… do you just wire up references in the Editor not giving it a second thought or do you strive to decouple things more by using code to set up these references such as using some kind of Messaging system or possibly even a single class containing all of the Editor hard-wired references?

I think the concerns you have are valid, but some of them are dependent on how the rest of the code is structured and where you decide an event subscription or hard reference is a good idea. It’s a really broad topic because at some point you must have references between objects or there is only giant multipurpose scripts that never communicate. The tricky part is structuring those classes and interfaces so that things communicate safely. I like observer style patterns.

For instance I try not to have to drag-n-drop references on anything that is not in the same hierarchy. Eg, Prefabs only. This basically keeps them entirely self sustaining. If I need scene references, I try to obtain them either through static variables when possible, or via some scene event which makes sense. If two things should be communicating then there is very likely some kind of interaction where you can pass the references between them safely and guarantee non-null communication. It’s really about control.

Usually I design this stuff backwards. I write the simple code that I want to use to talk to some object then I go to that object and figure out how to make that call possible. This makes communication interfaces simple and forces the target scripts to deal with validation and stuff instead of the observers/remote methods.

1 Like

I’ve done both… for things that I “believe” may be relatively static I’ll use the reference, perhaps as a list of elements that are just drag-drop in editor.

In some use cases, to ease reference handling, I have used a design pattern like Observer to do it as the objects may change frequently, and I want them to just register/de-register themselves.

Anything to avoid the “Find” object stuff… we all know that is lazy and slow.

2 Likes

I’m using a dumbest, simplest approach that will still work without potentially biting me in the future. See:
https://en.wikipedia.org/wiki/KISS_principle
https://en.wikipedia.org/wiki/You_aren’t_gonna_need_it

In case of your example - “Camera + player”, the idea of using .Find() is wrong, because you rely on magic hardcoded string “Player”, and because .Find is not guaranteed to be really fast.

What I’d do would be making a simple CameraTarget component, and have Camera component accept the reference it (via a CameraTarget typed field that is visible in editor) and orbit around it if it is specified and not null. This way you can attach empty “Target” game object to any thing and this way you do not depend on player being named “Player”.

That’s all there is to it.

7 Likes

Thanks for the replies. Just one tidbit with the use of the Find I’m not concerned about performance. I would use that only one time to get the reference and then store it. Not do some madness like use Find every frame. lol

So if I understand correctly… two of you are leaning toward use of an Observer pattern with subscribers and publishers. Which is basically my preference as well only further decoupling it to a stand alone NotificationsManager (that I already wrote about 3 years ago for Unity lol) so the subscriber and publisher don’t know anything about each other period no interfaces etc both sides just deal directly with the NM.

And one person favors wiring up the references in the Editor with the addition of a separate GameObject named CameraTarget. But still wired up in the Editor.

Which of course also provides a solution for the case of using Find on a Player that has been renamed. By using Find to get ref of CameraTarget child it doesn’t matter what the parent Player has been renamed to.

Still this gets back to the heart of the question… to wire up in the Editor or not to wire up in the Editor.

I think my struggle with it is I do believe in the same philosophies as @neginfinity yet at the same time I also believe in the value of decoupling at least to a degree.

I think at this point I would favor adding a CameraTarget “empty” child GO and using Find. It is very simple and yet decoupled. Sure if CameraTarget name is changed it will break but the chances of that name changing are far less than Player being renamed to Hero or maybe Bob. The observer pattern can be used but seems a tiny bit overkill for something so simple. Decoupling in the Editor!!! I guess I still have a hard time wrapping my head around the Editor and realizing these GameObjects are for anything & everything we want to use them for. lol

I think I’d consider this dedicated reference GO as a best practice. Thanks.

Magic numbers are evil. Magic strings are also evil.

No. Observer pattern notifies subscribers. My example does not notify anyone of anything.

In “Camera” component there’s a serializable field “CameraTarget cameraTarget = null”. If CameraTarget is set, Camera orbits around it. CameraTarget component is completely blank and have no functions or data in it, although I suppose if you wanna be fancy, you can add OnDrawGizmos/OnDrawGizmosSelected to it.

Basically, I create typed empty class, use its type as a filter to restrict number of objects that can be dragged into camera, and this way maintain a “weak link”. By the way, testing for null is overloaded in unity, meaning you don’t even need to check if the target object is dead.

Now, if you had a problem with grabbing player, then I’d probably go with something like UserController having a static method or a property that return “currentInstance”. Basically a singleton. The player object would register itself upon creation and unregister itself from distruction. This one is less universal, and closer to observer pattern, except there really isn’t an observer to notify anything.

Whichever floats your goat. I mean boat.

Basically… unity events, for example, allow one to add seven different notification receivers to a button click. Doing that is (IMO) bad and should be avoided, because it falls into category “it is going to bite you later”. However, if there’s one or maybe two methods added to notifier, this isn’t wrong.

I think I definitely would not use Find because it relies on string names.
If your method relies on an object name, then Murphy’s law says that the object is not present in the scene, named incorrectly, or will be renamed by another string (because you can change names on the fly at runtime) and you’ll only discover it two months after release. Unity object names also are not even guarnateed to be unique. You can have two players in the scene.

I’d either search for components, use a signleton method “UserController::getInstance()” and one more option would be actually make CameraTarget more active and register/deregister itself in global camera as a follow target. That’s mainly because there’s Camera.main and Camera.allCamera which do not rely on string names.

Basically, in all situation - types, classes, components and never object names. Because magic strings are evil and objects can be renamed. Class types cannot change at runtime and are compiled into the game.

4 Likes

@neginfinity Good points. I meant the other two people for Observer pattern. :slight_smile:

I considered using something similar to one thing you are describing. Defining an Interface Player and sticking it on the Player class.

A lot of this always comes down to personal preference. And there are always so many ways to do basically everything. Even this which is a very simple case and look at the number of strategies mentioned so far.

I think I will just try several of the “better” ways and see which I like the best. The rest of the game dev I think is easy. With Unity it is these most fundamental things that I wrestle with. I don’t want to spend ages on such simple things but at same time want a good reliable pattern for the future.

I actually agree with this. All you’re doing is inverting the call, not decoupling. That said, it’s a really handy way to invert the call. The alternative is:

public interface IHandleThing{ void DoThing(); }
public class Button{
 public List<IHandleThing> OnClickListeners = new List<>....
 protected void Notify(){ foreach( var i in OnClickListeners ){ i.DoThing(); }
}

The event/delegate approach is really just shorthand for all this and helps you not need a billion interfaces for everything.

I have used pub/sub systems in unity for a couple years. They’re ok. I tend to use the pub/sub stuff to move a message to horizontally to an unrelated subsystem, so I tend to use them for more state changes. Pub/Sub can be just as annoying as anything else and I keep my implementation very simple. I strongly type all messages and instead of just namespacing, I use nested types, so you must include the message ‘namespace’ when using the message.

public static class On{
  public class CharacterKilled{ ... }
}

public class Thingie : ISubscriber<On.CharacterKilled> { ... }

It works alright.

Problems are generally the same as any other decoupling strategy, makes it a bit harder to find stuff than tight coupling. I don’t always immediately notify (I guarantee notification is complete before sending more messages, which is not ‘out of box’ with events), and if you aren’t notifying immediately, you can lose the stack which can make debugging harder.

1 Like

I routinely use the various approaches @neginfinity just described and they work well for me.

No… one object is registering itself to an Event on another object, and to do that it must have a reference to that object. That object’s reference does not have to involve knowledge of a specific class. It could be a parent class, an Interface, or looked up by reflection off the top of my head.

In one game I made a couple of years ago I’ve got a “board” that has all of the pieces in it and then a bunch of other components that represent and implement rules. One that controls how moving works, one that controls how spawning works, one that controls how score works, etc. They all communicate via events, they are all aware of each other only via Interfaces, and no component cares what specific types of other components it’s working with. For instance, score is provided by an IScoreHandler, of which there are different implementations for different game modes. The UI only cares that there is an IScoreHandler in the scene to listen to score changes from, it doesn’t care what class is implementing IScoreHandler or how it works internally.

I can implement a different game mode just by writing new implementations for an interface and swapping one component out for another. No other component cares when I make such a change, and in many cases I can straight up delete things and the rest of the system just goes on doing its thing with the game remaining entirely playable. For instance, the “chillout” mode is exactly the same as one of my other modes, with the end game and score components deleted.

4 Likes

Yeah I get that. I am using the term loosely class. Ultimately it is an an instance of a class whether we get there through an interface or otherwise.

This is the kind of thing I used to love working on before I decided to throw it all out and simplify down to straightforward procedural programming. The kind of system you are talking about. Programming to interfaces instead of implementations. There is value in it.

Yep this is why I decided a year ago to throw out all of this stuff and simplify for game dev. And how I ended up where I was for that Unity Space Invaders again. The stuff is interesting & fun to work with but it is easy to spend way too much time messing around with all this overhead instead of actually working on the actual game.

I spent some time earlier throwing together 4 examples of getting a reference to the Camera from the Player. And while I was doing that I couldn’t help but to think how much simpler all of this would be if it was a more straightforward approach.

GameManager
player= CreatePlayer();
camera = CreateCamera(player);

and so forth. Dead simple. I am tempted to approach my Unity Game Dev this time around from this angle.

Anyway… I hate to see long discussions like this without any ready to go examples… so if anyone wants to see a test of 4 different ways to get the reference the link is below.

Unity 5.4 Project With 4 Examples Of Getting Player Reference to Camera Script

I have no idea why it is 3 MB zip file but that is what it ended up as.

Basically just drag the player around in each scene and watch the Game Window for testing.

Scripts are named to make it easy to recognize which scripts go with each scenes. I didn’t make folders specifically for each scene. Could have done that. But didn’t.

Also… I know some of the comments in there are not correct like I remember one I put this is called by the so-and-so script and the name I wrote was the current script. lol It is called by the PlayerControl script. But the point was just to illustrate various ways of doing the same thing. If nothing else it might be useful to someone just learning Unity. Maybe.

I did waste time trying to make an example of using SendMessage but for whatever reason it never worked. Kept complaining about no listeners despite me having the method in a script. Maybe it doesn’t do what I thought it did and you need a reference to the other object and use that to send the message. I have no idea but don’t need it for anything so won’t waste any more time on it.

I went pretty extreme with that project to see how it went. I was expecting it to be an unfollowable mess, because there’s no single place where the system flow is visible. To my surprise it was actually one of the smoothest, easiest to work in code bases I’ve used.

To be fair a part of that was because the game was fairly simple. But another part was because each component was small, did a simple job, had clear input and output expectations, and could be worked on almost in isolation. If there was a bug with something I knew exactly where to look for it and I knew exactly the scope of change for any modification I made.

I also never needed to write any game-specific configuration code, including not needing a “GameManager”. I put things in a scene and they looked after themselves. You say “dead simple”, but you’re hiding the details behind function calls. What goes on behind “CreateCamera(player);”? Is writing that code really any simpler than using Unity’s Editor to do what Unity’s Editor is meant to do?

4 Likes

I also really feel I should say… I’ve worked on projects that took the “simple” approach above and while it does work well enough on small things, as projects grow the maintenance costs just get huge.

1 Like

The Inspector is your friend. Do not fight it. Make use of drag and drop references. These can be altered via code to reference another of the same type at runtime. Don’t get anal. This is not Python nor MS C#. This is Unity components. Carry on.

3 Likes

Ha ha. I’m not bashing Unity here. I am saying for me it is simpler to just use other approaches. But the whole point of this (me revisiting Unity) is to try to connect with it. So while it would be much simpler IMO to use an approach where a manager knows all of the top level, sees all of the top level and delegates responsibilities to other managers. That is something that scales well IMO. I won’t use that approach and will try to focus on a more Unity style of game dev.

Unity is powerful there is no doubt about that. Mainly I’m trying to find how much I should embrace the Unity specific things. That is why I asked the question originally. If most experienced people here have just went with the approach of wiring everything up in the editor and found that it does work well for them even as the game scale increases then I’d give it a shot even though originally (when I first started using Unity) it was an area of concern for me.

Basically I am wondering how much of software engineering principles are people using in general and how much are they relying on the ways Unity allows us to do things.

I think I will have to get into Unity again so I can remember exactly what I was running into originally that turned me off to using the way a lot of folks seem to be. To be sure, I am not the only person who thinks these things or approaches it from this angle. Over these past few years I did a lot of searching just to see what other people were doing and they are using everything from a purely procedural approach (although different setup than I used) to an MVC model to basically just doing exactly what the Learn section shows for the beginning examples and various combinations. Just a huge amount of variety really. And that says a lot for Unity that it is so flexible.

Anyway, I am going to work on a little project just a simple one. Just a little 3D RPG in a small area. Of course, it will be primitives mainly. But this will be enough of a scale to get into it and really see how well I can adapt to it. And compare it to using a more procedural or standard OOP approach. Basically I am just going to have fun with it and try to spend more time in the Editor and taking advantage of what it has to offer. Who knows in the end I might just end up really enjoying it.

How many engineers does it take to decide on a strategy for script referencing?

1 Like

Exactly one.

4 Likes

Sure, but that’s not the distinction I’m asking about. You’re saying it’s simpler to put things in code explicitly. (At least I think that’s what you’re saying.) I’m saying that at some point it becomes simpler to use other tools for those things. (“I put things in a scene and they looked after themselves.”)

1 Like

Yes. And every engineer thinks that they are that one.

And we all are. There doesn’t have to be One Correct Way for everything.

2 Likes