1
\$\begingroup\$

Why does AudioSource not initializes itself?

Here is my code:

    using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraConfig : MonoBehaviour
{
    public GameObject objToFollow;

    public bool followRabbit;

    // Use this for initialization
    void Start()
    {
        followRabbit = true;
        LevelController.current.cameraWhichLooksForRabbit = this;

        setMusicSource();
        setSoundSources();
    }

    public AudioClip music, rabbitWalksSound, rabbitDiesSound, rabbitFallsSound, enemyAttacksSound;
    private AudioSource musicSrc, rabbitWalksSrc, rabbitDiesSrc, rabbitFallsSrc, enemyAttacksSrc;

    private void setMusicSource()
    {setClipForSrc(musicSrc, music, true);}

    private void setSoundSources()
    {
        setClipForSrc(rabbitWalksSrc, rabbitWalksSound, false);
        setClipForSrc(rabbitDiesSrc, rabbitDiesSound, false);
        setClipForSrc(rabbitFallsSrc, rabbitFallsSound, false);
        setClipForSrc(enemyAttacksSrc, enemyAttacksSound, false);
    }

    private void setClipForSrc(AudioSource src, AudioClip clip, bool loop)
    {
        src = gameObject.AddComponent<AudioSource>();
        src.clip = clip;
        src.loop = loop;
    }

    void Update()
    {
        checkMusicAndStopOrStartIfNecessary();

        if (!followRabbit)
        { return; }

        Transform rabit_transform = objToFollow.transform;
        Transform camera_transform = this.transform;

        Vector3 rabit_position = rabit_transform.position;
        Vector3 camera_position = camera_transform.position;

        camera_position.x = rabit_position.x;
        camera_position.y = rabit_position.y;

        camera_transform.position = camera_position;
    }

    public void playSoundRabbitWalks()
    {
        if (!rabbitWalksSrc.isPlaying)
        { rabbitWalksSrc.Play(); }
    }

    public void playSoundRabbitDies()
    { rabbitDiesSrc.Play(); }

    public void playSoundRabbitFalls()
    { rabbitFallsSrc.Play(); }

    public void playSoundEnemyAttacks()
    { enemyAttacksSrc.Play(); }

    public void stopSoundRabbitWalks()
    {
        if (rabbitWalksSrc.isPlaying)
        { rabbitWalksSrc.Stop(); }
    }

    public void stopSoundRabbitDies()
    { rabbitDiesSrc.Stop(); }

    public void stopSoundRabbitFalls()
    {rabbitFallsSrc.Stop();}

    public void stopSoundEnemyAttacks()
    {
        enemyAttacksSrc.Stop();
    }

    private void checkMusicAndStopOrStartIfNecessary()
    {
        if (SoundManager.Instance.isMusicOn() && !musicSrc.isPlaying)
        { musicSrc.Play(); }
        else if(!SoundManager.Instance.isMusicOn() && musicSrc.isPlaying)
        { musicSrc.Stop(); }
    }
}

Here are screenshot of the exceptions in console and inspector view:enter image description here enter image description here

\$\endgroup\$
2
\$\begingroup\$

AudioSource is a class, which means it is a reference type. The default value of a reference type that is declared without initialization

SomeReferenceType someThing;

is null. That's how C# works.

Even if it were possible for AudioSource to "initialize itself" when declared the way you are declaring them, how would it know what to initialize itself with? AudioSource is about playing back audio clips, so an individual audio source needs to know which clip to play, et cetera.

You need to either explicitly initialize your AudioSource instances in your code (musicSrc = new AudioSource(...) and so on) or expose them to the inspector and set them there. It sort of looks like that latter option is what you expected to be doing, given the screenshot of the inspector in your original screenshots, but what you've shown there is exposure and initialization of the audio clips. Not the sources.


Actually, it looks like you expected setClipForSrc to do this initialization for you, but if that's what you want you need to pass the clip using ref:

private void setClipForSrc(ref AudioSource src, AudioClip clip, bool loop)
{
    src = gameObject.AddComponent<AudioSource>();
    src.clip = clip;
    src.loop = loop;
}

and then call it as setClipForSrc(ref musicSrc, ...). Without ref, what you are doing is simply reseating the local reference inside the function to refer to a new value, you are not actually changing what the member variable references musicSrc et cetera refer to. This would work if all you wanted to do is call functions on src or otherwise mutate it, but if you to completely re-assign it to point to a new object, and you want that re-assignment to propagate beyond the function setClipForSrc, you need to pass the reference src by reference itself, using the ref keyword.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Okay. But is not it is the part of the code which does all the needed initialization: src = gameObject.AddComponent<AudioSource>();? \$\endgroup\$ – ohidano Jun 6 '17 at 16:39
  • 1
    \$\begingroup\$ Yes, I see that now that you switched to code I could search instead of screenshots. You're doing something else wrong in that function, I'll update my answer. \$\endgroup\$ – user1430 Jun 6 '17 at 16:41
  • 1
    \$\begingroup\$ @ohidano I've added more information. \$\endgroup\$ – user1430 Jun 6 '17 at 16:43
  • \$\begingroup\$ it strange, but why your name is not offered as an option when I type @Jos in comments? Anyway it seems like you added a lot of cool info and I am going to read it all right now! Thanks a lot for the help! \$\endgroup\$ – ohidano Jun 6 '17 at 16:46
  • \$\begingroup\$ @ohidano Because I will be pinged automatically by any comment on my answer, the site won't let you auto-complete my name in a comment on my answer, I guess, since it isn't necessary to ping me. \$\endgroup\$ – user1430 Jun 6 '17 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.