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\$
5
  • 1
    \$\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
    Commented Aug 14, 2020 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
    Commented Aug 14, 2020 at 13:56
  • \$\begingroup\$ Comments are not for extended discussion; this conversation has been moved to chat. \$\endgroup\$
    – DMGregory
    Commented Aug 14, 2020 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
    Commented Aug 16, 2020 at 18:19
  • \$\begingroup\$ Related: gamedev.stackexchange.com/questions/185200/… \$\endgroup\$
    – Evorlor
    Commented Aug 18, 2020 at 14:53

2 Answers 2

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

You must log in to answer this question.

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