使用条件

天下没有免费的午餐,在我使用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. Groovy安装配置

    一.介绍 Groovy是可以运行在 Java 平台上进行动态语言,使用方式基本与使用 Java 的方式相同,Groovy和java基本是可以实现无缝整合,它有以下一些特性: 是一个基于Java虚拟机的 ...

  2. Spark编译安装和运行

    一.环境说明 Mac OSX Java 1.7.0_71 Spark 二.编译安装 tar -zxvf spark-.tgz cd spark- ./sbt/sbt assembly ps:如果之前执 ...

  3. PHP 过滤 及 字符转换 函数

    PHP过滤html标签的内部函数. php过滤html的函数: strip_tags(string) 这样就可以过滤掉所有的html标签了. 如果想过滤掉除了<img src="&qu ...

  4. PHP GBK UTF8互转

    function gbk_to_utf8($str){     return mb_convert_encoding($str, 'utf-8', 'gbk'); }   function utf8_ ...

  5. Android常用布局

    FrameLayout(框架布局):从屏幕的左上角开始显示对象,一个覆盖一个,主要用于选项卡视图和图像切换器.# 所有的组件都放在屏幕的左上角,并且以层叠进行显示. LinearLayout(线性布局 ...

  6. java_final关键字的使用

    final : 最终.作为一个修饰符,1,可以修饰类,函数,变量.2,被final修饰的类不可以被继承.为了避免被继承,被子类复写功能.3,被final修饰的方法不可以被复写.4,被final修饰的变 ...

  7. MS SQL SERVER 2000 常用 Tran-SQL 语句

    一.创建数据库:create database mydb-创建数据库mydbon primary-在primary文件组中( name = mydb_data1,filename = 'd:\sql ...

  8. 【HTML5】Server-Sent服务器发送事件

    Server-Sent 事件 - 单向消息传递 Server-Sent 事件指的是网页自动获取来自服务器的更新. 以前也可能做到这一点,前提是网页不得不询问是否有可用的更新.通过服务器发送事件,更新能 ...

  9. 简单几何(极角排序) POJ 2007 Scrambled Polygon

    题目传送门 题意:裸的对原点的极角排序,凸包貌似不行. /************************************************ * Author :Running_Time ...

  10. 剪花布条[HDU2087]

    剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...