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

意思就是某个方法只能从主线程中被调用。这样一来,在我们的异步回调方法中,我们将不能再调用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在子线程中无法调用的限制问题。
战国工作室 供稿