Home > Enterprise >  Starting async Monobehaviour class from Button?
Starting async Monobehaviour class from Button?

Time:11-11

Im a total noob when it comes to Unity & C# and now I got a task that I find a bit overwhelming so any input would be much appreciated...

I got a class that looks like this:

//using directives

public class PipelineExample : MonoBehaviour
{
    private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    private bool res = false;

    // Start is called before the first frame update
    void Start()

    {
        StartPipeline();
        while (!res) ;
    }

    async void StartPipeline()
    {
        // create models, pipeline, pipeline step
        IModel fbxModel = new FbxModel();
        Pipeline<IModel> pipeline = new Pipeline<IModel>();
        IAction<IModel> pipelineStep = new GenericPipelineStep<IModel>();

        // add steps to pipeline
        pipeline.AddPipeLineStep(pipelineStep);



        try
        {
            res = await pipeline.Execute(fbxModel, cancellationTokenSource.Token);
            Console.Write("Result of pipeline: "   res);
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Canceled successfully!");
        }
    }


    // Update is called once per frame
    void Update()
    {
        
    }
}

Now I would like to call this startmethod(?) from another class somehow when I click on a Button "Start":

private void OnStartButtonClicked(MouseUpEvent evt)
{
    //What goes in here?
}

I cant just PipelineExample.Start obviously,

public PipelineExample something; something.Start also doesnt work.

So basically my question is, how can I start this PipeLineExample class from another class?

CodePudding user response:

If you ake some modifications to your PipelineExample class, you should be able to call the methods you're looking for.

Here is one example, of many ways, how you could achieve that:

public class PipelineExample : MonoBehaviour
{
    private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

    public static PipelineExample instance { get; private set; }
    public static bool initialised { get; private set; }

    public IModel fbxModel { get; private set; }
    public Pipeline<IModel> pipeline { get; private set; }

    // Unity will create an instance of this class. We then use it as a 'singleton'.
    private void Awake ( )
    {
        if ( instance != null )
            return;

        instance = this;
    }

    public async Task<bool> StartPipeline ( )
    {
        if ( initialised )
            return true;

        // create models, pipeline, pipeline step
        fbxModel = new FbxModel();
        pipeline = new Pipeline<IModel>();
        IAction<IModel> pipelineStep = new GenericPipelineStep<IModel>();

        // add steps to pipeline
        pipeline.AddPipeLineStep ( pipelineStep );

        try
        {
            initialised = await pipeline.Execute ( fbxModel, cancellationTokenSource.Token );
            Console.Write ( "Result of pipeline: "   initialised );
        }
        catch ( OperationCanceledException )
        {
            Console.WriteLine ( "Canceled successfully!" );
        }

        return initialised;
    }

    // You might want to include a method to cancel the pipeline setup using cancellationTokenSource?
}

Because it's a MonoBehaviour, Unity will handle creating an instance of this class. You could also implement it as a ScriptableObject (probably my preferred option) if you didn't want to attach this class as a component to an in-scene GameObject. But you might want scene specific values to drive this component later on in the application.

You would then call the setup like this:

private async void OnStartButtonClicked ( MouseUpEvent evt )
{
    if ( !PipelineExample.initialised )
    {
        // The pipeline isn't yet initialised. Alert user for a potential setup time.
        if ( !await PipelineExample.instance.StartPipeline ( ) )
        {
            // Something went wrong ... alert user?
            return;
        }
    }

    // PipelineExample is initialised.
    // PipelineExample.instance.fbxModel and PipelineExample.instance.pipeline are now set up.
}

Note that this will set up your pipeline when the button is clicked. If the loading times are long, you would probably benefit with some sort of user notification letting the user know that there's a potential delay.

CodePudding user response:

So I found a simple working solution to my problem.

I just made the methods in PipelineExample static and call the start in the button: PipelineExample.Start();

  • Related