Unity 中 使用c#线程
使用条件
天下没有免费的午餐,在我使用unity的那一刻,我就感觉到不自在,因为开源所以不知道底层实现,如果只是简单的做点简单游戏,那就无所谓的了,但真正用到实际地方的时候,就会发现一个挨着一个坑,然后你就跟着unity做各种妥协。如果开发中需要使用网络等等涉及到多线程的地方,就会用到c#的多线程,注意不是unity的协程,你要做的妥协参考下面(网友整理,我没去搜索)的:
1. 变量(都能指向相同的内存地址)都是共享的
2. 不是UnityEngine的API能在分线程运行
3. UnityEngine定义的基本结构(int,float,Struct定义的数据类型)可以在分线程计算,如 Vector3(Struct)可以 , 但Texture2d(class,根父类为Object)不可以。
4 UnityEngine定义的基本类型的函数可以在分线程运行,类的函数不能在分线程运行
unity设计之初应该就是一个单线程,不允许在另外的线程中进行渲染等等的工作可以理解,不然又要增加很多机制去处理这个问题,会给新来的人徒增很多烦恼,比如说我:
//class
public class NIDataManager: MonoBehaviour
{
public static NIDataManager GetInstance()
{
}
}
/*thread*/
private void RequestEvevtThread()
{
while (!m_IsExitThread)
{
/*wait set event*/
m_EventWait.WaitOne(-); /*reference SendRequestToService,error ,using subclass of MonoBehaviour in thread*/
if (NIDataManager.GetInstance().isServiceOpen())
{
if ( == ServiceInterface.sendRequest((int)(m_EventParam.ActionType), m_EventParam.DurationTime, ref m_EventParam.Response))
{
if (m_EventParam.DelegateCallback != null)
{
m_EventParam.DelegateCallback(m_EventParam.Response);
}
}
else
{
// Debug.Log("sendRequest false");
continue;
}
}
m_isProcessing = false;
}
}
如果你也这样干,恭喜你,会得到错误:CompareBaseObjectsInternal can only be called from the main thread.
关于这个错误的一些分析可以参考:http://forum.unity3d.com/threads/comparebaseobjectsinternal-error.184069/
委托是个坑
第一版思路
游戏通过向体感引擎申请动作识别结果,但是这个结果在处理结束之前,需要堵塞线程,交互设计本身是有问题的,如果在主线程做肯定不可能。OK ,一般情况下,游戏中角色申请完事件之后需要根据结果对人物的状态,如位置等等的进行修改,这其中肯定会涉及到unity的API ,看到这个地方之后我的第一个思路代码如下:

using System;
using System.Collections.Generic;
using System.Threading; public class NIEventThread
{
/*事件处理后的委托*/
public delegate void EventCallbackMethod(int bSuccess); /*Event申请使用的参数*/
public struct stEventParam
{
public int ActionType; //动作类型
public int DurationTime; //限定时间
public EventCallbackMethod DelegateCallback; //处理后的结果返回 public stEventParam(int type, int time, EventCallbackMethod func)
{
ActionType = type;
DurationTime = time;
DelegateCallback = func;
}
} /*线程中申请需要的参数*/
private stEventParam m_EventParam = new stEventParam();
/*线程控制量,等待申请事件*/
private AutoResetEvent m_WaitEvent = new AutoResetEvent(false);
/*线程结束控制*/
private bool m_IsExitThread = false;
/*线程,需要设置为后台线程*/
private Thread m_EventThread = null; public Thread GetThread
{
get { return m_EventThread; }
} /*初始化的时候就打开线程*/
public NIEventThread()
{
StartThread();
} ~NIEventThread()
{
EndThread();
} /*创建和开启线程*/
private void StartThread()
{
m_EventThread = new Thread(this.RequestEvevtThread);
m_EventThread.IsBackground = true;
m_EventThread.Start();
} /*结束线程*/
private void EndThread()
{
m_IsExitThread = false;
} /* 请求事件*/
public void RequestEvent(stEventParam param)
{
m_EventParam = param;
m_WaitEvent.Set();
} /*线程处理方法*/
public void RequestEvevtThread()
{
while (!m_IsExitThread)
{
/*等待事件激活*/
m_WaitEvent.WaitOne(-); Console.WriteLine("等你好久了" + "duration:" + m_EventParam.DurationTime); if (m_EventParam.DelegateCallback != null)
{
m_EventParam.DelegateCallback();
}
}
}
}
unity中的调用:
// Update is called once per frame
void Update ()
{
if (Input.GetKey(KeyCode.Space))
{
//申请事件
t.RequestEvent(new stEventParam(, ,test));
}
} void test(int t)
{
//掉用unity API
transform.Rotate(new Vector3(,,));
}
处理结果:
产生错误“InternalGetTransform can only be called from the main thread.”
也就是说:这个委托还在分支线程中执行,而不是在代码所在的主线程中执行,具体原因另外一篇文章讲解,其实在c#中控件也不允许在另外一个线程中进行控制,但是微软提供了方法,unity没提供或者说本身就不建议这么干。
怎么破?我这里给出我自己的思路,增加队列,在时间请求线程中先队列中增加要处理的事件,在unity主线程中取队列中的参数进行处理,OK ,看代码:
队列:

public sealed class RequestMessageQueue
{
private readonly static RequestMessageQueue mInstance = new RequestMessageQueue();
public static RequestMessageQueue GetInstance()
{
return mInstance;
} public void EnQueue(stEventResult st)
{
m_Event.Enqueue(st);
} public stEventResult DeQueue()
{
return m_Event.Dequeue();
} public int Count
{
get { return m_Event.Count; }
} private RequestMessageQueue()
{
m_Event = new Queue<stEventResult>() ;
} Queue<stEventResult> m_Event;
}
unity中事件处理
public class RequestMessageHandle : MonoBehaviour
{ // Use this for initialization
void Start ()
{ } // Update is called once per frame
void Update ()
{
while (RequestMessageQueue.GetInstance().Count != )
{
stEventResult st = RequestMessageQueue.GetInstance().DeQueue();
st.DelegateCallback(st.result);
}
}
}
再来看看线程中调用:
/*线程处理方法*/
public void RequestEvevtThread()
{
while (!m_IsExitThread)
{
/*等待事件激活*/
m_WaitEvent.WaitOne(-); Console.WriteLine("等你好久了" + "duration:" + m_EventParam.DurationTime); if (m_EventParam.DelegateCallback != null)
{
//m_EventParam.DelegateCallback(1);
RequestMessageQueue.GetInstance().EnQueue(new stEventResult(m_EventParam.ActionType,,m_EventParam.DelegateCallback));
}
}
}
修改完之后,unity中原先的逻辑不需要更该,就可以看到测试中按键点击后,物体的旋转。
Unity 中 使用c#线程的更多相关文章
- 【原创翻译】初识Unity中的Compute Shader
一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位 ...
- WP8:在Unity中使用OpenXLive
Unity 4.2正式版开始添加了对Windows 8.Windows Phone 8等其他平台的支持,而且开发者可以免费使用Unity引擎来开发游戏了.而作为Windows Phone和Window ...
- C#中的yield return与Unity中的Coroutine(协程)(下)
Unity中的Coroutine(协程) 估计熟悉Unity的人看过或者用过StartCoroutine() 假设我们在场景中有一个UGUI组件, Image: 将以下代码绑定到Image using ...
- Unity 中场景切换
Unity游戏开发中,单个Scene解决所有问题似乎不可能,那么多个Scene之间的切换是必然存在.如果仅仅是切换,似乎什么都好说,但是在场景比较大的时候不想让玩家等待加载或者说场景与场景之间想通过一 ...
- Unity中的协程(一)
这篇文章很不错的问题,推荐阅读英文原版: Introduction to Coroutines Scripting with Coroutines 这篇文章转自:http://blog.csdn. ...
- 【Unity】Unity中C#与Android中Java的互相调用遇到的一些问题
1.有关调用的一些问题: (1).在C#中直接调用java中的代码,无返回值: 在java中: public static void setAge(Context context , int leve ...
- unity中的构造函数
避免使用构造函数 不要在构造函数中初始化任何变量,使用Awake或Start实现这个目的.即使是在编辑模式中Unity也自动调用构造函数,这通常发生在一个脚本被编译之后,因为需要调用构造函数来取向一个 ...
- Unity中C#单例模式使用总结
一.单例模式优点 单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问: 意味着在内存中,只存在一个实例,减少了内存开销: 二.单例模式特点 只存在唯一一个实例: ...
- 了解Unity中的多线程及使用多线程
http://blog.csdn.net/hany3000/article/details/16917571 如果你想在游戏中使用多线程,你应该看看这篇文章,线程是一个相当复杂的话题,但如果你掌握了它 ...
随机推荐
- 数据库优化和SQL操作的相关题目
SQL操作 1.有一个数据库表peope,表有字段name,age,address三个属性(注:没有主键).现在如果表中有重复的数据,请删去重复只留下其中的一条.重复的定义就是两条记录的name,ag ...
- Unity3D入门之GUI基础以及常用GUI控件使用(2)
1.GUI基础 (1)GUI部分是每帧擦除重绘的,只应该在OnGUI中绘制GUI,按钮:GUILayout.Button(“Hello”); 只读标签:GUILayout.Label() (2)修改控 ...
- 在php4下可用,简单的php数组转成json格式,
function array_to_json( $array ){ if( !is_array( $array ) ){ return false; } $ ...
- NDK开发
1 CDT 是 Eclipse 插件,它将把 Eclipse 转换为功能强大的 C/C++ IDE. C/C++在Eclipse平台下的开发工具.它提供的功能包括:C/C++编辑器(一些基本的功能:语 ...
- cocos2dx游戏开发——微信打飞机学习笔记(十)——碰撞检测的搭建
一.七说八说 大家都发现了= =,做了那么多,发现就是摆设,完全没有打飞机的感觉,没有实现碰撞的监测.比如说呢,子弹和敌机,玩家与敌机就是需要有碰撞检测的说,然后在这篇我想会很长很长的教 ...
- zookeeper 4 letter 描述与实践
命令示例描述 Conf echo conf | nc localhost 2181 (New in 3.3.0)输出相关服务配置的详细信息.比如端口.zk数据及日志配置路径.最大连接数,session ...
- Android 编程下的 Secret Code
我们很多人应该都做过这样的操作,打开拨号键盘输入 *#*#4636#*#* 等字符就会弹出一个界面显示手机相关的一些信息,这个功能在 Android 中被称为 Android Secret Code, ...
- JavaScript中两个感叹号(!!)的作用是什么?
!!一般用来将后面的表达式强制转换为布尔类型的数据(boolean),也就是只能是true或者false. 看这么个例子: var a: var b=!!a; a默认是undefined.!a是tru ...
- D FFF团的怒火
Time Limit:1000MS Memory Limit:65535K 题型: 编程题 语言: 无限制 描述 在信软学院,男女比例失衡已经是习以为常的事情. 在这样的一个学院,诞生了一个神秘 ...
- 水题 Codeforces Round #302 (Div. 2) A Set of Strings
题目传送门 /* 题意:一个字符串分割成k段,每段开头字母不相同 水题:记录每个字母出现的次数,每一次分割把首字母的次数降为0,最后一段直接全部输出 */ #include <cstdio> ...