Activate function after completion of the previous in Update, Unity C# - c#

This is not the full script. I am only showing the part which I have problem with.
Issue Faced:
I wanted to make neat and clean script therefore I only call functions into my update.
I wanted to introduce (StartGameFreezeMovement) function into the first line of update.
I couldn't do it. Like the rest of the functions because this one has a timer in it.
Result Wanted:
My intention is to find a way for the first function in update to completely finish then load or activate the rest.
How can I achieve this?
public class PlayerController : MonoBehaviour {
private CharacterController controller;
public float speed;
private Vector3 moveVector;
private float verticalVelocity;
public float gravity;
private float animationDuration = 3.0f;
public Text text;
private float timer;
//-------------------------------------------------------------------------
void Start ()
{
text.text = "";
controller = GetComponent<CharacterController>();
}
//-------------------------------------------------------------------------
// Update is called once per frame
void Update ()
{
if(Time.time < animationDuration)
{
PlayerMovingForward();
return; //getout of if...
}
StartText();
PlayerMovingForward();
PlayerLeftnRight();
PlayerFalloffGravity();
}
//----------------------------------
void StartGameFreezeMovement()
{
if (Time.time < animationDuration)
{
PlayerMovingForward();
return; //getout of if...
}
}

My intention is to find a way for the first function in update to
completely finished then load or activate the rest.
You need a Coroutine function. The Update function is a void function. You will have to create a coroutine function and start it once then make sure that it doesn't exit so that it will imitate the Update function that is called every frame. This can be done by adding a while loop and yielding every frame.
Finally, turn the StartGameFreezeMovement function from void into a coroutine function, then change the if (Time.time < animationDuration) to while (Time.time < animationDuration) and yield inside it with yield return null; so that other scripts will get chance to execute while waiting for the StartGameFreezeMovement function to finish.
Below is a fixed version of the code from your question:
private void Start()
{
//Start once
StartCoroutine(YieldableUpdate());
}
IEnumerator YieldableUpdate()
{
//Call and wait for the StartGameFreezeMovement function to finish
yield return StartGameFreezeMovement();
//Run forever
while (true)
{
StartText();
PlayerMovingForward();
PlayerLeftnRight();
PlayerFalloffGravity();
//Wait a frame so that Unity doesn't freeze
yield return null;
}
}
IEnumerator StartGameFreezeMovement()
{
while (Time.time < animationDuration)
{
PlayerMovingForward();
//Wait a frame so that Unity doesn't freeze
yield return null;
}
}
If you need to check StartGameFreezeMovement() more than once the move yield return StartGameFreezeMovement(); inside the while (true) loop otherwise this check will only happen once.

You could change your StartGameFreezeMovement to a bool.
bool StartGameFreezeMovement()
{
if (Time.time < animationDuration)
{
PlayerMovingForward();
return true; //getout of if...
}
return false;
}
Then change your update function. And then to keep it clean, use return if you do not pass the boolean check to exit the update function early.
void Update ()
{
if (!StartGameFreezeMovement())
{
return;
}
StartText();
PlayerMovingForward();
PlayerLeftnRight();
PlayerFalloffGravity();
}

Related

How can i make my caroutine run in every x seconds

I created a caroutine, and i want it to run in every x seconds. i tried using while loop but it didn't worked for this caroutine. can anybody please help ? thanks.
IEnumerator StartFire()
{
{
Firing = true;
animator.SetBool("isFiring", true);
yield return new WaitForSeconds(2);
Firing = false;
animator.SetBool("isFiring", false);
}
}
I think you would be better off using InvokeRepeating(string methodName, float time, float repeatRate). You only need to call it once and it will repeat.
Example:
void Start()
{
InvokeRepeating("myTask", 1.5f, 1.5f);
}
void myTask()
{
// Execute repetitive task.
}
If you want to stop it at any point you simply have to call: CancelInvoke(string methodName);.
Example:
void Update()
{
if (Input.GetKeyDown(KeyCode.S))
CancelInvoke();
}
This would put an end to the repetitive task.

Move object from one position to the target position in x seconds, complete an action and repeat (Unity 2D c#) [duplicate]

I am learning Unity from a Swift SpriteKit background where moving a sprite's x Position is as straight forward as an running an action as below:
let moveLeft = SKAction.moveToX(self.frame.width/5, duration: 1.0)
let delayAction = SKAction.waitForDuration(1.0)
let handSequence = SKAction.sequence([delayAction, moveLeft])
sprite.runAction(handSequence)
I would like to know an equivalent or similar way of moving a sprite to a specific position for a specific duration (say, a second) with a delay that doesn't have to be called in the update function.
gjttt1's answer is close but is missing important functions and the use of WaitForSeconds() for moving GameObject is unacceptable. You should use combination of Lerp, Coroutine and Time.deltaTime. You must understand these stuff to be able to do animation from Script in Unity.
public GameObject objectectA;
public GameObject objectectB;
void Start()
{
StartCoroutine(moveToX(objectectA.transform, objectectB.transform.position, 1.0f));
}
bool isMoving = false;
IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
//Make sure there is only one instance of this function running
if (isMoving)
{
yield break; ///exit if this is still running
}
isMoving = true;
float counter = 0;
//Get the current position of the object to be moved
Vector3 startPos = fromPosition.position;
while (counter < duration)
{
counter += Time.deltaTime;
fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
yield return null;
}
isMoving = false;
}
Similar Question: SKAction.scaleXTo
The answer of git1 is good but there is another solution if you do not want to use couritines.
You can use InvokeRepeating to repeatedly trigger a function.
float duration; //duration of movement
float durationTime; //this will be the value used to check if Time.time passed the current duration set
void Start()
{
StartMovement();
}
void StartMovement()
{
InvokeRepeating("MovementFunction", Time.deltaTime, Time.deltaTime); //Time.deltaTime is the time passed between two frames
durationTime = Time.time + duration; //This is how long the invoke will repeat
}
void MovementFunction()
{
if(durationTime > Time.time)
{
//Movement
}
else
{
CancelInvoke("MovementFunction"); //Stop the invoking of this function
return;
}
}
You can use co-routines to do this. To do this, create a function that returns type IEnumerator and include a loop to do what you want:
private IEnumerator foo()
{
while(yourCondition) //for example check if two seconds has passed
{
//move the player on a per frame basis.
yeild return null;
}
}
Then you can call it by using StartCoroutine(foo())
This calls the function every frame but it picks up where it left off last time. So in this example it stops at yield return null on one frame and then starts again on the next: thus it repeats the code in the while loop every frame.
If you want to pause for a certain amount of time then you can use yield return WaitForSeconds(3) to wait for 3 seconds. You can also yield return other co-routines! This means the current routine will pause and run a second coroutine and then pick up again once the second co-routine has finished.
I recommend checking the docs as they do a far superior job of explaining this than I could here

Difference between while(true) in Coroutine then put it in the void Start() and not having while(true) but put it in the void Update()

I'm trying to make the game spawn enemies every random period of time so I'm using yield return new WaitForSeconds(...) in Coroutine and as the title says, I can use while(true) inside the Coroutine and call the Coroutine in the void Start() and the spawning thing works just fine. But when i removed the while(true) and call the Coroutine in void Update(), the enemies are spawned crazily without the delay. Why is this??
Because I guess you don't wait but rather start a new concurrent routine every frame so after the delay has passed once at the beginning you now get one call for each frame!
A Coroutine does not delay the outer code which starts it.
Either use e.g.
[SerializeField] private float delay;
private void Start()
{
StartCoroutine(Routine);
}
private IEnumerator Routine()
{
while(true)
{
yield return new WaitForSeconds(delay);
DoSomething();
}
}
or also directly
// If you make Start an IEnumerator then Unity automatically runs it as a Coroutine
private IEnumerator Start()
{
while(true)
{
yield return new WaitForSeconds(delay);
DoSomething();
}
}
Or if you want to go for Update the equivalent would require a counter like e.g.
private float timer;
private void Start()
{
timer = delay;
}
private void Udpate()
{
timer -= Time.deltaTime;
if(timer <= 0)
{
DoSomething();
timer = delay;
}
}
I wouldn't mix both things ;)
And personally I find Coroutines better to read and maintain most of the times.

Move GameObject to new position overtime [duplicate]

I am learning Unity from a Swift SpriteKit background where moving a sprite's x Position is as straight forward as an running an action as below:
let moveLeft = SKAction.moveToX(self.frame.width/5, duration: 1.0)
let delayAction = SKAction.waitForDuration(1.0)
let handSequence = SKAction.sequence([delayAction, moveLeft])
sprite.runAction(handSequence)
I would like to know an equivalent or similar way of moving a sprite to a specific position for a specific duration (say, a second) with a delay that doesn't have to be called in the update function.
gjttt1's answer is close but is missing important functions and the use of WaitForSeconds() for moving GameObject is unacceptable. You should use combination of Lerp, Coroutine and Time.deltaTime. You must understand these stuff to be able to do animation from Script in Unity.
public GameObject objectectA;
public GameObject objectectB;
void Start()
{
StartCoroutine(moveToX(objectectA.transform, objectectB.transform.position, 1.0f));
}
bool isMoving = false;
IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
//Make sure there is only one instance of this function running
if (isMoving)
{
yield break; ///exit if this is still running
}
isMoving = true;
float counter = 0;
//Get the current position of the object to be moved
Vector3 startPos = fromPosition.position;
while (counter < duration)
{
counter += Time.deltaTime;
fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
yield return null;
}
isMoving = false;
}
Similar Question: SKAction.scaleXTo
The answer of git1 is good but there is another solution if you do not want to use couritines.
You can use InvokeRepeating to repeatedly trigger a function.
float duration; //duration of movement
float durationTime; //this will be the value used to check if Time.time passed the current duration set
void Start()
{
StartMovement();
}
void StartMovement()
{
InvokeRepeating("MovementFunction", Time.deltaTime, Time.deltaTime); //Time.deltaTime is the time passed between two frames
durationTime = Time.time + duration; //This is how long the invoke will repeat
}
void MovementFunction()
{
if(durationTime > Time.time)
{
//Movement
}
else
{
CancelInvoke("MovementFunction"); //Stop the invoking of this function
return;
}
}
You can use co-routines to do this. To do this, create a function that returns type IEnumerator and include a loop to do what you want:
private IEnumerator foo()
{
while(yourCondition) //for example check if two seconds has passed
{
//move the player on a per frame basis.
yeild return null;
}
}
Then you can call it by using StartCoroutine(foo())
This calls the function every frame but it picks up where it left off last time. So in this example it stops at yield return null on one frame and then starts again on the next: thus it repeats the code in the while loop every frame.
If you want to pause for a certain amount of time then you can use yield return WaitForSeconds(3) to wait for 3 seconds. You can also yield return other co-routines! This means the current routine will pause and run a second coroutine and then pick up again once the second co-routine has finished.
I recommend checking the docs as they do a far superior job of explaining this than I could here

unity move object over time using Coroutine wont move the object precisely [duplicate]

I am learning Unity from a Swift SpriteKit background where moving a sprite's x Position is as straight forward as an running an action as below:
let moveLeft = SKAction.moveToX(self.frame.width/5, duration: 1.0)
let delayAction = SKAction.waitForDuration(1.0)
let handSequence = SKAction.sequence([delayAction, moveLeft])
sprite.runAction(handSequence)
I would like to know an equivalent or similar way of moving a sprite to a specific position for a specific duration (say, a second) with a delay that doesn't have to be called in the update function.
gjttt1's answer is close but is missing important functions and the use of WaitForSeconds() for moving GameObject is unacceptable. You should use combination of Lerp, Coroutine and Time.deltaTime. You must understand these stuff to be able to do animation from Script in Unity.
public GameObject objectectA;
public GameObject objectectB;
void Start()
{
StartCoroutine(moveToX(objectectA.transform, objectectB.transform.position, 1.0f));
}
bool isMoving = false;
IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
//Make sure there is only one instance of this function running
if (isMoving)
{
yield break; ///exit if this is still running
}
isMoving = true;
float counter = 0;
//Get the current position of the object to be moved
Vector3 startPos = fromPosition.position;
while (counter < duration)
{
counter += Time.deltaTime;
fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
yield return null;
}
isMoving = false;
}
Similar Question: SKAction.scaleXTo
The answer of git1 is good but there is another solution if you do not want to use couritines.
You can use InvokeRepeating to repeatedly trigger a function.
float duration; //duration of movement
float durationTime; //this will be the value used to check if Time.time passed the current duration set
void Start()
{
StartMovement();
}
void StartMovement()
{
InvokeRepeating("MovementFunction", Time.deltaTime, Time.deltaTime); //Time.deltaTime is the time passed between two frames
durationTime = Time.time + duration; //This is how long the invoke will repeat
}
void MovementFunction()
{
if(durationTime > Time.time)
{
//Movement
}
else
{
CancelInvoke("MovementFunction"); //Stop the invoking of this function
return;
}
}
You can use co-routines to do this. To do this, create a function that returns type IEnumerator and include a loop to do what you want:
private IEnumerator foo()
{
while(yourCondition) //for example check if two seconds has passed
{
//move the player on a per frame basis.
yeild return null;
}
}
Then you can call it by using StartCoroutine(foo())
This calls the function every frame but it picks up where it left off last time. So in this example it stops at yield return null on one frame and then starts again on the next: thus it repeats the code in the while loop every frame.
If you want to pause for a certain amount of time then you can use yield return WaitForSeconds(3) to wait for 3 seconds. You can also yield return other co-routines! This means the current routine will pause and run a second coroutine and then pick up again once the second co-routine has finished.
I recommend checking the docs as they do a far superior job of explaining this than I could here

Categories