Destroying balls

So I added “Lives” concept.
Saw that still if you clicked the mouse button balls still came up, so its resolved cheking before for “hasStarted”
but I wanted to destroy the balls.
When I destroy the ball (I take the object from the collision) its fine but when I try to destroy the next ball it says it already has destroyed the object. I can see on my game status the Serialized field I use as a mold (type Ball)

Hi Alfredo,

Any chance you could zip up your project files and share them? I would be happy to take a quick look at this for you.

The forum will allow uploads of up to 10MB, if your project files (zipped) are larger than that you would need to use a service such as Google Drive or Dropbox, and then share the URL.

Hi Rob! thanks for your time
https://drive.google.com/open?id=11T2YSYPsFBLo-Dt-WA9G5wlltssZivdl
when I try to destroy a ball for the second time it fails, if I dont destroy them everything goes smooth.
when There is a collision, from the collider I can get the game object it collided with for example “pill” but I dont know how to cast it as Pill nstead of game object.
I currently do a FindObjectOfType but if theres to which one would I know it is

Sorry if its too much

Alfredo

Hi Alfredo,

I will take a look now for you. :slight_smile:

Ok, I’ve had a look.

I’ve opened Level3, and I can see what you’re trying to do.

The NullReferenceException error being thrown in for line 90 of GameStatus.cs is because you are trying to access the gameObject of Ball in your Instantiate method, but it has no reference to this.

If you select your GameStatus GameObject in the Hierarchy and look at the Inspector you’ll note that you haven’t dragged it across to create that reference.

Once you’ve done this and run the game, you then get additional errors, lines 31 and 62 of Ball.cs, this time it’s because the Ball that you have just instantiate doesn’t have any references to the Paddle.

If you want to continue on the route you are on you will need to perhaps change some of your scripts so that they Find the GameObjects in the scene that they need to interact with when they are first instantiated, e.g. in the Awake or Start methods. Whilst this will work, there is a performance cost you using the Find methods, but you’ll probably not really notice it in a game of this size.

What you could consider is your player death process. Ask yourself, why is it that you want to both destroy and then instantiate the same GameObject? Depending on the number of objects involved, this can also lead to a performance issue, again, not for a game of this size, but something worth considering.

There is nothing special about the ball you are about to destroy, so why not just re-position it to the paddle instead of destroying and instantiating? That way you get to use the same GameObject and it’s the one you put in the scene initially and has all the references wired up.

You can achieve this by making the following changes;

  • select the GameStatus GameObject in the Hierarchy
  • drag the Ball GameObject from the scene into the Ball property of the GameStatus GameObject
  • add the following method to your Ball.cs script;
      public void Reset()
      {
          hasStarted = false;
          transform.position = new Vector2(paddle1.transform.position.x, 0.702f);
      }
    
  • modify your GameStatus.cs script as follows;
     public void LoseLife(GameObject x)  // this signature is no longer required
     {
     	lives--;
     	livesText.text = lives.ToString();
    
     	if (lives<=0)
     	{
     		SceneManager.LoadScene("GameOver");
     	}
     	else
     	{
     		ball.Reset();
     	}
     }
    
  • save the script
  • save the scene
  • run the game

You will now find that you lives system works. When the player misses the ball and it hits the lose collider the lives are reduced and the ball is respawned, because the Reset method within Ball.cs also resets the hasStarted bool, the ball patiently waits on the paddle to be launched.

Some additional points;

  • the method LoseLife within GameStatus.cs no longer required the GameObject x parameter to be passed from the OnCollisionEnter2D method within LoseCollider.cs, you can, and should, remove this.

  • you may want to have a think about the design/architecture of how things are hung together at the moment. For example, the Lose Collider gets a reference to the GameObject which has collided with it, this is the Ball. You run off to Find (expensive and slow) the GameStatus object. This has a reference to the Ball in the scene and calls it’s Reset method after updating the lives display. Quite a lot of things have to know about other things in this current setup. You could, for example, have the Lose Collider call Reset on the Ball, when you catch the collision, but should it?

    These are the questions you should start to ask yourself, is it appropriate for this object to know about that object. I don’t think it’s covered in this section, but later on your will cover delegates, these can be useful in situations like this as you can effective broadcast a message and have objects subsribe to receiving it. So you could, for example, have the Lives Display listening for a messagee that says “Life Lost”, at which point it does it’s thing, but it doesn’t care who said it, it just does what it has to do. The same could be true of the ball and so on.

    It does work, and it will give you a platform to continue from, but if you were to enhance/expand this game you might want to start to focus on this aspect a little bit more.

  • housekeeping - remove any unused code, e.g. methods that are not being referenced, unsused variables, commented out code, it will make what you are looking at easier to follow

Hope the above helps, if I’ve missed anything please let me know :slight_smile:

1 Like

Hi Rob!
First of all thanks for your answer, definitely its better to just reposition the ball. But at some point I had more than one ball I just wanted to destroy the unused ones.
I will make the changes as your suggestions.
Probably I was trying to drink from a hose at this point on my knowledge.
What I was doing in the Lose collider just frustrated me that from the collider I could get the gameobject is collided with, but I could cast it as a ball or pill so I couldnt access its methods.
And if I did a Find which as you say its expensive, but I had more than one how would I know which was the one that actually collided? If I have to pills running down which would be the one I catched with the paddle?

Thanks for your clarifications

1 Like

Hi Alfredo,

Ok, so quite a few questions in your reply, I’m going to try and unstitch them and reply to them all individually, if I miss anything please let me know.

But at some point I had more than one ball I just wanted to destroy the unused ones.

Aha! Ok, well that’s a bit different to the original problem, you obviously wouldn’t want to re-position them all on the paddle (as fun as that might be!). There are a couple of things you could do here…

If there are multiple balls in play then presumably the player has collected a power-up. You could use that to set a bool which would indicate that the power-up was in effect, perhaps something like this;

bool multiBall = true;

I’d probably also create an array to hold the references of the multiple instantiated Ball GameObjects, this would save us having to do a Find later on and provides us with a count of how many we have. I would also add the original Ball to the array also. It doesn’t matter which ball was the original, all that matters is that the player has at least one left or loses a life etc.

In the code which is currently detecting the collision of the ball and respawning it, you could first check to see if the multiBall power-up was in effect. If it isn’t, then we just respawn the ball - as long as the player has enough lives. That’s what you have now.

If the multiBall power-up is in effect then we would handle the situation differently. We have an array containing all of the Ball GameObjects, when we detect a collision we would remove the Ball that has made the collision from the array. Next, we check the count of balls in the array and act accordingly.

If there are 2 or more balls still in the array then we are still in multiBall power-up mode, in which case, we can safely Destroy the GameObject that made the collision;

Destroy(collision.gameObject);

When we test and there is only 1 ball left in the array then we are no longer in multiBall mode, so we should reset the bool to false;

multiBall = false;

We would then handle the collision as if it were a normal ball collision, e.g. if the player has lives left, respawn the ball on the paddle, reduce lives. If the player doesn’t have any lives left, load the game over scene.

There are probably several ways you could handle the multiball power-up mode, the above is just one suggestion. Keeping track of the GameObjects is key.

An alternative to the array might be to have an empty GameObject in the scene which you use as a parent for all of the balls, including the original. When there you get the power-up, instantiate more into that GameObject as children. You would get a reference once to the parent GameObject, but then in the above, rather than checking the length of the array, you could just return a count of the children the parent GameObject has.

What I was doing in the Lose collider just frustrated me that from the collider I could get the gameobject is collided with, but I could cast it as a ball or pill so I couldnt access its methods.

I’m assuming you mean you couldn’t cast it.

So, what you can do is base your detection upon the script components that you have on the GameObjects that are making the collision, for example;

private void OnCollisionEnter(Collision collision)
{
    GameObject theOtherGameObject = collision.gameObject;

    if(theOtherGameObject.GetComponent<Ball>)
    {
        // I am a ball
    }
    else if(theOtherGameObject.GetComponent<Pill>)
    {
        // I am a pill
    }
}

Note, the above logic assumes that nothing would have both a Ball and Pill script component attached.

You could also use tags, and then check the tag for the GameObject, but this would then mean you need to manage the tags and add scripts to your GameObjects, so you might as well just use the scripts.

And if I did a Find which as you say its expensive, but I had more than one how would I know which was the one that actually collided?

The GameObject that collided would be the gameObject of collision, e.g.

private void OnCollisionEnter(Collision collision)
{
    GameObject theGameObject = collision.gameObject;
}

I hope the above helps, fairly lengthy reply and lots to take in, I think I’ve answered all of your questions but if I’ve missed anything please let me know :slight_smile:

1 Like

Many thanks, I think I can pretty much do a lot with this

Thanks a lot for the arch class!

1 Like

You’re very welcome Alfredo. :slight_smile:

It would be great to see you share your game again after the next update, I would like to have a go with the multi-ball power-up :slight_smile:

BTW the only remaining question is I know I can get the game object from the collision, but its game object rather than a ball, pill, etc
how can I access its properties or methods? or cast it as its class

Hey,

Have a look above at the OnCollisionEnter example I have, in it I did this;

private void OnCollisionEnter(Collision collision)
{
    GameObject theOtherGameObject = collision.gameObject;

    if(theOtherGameObject.GetComponent<Ball>)
    {
        // I am a ball
    }
    else if(theOtherGameObject.GetComponent<Pill>)
    {
        // I am a pill
    }
}

That’s the first step, so you know which type of GameObject you are dealing with. If you then want to access specific members of the type Pill or Ball, you could do this;

theOtherGameObject.GetComponent<Pill>().EnablePowerUp();

or, if you have several things to do, perhaps get a reference to the component in the first place;

Pill pill = theOtherGameObject.GetComponent<Pill>();

pill.EnablePowerUp();
pill.EnableAwesomeParticleEffects();
pill.SomeOtherFunctionality();

Be conscious of what you start calling from where though, it easy to start creating situations where the wrong objects are running the show. Each object should have its own responsibilities.

The Pill itself perhaps doesn’t need a lot of functionality, just the type of power-up it is going to enable. At the point of collision you could then get a reference to the pill’s power-up type and enable that on the paddle (player).

private void OnCollisionEnter(Collision collision)
{
    GameObject theOtherGameObject = collision.gameObject;

    if(theOtherGameObject.GetComponent<Ball>)
    {
        // I am a ball
    }
    else if(theOtherGameObject.GetComponent<Pill>)
    {
        Pill pill = theOtherGameObject.GetComponent<Pill>();

        EnablePowerUp(pill.PowerUp);
    }
}

In the above, assumed to be on the paddle, the OnCollisionEnter method determines whether it’s made contact with the ball, or a pill. If it was a pill then it grabs a reference to it and then calls the EnablePowerUp method on the paddle, passing it the pills PowerUp as a parameter.

I’m not 100% happy with the above example, mainly because we are using the GetComponent<T> method to firstly determine what we are dealing with, and then use it again to actually deal with it, e.g. two calls to the same thing. As with all things, there will be ways to improve it but often its better to make it work and then tidy up / improve after.

Hope this helps :slight_smile:

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms