使用条件

天下没有免费的午餐,在我使用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#线程的更多相关文章

  1. 【原创翻译】初识Unity中的Compute Shader

    一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位 ...

  2. WP8:在Unity中使用OpenXLive

    Unity 4.2正式版开始添加了对Windows 8.Windows Phone 8等其他平台的支持,而且开发者可以免费使用Unity引擎来开发游戏了.而作为Windows Phone和Window ...

  3. C#中的yield return与Unity中的Coroutine(协程)(下)

    Unity中的Coroutine(协程) 估计熟悉Unity的人看过或者用过StartCoroutine() 假设我们在场景中有一个UGUI组件, Image: 将以下代码绑定到Image using ...

  4. Unity 中场景切换

    Unity游戏开发中,单个Scene解决所有问题似乎不可能,那么多个Scene之间的切换是必然存在.如果仅仅是切换,似乎什么都好说,但是在场景比较大的时候不想让玩家等待加载或者说场景与场景之间想通过一 ...

  5. Unity中的协程(一)

    这篇文章很不错的问题,推荐阅读英文原版: Introduction to Coroutines Scripting with Coroutines   这篇文章转自:http://blog.csdn. ...

  6. 【Unity】Unity中C#与Android中Java的互相调用遇到的一些问题

    1.有关调用的一些问题: (1).在C#中直接调用java中的代码,无返回值: 在java中: public static void setAge(Context context , int leve ...

  7. unity中的构造函数

    避免使用构造函数 不要在构造函数中初始化任何变量,使用Awake或Start实现这个目的.即使是在编辑模式中Unity也自动调用构造函数,这通常发生在一个脚本被编译之后,因为需要调用构造函数来取向一个 ...

  8. Unity中C#单例模式使用总结

    一.单例模式优点 单例模式核心在于对于某个单例类,在系统中同时只存在唯一一个实例,并且该实例容易被外界所访问: 意味着在内存中,只存在一个实例,减少了内存开销: 二.单例模式特点 只存在唯一一个实例: ...

  9. 了解Unity中的多线程及使用多线程

    http://blog.csdn.net/hany3000/article/details/16917571 如果你想在游戏中使用多线程,你应该看看这篇文章,线程是一个相当复杂的话题,但如果你掌握了它 ...

随机推荐

  1. tomcat The file is absent or does not have execute permission

    [root@centos02 bin]# ./startup.sh Cannot find ./catalina.sh The file is absent or does not have exec ...

  2. 2.简单工厂模式(Simple Factory)

    using System; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { //如果 ...

  3. 《Effective Java》笔记 使类和成员的可访问性最小化

    类和接口 第13条 使类和成员的可访问性最小化 1.设计良好的模块会隐藏所有的实现细节,把它的API与实现清晰的隔离开来,模块之间只通过它们的API进行通信,一个模块不需要知道其他模块的内部工作情况: ...

  4. 在Linux中创建静态库.a和动态库.so

    转自:http://www.cnblogs.com/laojie4321/archive/2012/03/28/2421056.html 在Linux中创建静态库.a和动态库.so 我们通常把一些公用 ...

  5. SqlServer2005或2008数据库字典--表结构.sql

    SELECT TOP 100 PERCENT --a.id,       CASE WHEN a.colorder = 1 THEN d.name ELSE '' END AS 表名,       C ...

  6. sql2005 将一列的多行内容拼接成一行

    select ID, Name = ( stuff ( ( select ',' + Name from Table_1 where ID = a.ID for xml path('') ),1,1, ...

  7. LCIS POJ 2172 Greatest Common Increasing Subsequence

    题目传送门 题意:LCIS(Longest Common Increasing Subsequence) 最长公共上升子序列 分析:a[i] != b[j]: dp[i][j] = dp[i-1][j ...

  8. UVa11324 The Largest Clique(强连通分量+缩点+记忆化搜索)

    题目给一张有向图G,要在其传递闭包T(G)上删除若干点,使得留下来的所有点具有单连通性,问最多能留下几个点. 其实这道题在T(G)上的连通性等同于在G上的连通性,所以考虑G就行了. 那么问题就简单了, ...

  9. HDU1796 How many integers can you find(容斥原理)

    题目给一个数字集合,问有多少个小于n的正整数能被集合里至少一个元素整除. 当然是容斥原理来计数了,计算1个元素组合的有几个减去2个元素组合的LCM有几个加上3个元素组合的LCM有几个.注意是LCM. ...

  10. Square Coins[HDU1398]

    Square Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...