ialex32x / unity-jsb

It brings Javascript runtime capability to Unity3D by integrating QuickJS.
MIT License
335 stars 41 forks source link

Call async/coroutine from project-monobehavior #76

Closed aleverdes closed 2 years ago

aleverdes commented 2 years ago

Hi @ialex32x

I decided to try to connect my JS-MonoBehaviour with the C#-MonoBehaviour available in the project, and call a coroutine or an Async method on it and wait for it. The method is called, but the await hangs forever. Am I doing something wrong or is this not supported out of the box?

JS:

        console.log("start color changing", this._tick++);
        let rendererBehaviour = this._collection.Get(0).GetRendererBehaviour();
        await rendererBehaviour.ChangeColorAsync(targetColor, 1);
        // await rendererBehaviour.StartCoroutine("ChangeColor");
        // await rendererBehaviour.StartCoroutine(rendererBehaviour.ChangeColor(targetColor, 1));
        console.log("awaited color changed", this._tick++);

C#:

        public IEnumerator ChangeColor(Color targetColor, float duration)
        {
            var startColor = _renderer.material.color; 

            var t = 0f;
            if (duration <= FloatEpsilon.Value)
            {
                _renderer.material.color = targetColor;
            }
            else
            {
                do
                {
                    t = Mathf.Clamp01(t + Time.deltaTime / duration);
                    _renderer.material.color = Color.Lerp(startColor, targetColor, t);
                    yield return null;
                }
                while (t <= 1f - FloatEpsilon.Value);
            }

            ColorChanged?.Invoke(targetColor);
        }

        public async void ChangeColorAsync(Color targetColor, float duration)
        {
            var startColor = _renderer.material.color; 

            var t = 0f;
            if (duration <= FloatEpsilon.Value)
            {
                _renderer.material.color = targetColor;
            }
            else
            {
                do
                {
                    t = Mathf.Clamp01(t + Time.deltaTime / duration);
                    _renderer.material.color = Color.Lerp(startColor, targetColor, t);
                    await Task.Yield();
                }
                while (t <= 1f - FloatEpsilon.Value);
            }

            ColorChanged?.Invoke(targetColor);
        }
aleverdes commented 2 years ago

I found example_async and tried to repeat it.

        console.log("start", this._tick++);
        await jsb.Yield(Varwin.RendererBehaviour.SimpleTest(1000));
        console.log("finish", this._tick++);
        public static async Task SimpleTest(int ms)
        {
            Debug.LogError("Before " + ms);
            await Task.Delay(ms);
            Debug.LogError("After " + ms);
        }

But the message "finish" is not displayed (all other logs are displayed). Where is the mistake?

aleverdes commented 2 years ago

Using a coroutine instead of Async-Task helped.

        console.log("start color changing", this._tick++);
        let rendererBehaviour = this._collection.Get(0).GetRendererBehaviour();
        await jsb.Yield(rendererBehaviour.ChangeColor(targetColor, 3));
        console.log("awaited color changed", this._tick++);
        public IEnumerator ChangeColor(Color targetColor, float duration)
        {
            var startColor = _renderer.material.color; 

            var t = 0f;
            if (duration <= FloatEpsilon.Value)
            {
                _renderer.material.color = targetColor;
            }
            else
            {
                do
                {
                    t = Mathf.Clamp01(t + Time.deltaTime / duration);
                    _renderer.material.color = Color.Lerp(startColor, targetColor, t);
                    yield return null;
                }
                while (t <= 1f - FloatEpsilon.Value);
            }

            ColorChanged?.Invoke(targetColor);
            Debug.LogError("FINAL ChangeColor");
        }