Logic placement best practices?

I’ve looked through every tutorial section (including “Best Practices,” which is limited to physics, assets, and UI) and I’m coming up blank… apologies if I’ve missed something obvious, but it’s not for lack of trying. :slight_smile:

After doing the UFO and zombie roguelike tutorials, I was going through the relevant discussion threads and noticing some people citing questionable practices, e.g. putting actor logic in the actor scripts themselves.

A lot of code and asset organization can be down to taste/experience or what makes sense for a particular project, but are there Unity-specific performance best practices that apply to things like where certain calculations/algorithms/behaviors should be kept/implemented?

Short answer: Not Unity-specific, but a decent reference: Design Patterns.

Long answer: It’ll come to you in your moment of need :slight_smile:

When I started Unity development, I tried every hard to find - and spent a lot of time researching - those so-called “best practices”, such as the MVC model, decoupling, etc.

As I got further and further into the game, I came to realize that these are not universal truths; rather, they’re tools to accomplish a specific job.

For example, if I want the destruction of a game object to trigger something in the game logic, I might be better off using an event. On the other hand, if I’m using object pooling, then I may as well assign the game logic script as a public reference in the prefab and call the relevant logic script’s function from the game object’s OnDisable().

Similarly, writing decoupled scripts is great in theory, but, more often than not, it forces you to rely on events to make scripts communicate - and, before you know it, you’ll have dozens of events and hundreds of listeners all ferrying information between scripts, which can quickly become overwhelming and impossible to debug. Besides, if the two scripts are going to be attached to the same component in 99% cases, do you really need to decouple them? Sure, they say that one should write re-usable code - but, honestly, what are the odds you’re going to be reusing your code in another game?

I guess the point I’m trying to make here is that, from my experience, at least, it makes very little sense to try to follow a specific pattern until you have enough experience to appreciate when doing so is or isn’t useful. In other words, I say do as you will as long as you harm no one, including yourself :slight_smile:

By that latter, of course, I mean basic things such as:

  • No GameObject.Find() in Update();
  • Object pooling, if warranted
  • No over-reliance on assigning variables in the inspector

Personally, the way I’m structuring my current project is as follows:

  • GameController.cs, which handles game logic and operations (e.g., purchasing things, applying multipliers, calculating XP requirements, dealing damage, etc)

  • UI_Controller.cs, which handles the majority of general UI interactions (e.g., showing a particular pop-up, refreshing select UI components in its Update() function, disabling UI gameobjects when dictated by the game logic, etc). Predictably, it contains a metric ton of public references to UI gameobjects

  • Attributes.cs, which stores character information and statistics, such as attack damage, level, coins, highest level ever achieved, resistance to specific damage types, etc). Attributes.cs is a static class, so it gets instantiated by GameController as a singleton at the start of every game. It’s also what gets saved and loaded every time you (re)start the game.

  • Finally, I have local, “low-level” scripts handling their specific roles, be they gameplay or UI, for example:

  • UI_StatsScreenController.cs script handles, in its FixedUpdate() function, the text of all player statistics such as total monsters killed, total damage dealt, etc;

  • UI_PurchaseItem.cs handles the UI behavior of items in one of the scrollable purchase menus - when they appear, what image they show, whether the “Buy” button becomes disabled when the player does not have enough money, etc.

  • Fall.cs script takes care of objects falling;

  • Spawn.cs script defines the attributes of an individual monster;

  • Spawner.cs script handles spawning monsters, etc.

Hope it helps,
George

4 Likes

Wow, thanks for an in-depth reply!

I suppose I should mention that I’m a professional developer, despite being new to Unity and C#. I spent enough time with the GoF Design Patterns book to cringe at the mention; solidly half of those were just hacks to work around Java’s insanity (and the other half were obvious enough that giving them names struck me as comical). Agreed that every project has its own requirements and best approach in terms of structure.

I definitely appreciate the GameObject.Find and inspector variable reliance tips; you call them basics, but that’s advice that you won’t find in the tutorials I’ve taken, so that’s the kind of thing I’m looking for. I’ll look into those further.