- Home /
Lerp only executes once?
void Update (){
if (coolDownReseting == true) {
coolDownLerp += nextFire * Time.deltaTime;
//coolDown.material.SetFloat ("_Cutoff", (Mathf.InverseLerp (1, 0, coolDownLerp)));
rockTimerImage.fillAmount = Mathf.InverseLerp (0, 1, coolDownLerp);
if (rockTimerImage.fillAmount >= 1){
coolDownReseting = false;
Debug.Log ("coolDownReseting = " + coolDownReseting);
rockTimerImage.fillAmount = 0.9f;
}
}
if (Input.GetButtonDown ("Fire1") && Time.time > nextFire) { coolDownReseting = true;
}
}
I have an image game object and I'm trying to manipulate the radial fill amount (360) to act as a cool down timer for my game. However, all of my solutions have ended in failure. In this one, the cooldown timer becomes active when the mouse is clicked, and the fill amount changes correctly in relation to the time until it can fire again.
The problem is I can't make it do it again. I try to reset the original value (or something close to it), but the lerp won't execute again. Is there something I'm missing?
Answer by DiegoSLTS · May 06, 2015 at 03:52 PM
Why are you using InverseLerp for that?
InverseLerp works this way: You pass a min and a max value, and a third value.
if "value" <= min, it returns 0.
if "value" >= max, it returns 1.
if "value" > min and "value" < max, it returns a value between 0 and 1.
In any case, using 0 and 1 as the first parameters is kind of useless, it's working like Mathf.Clamp01.
Also, you're not resetting coolDownLerp back to zero, so once it reached a value higher than 1 your inner "if" block" will always set the fill back to 0.9f
I went ahead and re-wrote allot of it.
if (coolDownReseting == true) {
coolDownLerp += nextFire * Time.deltaTime;
rockTimerImage.fillAmount = $$anonymous$$athf.Lerp (0, 1, coolDownLerp);
if (coolDownLerp > 1){
coolDownLerp = 0;
coolDownReseting = false;
}
}
Looks like resetting coolDownLoop and using a normal lerp ins$$anonymous$$d of an inverseLerp were the parts I couldn't figure out. I'm still having an issue with the speed of the lerp increasing everytime I run it, but I'm sure that's something I can easily figure out. Thanks for the help!
What you're doing with the Lerp is exactly the same you did with InverseLerp. Doing a Lerp of a value between 0 and 1 has the same result as before. If the third parameter is between 0 and 1 Lerp will return the exact same parameter, and if it's less than 0 or more than 1 it'll clamp the value to 0 or 1.
Just do this test and you'll see, log to the console coolDownLerp and rockTimerImage.fillAmount after the "Lerp" line and you'll see the same values while coolDownLerp is less than 1.
You don't even need to "clamp" the value, fillAmount will clamp the value internally when you assign a value to it.
I'm not seeing the issue that you are pointing out, but it might have to do with some of the code I omitted for simplicity's sake. In particular, the line "nextFire = Time.time + fireRate"
The issue I am having now is that nextFire controls my rate of fire, so over time as nextFire increases, so does coolDownLerp. I need some way to make my fire rate reset Time.time or something like that. Unless I'm not not quite understanding the problem?
void Update (){
//coolDown.material.SetFloat ("_Cutoff", ($$anonymous$$athf.InverseLerp (1, 0, coolDownLerp)));
if (coolDownReseting == true) {
coolDownLerp += nextFire * Time.deltaTime;
rockTimerImage.fillAmount = $$anonymous$$athf.Lerp (0, 1, coolDownLerp);
//Debug.Log ("nextFire= " + nextFire);
//Debug.Log ("fireRate= " + fireRate);
//Debug.Log ("cooldownLerp= " + coolDownLerp);
//Debug.Log ("fillAmount= " + rockTimerImage.fillAmount);
if (coolDownLerp > 1){
coolDownLerp = 0;
coolDownReseting = false;
}
}
//PC CONTROLS
if (touchControls == false) {
//Translates mouse position to work coordinates
if (Input.GetButtonDown ("Fire1") && Time.time > nextFire) {
coolDownReseting = true;
Vector3 mousePos = new Vector3 (Input.mousePosition.x, Input.mousePosition.y);
Vector3 worldPos;
Ray ray = Camera.main.ScreenPointToRay (mousePos);
RaycastHit hit;
if (Physics.Raycast (ray, out hit)) {
worldPos = hit.point;
rock.transform.position = worldPos;
} else {
worldPos = Camera.main.ScreenToWorldPoint (mousePos);
}
//deter$$anonymous$$es rate at which rock can fire
nextFire = Time.time + fireRate;
Debug.Log ("rock FIRED");
instance_rock = Instantiate (rock, new Vector3 (worldPos.x, spawnHeight, worldPos.z + spawnDistance), Quaternion.identity) as GameObject;
instance_rock.GetComponent<Rigidbody> ();
instance_rock.rigidbody.AddForce (Vector3.down * rockForce);
cat$$anonymous$$overAnim.SetBool ("cast", true);
instance_rockSpawnParticle = Instantiate (gameObj_rockSpawn, new Vector3 (worldPos.x, spawnHeight, worldPos.z + spawnDistance), Quaternion.identity) as GameObject;
instance_rockSpawnParticle.GetComponent<ParticleSystem> ();
instance_rockSpawnParticle.particleSystem.Play ();
Destroy (instance_rock, lifetime);
Destroy (instance_rockSpawnParticle, lifetime);
}
}
Here's an animated gif demonstrating the problem. The speed at which the circle fills increases every time because Time.time increasing over time. I need it to reset every time.
I've tested your code, the problem is this line:
coolDownLerp += nextFire * Time.deltaTime;
Ins$$anonymous$$d of just counting the elapsed time you're counting the elapsed time but multiplied by some value, and that value changes after each cooldown. Do this and the circle will always take 1 second to fill:
coolDownLerp += Time.deltaTime;
If you want it to fill in more or less time, use a constant multiplier, not nextFire (which changes all the time). I see you have a "fireRate" variable, which I assume is how many times it can fire in a second, so do this ins$$anonymous$$d:
coolDownLerp += Time.deltaTime * fireRate;
This way, if you want a fireRate of 1 fire every 2 seconds (i.e. fireRate == 0.5f), coolDownLerp will accumulate half the time elapsed for each frame, taking twice the frames to reach "1". If you want it to fire 2 times per second (fireRate == 2f) then coolDownLerp will accumulate twice the time elapsed for each frame, taking half the frames to reach "1".
The thing I'm saying with your wrong use of the Lerp is that if you run this code:
void Update() {
coolDownLerp += Time.deltaTime;
Debug.Log("Cooldown: " + coolDownLerp + "\nInverseLerp: " + $$anonymous$$athf.InverseLerp (0, 1, coolDownLerp) + "\nLerp: " + $$anonymous$$athf.Lerp (0, 1, coolDownLerp));
if (coolDownLerp > 1){
coolDownLerp = 0;
}
}
You'll get something like this in the console:
Cooldown: 0.02
InverseLerp: 0.02
Lerp: 0.02
Cooldown: 0.04
InverseLerp: 0.04
Lerp: 0.04
...
Cooldown: 0.9972172
InverseLerp: 0.9972172
Lerp: 0.9972172
Cooldown: 1.013784
InverseLerp: 1
Lerp: 1
Cooldown: 0.01656649
InverseLerp: 0.01656649
Lerp: 0.01656649
And even if the last step of a loop does change the value (by 0.013784), when you do:
rockTimerImage.fillAmount = whatever;
then the fillAmount will be clamped to the [0,1] range. So, your code could just look like this and it should work exactly the same:
if (coolDownReseting == true) {
coolDownLerp += Time.deltaTime;
rockTimerImage.fillAmount = coolDownLerp;
if (coolDownLerp > 1){
coolDownLerp = 0;
coolDownReseting = false;
}
}
As I said before, Lerp and InverseLerp between 0 and 1 work exactly the same as $$anonymous$$athf.Clamp01. If you want something different than Clamp then your using the Lerp functions in the wrong way.