Found a weird problem about AudioSource.PlayOneShot
AudioSource _AudioSource_1 = new GameObject().GetComponent<AudioSource>();
AudioSource _AudioSource_2 = null;
Debug.Log(_AudioSource_1.Equals(_AudioSource_2));
_AudioSource_1.PlayOneShot(new AudioClip());
Debug.Log("Pass1");
_AudioSource_2.PlayOneShot(new AudioClip());
Debug.Log("Pass2");
Here is my code and what console displayed.
I'd appreciate it if someone could tell me why this
_AudioSource_1.PlayOneShot(new AudioClip());
can pass.
console + image cannot be displayed, revise your question
Answer by hexagonius · Feb 23, 2017 at 07:50 PM
I know that unity overloaded null, maybe equals also, for several reasons. you are, somehow, successfully using the constructor on the returned AudioSource. maybe it creates a new instance but overrides null so that it's not pointing to any legal C++ native component anymore effectively comparing nulls.
don't use new on any unity class. use AddComponent if you need another.
Thanks a lot! That makes sense to me. By the way, AudioClip is derived from Object, it can't be added to a GameObject.
Answer by Hlero · Feb 24, 2017 at 08:29 AM
I did some research and found, truly like @hexagonius said, unity overrided something like Equals, == and != to build a Null Object pattern.
So here is my code to test:
AudioSource _AudioSource_1 = new GameObject().GetComponent<AudioSource>();
Debug.Log(object.Equals(_AudioSource_1,
FormatterServices.GetUninitializedObject(typeof(AudioSource))));
Debug.Log(_AudioSource_1.GetType());
Debug.Log(_AudioSource_1);
_AudioSource_1.PlayOneShot(null);
Debug.Log("Pass1");
And Console:
It looks like GetComponent<T> will always return reference of a T type instance if T is a NATIVE component type, whether or not there is a T component attached to the gameobject.
But when you want to get a custom component, if there is no one attached, GetComponent will definitely return a real null. Like this:
GameDataState _GameDataState = new GameObject().GetComponent<GameDataState>();
Debug.Log(object.Equals(_GameDataState, null));
Debug.Log(_GameDataState.enabled);
Debug.Log("Pass");
It would yield a NullReferenceException.
So you can see unity overrided some method to make you think it's null when you try to get a not attached component, and i think maybe they forgot to deal with this PlayOneShot method so it can be invoked.
it's just plain wrong to use new here. A GameObject must not be created through it's constructor. and now that I read more careful it's just that you call GetComponent on a new gameobject that simply returns null because there's no such component. So it's not even some strange overload, it's simply what GetComponent does when there's no component.
I use new just for test and i have tried to create a gameobject through inspector and find it, then i called GetComponent<AudioSource>().PlayOneShot(null), the result was same. Look the question my friend! $$anonymous$$y problem is when i call GetComponent<AudioSource> on a gameobject without AudioSource, it returns me a reference of an AudioSource instance, and i can call PlayOneShot method of it without any exception. It is supposed to be a NullReferenceException but it's not! That's what confused me ok?
Your answer
Follow this Question
Related Questions
AudioSource.PlayOneShot with negative pitch won't start new sounds 0 Answers
Help to play music whenever the character enters a GameObject... 1 Answer
Second AudioClip won't play 0 Answers
How to make an editor extension to unity ui for switching audio clips? 0 Answers
AudioSource.Play plays every sound at once,AudioSource.Play Plays every source at once 0 Answers