Write more but shorter lines [Unity Essentials]

The primary concern by far when writing code is to write readable, maintainable code.

Such code is also “more debuggable” because the debugger lets you step over code line by line, not statement by statement (or at least it makes it more complicated).

The main thing to keep in mind is to trade vertical space for horizontal space. In other words: write more lines but each line is short.

Perhaps you are still used to write trainwreck code like this:

if (GameObject.Find(“Player”).GetComponent<PlayerController>().Stats.Strength.Min > 0 && GameObject.Find(“Player”).GetComponent<PlayerController>().Stats.Strength.Max <= 15)
        // do something
if (GameObject.Find(“Player”).GetComponent<PlayerController>().Stats.Charisma.Min > 0 && GameObject.Find(“Player”).GetComponent<PlayerController>().Stats.Charisma.Max <= 13)
        // do something

Let it go! This is not code, it’s copypasta!

Change it to something more readable and debuggable like this:

var playerObj = GameObject.Find(“Player”);
var playerCtrl = playerObj.GetComponent<PlayerController>()
var stats = playerCtrl.Stats;

if (stats.Strength.Min > 0 && stats.Strength.Max <= 15)
    // do something
if (stats.Charisma.Min > 0 && stats.Charisma.Max <= 13)
    // do something

And why is that more readable? Because not just the debugger, you yourself also step over individual lines! We simply cannot efficiently process long lines the same way we can scan short, concise lines rather quickly.

One statement per line is a good rule to follow in general as it lets you focus on a particular statement rather than a long blob of text. A statement is either an assignment or a method call or both combined.

The refactored code is also more efficient. It keep the things it found or got once in a variable, rather than finding or getting it all over again repeatedly.

Improve Conditionals

This code still has the condition awkwardly AND-ed together and it’s not perfectly readable what the intent is:

if (stats.Strength.Min > 0 && stats.Strength.Max <= 15)
    // do something

Again, variables help to provide meaning and context:

var isWithinStrengthThreshold = stats.Strength.Min > 0 && stats.Strength.Max <= 15;
if (isWithinStrengthThreshold)
    // do something

This may seem like overkill but it has the great benefit that now the if statement is very, very readable. As in: “if (the thing) is within strength threshold (then) …”. You get the point. It’s also crucial to not repeat yourself - if you need that condition multiple times, you write it once and assign it to a variable!

9 Likes

I was thinking of doing this same thing! (starting my own tutorial series) Cool to see some nice open resources being posted in these parts and not the usual endless technical questions or complaining :+1:.

1 Like

It is admirable to try to educate novice coders. One can hope more folks search generic coding and in particular C# coding information sources. Some do I’m sure.

As a matter of discussion I personally would not likely use a variable to define what is essentially a rule. Wouldn’t it be handier and more testable to have the Stats class include such a rule and return what strengths within this range mean?

3 Likes

But the question becomes, where do you draw the line of what to show in a given tutorial? If you’re introducing multiple concepts you’re going to lose the viewer. No one just sits down and learns C# in 5 minutes.

It’s nice that this demo explains one concept and shows it in a use case without added complexity that will confuse the reader.

But yeah, this is a great concept that’s also super useful (If i’m understanding your reply) that I never knew about for way too long. Rather than having random bits of logic scattered in our code it’s way cleaner and easier to work with if we have some bit of logic that’s just:

public bool canExecuteSmash => bothButtonsPressedForSmash && hitsThisComboChain >= hitsRequiredForSmash;

Unfortunately due to the out of the box restrictions of Unity most beginner devs won’t have access to Odin Inspector which is what many of us need to expose this logic for debugging in the inspector with the tag [ShowInInspector]

Probably the kind of thing where, if you see yourself writing the same bit of code a lot, then yeah you ought to move that into a handier, reusable method.

I wasn’t trying to hijack the thread. All that really needed to be added was a line or two such as “…or with a little more effort the logic could be moved into a class”. It is a good idea to implant the concept that investigating more on their own is a good thing.

I do not actually know what you meant by needing Odin Inspector. It would typically be a public method as it might require a parameter. The Stat class is given as a hypothetical right? The novice is being asked to recognize that class has properties named Strength and Charisma which (I assume) are classes that contain Min and Max properties.

In any case “essentials” are a good way to convey short pieces of useful info.

1 Like

You can use functions or whatever to set these conditionals, but that leaves you open to order of operation errors at any given time, and sometimes these checks can be frame specific. I’ve just found this means of checking bools to be all around superior for code cleanliness and reliability of getting the right data at the right time.

By defining bools directly where we create them (I know my code lingo isn’t the best) it keeps the code super tight and removes all doubt about when the values are applied, any parameters you might want to modify the conditional you can include right there.

The reason I say that we need Odin is because out of the box there is no way to get the property:

public bool canExecuteSmash => bothButtonsPressedForSmash && hitsThisComboChain >= hitsRequiredForSmash;

To show at runtime for debugging. You need to have odin inspector so you can add the tag

[ShowInInspector] public bool canExecuteSmash => bothButtonsPressedForSmash && hitsThisComboChain >= hitsRequiredForSmash;

And then you’re able to see the bool functioning at runtime.

I’m still learning the ropes here so feel free to let me know why this is a bad idea :stuck_out_tongue:

The inspector is not a debugging tool, to be honest. Or if it is, it is the least effective one.

And properties are just methods. They’re effectively the same thing.

Would you recommend creating tertiary UI that displays combat stats in real time? Or is there some sort of utility I’m not familiar with? Or maybe I just need to set up better debug messaging.

I dunno, in a pinch I just use the inspector and it’s served me ok. Doesn’t require any special code or anything.

Well anyhow, when I’m testing runtime logic that requires play I find it very useful to have these values visible in the inspector and I can see them toggling on and off if I need to see if conditionals are working at runtime, just gotta be sure the game object is selected.

I mean our smiling coder made a post about that too: Debug Thy Code! [Unity Essentials]

Managed code debugging is the most comprehensive manner.

And in certain circumstances I may make simple IMGUI overlays or gizmos to debug values and properties.

3 Likes

I see @spiney199 has covered the bulk of your questions. There are however some concepts that are valuable to discuss. The first will be the one I quoted above.

Ordinarily we are not open to operation errors of any kind at any time. There is nothing fundamentally different about coding in C# (with Unity) and coding in C# for other targets. I don’t know what errors you’ve encountered due to order of operations but they are easily determined in 99.9% of the cases.

The goal of “super tight” is conceptually the opposite of what I do in my development. An object acts like the object it is. Nothing consuming that object should need to account for conditions related to that object. The “further away” the usage is from the implementation the better. It is a big part and a key benefit of inheritance.

As for debugging (as noted) the Inspector is a fleeting view at best. I have 100’s of log lines typically one per method as I start out. These log to a file which permits me to run at play speed and to review at leisure. I can compare the last run with a previous run. I have my log set up to report the date/time, class, method and property/parameter values. The line include the “time since started” so I can not only see that it happened at 3pm but 3 minutes or 10 minutes into the app.

I can also see (in the case of my VRChat app) that all the Start methods ran, my Init methods then ran and then all my InitMaster methods (if the player is the master) ran in an orderly fashion.

One also gets a log per player so the interactions between players is visible as well.

In a nutshell, you want to encapsulate “business logic” into the class so that each consumer doesn’t make up their own rules. When the rules change one edits the “definer of the rule” and the consumers adapt.

Good software development is a well organized dance.

Looking at this code, it seems like it will throw errors if a player is not found or the player does not have a PlayerController component on it.

Sometimes I throw in a null check for things like this, but I guess I wonder what most people do. Is it just assumed that the scene must have a “Player” or the whole game breaks? Likewise for the component. I don’t really have logic for when I decide a null check is needed, I just add one when an error shows up in an unexpected situation.

I guess my question is when is it appropriate to check for null vs. assuming things are set up correctly in the scene?

In your script, I think I likely would have set up private variables and during Awake check for null and write an error message telling the person to setup the scene properly or nothing is going to work.

I think you are asking a good question that is fairly common to ask. I recommend that people avoid null checking references that clearly have to exist or the game won’t start. A sort of “fail fast” implementation if you will. Absolutely do not check these conditions in “inner” methods as there is no way to have gotten that far if a principle object was null. It isn’t that it is “bad” it is simply a waste of time.

Checking the state of things in Awake is seemingly useful. I am developing for VRChat at the moment and we don’t have access to Awake however and first availability is Start.

If they are assigned in the Inspector I have Odin check them. I also have it check whether arrays have elements, that they have the correct number (when it can be determined) and if they are formed correctly. Sometimes a pattern is involved (I have arrays of URLs for instance) and if there are 30 of them it isn’t hard to misspell a few.

When possible I rely on to convention these days. The parent object will have its children directly under it so I can grab references without assigning (sometimes a dozen or more) in the Inspector.

I typically log whether such objects are null so while the app will start and fail the reason for the failure is easily discovered.

So I would say it comes down to “is null an impossibility” meaning there is nothing a player can do as the code is broken or “is null a possibility” meaning that null is a valid return value indicating some thing was not available. Those are not errors, they are valid results.

I think this thread’s intent is really just about breaking lines of code down into smaller, more understandable pieces.

What that code actually does is kinda beside the point.

If you’re new to code you’re often setting your conditionals in update loops which can cause a frame of difference on top of script order.

Gah I can see why no one likes to talk about code any more. You guys sweep into a thread meant to teach new developers basic concepts and use the entire thread to show off vague, higher level concepts that no one who would benefit from this post will learn from.

Are we here to teach people or to engage in the usual negging that goes no in tech?

This conversation now has nothing to do with helping new coders learn low level concepts to get up to speed, it’s just the usual bickering about how higher level code is the only way to do things and no learning will be done outside the top comment.

I REALLY question the validity of things at times, because sometimes it feels like people are more concerned with looking smart or putting other people down than in finding best solutions or doing their best to help others learn. And I don’t need to tell most anyone reading this, but this isn’t a problem just in this thread, but all of tech. For all the talk of logic in these parts there’s a lot of cognitive dissonance that finds its way into our pipelines and code.

It’s just how coders are. We have lots of thoughts and we tend to share them. Which all in all is a good thing, as it’s better to have the information out there than it is to keep it to one’s self.

You could stand to be a bit less sensitive, to be honest. Your rambles are becoming a daily occurrence.

Always with the negging… Just be up front about it.

And I disagree, it’s not thoughtfulness, it’s a destructive force that has ruined this industry, you may think it’s a positive attitude, but it’s just thinly veiled gatekeeping and character attacks.

You know why these forums are dead and no one talks? Everyone is tired of being destroyed by your subversions.

Edit: “sensitive”. God forbid people care about this community and this engine. Sorry my posts stick out, if this community weren’t destroyed by this toxicity they wouldn’t.

The rest of us are happy to engage in discussion about these things without getting forever arced up about them. It’s just you with the persecution complex.

And I’d wager your prophetic doomscrying has had a stronger repelling effect. Nevermind the forums are more active by metrics, and it’s just the old guard who left because they couldn’t handle a change in forum architecture.

There’s no Unity community any more, it’s a free tech support platform.

What can you even do? There are clearly subversive elements at play (maybe I’m just crazy), say I have a persecution complex, gaslight whatever. Call it out and get mocked. Just shut up like everyone else and the cry bullies win.

What even is gamedev any more?

Just some stone cold business venture coopted by suits and moralists scratching one another’s backs.

Anyway, apologies to OP. It was not my intention to derail this thread, maybe I am being overly sensitive.

I don’t even know any more. This industry blows.

Some of us disagree with your assessment. I’ll curtail direct responses to your messages from now on. Hopefully it will help you in some small way.