Caching confusion

It is kind of confusing when Sam says calculate something instead of caching it, because don’t you still need to calculate it before you can cache it? Does he means: don’t calculate it once and then cache it as a variable or field, but instead calculate it each time you need it?

I could totally be wrong, but my idea of caching a variable is just to label it at the top of a script so any method can have access to it, and unless you initialize it with a value, it will be set to null or 0, which is the cache since it always needs to have some sort of identification. I believe you can cache a variable and then change it in a later method. For example:

int cachedVariable; //this will be set to 0 apon initialization.

void Example(int newVariable)
{
     newVariable = 3;
     this.cachedVariable = newVariable;
     print(this.cachedVariable); //this will print 3.
}

Also, generally, it’s good practice not to calculate a variable every time you need to use it, especially if it’s an expensive process. Unfortunately, my personal answer to your last question is it depends(I’m not going to go ahead and say I’m right though, because it was kind of hard for me to read your question and I didn’t watch the lecture you’re commenting on.)

1 Like

Well if you only calculate the area just once and the height and width change then it will become invalid. If you calculate when the height or width change then that would get really expensive. I think it would be best to calculate and save the value; then the next time you need to use it verify that height and width did not change before using it again. Of course, to reduce the chances for bugs it would probably be best to just calculate it each time you use it (especially in less simplistic situations) because you may not have access or overlook all the possible variables involved in more complicated scenarios. Yes it would be more costly (but not in significant way) but with the added benefits of being a lot less buggy. I may be wrong, but I think that’s what his main point was.

Yeah my answer was running off of 0 context because I didn’t see the lecture lol so I’m gonna go ahead and say that your answer is a lot better than mine

As a rule of thumb, I tend to cache things like component references on the same GameObject that are not likely to change over the course of the game…
So this means that rather than using

GetComponent<Animator>().SetFloat("speed", 1.0f);

I will cache the animator in Awake() and use

anim.SetFloat("speed", 1.0f);

This is reference caching, and assuming they are references unlikely to change, they are generally safe (and effective) to cache.

State is almost never safe to cache… While the Health component may have some state set to indicate that the character is dead, all other components should not cache the player’s alive or dead state, instead getting it from the Health component. Even in the Health component, I don’t have an IsDead boolean variable, I use a property

public bool IsDead => currentHealth<=0;

This means that even though IsDead looks and acts like a readonly variable, it is actually calculated each and every time it is referenced.

Caching state in other components can lead to a mismatch between the actual state and the cached states.

2 Likes

Yeah, that sound Reasonable;
I was also going to say why not also make it read-only via an init-only property since it is not likely to change, but when I tried to use it I get the following error: System.Runtime.CompilerService.IsExternalInit is not defined or imported. I guess that feature has not been added; or the version I am currently using(2022.1.0f1) does not have that feature.

=> comes up pretty often, but I still don’t understand it. What exactly does it do? It seems like it can vary?

It depends on the context. In this case, => is used for return statements that are one liners…

public bool IsDead
{
    get
    {
         return currentHealth<0;
    }
}

All that is in the getter is return currentHealth<0 and there is no setter, so we can shorthand the expression with

public bool IsDead => currentHealth<0;

In Delegate assignments (like say, subscribing to an Event), they are used to create anonymous functions, known as lambda expressions or closures.

Something like

x = Random.Range(1,100);
Debug.Log($"The random number is {x} and we are assigning to the OnClick now");
myButton.onClick += ()=> 
{
    Debug.Log("This is an anonymous function, a function with no name");
    Debug.Log("The code inside this function is fixed when the function is created");
    Debug.Log($"When the button was assigned, the random number was {x}");
}
x = Random.Range(1,100);
Debug.Log($"After the button was assigned, X was changed to {x}");

Supposing that X was first randomly set to 50, and then after the assignment randomly set to 75, the console output would be

The random number is 50 and we are assigning to the OnClick now
After the button was assigned, X was changed to 75

Then when you click on the button, it would display all three Debugs, and the last one would read

When the button was assigned, the random number was 50

These anonymous functions can be very powerful.

So, when you subscribe an anonymous function, everything in it is set in stone basically?

Yep. That’s why it’s often referred to as a closure. The variables inside of the method are enclosed, within.

Privacy & Terms