- Home /
Powerup Timer not Working
I cannot figure out how to make my timer work! If the player collides with the slowdown powerup (slowing all objects on the screen) the slowdown continues forever even though I have a timer setup. Do I have the timer in the wrong spot in Update? Does this have something to do with how I have variables setup and Time.timescale? I have looked on unity answers, youtube, and google for days, but there is nothing. This cannot be that difficult and I am so close! This is driving me crazy!
Here is my code:
Code 1:
using UnityEngine;
using System.Collections;
public class PowerUpManager : MonoBehaviour {
private bool doublePoints;
private bool slowMo;
private bool fastMo;
private bool powerUpActive;
private float powerUpLengthCounter;
private ScoreManager theScoreManager;
private float score;
private float slowDown = Time.timeScale ;
//private float slowDown = Time.unscaledDeltaTime ;
// Use this for initialization
void Start () {
theScoreManager = FindObjectOfType <ScoreManager > ();
}
// Update is called once per frame
void Update () {
if (powerUpActive) {
powerUpLengthCounter -= Time.deltaTime;
if (slowMo) {
//Time.unscaledDeltaTime = slowDown;
Time.timeScale = slowDown;
slowDown = 0.5f;
}
}
if (powerUpLengthCounter <= 0) {
//Time.unscaledDeltaTime = slowDown;
Time.timeScale = slowDown;
slowDown = 1f;
powerUpActive = false;
}
}
public void ActivatePowerUpSlowMotion(bool slow, float time, float effect){
slowMo = slow;
powerUpLengthCounter = time ;
slowDown = effect;
powerUpActive = true;
}
}
Code 2:
using UnityEngine;
using System.Collections;
public class PowerUp : MonoBehaviour {
public bool doublePoints;
public bool slow;
public bool fast;
public float speed=Time .timeScale ;
public float powerUpLength;
private PowerUpManager thePowerUpManager;
// Use this for initialization
void Start () {
thePowerUpManager = FindObjectOfType <PowerUpManager > ();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D other){
if (other.tag == "Player") {
thePowerUpManager.ActivatePowerUpSlowMotion (slow, powerUpLength,speed );
}
gameObject.SetActive (false);
Destroy(gameObject);
}
}
A few concerns looking at your code:
What is this "slow" variable? In Code 2, it doesn't seem to be initialized, so it'll always be false.
Also, in the following lines:
Time.timeScale = slowDown;
slowDown = 1f;
and
Time.timeScale = slowDown;
slowDown = 0.5f;
It seems like you should be setting slowDown first before assigning it to Time.timsScale. This is most likely what's causing it to not revert to a normal time scale.
I appreciate you getting back to me! I understand what you are saying about switching the order of the Time.timeScale= slowdown and slowdown = (x)f, but why does it need to be in this order?
Also I see the "slow" variable is not initialized. I have that variable there along with fast and double points so that I can check which powerup does what in the inspector. I was watching this tutorial - https://www.youtube.com/watch?v=oQ58w0sx-io. This is confusing because the tutorial only covers double points and invincibility and does not involve altering the timescale. Could I define the slow variable like so: slow=Time.timescale. I won't be home until later to try this out. I have been working on this for a week now and this is one of the last parts I have to figure out for my game.
(FYI Post your comment as a reply to my comment, not as a new comment for to your question)
The time scale at which the game runs is set by "Time.timeScale". If you do "slowDown = 1f; Time.timeScale = slowDown;" in that order, you are setting slowDown to 1, and then Time.timeScale to the value of slowDown (which is a value 1). If you do it the other way, namely "Time.timeScale = slowDown; slowDown = 1f;" Then you are setting Time.timeScale to whatever value slowDown was previously set to (which would be 0.5f in your code, if I'm not mistaken), and then you're setting slowDown to 1f, which has no effect on the Time.timeScale, so it has no effect on the game.
For some reason I cannot mark my comments as a reply. It might have to do with the browser at work.
$$anonymous$$y game slows down and speeds up when the player collides with the powerup, but the game continues to move at the same speed and the "powerUpLength" does not appear to be working.
When you were explaining the switching of Time.timescale=slowDown and slowdown=(x)f - The last sentence in your response says "which has no effect on the Time.timeScale, so it has no effect on the game." Did you mean the effect would not occur in game (because currently the effect does occur, but like I said earlier the timer or powerUpLength is not working)?
Answer by JoshDangIt · May 24, 2016 at 11:35 PM
Have you tried using a coroutine like this? (Untested)
public void ActivatePowerUpSlowMotion(float time, float speed)
{
StartCoroutine (SlowMoRoutine (time, speed));
}
IEnumerator SlowMoRoutine(float time, float speed)
{
float duration = time * speed; //Convert the powerup duration to realtime, since WaitForSeconds uses gametime. My math may be off here.
Time.timeScale = speed;
yield return new WaitForSeconds (duration);
Time.timeScale = 1f;
}
The only downside to this is that there's no way to stop the powerup prematurely. If you don't need to do that this code should work fine.
I like the idea! I was thinking about this as well since IEnumerators allow waitforseconds. However I tried implementing your code into my own and am able to get the slowmo to trigger when player and powerup collide, but again game continues to run at the speed I choose and never stop. I understand how coroutines work, but don't have experience when calling on them in other methods. I got a parser error when trying to call the ActivatePowerUpSlow$$anonymous$$otion(float time, float speed). The error said it was expecting a '.' before time? I tried researching and could not find anything except for mistakes with brackets which all seem to be fine in my code. I was able to build the code creating time and speed references, but ,again, the powerup never stops. Would it be possible to consolidate the code like I was attempting in Code1 or do I still need to use both codes? I really appreciate your help.
Code1:
using UnityEngine;
using System.Collections;
public class PWRUP : $$anonymous$$onoBehaviour {
//public float time;
//public float speed;
public void ActivatePowerUpSlow$$anonymous$$otion(float time, float speed)
{
StartCoroutine (Slow$$anonymous$$oRoutine (time, speed));
}
IEnumerator Slow$$anonymous$$oRoutine(float time, float speed)
{
float duration = time * speed;
Time.timeScale = speed;
yield return new WaitForSeconds (duration);
Time.timeScale = 1f;
}
/*void OnTriggerEnter2D(Collider2D other){
if (other.tag == "Player") {
ActivatePowerUpSlow$$anonymous$$otion(float time, float speed);
}
gameObject.SetActive (false);
Destroy(gameObject);
}*/
}
Code2:
using UnityEngine;
using System.Collections;
public class PowerUp : $$anonymous$$onoBehaviour {
public bool doublePoints;
public bool slow;
public bool fast;
//public float speed;
//public float time;
private PWRUP thePowerUp$$anonymous$$anager;
// Use this for initialization
void Start () {
thePowerUp$$anonymous$$anager = FindObjectOfType <PWRUP> ();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D other){
if (other.tag == "Player") {
//the below line of code will not work and says parser error on 'time'
//I added the public float speed, time above which allowed the code to build, but this is not correct
//thePowerUp$$anonymous$$anager.ActivatePowerUpSlow$$anonymous$$otion(float time, float speed);
}
gameObject.SetActive (false);
Destroy(gameObject);
}
}
When you destroy the gameobject you destroy the component, therefore stopping the coroutine. I meant for you to put those 2 functions I made in your powerup manager and reference it from your pickup script.
Answer by Dave29483 · May 25, 2016 at 07:26 AM
After having a quick read, both methods you tried involves either deltaTime or WaitForSeconds(). Both rely on the time scale. Effectively your timer slows down too. You can either scale the wait duration with the time scale so it takes the right amount of time still or use a timer not affected by time scale. i.e. Time.unscaledTime.
Hope this helps.
If you look at my initial post I have some code commented out where I was trying to utilize Time.unscaledTime (Code 1: Lines 18, 36, and 46) but, I was unable to get it to work. How can I implement an unscaled timer into my code? Thanks for any help!
Answer by Kryzarel · May 27, 2016 at 04:01 PM
Hi there, I think Time.realtimeSinceStartup
would have the effect you want. It is not affected by Time.deltaTime
. Here's a link to its documentation if you wanna read more on it.
I believe something like the following should work (or at least set you on the right track):
private float powerUpStartingTime;
void Update ()
{
if (powerUpActive)
{
//calculate how much time has passed since the powerup was activated
float timePassed = Time.realtimeSinceStartup - powerUpStartingTime;
//if that amount of time is equal to, or bigger than
//the power up duration, deactivate the power up
if(timePassed >= powerUpLengthCounter)
{
Time.timeScale = 1;
powerUpActive = false;
}
}
}
public void ActivatePowerUpSlowMotion(float time, float effect)
{
//activate the power up
powerUpActive = true;
//get the duration of the power up
powerUpLengthCounter = time;
//apply the desired time slow amount
Time.timeScale = effect;
//save time of power up activation
powerUpStartingTime = Time.realtimeSinceStartup;
}
Your answer
![](https://koobas.hobune.stream/wayback/20220612081420im_/https://answers.unity.com/themes/thub/images/avi.jpg)