使用条件

天下没有免费的午餐,在我使用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. php 三元运算符使用说明和写法

    PHP三元运算的2种写法代码实例 首先,我们现在看一个简单的例子: 代码如下: <?php //写法一: $a = 2; ($a == 1) ? $test = "我们" : ...

  2. try-catch 示例

    package unit5; import java.util.Scanner; import javax.print.CancelablePrintJob; import javax.sound.m ...

  3. 实现textbox文本页面改变触发textchanged事件,代码里修改不触发

    今天弄控件遇到一个问题,就是TextChanged,如果在代码里或在页面修改修改text值,就会触发事情,但如果在textchanged里修改text,它会不会触发呢,不会,我调试跟踪,并没发现它会重 ...

  4. Maven中多模块的编译顺序

    在多模块的工程中,如果模块之间存在依赖关系,那模块的编译必须要有顺序的要求.例如:P(parent)中包含A模块和B模块,且A模块依赖于B模块,那么在P中的pom,xml中需申明为: <modu ...

  5. ConversionPattern 解析

    Sample <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] %X{auth} - Line ...

  6. POJ2817 WordStack(状压DP)

    题目给几个字符串,可以给它们添加前导空格,然后排列,计算每一个字符串和前一个字符串相同非空格字符相等的个数,求可能的最大个数. 状态DP: d[S][i][j]表示已经用的字符串集合S且排列的最后一个 ...

  7. BZOJ3790 : 神奇项链

    Manacher求出所有极长回文子串后,得到一堆线段,转化成线段覆盖问题 预处理出g[i]表示左端点不超过i的右端点的最大值 贪心地线段覆盖即可 时间复杂度$O(n)$ #include<cst ...

  8. ERROR 2013 (HY000): Lost connection to MySQL server at 'waiting for initial communication packet', system error: 2

    ERROR (HY000): Lost connection to MySQL server at 'waiting for initial communication packet', system ...

  9. 循环repeater中的每一列,并计算数据和

    <asp:Repeater ID="rpt" runat="server"> <ItemTemplate> <td>< ...

  10. juniper-cisco-HP上网设置

    网络拓扑: 路由模式: 第一步.配置防火墙的接口地址 编辑外网接口: 配置内网口(原理同上)(interface mode:nat) 第二步.配置防火墙的路由 第三步.配置防火墙安全策略 Cisco交 ...