Confusion about AudioSource and caching?

Hi Everyone,

It seems AudioClip and AudioSource are types of variable. However, shouldn’t variables begin with a lowercase letter (camel casing)?

For example, why not:

[SerializeField] int number;
[SerializeField] audioClip audioClip

audioSource audioSource

I am new to coding - is there something I have not understood here?

I also don’t understand why AudioSource has to be declared at the start of the script in order to use the PlayOneShot method later. The correct script is this:

            audioSource.PlayOneShot(audioClip);

However, why is this wrong:

            AudioSource.PlayOneShot(audioClip);

I understand that PlayOneShot is a method, and that we need to define the variable ‘AudioClip’ as audioClip for it to know what to play.

However, why is the ‘AudioSource’ part necessary? I thought that AudioSource might be a class, and we are calling the PlayOneShot method defined within that AudioSource class, but then it does not make sense that AudioSource would be used as a variable.

Thanks!

Hi Killerbanana,

Welcome to our community! :slight_smile:

It seems AudioClip and AudioSource are types of variable.

Yes, they are types.

However, shouldn’t variables begin with a lowercase letter (camel casing)?

Yes, the names of variables usually start with a minuscule letter. However, that’s just a naming convention. If you introduced a name, you have to use that name “as it is” because C# is case-sensitive.

[SerializeField] audioClip audioClip is invalid because AudioClip is the type, and it is spelt AudioClip, not audioClip. The variable name audioClip is fine because it is something that you introduce here. The AudioClip type/class already exists.

AudioSource.PlayOneShot(audioClip); would mean that you call this method on the class. The method requires an instance/object, though. For this reason, you need a variable. For example:

AudioSource abc = GetComponent<AudioSource>();
abc.PlayOneShot(audioClip);

I named the variable abc on purpose, so it is obvious what the variable name is. Of course, I could have named my variable audioSource.

Did this clear it up for you?


See also:

AudioClip and AudioSource are classes. They’re a special kind of class that’s a Component. Basically, the code (blueprint) that the object is made from.

It’s typical to name the object that was created (or instantiated) with lowercase, though technically you can use upper case if you choose.

When you put a component (like AudioSource) on a GameObject and instantiate (puts it into memory) that GameObject into a gameObject, it also instantiates those components into memory and connects them to that gameObject.

Thank you both for your fast answers!

From what I’ve understood, a class is not an object, and thus because C# is an object oriented language we can’t do stuff to a class (i.e. call a method on a class).

So, we need to instantiate a class as an object by declaring a variable of the class’s type before we can call methods on it. Without doing this would it be like trying to call a method on ‘float’ rather than an actual number? Is that basically what caching is, and the point of caching?

There’s still one thing I don’t understand conceptually. Doesn’t AudioSource.PlayOneShot(audioClip) already have an object: audioClip? Or does AudioSource need also to be an object because we are manipulating one of its properties by making a sound inside the component play? In this case, is the ‘PlayOneShot’ method acting on two objects?

Out of curiosity, what are the differences between this way of doing things:

AudioClip audioClip;
AudioSource audioSource;

void Start()
{
audioSource = GetComponent();
}

void OnCollisionEnter(Collision other)
{
audioSource.PlayOneShot(audioClip);
}

and:

AudioClip audioClip

void OnCollisionEnter(Collision other)
{
GetComponent().PlayOneShot(audioClip);
}

Bonus question: why does ‘audioSource = GetComponent();’ have to be declared inside another method? The Start() method is used in the tutorial video, but I noticed it works if you put it anywhere as long as it is inside another method.

Apologies for asking so many questions, but thank you again for your kind help :slight_smile:

That’s correct. The only exception are static members. For example, we are able to call static methods on the class, and we cannot call static methods on objects. A static method is, for example, Mathf.Clamp(). We cannot create an object of type Mathf and call Clamp on it. Feel free to test that. The compiler will complain immediately. Read the error message.

Here is another example for a static method: AudioSource.PlayClipAtPoint(audioClip);. AudioSource is not a variable but the classname. In your IDE, hover your mouse over PlayClipAtPoint to get a little popup window with additional information.

PlayOneShot is a non-static method in the AudioSource class, hence it requires an object. C# does not care where the object comes from. GetComponent<AudioSource>() returns the first AudioSource object it finds. If it does not find any, it returns null, and you will get a NullReferenceException error.

If you find GetComponent(AudioSource).PlayOneShot(audioClip); difficult to grasp, you could write it this way:

AudioSource as = GetComponent(AudioSource)
as.PlayOneShot(audioClip);

I named the variable as, so my example does not confuse you. Of course, I could have named it audioSource but for the sake of clarity, I opted for as.


Without doing this would it be like trying to call a method on ‘float’ rather than an actual number?

What do you mean by that? Do you have an example?


Is that basically what caching is, and the point of caching?

The computer immediately “forgets” things. We create variables to keep results over time. The reason could be to improve the readability of our code, or because recalculating something is too expensive, or because we must “remember” the value for some other reason.

In C#, objects do not have a name. For this reason, we assign a value to a variable and do things with the variable. In the past, we had to remember the memory address to find our data again. That’s not necessary anymore. The computer does that for us, and we simply use variables.


There’s still one thing I don’t understand conceptually. Doesn’t AudioSource.PlayOneShot(audioClip) already have an object: audioClip?

audioClip is not an object. It is a variable. And that variable may or may not reference an object. We also do not pass on the variable but the value of the variable.


why does ‘audioSource = GetComponent();’ have to be declared inside another method?

It does not matter where you look for the reference. What matters is: audioSource must not be null when you call audioSource.PlayOneShot(clip);. Since GetComponent is a relatively slow method, it might make sense to cache the reference to the AudioSource object instead of calling GetComponent multiple times to look for the same AudioSource object. “Multiple times” is the reason why caching might make sense.

If we call audioSource.PlayOneShot(clip); only once during the lifetime of our object, GetComponent(AudioSource).PlayOneShot(audioClip); is perfectly fine. The only reason for caching might be to increase the readability of the code. See my example with as.


Apologies for asking so many questions, but thank you again for your kind help :slight_smile:

As long as you are genuinely interested in the answers, please don’t apologise for asking questions. :slight_smile:

2 Likes

Caching is basically saving a result of an expression for later use.

While not completely useful, you could have an expression
c = a + b;

So later on, you could use c, instead of having to use a + b. Most times caching is used for storing more costly operations so you don’t need to bog the computer down with a lot of heavy code.

Yes, it does. audioClip is an reference variable (which is an object) that holds a memory location to another object i the heap memory.

Under the hood it is an object. Since that’s run as a static, I believe in Unity it’s loaded into memory on its first use.

Not a lot, they’ll both hit you with a null reference exception since audioClip isn’t defined in either pieces of code :wink:

Both of your versions of code are similar, except in the first version, you cache the GetComponent result. It used to be important to do this a while back when GetComponent calls were resource heavy. You still see it taught. I believe it’s about 2020.1 they started to cache those calls. That being said, Unity also has a habit of removing performance perks like this without notice. That also being said, it is faster to cache it, but to put it in perspective, you might shave a millisecond every now and then.

If you really want to find out, try out the profiler and run a lot of those GetComponent calls and see how it goes compared to cached reference. Add in a simple animation, like a bouncing ball (or 50) and you’ll see how little resources they actually take compared to how powerful devices are these days.

It’s part of the rules of the C# and many other languages. If it didn’t happen this way, the program wouldn’t know when to execure what lines of code.

2 Likes

Privacy & Terms