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 如果你想在游戏中使用多线程,你应该看看这篇文章,线程是一个相当复杂的话题,但如果你掌握了它 ...
随机推荐
- 从几个方向进行Web渗透测试
渗透测试就是对系统安全性的测试,通过模拟恶意黑客的攻击方法,来评估系统安全的一种评估方法. 渗透测试可以包括各种形式的攻击,一般来说会有专门的公司提供这种服务,这里整理了几种常见的渗透测试方法,可以对 ...
- IE下AjaxForm上传文件直接提示下载的兼容性Bug
使用AjaxForm上传文件时候,在IE下直接提示下载保存: 我的示例代码: return this.Json( new { prop1 = 5, prop2 = 10 }); 这种问题只出现在IE下 ...
- php设置和获取cookie
php设置和获取cookie setcookie()调用只带有name参数的setcookie(); ()使失效时间为time()或time-; <?php setcookie(); PHP提供 ...
- 利用OData轻易实现串流数据的可视化
OData(开放数据协议,Open Data Protocol)一直是我喜欢一种的标准(OASIS 标准),它基于RESTful协议提供了一种强大的查询和编辑数据的访问接口.虽然是微软推出的,不过在诞 ...
- java_ant详解
转自:http://hi.baidu.com/victorlin23/item/721b892c770be3d7a517b695 1,什么是antant是构建工具2,什么是构建概念到处可查到,形象来说 ...
- Servlet应用的运行流程
其中,红色部分为我们开发人员要做的,其他部分是框架做的. 学习就要搞懂整个运行的流程!否则,不利于个人技术的积累!
- Scala中的match(模式匹配)
文章来自:http://www.cnblogs.com/hark0623/p/4196261.html 转载请注明 代码如下: /** * 模式匹配 */ case class Class1(pa ...
- CodeForces 433C Ryouko's Memory Note-暴力
Ryouko's Memory Note Time Limit:1000MS Memory Limit:262 ...
- zoj 1097 普吕弗序列
题目大意:输入一颗无根树的括号序列,求这棵树的普吕弗序列. 分析思路: 1)普吕弗序列,可以参考维基百科,其做法是找出树中编号最小的叶子节点,并将此叶子节点及边删除,并输出其邻接的节点标号: 2)递归 ...
- BZOJ3325 : [Scoi2013]密码
从以每一位为中心的回文串长度可以用Manacher倒推出$O(n)$对相等和不等关系. 将相等的用并查集维护,不等的连边. 然后输出方案时若还没被染过色,则求一个mex. #include<cs ...