How to stop execution of a functions after x seconds

in my code there is a function to change the gravity scale of a rigidbody2d and its working fine
but i want to stop the execution of this function and reset the gravity scale value to its original value after 30 seconds

code :

void OnTriggerEnter2D(Collider2D x){

	if (x.gameObject.tag == "Player") {
		ball.gameObject.GetComponent<Rigidbody2D> ().gravityScale = 0.7f;}

the Original gravity scale is set to 1

Hello @Kamal_Ezz-eldin,

You could use a coroutine for this. Using a coroutine would allow the execution / checking whether the 30 seconds had expired but without holding up the current frame.

Hope this helps.


See also;

1 Like

Thanks Rob i applied the coroutine to my code but i found that my code after ( yield return new WaitForSeconds(); ) isn’t working
So i created a simple croutine got only print functions to test how it works
here it is

void OnTriggerEnter2D (Collider2D x)
{
if (x.gameObject.tag == “Player”) {
StartCoroutine (speedUp());
}
}

IEnumerator speedUp(){
	print ("message delayed for 3 sec");
	yield return new WaitForSeconds (3f);
	print("hello world");

}

it should after 3 seconds display hello world , unfortunately it is not showing hello world
also for the test purpose i tried to set different values to WaitForSeconds
i tried 0 and it worked but for sure there is no delay
i tried 0.003 it worked but also there is no noticeable delay
i checked the time manager and tried different values but nothing worked

also i tried to test the same coroutine in a new project and it worked fine as i want print(" Hello world"); delayed 3 seconds exactly
i got a headache while trying to figure it out :dizzy_face:

Hi,

It’s interesting that it works fine in a new project.

What I would suggest trying is this;

void OnTriggerEnter2D (Collider2D x)
{
    Debug.Log("OnTriggerEnter2D has been called");

    if (x.gameObject.tag == "Player") {
        Debug.Log("gameObject.tag = Player");
        StartCoroutine (speedUp());
        Debug.Log("Coroutine started");
    }
}

This would enable you to verify that you are getting the correct conditions in the first place to start the coroutine.

Another thought that crossed my mind was whether those conditions may no longer be true on the next frame, e.g. the trigger being entered, I wouldn’t have thought this would matter as I would expect your speedUp() method to continue to the next line regardless, but it may be worth checking as well. A little harder to tell without the project :slight_smile:

1 Like

@Rob i tried this and wrote this debug.log line before the if statement and here is a screen shot for my console

as you see the trigger has entered and the coroutine got called but it stop the code at yield return new WaitForSecond(3f); and does’t debug hello world to the console

here is more details about what i want to actually do so
im still at the Block Breaker section in the course , i want to spend more time and try some advanced things so i added a bonuses to my bricks when the brick get destroyed it Instantiate the bonus game object it has collider component and trigger is checked also has RigidBody2D dyamic type and when it Enter the player which is the paddle it give some force , in this case i want to add more speed to the ball so i have to change the gravityScale and the velocity for few seconds so i used coroutines after you recommended it ,but a my code is not working after the yield return new WaitForSeconds(); line

out of curiosity, instead of using the WaitForSeconds, try
yield return new WaitForSecondsRealtime(3f);

see if it still gets the same outcome.

this will use unscaled time, just in case theres something funky going on.

1 Like

i tried it but doesn’t change anything :disappointed:

Can you try something else for me @Kamal_Ezz-eldin…

Instead of using StartCoroutine in the OnTriggerEnter2D() method, can you call it from the Start() method, you said that this same code worked from a separate project, so I’d like to eliminate some factors.


Updated Sat Jun 24 2017 16:09

…and another thought… I’m not sure what game object this script is attached to, but, you wouldn’t have anything that is actually destroying the game object this script is attached to would you?

1 Like

@Rob it worked !!
so its seems like the problem occur when calling StartCoroutine in the OnTriggerEnter2D()
but it supposed to work correctly even OnTriggerEnter2D() because the the condition met which is the trigger enter ,what is the wrong with this !!!

1 Like

Hi,

Ok, so we can stop looking specifically at the speedUp() method at this point, as we know that is seemingly ok.

So, what object is this script attached to, what is it you are detecting collisions on?

Its attached to a the Sprite of the speed up and this sprite is attached to a Game Object
here is screen shots to make it clear

and here is a screen shot for this sprite compenents


and also to link the game object ( Speed Up ) to the brick i created a Public GameObject Speed up ;
and drag the game object to the field Speed Up
here it is

so when the brick destroyed it instantiate the GameObject(Speed Up) and the sprite show up in the position of the brick and start to fall down when the Paddle Enter it it execute the script .

i really appreciate your efforts trying helping me to figure out what is the wrong in my code

1 Like

[…] the brick and start to fall down when the Paddle Enter it it execute the script .

When the speed up falls down to the paddle, putting the script aside, what happens to the speedup game object that has fallen? Does it just land and sit on the paddle, or, do you destroy it so that it is effectively “collected” and no longer seen?

Finally i figured it out the problem is not when the speed up Enter the paddle its when it pass the paddle and enter the bottom box collider which there is a script there attached to the bottom box collider to execute lose scene when the ball enter the boxcollider and here is the code

if (x.gameObject.tag== "Ball") {
			if (livesPc.lives > 0) {
				SceneManager.LoadSceneAsync ("losePc");

		} else if (livesPc.lives <= 0) {
			SceneManager.LoadScene ("Start");
		}
	} 
else 
Destroy (x.gameObject);

but there is something else , i want to hide the speed up game object when it enter the paddle immedietly is there a way to hide it on trigger enter ?

Thank you Rob so much
Really appreciate your help
and without your help i would keep trying for hours :joy:

1 Like

Hi,

Ok, great, so the issue is that the object is being destroyed then and as such the coroutine is lost with it.

I would suggest moving the coroutine code to a more appropriate object from an object orientated perspective, for example…

I am assuming that the speed up relates to the paddle, e.g. you make it move a bit faster for a short period of time.

Assuming so, SpeedUp() should really be a method on the Paddle, as it is a behaviour of the Paddle.

I would probably also move the collision test also, rather than having that on the falling power-up game object, I’d place it on the Paddle. You could incorporate a switch() statement and use an enum to then determine which power-up the Paddle has collided with, and from that, call the relevant method on the Paddle itself, e.g.

// pop this within the collision detection on the paddle

// assumes "x" is the other game object that made the collision, e.g. the falling power-up
// and that your public variable, exposing the Paddle's PowerUp enumerator is called "type"
switch (x.type)
{
	case PowerUp.Type.SpeedUp:
		SpeedUp();
		break;
	case PowerUp.Type.SpeedDown:
		SpeedDown();
		break;
}

To incorporate this the falling power-up would need to know what type of power-up it was, so a PowerUp script could be attached to it. This could either have a public variable which you then set to be one of the PowerUp Type enumerators (SpeedUp, SpeedDown etc), or, a private variable but with a public property (at this stage you are probably more used to exposing the data via a public variable so maybe stick with that. e.g.

using UnityEngine;

public class PowerUp : MonoBehaviour
{
    public enum Type { None, SpeedUp, SpeedDown };

    public Type type;
}

You could then use prefabs in order to create different power-ups as you can set their type through that exposed variable.

The SpeedUp() method can contain the coroutine call, which will facilitate the 3 second life time of the power-up, the Paddle object is not destroyed unless another level is loaded, in which case the fact that the power-up has now ended doesn’t matter anyway.

The shredder at the bottom of the game should destroy any falling power-ups that reach it, so I think what you already have above should still handle that.

The only thing that would leave is then destroying the power-up when it makes contact with the Paddle, by moving SpeedUp() method and coroutine call to the Paddle as describe above, simply calling Destroy() on the power-up upon the collision will now be ok, as the Paddle will handle the rest. Just make sure that you use the Destroy() method after calling SpeedUp() on the Paddle.

Hope this helps :slight_smile:


Updated Sat Jun 24 2017 18:28

I updated the above with a couple of small code examples.


Updated Sat Jun 24 2017 18:44

Updated the small code examples to not be syntactically incorrect!.. lol…

1 Like

YES YES
Finally !! it worked great :grin:
Thank you mr.Rob

1 Like

You are very welcome :slight_smile:

1 Like

Privacy & Terms