unity3d start 为什么切换场景相当于退出 start函数

Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享 - One thing I know,that is I know nothing.(Socrates Greek)
- ITeye博客
博客分类:
Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
By D.S.Qiu
尊重他人的劳动,支持原创,转载请注明出处:http.
熟悉Unity的developer都知道在Unity中的线程不能使用Unity的对象,但可以使用Unity的值类型变量,如Vector3等。这样就使得线程在Unity中显的很鸡肋和蹩脚,因为很多函数很都是UnityEngine类或函数的调用的,对于哪些是可以在多线程使用,风雨冲进行了如下总结:
0. 变量(都能指向相同的内存地址)都是共享的
1. 不是UnityEngine的API能在分线程运行
2. UnityEngine定义的基本结构(int,float,Struct定义的数据类型)可以在分线程计算,如 Vector3(Struct)可以 , 但Texture2d(class,根父类为Object)不可以。
3. UnityEngine定义的基本类型的函数可以在分线程运行,如
int i = 99;
print (i.ToString());
Vector3 x = new Vector3(0,0,9);
x.Normalize();
类的函数不能在分线程运行
实际是get_name函数,分线程报错误:get_name
can only be called from the main thread.
Texture2D tt = new Texture2D(10,10);
实际会调用UnityEngine里的Internal_Create,分线程报错误:Internal_Create
can only be called from the main thread.
其他transform.position,Texture.Apply()等等都不能在分线程里运行。
结论: 分线程可以做 基本类型的计算, 以及非Unity(包括.Net及SDK)的API。
D.S.Qiu觉得Unity做了这个限制,主要是Unity的函数执行机制是帧序列调用,甚至连Unity的协程Coroutine的执行机制都是确定的,如果可以使用多线程访问UnityEngine的对象和api就得考虑同步问题了,也就是说Unity其实根本没有多线程的机制,协程只是达到一个延时或者是当指定条件满足是才继续执行的机制。
我们的项目目前还有没有比较耗时的计算,所以还没有看到Thread的使用。本来一直没有太考虑着方面的事情,直到在看到Loom这个类,叹为观止呀。直接贴出人家的介绍(没必要翻译了):
Threads on a Loom
Our class is called Loom.
Loom lets you easily run code on another thread and have that other thread run code on the main game thread when it needs to.
There are only two functions to worry about:
RunAsync(Action) which runs a set of statements on another thread
QueueOnMainThread(Action, [optional] float time) - which runs a set of statements on the main thread (with an optional delay).
You access Loom using Loom.Current - it deals with creating an invisible game object to interact with the games main thread.
我们只需要关系两个函数:RunAsync(Action)和QueueOnMainThread(Action, [optional] float time) 就可以轻松实现一个函数的两段代码在C#线程和Unity的主线程中交叉运行。原理也很简单:用线程池去运行RunAsync(Action)的函数,在Update中运行QueueOnMainThread(Acition, [optional] float time)传入的函数。
直接贴出源码,供拜读:
using UnityE
using System.C
using System.Collections.G
using System.T
using System.L
public class Loom : MonoBehaviour
public static int maxThreads = 8;
static int numT
private static Loom _
private int _
public static Loom Current
Initialize();
void Awake()
_current =
initialized =
static void Initialize()
if (!initialized)
if(!Application.isPlaying)
initialized =
var g = new GameObject("Loom");
_current = g.AddComponent&Loom&();
private List&Action& _actions = new List&Action&();
public struct DelayedQueueItem
private List&DelayedQueueItem& _delayed = new
List&DelayedQueueItem&();
List&DelayedQueueItem& _currentDelayed = new List&DelayedQueueItem&();
public static void QueueOnMainThread(Action action)
QueueOnMainThread( action, 0f);
public static void QueueOnMainThread(Action action, float time)
if(time != 0)
lock(Current._delayed)
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action});
lock (Current._actions)
Current._actions.Add(action);
public static Thread RunAsync(Action a)
Initialize();
while(numThreads &= maxThreads)
Thread.Sleep(1);
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
private static void RunAction(object action)
((Action)action)();
Interlocked.Decrement(ref numThreads);
void OnDisable()
if (_current == this)
_current =
// Use this for initialization
void Start()
List&Action& _currentActions = new List&Action&();
// Update is called once per frame
void Update()
lock (_actions)
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
foreach(var a in _currentActions)
lock(_delayed)
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d=&d.time &= Time.time));
foreach(var item in _currentDelayed)
_delayed.Remove(item);
foreach(var delayed in _currentDelayed)
delayed.action();
怎么实现一个函数内使用多线程计算又保持函数体内代码的顺序执行,印象中使用多线程就是要摆脱代码块的顺序执行,但这里是把原本一个函数分拆成为两部分:一部分在C#线程中使用,另一部还是得在Unity的MainThread中使用,怎么解决呢,还得看例子:
//Scale a mesh on a second thread
void ScaleMesh(Mesh mesh, float scale)
//Get the vertices of a mesh
var vertices = mesh.
//Run the action on a new thread
Loom.RunAsync(()=&{
//Loop through the vertices
for(var i = 0; i & vertices.L i++)
//Scale the vertex
vertices[i] = vertices[i] *
//Run some code on the main thread
//to update the mesh
Loom.QueueOnMainThread(()=&{
//Set the vertices
mesh.vertices =
//Recalculate the bounds
mesh.RecalculateBounds();
这个例子是对Mesh的顶点进行放缩,同时也是一个使用闭包(closure)和lambda表达式的一个很好例子。看完例子,是不是很有把项目中一些耗时的函数给拆分出来,D.S.Qiu就想用这个方法来改进下NGUI的底层机制(看下性能不能改进)。
D.S.Qiu在编程技术掌握还是一个菜鸟,Thread还是停留在实现Runable接口或继承Thread的一个水平上,对多线程编程的认识还只是九牛一毛。本来我以为Loom的实现会比较复杂,当我发现只有100多行的代码是大为惊叹,这也得益于现在语言的改进,至少从语言使用的便利性上还是有很大的进步的。
有了Loom这个工具类,在很多涉及UnityEngine对象的耗时计算还是可以得到一个解决方法的:
如在场景中用A*算法进行大量的数据计算
变形网格中操作大量的顶点
持续的要运行上传数据到服务器
二维码识别等图像处理
Loom简单而又巧妙,佩服Loom的作者。
如果您对D.S.Qiu有任何建议或意见可以在文章后面评论,或者发邮件(gd.s.)交流,您的鼓励和支持是我前进的动力,希望能有更多更好的分享。
转载请在文首注明出处:
更多精彩请关注D.S.Qiu的和微博(ID:静水逐风)
①UnityGems:
下载次数: 99
浏览 29154
sxmad 写道这个,当切换场景时就不可以了。比如我后台一个Socket,用多线程异步处理的。返回消息肯定不是在主线程上,那QueueOnMainThread调用时没问题。但是如果切换场景这个就会报错,我的socket是单例。Loom.cs 是要挂到场景里面的,只要不销毁loom挂的物体,应该是没有问题的。&&
这个,当切换场景时就不可以了。比如我后台一个Socket,用多线程异步处理的。返回消息肯定不是在主线程上,那QueueOnMainThread调用时没问题。但是如果切换场景这个就会报错,我的socket是单例。Loom.cs 是要挂到场景里面的,只要不销毁loom挂的物体,应该是没有问题的。
QueueOnMainThread(Action action, float time)& 这个函数中当time!=0时,会用到Time.time,这个貌似是不允许的吧,楼主有测过吗?QueueOnMainThread 这是在Unity的主线程上运行的,所以是没有问题的;RunAsync 这个才是在其他线程上运行的。
浏览: 898047 次
来自: 广州
浏览量:150038
[quo[color=red]te][/color]
博主,你好,一直都有个问题没有搞明白,就是 2.x的版本是通过 ...
感谢楼主!
感谢!从你的博客里学到了很多
学习了~,话说现在的版本custom还真的变委托了Unity切换场景淡入淡出效果 - q的博客 - CSDN博客
Unity切换场景淡入淡出效果
在制作游戏时,我们在切换场景时经常需要增加一个淡入淡出的效果。这里,我们利用Unity自带的动画系统制作一个场景的淡入淡出的效果。步骤如下:
1.在游戏中新建一个游戏对象,给游戏添加一个GUITexture组件,并设置好相关的参数后,制作成prefab。如下图:
![这里写图片描述](http://img.blog.csdn.net/47320?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcTU2ODM2MDQ0Nw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
2.给这个prefab制作1个动作文件Animation,这个动作一会持续2秒,动画的持续过程会改变此prefab中GUITexture里的Color.a的值。在第0帧处,color.a的值为0,在动画的第1秒处color.a的值为0.5,在动画第2秒处color.a的值又变化为0.此时就完成了一个alpha值的渐变动画。
3.加控制代码。
using UnityE
using System.C
using UnityEngine.SceneM
public class LoadLevelFadeEffect : MonoBehaviour {
[HideInInspector]
public int levelI
void Awake () {
DontDestroyOnLoad(this.gameObject);
void Update () {
注:这个方法在unity引擎中的动画系统中利用事件调用。下面的DestroySelf同样在Unity中调用
public void Test()
SceneManager.LoadScene(levelIndex);
public void DestroySelf()
Destroy(this.gameObject);
4.将上面的脚本添加给我们制作的prefab中,并在该prefab的动画的第1秒处的关键帧上添加事件,执行Test()函数。在动画播放完毕后的关键帧上再添加事件,执行DestroySelf()函数。表示销毁自身。
至此,整个切换场景的淡入淡出效果实现完毕。但是这样做有几点是需要注意的:
1、在需要切换场景的时候只需要生成这个Prefab即可,生成代码如下:
//在场景中生成该Prefab
GameObject go = UIManager.Instance.LoadGameObject("Others/Fade")
GUITexture gt = go.GetComponent&GUITexture&()
//保证GUITexture可以覆盖整个游戏屏幕
gt.pixelInset = new Rect(-100, -100, Screen.width, Screen.height)
2.这个淡入淡出只针对游戏内的场景有效,无法将游戏中的UI也淡入淡出。
3.这样做会让游戏中的很多代码在工程外调用,由引擎调用,因此后期在维护时会增加成本。因此必须在调用代码时做好注释,表明这一段代码是由引擎调用的。
我的热门文章
即使是一小步也想与你分享 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
unity常见面试题目
下载积分:3000
内容提示:unity常见面试题目
文档格式:DOCX|
浏览次数:18|
上传日期: 20:58:16|
文档星级:
全文阅读已结束,如果下载本文需要使用
 3000 积分
下载此文档
该用户还上传了这些文档
unity常见面试题目
官方公共微信鏌ョ湅: 12957|鍥炲?: 17
鎺у埗鍒囨崲鍦烘櫙娣″叆娣″嚭鐨勬暀绋}

我要回帖

更多关于 unity3d start 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信