2
\$\begingroup\$

I am trying to make a reload mechanism in Unity, but the function is in a scriptable object. This means I cannot use Coroutine as it is in MonoBehaviour. I could think of solving with a simple timer with Time.time and Time.deltaTime but for that, I should call the function every frame which seems not too right for me, I'd like to avoid this solution.

I thought about using C#'s built-in Async Await functions but I never used it before and it's quite confusing, I have no idea how to implement it after looking at Microsoft's documentation. I've tried implementing it but I always get an error saying

The body of 'Weapon.Reload()' cannot be an iterator block because 'void' is not an iterator interface type

I've done a coroutine implementation so it's easier to see what I want to achieve using Async/Await.

public virtual IEnumerator Reload()
{
    if (currentMagazine == magazineSize)
        yield break;

    if (!reloading)
    {
        Debug.Log("Started reloading");
        reloading = true;
    } 
    else 
    {
        yield return new WaitForSeconds(reloadTime);
        currentMagazine = magazineSize;
        reloading = false;
        Debug.Log("Reload time over");
    }

    Debug.Log("Finished reloading");
    yield break;
}

I want to be able to call this function and just let it do its job over time, without stopping code execution. At first, I tried the simple timer solution with a while loop then realized that just stops code execution so it's not working properly.

How could I do this using C#'s Async/Await?

\$\endgroup\$
  • \$\begingroup\$ This looks like exactly the code that should be in a MonoBehaviour, not in a ScriptableObject, as it's describing/manipulating the current state of a runtime instance of something, not a persistent data asset. Can you show us more of your architecture and why moving this to a MonoBehaviour is not available as a solution in this case? \$\endgroup\$ – DMGregory Aug 14 '20 at 13:53
  • \$\begingroup\$ It is a scriptable object because I want it anyone to be able to create a simple weapon, but it has virtual methods so if you want more complex behaviour a programmer can just overwrite the shoot or reload function. \$\endgroup\$ – 66Gramms Aug 14 '20 at 13:56
  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$ – DMGregory Aug 14 '20 at 14:04
  • \$\begingroup\$ You can pass a MonoBehaviour to the scriptable object. Then the scriptable object use that MonoBehaviour to start the Reload coroutine. \$\endgroup\$ – Nikaas Aug 16 '20 at 18:19
  • \$\begingroup\$ Related: gamedev.stackexchange.com/questions/185200/… \$\endgroup\$ – Evorlor Aug 18 '20 at 14:53
2
\$\begingroup\$

You can have a coroutine runner MonoBehaviour that runs coroutines defined elsewhere. For example:

public class CoroutineRunner : MonoBehaviour {
  private static CoroutineRunner instance;
  public static void RunCoroutine(IEnumerator coroutine) {
    if (instance == null) {
      instance = new GameObject("runner").AddComponent<CoroutineRunner>();
    }
    instance.StartCoroutine(coroutine);
  }
}

And to use it:

CoroutineRunner.RunCoroutine(Reload());

I know this doesn’t answer your question, but it does solve your problem by challenging your assumption that you cannot use coroutines in a scriptable object (or anywhere you want).

\$\endgroup\$
0
\$\begingroup\$
public virtual async void Reload()
{
    if (currentMagazine == magazineSize)
        return;

    if (!reloading)
    {
        Debug.Log("Started reloading");
        reloading = true;
    } 
    else 
    {
        await Task.Delay(reloadTime * 1000);
        currentMagazine = magazineSize;
        reloading = false;
        Debug.Log("Reload time over");
    }

    Debug.Log("Finished reloading");
}

To call, just use Reload().

\$\endgroup\$
  • \$\begingroup\$ I tried doing this but I receive the error message I detailed in my question \$\endgroup\$ – 66Gramms Aug 15 '20 at 21:06
  • \$\begingroup\$ Just use Reload() to call it. I updated my answer. \$\endgroup\$ – Evorlor Aug 15 '20 at 21:08
  • \$\begingroup\$ The error is coming from Reload's declaration, not calling it \$\endgroup\$ – 66Gramms Aug 15 '20 at 21:12
  • \$\begingroup\$ Can you be more specific? What line is having the problem? I wrote that freehand (no compiler). \$\endgroup\$ – Evorlor Aug 15 '20 at 21:13
  • 1
    \$\begingroup\$ Sounds like you have a typo in the body. Find the word yield, and fix that. \$\endgroup\$ – Evorlor Aug 15 '20 at 21:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.