处理异步通信与Unity API调用冲突的问题-新闻详情

处理异步通信与Unity API调用冲突的问题


发布时间:2017-03-02责任编辑:朱明 浏览:2447


最近在测试游戏通信功能的过程中,遇到了这么一个问题:Unity的API函数只能在主线程中调用,而我们的游戏客户端使用了异步的方式与服务器进行通信,在通信完成的回调函数中,会触发一些操作,这些操作涉及到了UnityAPI函数的调用,产生的结果就是直接报出了错误:

 

处理异步通信与Unity API调用冲突的问题1.jpg

 

意思就是某个方法只能从主线程中被调用。这样一来,在我们的异步回调方法中,我们将不能再调用Unity的API函数,那么我们所做的许多处理也就无法进行了。

 

经过一些测试,我们知道了尽管API不能跨线程调用,但是通信返回的数据以及共享的数据对象并不会受到此限制,它们是可以跨线程使用的。于是,解决此问题的思路就是,通过添加一个lock对象,并设置它的多个不同状态,通过检测来实现异步接收数据,在主线程中调用回调响应的方式。

 

首先,在异步通信开始时,将lock对象的状态设置为等待;

 

    public void AsyncProcessBegin()

    {

        lock( asyncStatusObj )

        {

            asyncStatusObj.asyncStatus = AsyncStatus.Wait;

        }

    }

 

然后,在异步结束时,保存从服务端收到的数据,并将lock对象的状态设置为完成;

 

    public void AsyncProcessEnd(Action callback)

    {

        lock( asyncStatusObj )

        {

            asyncStatusObj.asyncStatus = AsyncStatus.Complete;

            asyncStatusObj.asyncEndAction = callback;

        }

    }

 

在主线程的Update中不断检测lock对象的状态,如果它处于完成状态,则根据异步获取到的数据,在主线程中执行回调处理。并将lock对象的状态置回待机。

 

    private void Update()

    {

        lock( asyncStatusObj )

        {

            if( AsyncStatus.Complete == asyncStatusObj.asyncStatus )

            {

                asyncStatusObj.asyncEndAction();

                asyncStatusObj.asyncEndAction = null;

                asyncStatusObj.asyncStatus = AsyncStatus.None;

            }

        }

    }

 

最后,在我们的程序启动运行时,进行异步检测对象的初始化操作,

 

    private static void Initialize()

    {

        if( !initialized )

        {

            GameObject go = new GameObject();

            go.name = "AsyncDetectionManager";

            instance = go.AddComponent<AsyncDetectionManager>();

            go.transform.parent = GameRoot.Trans;

            initialized = true;

        }

    }

 

经测试,这种方式成功克服了Unity API在子线程中无法调用的限制问题。

 



战国工作室   供稿