【发布时间】:2016-03-24 17:13:23
【问题描述】:
我们正在制作一个统一游戏,它使用从 tcp 套接字接收的命令来处理游戏某个校准状态下的动作。 当接收到新字符串时,状态管理器会处理由套接字管理器引发的事件。然后,该状态管理器必须在开始时在字段中引用的游戏对象上触发一个方法。
我们现在面临的问题是处理这些事件的线程无法访问这个对象。我们得到以下错误:
ToString 只能从主线程调用。加载场景时,构造函数和字段初始化器将从加载线程中执行。
在标有这行给出错误的行
Unity 如何使用 EventHandlers 处理线程以及我们如何访问这个对象?
提前致谢!
public class StateManager : MonoBehaviour {
private bool initialized;
private GameObject calibrationController;
void Start(){
InitializeEventHandler ();
}
void OnLevelWasLoaded(int level) {
if (level == 3) {
calibrationController = GameObject.FindGameObjectWithTag("CalibrationController");
Debug.Log ("calibrationController 1: " + calibrationController);
calibrationController.GetComponent<CalibrationController> ().NewState += NewCalibrationState;
calibrationController.GetComponent<CalibrationController>().setupCalibration();
}
}
private void InitializeEventHandler(){
GetComponent<GameSocket> ().NewCommand += NewCommandReceived;
}
private void NewCommandReceived(object sender, NewCommandEventArgs e){
HandleCommandReceived (e.Command);
}
private void NewCalibrationState(object sender, NewCalibrationStateEventArgs e)
{
HandleNewCalibrationState (e.State);
}
private void HandleCommandReceived(string command){
switch (command) {
case "startcalibrationcomplete":
Debug.Log ("startcalibrationcomplete");
Debug.Log ("calibrationController 2: " + calibrationController); THIS LINE GIVES THE ERROR !!!
Debug.Log(GameObject.FindGameObjectWithTag("CalibrationController"));
break;
default:
Debug.Log ("state10");
break;
}
}
private void HandleNewCalibrationState(string state){
switch (state) {
case "startcalibration":
GetComponent<GameSocket>().MySend("startcalibration");
// ...
break;
case "animationdone":
GetComponent<GameSocket>().MySend("animationdone");
break;
default:
Debug.Log ("state10");
break;
}
}
对于未来的读者:由于 Unity 的线程不佳,无法从事件处理程序调用游戏对象上的方法。 通过让事件处理程序在一个空的游戏对象上设置数据脚本的属性,我找到了一种解决方法。 可以从任何游戏对象(即在更新周期中)访问此脚本上的数据。
【问题讨论】:
-
(1) Unity 不是多线程的,与多线程无关。 (2) 出于这个原因,每个 Unity 调用(“ToString”和每个其他 Unity 函数) 仅适用于主线程。这是关于 Unity (3) 的一个基本事实,在极少数情况下您需要启动另一个线程(为什么?),因此您必须“返回”主线程来告诉您的应用程序任何事情。 (4) 线程编程困难;如果您正在线程化,您将知道如何“回到”Unity 中的主线程!最后(5)你应该使用
UnityEvent(这太棒了) -
除 UnityEvent 外,我同意你的所有观点。 UnityEvent 非常慢。非常非常慢。几年前我做了一个基准测试,还用谷歌搜索了我的结果来验证我得到了什么,这不值得。 Unity 知道这一点,他们将根据他们的一位程序员将其删除或在 Unity 6 中重新编写。代表和活动更快。
-
那个“非常非常慢”的参数只对更新事件有效。如果您的事件偶尔被调用,UnityEvent 很好。它实际上也更安全,因为它们不是真实事件,只是根据请求迭代的委托列表。缓慢的部分来自检查对象是否活着。
标签: c# multithreading unity3d