- Home /
Decrease Variable By Second Whilst Button Held
Hi,
I'm making a shooting script for a phone game that is meant to decrease my ammo variable once every second. The problem is I'm using a system where this has to happen when the player is touching down on a collider. I.e touch phase is stationary and so works every frame right?
My problem is that the variable is decreasing every frame. So, since I'm working in c#, I tried using IEnumerator and the wait seconds feature but I'm still having the dame problem since the IEnumerator is being called every frame. Need a simple work around for decreasing a variable slowly in a stationary/update type of function. Thanks.
Answer by whydoidoit · Aug 11, 2013 at 08:12 AM
For completeness in your answers: here is the Coroutine version of reducing a value every n seconds with a key press...
public int ammo;
void Update()
{
if(Input.GetKeyDown(KeyCode.Y))
{
StartCoroutine(DecreaseAmmoOnButton(1, KeyCode.Y));
}
}
public IEnumerator DecreaseAmmoOnButton(float delay, KeyCode code)
{
while(Input.GetKey(code))
{
ammo--;
yield return new WaitForSeconds(delay);
}
}
Hello, thanks for your answer. However what would I put ins$$anonymous$$d of all the keycode stuff since I'm working with a touch phase on a GUI element?
try with Input.touchCount > 0
, you may have to perform some more raycasting to check if the touch is over the collider.
Answer by dood2 · Aug 11, 2013 at 06:47 AM
I'm almost certain there is some way to do this with less code, but something like this should do. Let me know if you have any questions.
using UnityEngine;
using System.Collections;
public class Timer
{
public delegate void TimerExpiredDelegate();
public delegate void TimerUpdateDelegate();
private TimerUpdateDelegate _timerUpdate= null;
private TimerExpiredDelegate _timerExpired= null;
private float _startTimeSeconds= 0.0f;
private float _currentTimeSeconds= 0.0f;
private float _endTimeSeconds= 0.0f;
public float TimerFraction { get; private set;}
public bool Update(float dt)
{
bool result = true;
_currentTimeSeconds += dt;
TimerFraction = _currentTimeSeconds / (_endTimeSeconds - _startTimeSeconds);
if (_currentTimeSeconds >= _endTimeSeconds)
{
if (_timerExpired != null)
{
_timerExpired();
result = false;
}
}
else
{
if (_timerUpdate != null)
{
_timerUpdate();
}
}
return result;
}
public Timer(float totalSeconds, TimerUpdateDelegate onUpdate = null, TimerExpiredDelegate onExpired = null)
{
_startTimeSeconds = 0.0f;
_currentTimeSeconds = _startTimeSeconds;
_endTimeSeconds = _startTimeSeconds + totalSeconds;
_timerUpdate = onUpdate;
_timerExpired = onExpired;
}
}
public class ExampleCS : MonoBehaviour
{
private Timer _timer = null;
private Timer.TimerExpiredDelegate _timerExpired = null;
private Timer.TimerUpdateDelegate _timerUpdate = null;
public float timerDuration = 1.0f; // 1 second.
public float variableStartingValue= 10.0f;
public float variableToDecreaseOverTime = 0.0f;
private void Start()
{
_timerExpired = TimerExpired;
_timerUpdate = TimerUpdate;
variableToDecreaseOverTime= variableStartingValue;
}
private void Update()
{
if (Input.GetKey(KeyCode.Space))
{
if (_timer == null)
{
Debug.Log ("Creating new timer.");
_timer = new Timer(timerDuration, _timerUpdate, _timerExpired);
}
else
{
if (_timer.Update(Time.deltaTime))
{
// timer has not expired.
}
else
{
// timer has expired and the delegate will be called.
}
}
}
}
internal void TimerExpired()
{
_timer = null;
variableToDecreaseOverTime = variableStartingValue;
Debug.Log ("Timer expired!");
}
internal void TimerUpdate()
{
variableToDecreaseOverTime= variableStartingValue * (1.0f - _timer.TimerFraction);
Debug.Log (string.Format("{0}",variableToDecreaseOverTime));
}
}
Answer by Jamora · Aug 11, 2013 at 07:20 AM
While dood's solution does follow the OOP paradigm (which is always good in my opinion), the simpler solution the OP asks for is to use InvokeRepeating. You can prevent the every frame effect by then checking IsInvoking on the counter method.
So something like this
//if (touchphase.stationary && touching collider)
{
If(!IsInvoking("DecreaseAmmo"))
InvokeRepeating("DecreaseAmmo",0f,1f);
}
//if( not touching collider)
CancelInvoke("DecreaseAmmo");
Your answer
Follow this Question
Related Questions
How often is the update function called ? 1 Answer
Variable Doesn't Update in "Update" function 0 Answers
Transfering Variables Between Sections [SOLVED] 2 Answers
Activate Animation => Wait => Hide Gameobject 2 Answers
Set guiText 1 Answer