Home > Back-end >  The object of type 'BallMovement' has been destroyed but you are still trying to access it
The object of type 'BallMovement' has been destroyed but you are still trying to access it

Time:05-21

I checked all over SO but couldn't find an answer that worked (or at least that I understood how to implement).

I just started Unity not too long ago and I'm trying to make a Pong clone. The game work great on the first run, but when a player wins and it switches to scene 2, then you press the Play Again button and go back to scene 1 (gameplay scene) I get this error while trying to play:

enter image description here

heres my Start method for the problematic class.

public class BallMovement : MonoBehaviour
{
    Rigidbody2D ball;
    Vector2 vel;

    // Start is called before the first frame update
    void Start()
    {
        float posY = Random.Range(-150, 150);
        ball = GameObject.FindGameObjectWithTag("Ball").GetComponent<Rigidbody2D>();
        transform.localPosition = new Vector2(-19, posY);
        vel.x = 250;
        vel.y = -150;
        ball.velocity = vel;

        GameStateManager.PlayerScored  = Start;
    }
...

sorry for asking such a dumb/ vague question but I'm seriously stuck, I've been working on this pong clone for 8 hours and I managed to cross every hurdle on my own besides this

CodePudding user response:

Mmm I think your bug probably lies on this line:

GameStateManager.PlayerScored  = Start;

I'm going to guess that GameStateManager is somehow surviving across scene loads, whether that's a GameObject that doesn't destroy or a ScriptableObject or something.

What I think is happening is that you're adding a delegate to your PlayerScored event and then that event isn't getting reset when you're changing scenes. When you come back to the scene the second time, that instance of the BallMovement class has been deleted, and when that event fires you get the error The object of type 'BallMovement' has been destroyed but you are still trying to access it.

Another kind of concerning thing I see with this is that you're having a method add itself to an event - when you run Start the first time, on the Unity Start callback, you add yourself to the PlayerScored event.

Then, when PlayerScored fires, you add Start to the PlayerScored event a second time. Then the second time PlayerScored triggers it fires Start twice, so you add it twice, and the third trigger now has four events to call. Duplicates are allowed in event invocation lists so you'll trigger Start for every time it's in the PlayerScored list, and every time it's called it adds itself again.

The way around this would be to move that functionality out of start, and to remove the delegate from the event when the GameObject is destroyed. Consider the following instead:

public class BallMovement : MonoBehaviour
{
    Rigidbody2D ball;
    Vector2 vel;

    // Start is called before the first frame update
    void Start()
    {
        GameStateManager.PlayerScored  = OnPlayerScored;
        OnPlayerScored(); // Fire this once on Start to get everything setup!
    }

    void OnPlayerScored()
    {
        float posY = Random.Range(-150, 150);
        ball = GameObject.FindGameObjectWithTag("Ball").GetComponent<Rigidbody2D>();
        transform.localPosition = new Vector2(-19, posY);
        vel.x = 250;
        vel.y = -150;
        ball.velocity = vel;
    }

    void OnDestroy()
    {
        GameStateManager.PlayerScored -= OnPlayerScored;
    }

// ...

CodePudding user response:

It seems you Delete/ Dispose the BallMovement class. I assume this is because you Delete/ Dispose the ball, and don't create the new ball with the BallMovement class/ script.

  • Related