#Smartest way of using delays.
1 messages · Page 1 of 1 (latest)
Well, anything that increases complexity, increases chances of bugs. It's up to you to handle that correctly.
You could write your own timer enque/dispatch manager that would work completely on update loop and timers. But that would basically be reinventing the coroutines.
Could also just make like a Timer stuct that abstracts away the float comparisons etc.
For example something like this```cs
public struct Timer
{
public float startTime;
public float GetAge() => Time.time - startTime;
public float Reset() => startTime = Time.time;
public bool IsActive(float duration) => GetAge() < duration;
}
/// ...
Timer myTimer;
/// ...
if(myTimer.IsActive(someDuration)) { /* Do stuff */ }
Just threw it quickly together so not the best naming etc. but you get the idea
Point being that you still use "float timers" but it's a bit neater
I use this kind of thing for some cooldowns etc.
But yeah, using coroutine or async with Awaitable is perfectly fine too.
Also note that avoiding coroutines or async because they "sometimes cause bugs" isn't rational. The bugs don't just randomly appear, if it doesn't work it's because you made a mistake and it can be fixed. Timers in Update can have bugs just the same.
Thanks to all of you. I think I should think about coroutines. 😊
If you use async then be warned that you must either use cancellation tokens or manual checks to stop it when your monobehaviour is destroyed
MonoBehaviour.destroyCancellationToken exists to help with this
I can recommend UniTask for such things, it was made to fix some issues that Unity Async style brings
UniTask is just better than Awaitable in every way
Anything is fine imo
Just make sure that async process/timer/delayed callback/tween/whatever is:
-cleanly killable, you should be able to interrupt it without problems
-it handles all the possible cases of the objects its working with, like for example if the callback is going to do something to an object after x seconds, it should be able to handle the case where that object is prematurely destructed by something else
or make sure nothing else will mess with those objects
-I often use coroutines and tweens and nothing else pretty much
if i need something more complex, i just implement something like a state machine
Awaitable and UniTask delays can take cancellation token arguments which solves this issue
Yeah can be cool
We often use dotween tweens most of the time
like 95%
We always used tweens where there was not a variable wait duration
Tween has OnKill which runs when it ends either way
Dotween is amazing and i use it too where possible
But for things like tracking a sequence of things, like tutorials or maybe in a strategy game where you queue tasks and stuff
I think something like a state machine is needed or any other custom state driven thing
I wouldn't want complex control from these async things
Otherwise it becomes a hard to debug thing
Its got a bunch of states in its closure allocation and I can't debug it
Ive done tutorials with async before. A queue of tutorial objects with stages would be configured and their execution was an async function that could trigger and wait for actions
It made good use of cancellation tokens and other things to ensure it can stop and restart if needed.
What do you do when the player does something that makes the sequence impossible to follow through?
Do you not allow it?
Or do you restart the tutorial and put the scene back into the original state where the tutorial started?
Like for example, player was supposed to shoot the red baloon in step 6, but then the player ran out of bullets
I think with these sequences, it's a little more difficult to detect something like that and give player arrows or something
It usually had a mix of forced actions and open ended actions that waited for certain game events
I see
So i didnt just pray they did it in a way that worked, I ensured it was going to work
e.g. disable pausing, force some unit to be the only one they can drag
In that specific case you would let them just have infinite ammunition for example. Always expect the user/player to handle it the worst way 😉 Your player should never dictate the circumstances of your gamestate, only act within its limits and the system reacts to it.