Adding Power Ball Power-Up

Hello, I’ve uploaded my project to WeTransfer (29.3MB): https://we.tl/t-PabgbxqKpa

You can active Power-Ball with Yellow Up sprites. You can simply re-produce error by playing. I am sorry if my code is messy :slight_smile: Thank you very much!

Hi Tugberk,

So, I ran your game and I see no error messages.

I dragged the yellow PowerUpPowerBall prefab into the scene, just above the paddle and ran the game, again it ran without any errors.

Can you perhaps provide more detailed steps of how to produce the actual error?

Hello,

Sorry, my mistake. You need to play the game and active Powerball powerup. I get the error when trying to activate Powerball. But, sometimes I don’t get the error and Powerball gets activated. I guess it is about timing. I believe you’ll get the error if you play 3-4 times.

When you say “activate the Powerball” - what does that actually mean? Do you mean I need to collect the yellow power-up which falls from a block?

Yes exactly, it is when I get the error

Ok, so for testing purposes, how do you limit your power-ups so that only the PowerBall power-up is available in your game? Is this what the array of “Ball Types” is on the Player GameObject?


Updated Thu Jan 31 2019 20:04

Don’t worry, I see it, its just in code, a bit of randomness


Updated Thu Jan 31 2019 20:11

Tweaked a couple of things to make the problem occur more reliably.

First, I change PowerUpInstantiate within Block.cs to set whichPowerUp to 4 instead of a random value, we don’t care about the other power-ups at this point;

whichPowerUp = 4;

Next, I changed PowerBall within Paddle.cs so that the yield was for only 3 seconds instead of 30;

yield return new WaitForSeconds(3);

When I run the game now the only powerups I get are the PowerBall and the error is produced.

If I collect a power-up and then pause the game I can step through frame by frame. After the 3 seconds of power-up has run out, your error occurs - if - a block has been destroyed.

As the physics engine is being used to detect collisions, and this takes place more than once per frame, I suspect what is happening is that the collision occurs with the ball and the block, the block is destroyed, but it has not yet been removed from your list of blocks in Block.cs, and for a briefly moment you try to access an object that no longer exists.

To protect against this you can put a check around your code where you try to access the blocks in your list, specifically, in Paddle.cs in the PowerBall method;

IEnumerator PowerBall()
{

    LoadPowerBallSprite();

    foreach (Block blocks in Block.blocks)
    {
        if(blocks)
        {
            blocks.GetComponent<BoxCollider2D>().isTrigger = true;
        }     
    }

    yield return new WaitForSeconds(3);

    LoadRegularBallSprite();

    foreach (Block blocks in Block.blocks)
    {
        if (blocks)
        {
            blocks.GetComponent<BoxCollider2D>().isTrigger = false;
        }
            
    }
}

In the above you can see the two if statements I have added, which basically say, whilst iterating through the list of blocks, only if the block exists at this moment in time, change the isTrigger property.

Running the game after these changes I was unable to reproduce the error.

Hope this helps :slight_smile:

p.s. for readability I’d change your foreach statements to read like this;

foreach(Block block in Block.blocks)
{
    // ...
}

e.g for each singular in multiple :slight_smile:

No, I use Ball Types for changing ball sprite. When a block destroyed I call PowerUpInstantiate method where you can arrange power-ups:

  private void PowerUpInstantiate()
    {
        whichPowerUp = Random.Range(1, 6);
        if (whichPowerUp == 1)
        {
            Instantiate(powerUpPaddleIncrease, transform.position, powerUpPaddleIncrease.rotation);
        }
        if (whichPowerUp == 2)
        {
            Instantiate(powerUpExtraBall, transform.position, powerUpExtraBall.rotation);
        }
        if (whichPowerUp == 3)
        {
            Instantiate(powerUpPaddleDecrease, transform.position, powerUpPaddleDecrease.rotation);
        }
        if (whichPowerUp == 4)
        {
            Instantiate(powerUpPowerBall, transform.position, powerUpPowerBall.rotation);
        }
        if (whichPowerUp == 5)
        {
            Instantiate(powerUpPaddleLock, transform.position, powerUpPaddleLock.rotation);
        }
    }

Oh, I see you found it :slight_smile:

See above, you replied as I was updating my previous post and the above has a solution for you.

Incidentally, on a game play related note, have you considered what happens when the player runs out of white blocks where they can get a power-up and the one red block still remains - they will be unable to destroy it.

Thank you, I understand the problem. Actually, I’ve suspected of this and tried to change Script Execution Order to Ball > Paddle. What do you think about this approach?

Yes, I’m aware of this. Current level design is just for test purposes.

1 Like

The execution order is another possibility, it crossed my mind earlier today, however that does tuck away any potential fix (if it works), e.g. you have to remember that you’ve made that change in the execution order.

Yes, if statement looks like a better solution. I’ve added if statements to my code. I didn’t get the error, but sometimes Powerball doesn’t get activated.

1 Like

So, this would be when you collect the power-up but then nothing happens? Again, is that re-producible?

Yes, exactly. I think it is the same with the error. Instead of giving the error, nothing happens.

I would start by adding some Debug.Log statements where you detect the collision. Make sure you don’t out them in any if statements initially, just check that the console outputs a message when you have collected the power- up.

From there, start adding the Debug.Log statements in the methods which are called subsequently and both in and around any logic so you can see if the code gets called so far but then because of something else doesn’t happen.

The null check we talked about yesterday is only affecting the isTrigger property of a block, there’s no reason this would hide and issue collecting a power-up.

Hello,

I can collect the power-up and it actually loads the ball sprite for power ball I assigned. The problem is it doesn’t call isTrigger = true. I’ve tested with Debug.Log statements, this is where I have a problem:

  IEnumerator PowerBall()
    {
       
        LoadPowerBallSprite();

        foreach (Block blocks in Block.blocks)
        {
            if (blocks)
            {
                Debug.Log("Bug");
                blocks.GetComponent<BoxCollider2D>().isTrigger = true;
            }
        }

It doesn’t call Debug.Log statement here. However, I think I’ll pass this bug and go on with the course. Thank you for your help!

Hi,

That Debug.Log statement doesn’t really imply a bug, it just mea s you iterated through your collection of blocks and on each iteration, where there was a block you output a message.

A better use might be;

if(blocks) 
{
    blocks.GetComponent<BoxCollider2D>().isTrigger = true;

    if(blocks.GetComponent<BoxCollider>().isTrigger != true) 
    {
        Debug.Log(blocks.name + ' isTrigger = false') ;
    } 
} 

Unless you have something else changing the isTrigger property of the blocks you should see this message at all when the power up is enable, which would be a good thing.

Hi @Tugberk_Dilbaz, is this resolved now?


See also;

Privacy & Terms