- Home /
A more efficient way of measuring time?
I've been using the same formula over and over, and I have concerns for its efficiency.
if (Time.time > lastFireTimeLeft && Time.time > ammoRechargeLeft && leftAmmo < 20)
{
Debug.Log("Left");
//lastFireTimeLeft = Time.time + ammoDelay;
ammoRechargeLeft = ammoRechargeRate + Time.time;
leftAmmo = leftAmmo + 1;
}
It's been perfectly effective to do exactly what I want, but of course, this means that the value keeps changing the longer the scene is running. I'm not super concerned for its efficiency at this time, but I don't want to shoot myself in the foot.
There is no problem with the efficiency of this condition, they are just comparisons of primitive types, and they are linked with lazy boolean AND.
However, I'm not sure it does what you want it to do: Time.time
tells you "the time in seconds since the start of the game" (see the scripting API). So unless you base the values of lastFireTimeLeft
and ammoRechargeLeft
on Time.time
, they will become always true pretty fast.
It's just a small, small snippet of example coding. In playtesting, the system is working like a charm, but I had concerns for the practicality of this since the value keeps climbing and climbing the longer the scene runs.
Answer by Dray · Jan 19, 2018 at 03:23 PM
All that "wait for X seconds and then do this and that" kind of stuff can be managed pretty nicely using Coroutines!
You write something like this:
IEnumerator YourTimedCommand() {
SomeCommand();
// execution will pause here and return to the same point
// after 0.5 Seconds, without pausing any other scripts.
yield return new WaitForSeconds(.5f);
SomeLateCommand();
}
And then start it using StartCoroutine():
StartCoroutine("YourTimedCommand");
That even works with loops and all that and as soon as the bottom of your method is reached, the coroutine stops. So you could either run an endless loop until some condition is fullfilled or just have one "async" method with some delays in it, depending on what you need, it's pretty usefull ;)
As a beginner, it'll take me a little bit to wrap my head around that, but I really appreciate the response!
Indeed coroutines are a great solution for delayed calls. The only thing I would add that it is better to call your coroutine as a function ins$$anonymous$$d by name (see example below), because the string version has to find the coroutine function you want to call (adds a lot of unnecessary cost), and later it is more difficult to cancel it. So ins$$anonymous$$d of
StartCoroutine("YourTimedCommand");
use
StartCoroutine(YourTimedCommand());
Also, this second way you can pass typed parameters ( int
, float
, $$anonymous$$yCustomClass
), while with the string way you can only pass an object
(see scripting reference for more info).
I've been attempting a coroutine on the throttle controls, because i haven't been able to get the throttle to increase or decrease at a consistent rate, but I can't figure out a way to meld a coroutine with a Get$$anonymous$$ey. Ultimately what I'm trying to get with this one in particular is if I hold down the bumper (on my controller because mouse ai$$anonymous$$g in a flight sim is the worst ever) I want the speed to increase at a rate of 1 every 0.5s. Everything I tried so far has not worked at all. Any suggestions?
I wouldn't use a coroutine for a continuous change, I would use Update()
:
// adding [SerializeField] will expose the variable in the Inspector so you can experiment with it
[SerializeField] private float speedChangeRate = 2; // 1 unit every 0.5s is 2 units every 1s ;)
[SerializeField] private string increaseSpeedButtonName; // fill with name of button
[SerializeField] private $$anonymous$$eyCode decreaseSpeedButtonName; // fill with name of button
private float speed = 0; // use the value of speed to drive physics in FixedUpdate()
private void Update () {
if (Input.GetButton(increaseSpeed$$anonymous$$ey)) { speed += speedChangeRate * Time.deltaTime; }
if (Input.GetButton(decreaseSpeed$$anonymous$$ey)) { speed -= speedChangeRate * Time.deltaTime; }
}
@Harinezumi yea you're totally right, that's the better way to start them and furthermore it avoids any typos. For some reason I keep using the string input version though, I don't even know why :D It's not like it looks better or anything lol
Answer by ransomink · Jan 23, 2018 at 04:57 AM
I think it could be a bit simpler. I wouldn't have so many operands at once because if one condition is not true, you won't have to check the others. A simple way to measure time, you can do:
public float fireRate;
private float lastShot;
void Update()
{
if ( Input.GetMouseButton( 0 ) )
{
Shoot();
}
}
void Shoot()
{
if ( lastShot + fireRate < Time.time )
{
// Pool or instantiate your bullet
// Set whatever properties you need
// Fire it off
lastShot = Time.time;
}
}
If you're afraid of the number constantly increasing you can do it a different way.
public float fireRate;
private float lastShot;
private float defaultFireRate;
void Awake()
{
defaultFireRate = fireRate;
}
void Update()
{
if ( fireRate <= 0 )
{
if ( Input.GetMouseButton( 0 ) )
{
Shoot();
}
}
else
{
fireRate -= Time.deltaTime;
}
}
void Shoot()
{
// Pool or instantiate your bullet
// Set whatever properties you need
// Fire it off
fireRate = defaultFireRate;
}
Coroutines are great but not the best for constantly changing values. They also generate garbage, so use them only when needed.
Personally, I believe the best option is to create Timer class and use that to set/check time for your game...
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Is it bad to have this many materials? 2 Answers
Alternative to KeyedByTypeCollection in Mono .Net 1 Answer
Small Timer in C#? 2 Answers