Typical code problems in Unity projects

Hello everyone!

I want to analyze typical code problems in Unity projects. Each one of us faced strange and unexpected code constructions in scripts, sometimes in legacy projects we need to support, sometimes in our own projects.

I want to understand a sources of this problems, and, maybe, make a guide how to awoid this - something like “How to make a good code for Unity”.

Can you share an examples of such code or such troubles (most exceptional sh[beep]tcode you saw in your practice)?

For example, what I faced in my practice:

  1. Totally incorrect usage of Unity. One company tried to make a mobile app for video editing using Unity, motivating this like “well, Unity is good for multi-platform apps, so we can shorten the time for development of interface for Android an iPhone using Unity”. And I don’t want to remember about how its code looked (you all may imagine how to edit video “between” Update() calls).
  2. Using “non-Unity-way”. Animating assets through code from MonoBehaviour without using Animator. Ignoring Unity tools (like, changing color of sprite through redrawing all of its pixels in memory). Forced usage of OOP principles and patterns in Unity projects, ignoring MonoBehaviour-based behaviour logic. Using MVC, inverted direct dependency injection and other techniques which is not utterly necessary in game projects. Making a code for Unity in a way used in other PL and stacks (Golang, Java, Fortran, you name it)… And so on.
  3. Overthinking and overdoing. That’s continuing of what I said about force usage of OOP - everything is abstract, making a code with 3 levels of abstraction and overloading bitshifting operators on simple demo with 3 moving objects
  4. Creating Unity over Unity. I.e., when developer has an experience from other stack and PL, and trying to make sort of a “wrapper” for “big an misterious Unity” for himself.

Also, I appreciate you to say your opinion about sources of such problems. What is the roots of this? How can developer avoid it?

(Sorry if I posted it at wrong forum. But I thought that it’s not only about code, but also about code quality, coding theory, and, we can say “way of thinking”. If it’s in wrong place please say or transfer it)

3 Likes

Animating assets through code from MonoBehaviour without using Animator.

This is not an error. DoTween says hi.

3 Likes

I’ve been doing that for so long I cannot remember. You caught my interest with just this first sentence. :slight_smile:

I just released a video where I talk about the many things devs do wrong (out of habit, ritual, cargo cult) in relation to the AssetDatabase, and examples were saddeningly easy to find via GitHub. For each snippet in this video I only had to look into two or three scripts at a time:

https://www.youtube.com/watch?v=GQBWJOR3EsQ

In summary, the issues in my video exist because:

  • Examples and tutorials were incorrect to begin with. Repetition creates truth.
  • Developers simply apply what they know. They work with their blinders on for various reasons (time pressure, getting things done, why question what works, etc).
  • The API is confusing, inconsistent, not discoverable, too technical, bloated. Hence [my complete refactoring of the AssetDatabase](http://Keine Ahnung ob dein Asset schon verfuegbar sein sollte, aber das bekomme ich auf: https://assetstore.unity.com/packages/slug/270771).

Take the latter. You want to do something with labels with the AssetDatabase? Autocompletion is not too helpful, not even after you type two letters:

Whereas my version, you can even pick the right category straight from the initial list:

And then you see all the functionality at once:

As to your examples:

  • Clearly a case of technical incompetence on behalf of both developers and decision-makers.

  • In a software dev team, I’d expect even the most non-technical product manager to understand the differences between realtime 3D rendering and native GUI development and their implications.

  • I imagine highly motivated juniors or inept devs convincing management otherwise simply because they know/like the technology or want to have it on their CV (this happens!).

  • A case of lack of experience with Unity, blindly buying into paradigms, and/or not enough research.

  • Likely involves inexperienced developers and/or those that blindly apply principles, paradigms or tech that they’re either familiar with or recently became followers of.

  • Chance of decision makers to blame, though they may be the same as above. Or they may have forced their team to a very tight schedule which often results in applying what you already know rather than properly researching/learning the new stuff.

  • Close to #2 but clearly with a focus on trying to apply best practices / not repeating past mistakes.

  • Commonly happens in rewrites or major refactorings of a previous project. This time, we’ll do it right!

  • This has Technical Direction failure written all over it. Either there was a lack of senior developer competence in the team or the senior(s) forced those paradigms onto their team, perhaps to enforce architectural boundaries, divide up the work, and similar well-meaning ideas.

  • That’s #2/#3 again.

Overall, I’d say your examples are mostly caused by ineptness or incompetence, and inexperience - which is practically the same except there’s still hope for learning.

I attribute your examples 100% to teams that consist of people either largely in the Ignorant stage (example #1) or within the Cultured low (examples #2-4) with none, not enough, or not influential enough seniors/experts. In the Cultured area you’ll most often, and fittingly, find Cargo-Cult Programmers.

Personally, I’d say for Programmers specifically the upward trending curve ought to be way flatter than it is. As you move towards Expert level, programmers often fall prey to questioning too much, which ends in analysis paralysis or over-engineering solutions.

4 Likes

Unity recommended ScriptableObject event architecture to avoid those problems and to make the code more modular. They posted a video about it on their YouTube channel with a PDF link to explain the concept in details and made a comprehensive example with their first open project or UOP1

PrimeTween might be better these days. Next to no allocations, async compatible and is safely destroyed with the gameobject, no need to track stuff manually for transforms.

2 Likes

LitMotion is the one that I’ve been watching the development of lately as it’s DOTS-based.

https://discussions.unity.com/t/936361

3 Likes

Looks great, but the dependencies likely are not supported on WebGL. Probably really good for desktop/console folks, though.

Speaking of Dunning-Kruger effect.

4 Likes

The only constraint to what code problems you might encounter is your own imagination. Anything is possible and the sky is the limit!

1 Like

Well, no, that’s not what I mean. I spoke about situation when developer developing “his own” DoTween. I mean, when you facing a script, for example, where someone moving parts of object with bare code, like applying new Transform.position at key times.

And yes, btw, DoTween is slow and why you need it when you already have Animator?

Great video, CodeSmile! And that’s really great that you understanding what I’m talking about. I deeply agreed with issues you wrote. One of the most important, by my opinion, is problem with examples and tutorials, multiplied by misunderstanding of concepts how Unity works.

For example, I’d say that Unity is a thing working in “soft real time”, because of its frame-linked logic. So programming for it is closer to a programming drones and industrial robots, than to general programming. A lot of developers never thought about this (many of them didn’t get deep even in Unity’s official documentation) and from this grows a lot of issues. It’s exactly a multiplication - without understanding a basic concept coder could make a lot of weird solutions to force app to work.

Yes, lack of competence is a scourge of Unity development (and developers). Unity has relatively low entry threshold - any school-grader, having a computer and motivation to make games, could get a try. Some of them even achieving some success. Of course, nobody needs them in professional teams - but team leaders and product managers, especially in cases where is no experienced seniors in a team, could be catch in a trap named “schoolboy on Youtube said that it’s easy”.:rage: And a trouble is that a lot of programmers trust them (or supporting their decisions 'cause of different reasons).

I have an additional question to you. What you can say about usage of OOP paradigms, rules (like SOLID principles) and templates in Unity development? It’s interesting to hear your opinion.

Well, that’s not exactly what I’m talking about. Usage of ScriptableObject can help in some cases, but it’s not a silver bullet. But your opinion also could be an example of what I’m talking about in sence that good developer should know his tools. Not everyone using ScriptableObject in their projects.

No. I strongly disagree. Don’t forget - someone could need to support your code after you. Self-expressing via code, especially in commercial projects, is a bad thing.

I really dislike this stance. A lot of these have important uses in certain situations, even in games. MVC especially. My current project wouldn’t even work without applying the pattern. It’s also a very good pattern when it comes to UI.

And there’s plenty of reasons to ignore or bypass Unity’s built in tools. Some are incomplete, others like the Animator are massive performance sinks and often overkill for simple situations where a few lines of code will do the job.

It’s really about applying the right tool for the right job. Monobehaviours are a good tool for certain jobs. Sometimes they’re not.

Which is also not an error. Dotween is an external dependency, and explicitly forbid redistribution of modified versions. It is not MIT or opensource. That means you can’t tweak it and put modified version onto github.

You’d have stronger point if it was MIT/BSD software, but it isn’t.

To drive procedural animation.

Ken perlin had a lot of good examples at one point on his page, before java got discontinued. Animator does not work for every situation.

1 Like

I agree with you in general, except this one. MVC is an archaic pattern when it comes UI-based applications. I think MVP is a step in the right direction, but it’s still too limiting at databinding. “The good” pattern when it comes to UI is MVVM. It facilitates bi-directional binding and still keeps separated and clear boundaries between components. IMHO if you bother to setup any kind of pattern to serve your UI, it should be MVVM most of the time. Quick rundown why. As always: IMHO.

2 Likes

To be honest I wasn’t quite aware the various ‘MV’ acronyms actually represented slightly different patterns. Figured they were just different names for the same thing, or slightly different things that ultimately do the same thing.

To me it’s generally just about separating your data from the view, however the implementation of that may end up being structured. So TIL I suppose!

2 Likes

Because animator has a ton of performance overhead (and I mean, if you think DoTween is slow, have you profiled the animator?) and its controller gets messy real fast if you have a ton of animations, has a ton of weird implementations (like if you animate a var in ANY animation in a controller, that var gets stuck in default value for all animation clips), it is the source of many off by one bugs and weirdness and in general just sucks for many situations.

5 Likes

I still feel that way. The more I research MVC, MVP, MVVM, the more I think everyone is trying to describe their own idiosyncratic application that they wrote one time. I take all the useful concepts swirling around in my head from all that research, including the stuff that flat out does not / can not / should never apply to Unity that people still seem to push anyway. Then, instead of trying to make up a new acronym like MVCVMP, I just go back to hand waving at the general concepts to properly separate your application layers as “MVC.” There are at least three different types of “controllers” that I can think of, that should be used in any Unity project, that are completely unrelated to one another. Trying to get hyper-specific always ends up describing someone’s particular architecture or taking in circles in my humble opinion. I think the general concepts, and the ability to apply them properly when building up a system are more important than this particular acronym versus another. The source acronyms usually don’t originate from within the Unity environment anyway. Like in the linked article, there is no consideration given to working in a loop based environment, as all games are. Everything is event based like it’s an enterprise application, and the view needs to be told to update. In Unity, a view widget can just have an Update method that invokes a loosely coupled callback to poll the current data each frame, with no hard dependencies. That design isn’t even mentioned because half of the trademarked coding wisdom on the web comes from event based app architecture. However, I want to be clear that I’m not disagreeing with LurkingNinja because in the context of that article, I think that the main point is that views should not have hard dependencies on models, and I totally agree with that.

2 Likes

DOTween is slow and generates garbage but Animator isn’t any better and in some cases it’s actually worse. For example it’s actually really bad to animate UGUI with Animator because it will continuously trigger a refresh (ie it will set the dirty flag) even when nothing is changing. This was covered way back at Unite 2017 by Ian.

Unite 2017 - Squeezing Unity: Tips for raising performance - Timestamp 48:00

Of course you shouldn’t use DOTween either. It’s incredibly outdated at this point with multiple alternatives that are not only an order of magnitude faster but generate zero garbage. We’ve mentioned PrimeTween and LitMotion but there’s also MagicTween (same developer as LitMotion).

PrimeTween is licensed under the Unity Asset Store license. MagicTween and LitMotion are MIT and on GitHub.

https://github.com/AnnulusGames/MagicTween
https://github.com/AnnulusGames/LitMotion

3 Likes

Lerps, timers based on for free deltaTime and duration alongside an animation curve eval can make any custom tween happen on nearly any type…floats, color, vectors, strings changing text walking their char indexes through the alphabet…3 lines of code.

5 Likes

Yea, but then you’d probably want to abstract those 3 lines so you are not copy/pasting the same code all over the place. And then you’d probably want to sequence some of that, add cancellation logic, various callbacks, etc, etc. Some of the additional features introduce allocations if done the easy way. You can easily spend weeks writing your own in-depth tweener engine to cover common use cases and then have to maintain it.

The benefit of a high performance 3rd party library is that it already does all of that and with very good performance and you don’t have to spend time on maintaining it.

3 Likes

I make a utility. I can drop it on anything. Makes Rube Goldberg-ing easy and fast. I make my own libraries…often faster than available…because they are custom to my purpose and I do not have to use flawed implementations, often discovered after adding the code, running into roadblocks and jumping thru hoops to extend or compile code I have no need for. Weeks writing a tween library…heh…that is like a late night session and a cup of coffee. We wrote a custom curves library in a few hours. Has all the tween curve types and a dozen custom eval curves we found useful. It is a prefab. You drop it in a scene and send a value and curve type to evaluate. Here are some math libraries we wrote https://github.com/OpenBrainTrust/OBT.Maths

3 Likes