0
\$\begingroup\$

I'm making a 2D platformer controller and I want to implement a coyote time and buffered jump, the way I implement both is by setting a bool to true when either action is enabled like this:

private IEnumerator ApplyCoyote()
{
    isCoyote = true;
    yield return coyoteDelay;
    isCoyote = false;
}

So if you were to press jump while isCoyote is true you would jump. But every now and then the coroutine appears not to work and isCoyote becomes false immediately. I confirmed this by logging the changes to isCoyote and most of the time I can notice the delay between it becoming true and false plus the time on both logs is different, but when it fails it just prints them at the same time.

BTW I'm not disabling any scripts and I stop any previous calls to this coroutine before starting a new one

\$\endgroup\$
6
  • 1
    \$\begingroup\$ We're unable to reproduce the problem using only the code here. Unity does not selectively skip delays, so the error in your code is somewhere outside this snippet. Please create a small self-contained script to share as a Minimal Complete Verifiable Example of the problem. Once we can reproduce the problem, we can test potential solutions to be sure they'll work for you. \$\endgroup\$
    – DMGregory
    Jun 11 at 11:17
  • 3
    \$\begingroup\$ As an aside, this is not a good way to implement coyote time, jump buffers, or other periods of validity in the first place, since it incurs a heap allocation for the coroutine instance every time it's used. A simpler solution is to either store a timestamp or zero a time accumulator. Then you can implement your condition variable as a getter: bool isCoyote => timeSinceGround <= coyoteDuration; or bool isCoyote => (Time.time - lastGroundTime) <= coyoteDuration; \$\endgroup\$
    – DMGregory
    Jun 11 at 11:22
  • 1
    \$\begingroup\$ @DMGregory I implemented coyote time as you suggested, it works perfectly now. I don't know what was I thinking implementing it with a coroutine. In any case however it still makes no sense that the coroutine wouldn't yield some times. Most of the time it does, but some times it doesn't. \$\endgroup\$
    – lsauceda
    Jun 12 at 18:02
  • 2
    \$\begingroup\$ What's more likely is your coroutine is yielding exactly as expected, but something about the way you're using it in your other code causes it to appear otherwise. You'll need to edit your question to include a MCVE before we can investigate that. \$\endgroup\$
    – DMGregory
    Jun 12 at 19:07
  • \$\begingroup\$ Have you tried adding some logging statements, e.g. Debug.Log("isCoyote = true");? \$\endgroup\$
    – Kevin
    Jun 13 at 23:50

1 Answer 1

1
\$\begingroup\$

For making the coroutine wait for a few seconds before executing isCoyote = false, you will need to use new WaitForSeconds().

What this function does is it waits for that delay and then executes isCoyote = false.

Try this code:

private IEnumerator ApplyCoyote()
{
    isCoyote = true;
    yield return new WaitForSeconds(coyoteDelay);
    isCoyote = false;
}
\$\endgroup\$
1
  • \$\begingroup\$ Presumably, coyoteDelay was already declared and assigned as a new WaitForSeconds() elsewhere in the code. Yield instructions can be re-used, so you don't need to construct a new one for every use. \$\endgroup\$
    – DMGregory
    Jun 14 at 11:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .