Yes, this code freezes the game, because it is an infinite loop. You seem to have two misconceptions which seem to have lead you to writing this code:
- Unity processes each
Update
-method in an independent threat of execution. That's wrong! While an Update
method is being executed, nothing else happens in the engine. So it is important that your Update
methods (as well as any other message handlers) return quickly.
- When an
Update
method takes a while, Time.deltaTime
increases. Also wrong! It gives you the time in seconds it took to complete the last frame, so it will only change between Update
's.
Casting Time.deltaTime
to int
will round it down. Time.deltaTime
only changes between Update
's and will almost always be far lower than 1.0
. that means 0
gets added to t1
over and over again. This for-loop will loop forever and not let Unity do anything else. If you want Unity to be able to resume the normal gameplay while the special power is active, you need to return the program's execution flow back to the engine by leaving your Update
method.
There are several patterns you could use to implement this.
Temporary component
You could implement your special effect as a Component
which you add to the gameObject when the special effect is activated. Program the component to automatically remove itself when the effect time is over. You can do that by taking the time it was created and having the update-method check if the time has elapsed.
public class ActiveSpecialPower : MonoBehaviour {
private float startTime;
private static readonly float POWER_DURATION_IN_SECONDS = 5.0f;
void Start() {
startTime = Time.time;
// code which happens on activation of the special power
}
void Update () {
if (Time.time > startTime + POWER_DURATION_IN_SECONDS) {
// code which happens on deactivation of special power
Destroy(this);
}
}
}
Code for activating the special power:
gameObject.AddComponent<ActiveSpecialPower>();
Code for checking if special power is currently active:
if(gameObject.GetComponent<ActiveSpecialPower>() != null) {
Permanent Component
Or you could have your SpecialPower
component permanently on your player game object and have a method to activate it:
public class SpecialPower : MonoBehaviour {
public float remainingTime;
private static readonly float POWER_DURATION_IN_SECONDS = 5.0f;
public void Activate() {
// code which happens on activation of the special power
remainingTime = POWER_DURATION_IN_SECONDS;
}
void Update () {
if (remainingTime > 0.0f) {
// code which happens every update while the power is active
remainingTime -= Time.deltaTime;
if (remainingTime <= 0.0f) {
// code which happens on deactivation of special power
}
}
}
}
Code for activating the special power:
gameObject.GetComponent<SpecialPower>().Activate();
Code for checking if special power is currently active:
if(gameObject.GetComponent<SpecialPower>().remainingTime > 0.0f) {
Coroutine
Another option is to implement your special effect as a Coroutine. A coroutine can use the construct yield return WaitForSeconds(n)
to return the program flow back to the engine and continue it after the given time has passed. Such a coroutine-method could look like this:
private IEnumerator ActivateSpecialPowerCoroutine() {
// code which happens on start of special power
yield return new WaitForSeconds(POWER_DURATION_IN_SECONDS);
// code which happens on end of special power
}
Code for activating the special power:
StartCoroutine(ActivateSpecialPowerCoroutine());
Unfortunately there is no good way to check if a coroutine is currently being executed.
deltaTime
to int? That is locking yourfor
loop endlessly, becausedeltaTime
is usually around 16.67ms, which makes it inhibit the value0.1667f
which when cast to int is rounded and due to it being < 0.5, equals 0. You can imagine that 0 + 0 will never reach >= 5, therefore never exit your loop and therefore, lock Unity. \$\endgroup\$