原 文:http://cache.baiducontent.com /c?m=9d78d513d9841df41ea6837e7c01a6660e20f6743da7c76508c3e34f84152d563763f7fc677c1f5e95833e7000dc5441afb57365377471ebcb96d51f9cac925f7ed578292d42d01e418f04fc8b007e907ec71bf4af1fe5b1f73290b9d2a485120c94&p=9357d40586cc41ac5dabdb2d021482&newp=c07bc64ad4934eaf5be8d22554648f231610db2151d0d216&user=baidu&fm=sc&query=UNITY+%C2%FD%BE%B5%CD%B7&qid=eca8a31a0000a1fa&p1=1

操作transform.localPosition的时候请小心

移动GameObject是非常平常的一件事情,一下代码看起来很简单:

transform.localPosition += new Vector3 ( 10.0f * Time.deltaTime, 0.0f, 0.0f );

但是小心了,假设上面这个GameObject有一个parent, 并且这个parent GameObject的localScale是(2.0f,2.0f,2.0f)。你的GameObject将会移动20.0个单位/秒。因为该 GameObject的world position等于:
Vector3 offset = new Vector3( my.localPosition.x * parent.lossyScale.x,
my.localPosition.y * parent.lossyScale.y,
my.localPosition.z * parent.lossyScale.z );
Vector3 worldPosition = parent.position + parent.rotation * offset;
换句话说,上面这种直接操作localPosition的方式是在没有考虑scale计算的时候进行的,为了解决这个问题,transform.Translate ( 10.0f * Time.deltaTime, 0.0f, 0.0f );

曝出在Inspector的变量同样的也能被Animation View Editor所使用

有时候我们会想用Unity3D自身的component,还可以操作我们自定义的MonoBehavior中的各个Property。所以加入 你有个float值需要用曲线操作,你可以简单的将它曝出到成可以serialize的类型,如:

public float foobar = 1.0f;

这样,这个变量不仅会在Inspector中出现,还可以在animation view中进行操作,生成AnimationClip供我们通过AnimationComponent调用。

范例:

public class TestCurve : MonoBehaviour {
public float foobar = 0.0f;
 
IEnumerator Start () {
yield return new WaitForSeconds (2.0f);
animation.Play("foobar_op");
InvokeRepeating ( "LogFoobar", 0.0f, 0.2f );
yield return new WaitForSeconds (animation["foobar_op"].length);
CancelInvoke ("LogFoobar");
}
 
void LogFoobar () {
Debug.Log("foobar = " + foobar);
}
}

GetComopnent<T> 可以取父类类型

Unity3D 允许我们对MonoBehavior做派生,所以你可能有以下代码:

public class foo : MonoBehaviour {
...
}
 
public class bar : foo {
...
}

假设我们现在有A,B两个GameObject, A包含foo, B包含bar, 当我们写

foo comp1 = A.GetComponent<foo>();
bar comp2 = B.GetComponent<bar>();

可以看到comp1, comp2都得到了应得的Component。那如果我们对B的操作改成:

foo comp2 = B.GetComponent<foo>();

答案是comp2还是会返回bar Component并且转换为foo类型。你同样可以用向下转换得到有效变量:

bar comp2_bar = comp2 as bar;

合理利用GetComponent<base_type>()可以让我们设计Component的时候耦合性更低。

Invoke, yield 等函数会受 Time.timeScale 影响

Unity3D的使用者,会误导性的认为Time.timeScale同样可以适用于游戏中的暂停(Pause)和开始(Resume)。所以很多人有习惯写:

Time.timeScale = 0.0f

对 于游戏的暂停/开始,是游戏系统设计的一部分,而Time.timeScale不不是用于这个部分的操作。正确的做法应该是搜集需要暂停的脚本或 GameObject,通过设置他们的enabled = false 来停止他们的脚本活动或者通过特定函数来设置这些物件暂停时需要关闭那些操作。

Time.timeScale 更多的是用于游戏中Unity3D的许多时间相关的函数都和 timeScale挂钩,而timeScale = 0.0f将使这些函数或动画处于完全停止的状态,这也是为什么它不适合做暂停操作的主要原因。

这里列出受timeScale影响的一些主要函数和Component:

  • MonoBehaviour.Invoke(…)
  • MonoBehaviour.InvokeRepeating(…)
  • yield WaitForSeconds(…)
  • GameObject.Destroy(…)
  • Animation Component
  • Time.time, Time.deltaTime

Coroutine 和 IEnumerator的关系

初写Unity3D C#脚本的时候,我们经常会犯的错误是调用Coroutine函数忘记使用StartCoroutine的方式。如:

TestCoroutine.cs

IEnumerator CoLog () {
yield return new WaitForSeconds (2.0f);
Debug.Log("hello foobar");
}

当我们用以下代码去调用上述函数:

TestCoroutine  testCo = GetComponent<TestCoroutine>();
testCo.CoLog ();
testCo.StartCoroutine ( "CoLog" );

那么testCo.CoLog()的调用将不会起任何作用。

StartCoroutine, InvokeRepeating 和其调用者关联

通常我们只在一份GameObject中去调用StartCoroutine或者InvokeRepeating, 我们写:

StartCoroutine ( Foobar() );
InvokeRepeating ( "Foobar", 0.0f, 0.1f );

所以如果这个GameObject被disable或者destroy了,这些coroutine和invokes将会被取消。就好比我们手动调用:

StopAllCoroutines ();
CancelInvoke ();

这看上去很美妙,对于AI来说,这就像告诉一个NPC你已经死了,你自己的那些小动作就都听下来吧。

但 是注意了,假如这样的代码用在了一个Manager类型的控制AI上,他有可能去控制其他的AI, 也有可能通过Invoke, Coroutine去做一些微线程的操作,这个时候就要明确StartCoroutine或者InvokeRepeating的调用者的设计。讨论之前我 们先要理解,StartCoroutine或InvokeRepeating的调用会在该MonoBehavior中开启一份Thread State, 并将需要操作的函数,变量以及计时器放入这份Stack中通过并在引擎每帧Update的最后,Renderer渲染之前统一做处理。所以如果这个 MonoBehavior被Destroy了,那么这份Thread State也就随之消失,那么所有他存储的调用也就失效了。

如果有两 份GameObject A和B, 他们互相知道对方,假如A中通过StartCoroutine或InvokeRepeating去调用B的函数从而控制B,这个时候Thread State是存放在A里,当A被disable或者destroy了,这些可能需要一段时间的控制函数也就失效了,这个时候B明明还没死,也不会动了。更 好的做法是让在A的函数中通过B.StartCoroutine ( … ) 让这份Thread State存放于B中。

// class TestCortouine
public class TestCoroutine : MonoBehaviour {
public IEnumerator CoLog ( string _name ) {
Debug.Log(_name + " hello foobar 01");
yield return new WaitForSeconds (2.0f);
Debug.Log(_name + " hello foobar 02");
}
}
 
// component attached on GameObject A
public class A: MonoBehaviour {
public GameObject B;
 
void Start () {
TestCoroutine compB = B.GetComponent<TestCoroutine>();
 
// GOOD, thread state in B
// same as: compB.StartCoroutine ( "CoLog", "B" );
compB.StartCoroutine ( compB.CoLog("B") );
 
// BAD, thread state in A
StartCoroutine ( compB.CoLog("A") );
 
Debug.Log("Bye bye A, we'll miss you");
Destroy(gameObject); // T_T I don't want to die...
}
}

以上代码,得到的结果将会是:

B hello foobar 01
A hello foobar 01
Bye bye A, we'll miss you
B hello foobar 02

如不需要Start, Update, LateUpdate函数,请去掉他们

当你的脚本里没有任何Start, Update, LateUpdate函数的时候,Unity3D将不会将它们加入到他的Update List中,有利于脚本整体效率的提升。

我们可以从这两个脚本中看到区别:

Update_01.cs

public class Update_01 : MonoBehaviour {
void Start () {}
void Update () {}
}

Update_02.cs

public class Update_02 : MonoBehaviour {
}

【转】使用unity3d需要注意到细节的更多相关文章

  1. unity3D总结的一些细节,不注意有些要折腾非常多天!

    1. 注意!!ps保存图片时,若保存为ps格式,若关闭最大兼容将会导致unity导入失败!(n天) 2.switch 推断NGUI popuplist传来的value字符串时一定要trim一下去掉空格 ...

  2. Unity3D细节整理:AssetBundle对应的各种格式文件的类型

    我们打包AssetBundle后,Unity3D会根据文件的后缀名将文件转换为特定的类型对象存储起来,我们后期获取时需要根据这些类型取出打包的数据,这里记录下不同后缀文件打包后的类型. 文本格式 支持 ...

  3. (转)[Unity3D]UI方案及制作细节(NGUI/EZGUI/原生UI系统) 内附unused-assets清除实例

    转载请留下本文原始链接,谢谢.本文会不定期更新维护,最近更新于2013.09.17.   http://blog.sina.com.cn/s/blog_5b6cb9500101bplv.html   ...

  4. [Unity3D]UI方案及制作细节(NGUI/EZGUI/原生UI系统)

    转载请留下本文原始链接,谢谢.本文会不定期更新维护,最近更新于2013.09.17.   http://blog.sina.com.cn/s/blog_5b6cb9500101bplv.html   ...

  5. Thinking in Unity3D:基于物理着色(PBS)的材质系统

    关于<Thinking in Unity3D> 笔者在研究和使用Unity3D的过程中,获得了一些Unity3D方面的信息,同时也感叹Unity3D设计之精妙.不得不说,笔者最近几年的引擎 ...

  6. Thinking in Unity3D:材质系统概览

    关于<Thinking in Unity3D> 笔者在研究和使用Unity3D的过程中,获得了一些Unity3D方面的信息,同时也感叹Unity3D设计之精妙.不得不说,笔者最近几年的引擎 ...

  7. 【译】Unity3D Shader 新手教程(2/6) —— 积雪Shader

    本文为翻译,附上原文链接. 转载请注明出处--polobymulberry-博客园. 如果你是一个shader编程的新手,并且你想学到下面这些酷炫的技术,我觉得你可以看看这篇教程: 实现一个积雪效果的 ...

  8. 【译】Unity3D Shader 新手教程(1/6)

    本文为翻译,附上原文链接. 转载请注明出处--polobymulberry-博客园. 刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D ...

  9. Unity3d连接SQL Server数据库出现SocketException: 使用了与请求的协议不兼容的地址错误

    这两天,同学问我Unity3d连接SQL Server的问题,当时我只是简单的说:“应该一样吧,就是那简单的几句啊”.之后他让我试了下,我才发现有问题了.故此写下一篇博客,要牢记这件事的教训,操作数据 ...

随机推荐

  1. 在MessageBox的Show方法中如何无限使用参数值?

    今天发现在show方法中不能使用花括号的方式使用多个可变参数,经过查询得出结果.在show方法中是不存在花括号的方式使用参数的.在Console.WriteLine中是存在的,如下: 那么在show方 ...

  2. ubuntu 13.04 xrdp 远程桌面连接问题[转载]

    本人ubuntu12.04,遇到了同样的问题,用一下方法解决了,mark一下. ubuntu 13.04 xrdp 远程桌面连接问题. win 7 远程桌面连接 ubuntu desktop 有几种办 ...

  3. ORACLE如何停止一个JOB

    ORACLE如何停止一个JOB1 相关表.视图2 问题描述为同事解决一个因为网络连接情况不佳时,执行一个超长时间的SQL插入操作.既然网络状况不好,就选择了使用一次性使用JOB来完成该插入操作.在JO ...

  4. Angularjs总结(七) 路由及请求服务等

    define(['angular'], function (ng) { 'use strict'; var app = ng.module('index-module', ['ngCookies', ...

  5. easyui实现datagrid数字排序问题

    我们在使用easyui对列进行自动排序的时候(即顺序倒序),正常情况下是通过设置field中的sortable:true属性来控制是否可以排序.但是我们会发现一个有趣的问题,在对数字进行排序的时候,这 ...

  6. ZOJ 3725 Painting Storages(DP+排列组合)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5048 Sample Input 4 3 Sample Output ...

  7. 读书笔记之 - javascript 设计模式 - 装饰者模式

    本章讨论的是一种为对象增添特性的技术,它并不使用创建新子类这种手段. 装饰者模式可以透明地把对象包装在具有同样接口的另一对象之中,这样一来,你可以给一些方法添加一些行为,然后将方法调用传递给原始对象. ...

  8. jQuery EasyUI 1.4.4 Combobox无法检索中文输入的问题

    在项目里使用了EasyUI的Combobox,当ComboBox的item是英文时,都能正常检索出对应项,但是如果使用中文输入法输入几个字母然后通过按shift键输入时,奇怪的事情发生了,combob ...

  9. 深入了解jquery中的键盘事件

    很多时候,我们需要获取用户的键盘事件,下面就一起来看看jquery是如何操作键盘事件的. 一.首先需要知道的是: 1.keydown() keydown事件会在键盘按下时触发. 2.keyup() k ...

  10. C#.Net网页加载等待效果漂亮并且简单

    最近网页加载数据比较多,点击后给用户就是白板很不友好,想了很久找了些资料,在网页加载中显示等待画面给客户,页面加载完成自动隐藏等待效果. 在网页后台cs代码:    protected void Pa ...