Trouble understanding why GameObject.Find works but declaring/initializing a GameObject and using GetComponent does not
I have two scripts. EnemyTriggerScript.cs which I want to handle collision detection and play audio from my AudioManagerScript.cs.
The code below works if I use GameObject.Find but will not work when I provide an audioManagerGameObject and do a GetComponent on it.
I have verified that my GameObjects are assigned to the respective scripts in the inspector.
The error I get is "Unassigned Reference Exception: The variable audioSource of AudioManagerScript has not been assigned. You probably need to assign the audioSource variable of the AudioManagerScript script in the inspector."
Obviously this is telling me what is wrong, however I thought that initializing my audioSource in the AudioManagerScript was doing that???
audioSource = GetComponent();
I also looked throughout the inspector and specifically at the AudioManagerGameObject and AudioManagerScript.cs which I am not sure how to assign an audio source even if I made my variable public.
I am still really new to all of Unity and C# so I understand this is probably something simple but I have been searching for hours on end trying to solve this, any help would be appreciated.
EnemyTriggersScript.cs
using UnityEngine;
using System.Collections;
using UnityEditor;
public class EnemyTriggersScript : MonoBehaviour
{
[SerializeField] private GameObject audioManagerGameObject;
private AudioManagerScript audioManagerScript;
void Start ()
{
// This is the GetComponent that is not working
//audioManagerScript = audioManagerGameObject.GetComponent<AudioManagerScript>();
// This is working
audioManagerScript = GameObject.Find("AudioManagerGO").GetComponent<AudioManagerScript>();
}
void OnTriggerEnter2D(Collider2D collision)
{
// checking for collision with shield2
if (collision.gameObject.name == "shield2")
{
audioManagerScript.AudioPlayPlayerShieldDown();
}
}
AudioManagerScript.cs
using UnityEngine;
using System.Collections;
public class AudioManagerScript : MonoBehaviour
{
[SerializeField] private GameObject audioManagerGameObject;
[SerializeField] private AudioClip audioClipPlayerShieldDown;
private AudioSource audioSource;
void Start ()
{
audioSource = GetComponent<AudioSource>();
}
public void AudioPlayPlayerShieldDown()
{
audioSource.PlayOneShot(audioClipPlayerShieldDown, 1);
}
}
@Thajocoth @$$anonymous$$avina
So I just started a brand new 2D Project. Created 3 cubes, gave them all rigidbody2d and box colliders. Spaced them apart top, middle, and bottom, idea is to have middle cube bound between the top and bottom cubes and play sounds when it collides then reverse direction. In the two screenshots you can see that I only exposed the two audioclips on the Audio$$anonymous$$anagerGameObject and the Audio$$anonymous$$anagerGameObject to the EnemyGameObject and it all works. However going back to my original code I cannot reproduce the desired result.
Audio$$anonymous$$anagerScript.cs
using UnityEngine;
using System.Collections;
public class Audio$$anonymous$$anagerScript : $$anonymous$$onoBehaviour
{
public AudioClip audioClipOne;
public AudioClip audioClipTwo;
private AudioSource audio$$anonymous$$anagerScriptAudioSource;
void Start ()
{
audio$$anonymous$$anagerScriptAudioSource = GetComponent<AudioSource>();
}
public void PlayClipOne()
{
audio$$anonymous$$anagerScriptAudioSource.clip = audioClipOne;
audio$$anonymous$$anagerScriptAudioSource.Play();
}
public void PlayClipTwo()
{
audio$$anonymous$$anagerScriptAudioSource.PlayOneShot(audioClipTwo,1);
}
}
EnemyScript.cs
using UnityEngine;
using System.Collections;
using UnityEditor;
public class EnemyScript : $$anonymous$$onoBehaviour
{
private float speed = 5.0f;
Vector3 movedir = new Vector3(0,1,0);
[SerializeField] private GameObject audio$$anonymous$$anagerGameObject;
private Audio$$anonymous$$anagerScript audio$$anonymous$$anagerScript;
private AudioSource audioSource;
void Start ()
{
audio$$anonymous$$anagerScript = audio$$anonymous$$anagerGameObject.GetComponent<Audio$$anonymous$$anagerScript>();
audioSource = audio$$anonymous$$anagerGameObject.GetComponent<AudioSource>();
}
void Update()
{
transform.position += movedir * speed * Time.deltaTime;
}
void OnTriggerEnter2D(Collider2D wut)
{
if (wut.gameObject.name == "TopCube")
{
movedir.y = movedir.y*-1;
audio$$anonymous$$anagerScript.PlayClipOne();
}
if (wut.gameObject.name == "BotCube")
{
movedir.y = movedir.y*-1;
audio$$anonymous$$anagerScript.PlayClipTwo();
}
}
}
This is because Audio$$anonymous$$anagerScript.cs is not the same as your original post.
If you look at the very top where you first post Audio$$anonymous$$anagerScript.cs you will see these variables declared
[SerializeField] private AudioClip audioClipPlayerShieldDown;
audioClipPlayerShieldDown is private which means it is null and is never set. So when you go access it here
public void AudioPlayPlayerShieldDown()
{
audioSource.PlayOneShot(audioClipPlayerShieldDown, 1);
}
You will get an error because audioClipPlayerShieldDown is null.
Now your new script looks like this
public AudioClip audioClipOne;
public AudioClip audioClipTwo;
which allows you to actually set the variables in the inspector. As long as they have been set in the inspector you will not get an error. But if you set them to None in the inspector you will.
To test that I switched them from public to [Serialized] private and it still works...Serialized still allows me to assign them in the inspector. Which is what I had all along. I do appreciate you guys looking at this though.
using UnityEngine;
using System.Collections;
public class Audio$$anonymous$$anagerScript : $$anonymous$$onoBehaviour
{
[SerializeField] private AudioClip audioClipOne;
[SerializeField] private AudioClip audioClipTwo;
private AudioSource audio$$anonymous$$anagerScriptAudioSource;
void Start ()
{
audio$$anonymous$$anagerScriptAudioSource = GetComponent<AudioSource>();
}
public void PlayClipOne()
{
audio$$anonymous$$anagerScriptAudioSource.clip = audioClipOne;
audio$$anonymous$$anagerScriptAudioSource.Play();
}
public void PlayClipTwo()
{
audio$$anonymous$$anagerScriptAudioSource.PlayOneShot(audioClipTwo,1);
}
}
Answer by Thajocoth · Jun 20, 2016 at 05:20 PM
Wouldn't audioManagerGameObject be null in that first Start()? It's declared, but not set to anything. If it was public, you could set that in the inspector to point to the right object.
GameObject.Find() will search through ALL gameObjects in the scene to find the first one that matches what you're looking for. When possible, I recommend staying away from such searches in favor of setting the variable directly in the inspector by making it public.