3
votes

I'm facing audio problems in my project. There are three paddle game objects and one cube. Cube has Rigidbody2d or BoxCollider2d. And there is also a button script attach to cube which has button function when we click on button cube Kinematic becomes false and drop on the paddle. When it's collide with any paddle cube destroy and instantiate again with new prefab. When Cube is falling sound is play and cube is destroy. New cube is instantiate when again click on button then error came.

MissingReferenceException: The object of type AudioSource has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.

Scripts on all paddles:

public class Paddle : MonoBehaviour
{
    [SerializeField]
    private AudioSource source;
    [SerializeField]
    private AudioClip hit;
    [SerializeField]
    private BoxCollider2D collide;
    [SerializeField]
    private GameObject Clone;

    void Awake()
    {
        collide.isTrigger = true;
    }

    void OnTriggerEnter2D(Collider2D target)
    {
        source.PlayOneShot(hit);
        Destroy(target.gameObject);
        Instantiate(Clone, new Vector3(0f, 4.51f, 0f), Quaternion.identity);
    }
}

Cube Script:

public class Cube : MonoBehaviour 
{
    [SerializeField]
    private AudioSource source;
    [SerializeField]
    private Rigidbody2D body;
    [SerializeField]
    private AudioClip play;
    private Button bt;
    private float pos;
    public bool check;

    void Start()
    {
        bt = GameObject.FindGameObjectWithTag("Button").GetComponent<Button>();
        bt.onClick.AddListener(Fire);
        body.isKinematic = true;
    }

    void Update()
    {
        if (check)
        {
            return;
        }

        Vector3 temp = transform.position;
        pos = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
        temp.x = Mathf.Clamp(pos, -6.25f, 6.25f);
        body.position = temp;
    }

    public void Fire()
    {
        GameObject.FindGameObjectWithTag("Player").GetComponent<Cube>().check = true;
        GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody2D>().isKinematic = false;
        source.PlayOneShot(play);
    }
}

Cube image: enter image description here

Paddles image: enter image description here

New Export package: https://drive.google.com/file/d/0B1H5fdK2PJAnSXVPdmE5Z3J1SUU

Problem in Video: https://drive.google.com/file/d/0B1H5fdK2PJAnYzRfVnlQT1FyTlE

3
You should show the methods that the button calls, the one creating the new cube. I guess it is calling on the cube and is linked to the old AudioSource that is destroyed with the first cube. You would have to update the reference with the new AudioSource attached on the new Cube.Everts
@fafase on Cube Script public void Fire() method call on button click and in paddle image i show a clone prefab which add in paddle inspectorVen Nilson
Is it on the same link? Coz that one works just fine again.Everts
@fafase i edit my question and reuploaded linkVen Nilson
The Reagain package is working just like the previous.Everts

3 Answers

3
votes

Your linked package works fine, it does play the sound every time I launch and destroy a cube.

Nonetheless, you should remove the method on destroy. Unity does not throw any error nor warning when a non-persistent listener is null, kinda weird but this is how it is. You should remove it manually:

void OnDestroy(){
    bt.onClick.RemoveListener (Fire);
}

But your package does not throw any error when I run it.

Though, I would rethink your approach, instead of the cube assigning its Fire method to the Button event, I would have a script on the button containing the Fire method as well as the AudoiSource and clip. Then on Start, the Cube would pass itself so that the button could access its Cube and Rigidbody2D component.

Best would be to pass a class that contains those are members:

public class CubeArgument{
    public readonly Rigidbody2D rg = null;
    public readonly Cube cube = null;  
    public CubeArgument(Rigidbody2D rg, Cube cube){
        this.rg = rg;
        this.cube = cube;
    }
}

then here goes your Cube start method:

void Start () {
    bt = GameObject.FindGameObjectWithTag ("Button");
    bt.GetComponent<ButtonController> ().Init(new CubeArgument(body, this));
    body.isKinematic = true;
}

The ButtonController reference could even be made static since there is only one for the whole level.

and then on the button you have a ButtonController:

public class ButtonController : MonoBehaviour{

     Cube currentCube = null;
     Rigodbody2D currentRig = null;
     public void Init(CubeArgument ca){
         currentRig = ca.rg;
         currentCube = ca.cube;
     }
     public void Fire(){
         if(currentCube != null){ currentCube.check = true; }
         if(currentRig != null) { currentRig.isKinematic = false; }
     }
}

Fire is passed as listener to the Button onClick and this is it.

1
votes

your problem can be from many different places. my guesses: 1)problem with your build: rebuild your code or export all of your package to new project and retest.

2)your target framework: latest version of unity(i have 5.1) just support to .net 3,5 and unity 4.x supports 2,5 i think. so chek your target framework to not to use functions that is not functional in your version

3)settings of your platform that your editor is running on: it can be volume of your platform to many other settings, first option to know that is run your project on other machine (maybe its a unity bug that part of code is not good for your hardware or driver on platform)

1
votes

Edit: OP was using version 5.1.1. This error does not repeat after Unity 5.2.

Tried your package and it is working fine! No errors. Audio played when instantiated.

Are you still facing errors? Weird, dude. Sounds like something is not clean enough. Maybe there is some issue with your build.

Few things you could try:

1- Try restarting your Unity. Maybe this will force Clean things.

2- Create a new project and import your own package to test it!

3- I'm using Unity 5.3.0f4 what Unity version are you using? Try an update.

If none of above works, there is something wicked going on with your AudioSource reference and I can't help you with my actual knowledge. But still we can try to do different approaches for that. Instead of physically referenced it (Dragging and dropping), do it at the start of your script.

Desperate approach 1

On Cube.cs:

First remove [SerializeField] located above of private AudioSource source; and add the following line on the Start() method:

source = gameObject.GetComponent<AudioSource> ();

Practically the same, but now the script is referencing the own object Audio Source for you. Do the same approach with Paddle.cs. [remember to check the audio name when applying the approach for Paddle script. On paddle the audio name is PlayOneShot (hit) not PlayOneShot (play)].

If this still trigger some error. Let's try another approach.

Desperate approach 2

On Cube.cs:

Remove/Comment the following line on Fire() method:

source.PlayOneShot (play);

Add the following line to Fire() method:

gameObject.GetComponent<AudioSource> ().PlayOneShot (play);

This will get your actual AudioSource on the go. Do the same approach on Paddle.cs [remember to check the audio name when applying the approach for Paddle script. On paddle the audio name is PlayOneShot (hit) not PlayOneShot (play)].