Unity3d笔记
- 当变量重命名后,已序列化保存的值会丢失,如果希望继续保留其数值,可使用FormerlySerializedAs,如下代码所示:
[UnityEngine.Serialization.FormerlySerializedAs("hp")]
public int newHp = ; Unity有个隐藏的彩蛋:void Main(){},它的调用在Awake() OnEnable()之后Start()之前。
- unity对文件名以点开头的文件视而不见
- 当用enum枚举值作为Dictionary的key,在访问字典时则会产生GC,应该是内部在对enum值进行查找时产生的,而其他如int等值类型作为key则不会有GC,建议在需要用到enum作为key时先强转为int再将int作为key。
C#属性(Property)想要显示在Inspector上且set get能被正常执行:https://github.com/LMNRY/SetProperty
[SerializeField, SetProperty ("Number")]
private float number;
public float Number
{
get
{
return number;
}
private set
{
number = Mathf.Clamp01(value);
}
}- 当你在Unity中编辑场景,突然死机时,可以在项目文件目录中找到Temp文件夹,双击文件夹,找到_Backupscenes文件夹,把后缀为.backup的文件后缀改为.unity,然后拖进Unity的Project界面里面,这样就可以还原死机前场景最后情况。
- 通过Debug.Log获取执行此语句物件:在脚本的Debug.Log语句中加入gameObject,即Debug.Log("Test", gameObject); 脚本运行时点击Console界面中的输出语句,就能在Hierarchy界面中看到哪个物件执行了这个脚本。
- Debug.Break()可以在任何地方暂停游戏,调试小技巧。
- 性能调试时将你想观察的那部分代码放入
Profiler.BeginSample ("aaa");
Profiler.EndSample ();
代码之间就可指定查看该部分代码的开销。 - 当修改了Prefab并想将该改动应用到所有的物体上:
若是在Project视图中直接修改的该prefab则一定要记得执行File->Save Project,unity并不会将改动直接保存到磁盘。
若是在Hierarchy视图中修改的该prefab,必须点击Apply,若同时还需要保存场景时,则尽量记住先执行Save Project操作再执行Save Scene,不然你场景中的prefab很可能跟它本身的prefab永久丢失关联。 - 屏幕坐标与鼠标位置:
屏幕坐标系以左上角为原点(0, 0),右下角为(Screen.Width, Screen.Height)。
Input.mousePosition鼠标位置以屏幕左下角为原点(0, 0),屏幕右上角为(Screen.Width, Screen.Height)。 - Awake会在物体初始化之后被调用,无论脚本本身是否被启用(是否被禁用,在Inspector视图上脚本前面的复选框是否被勾上,实际上该复选框只有脚本在存在Start(), Update(), FixedUpdate(), and OnGUI()至少一个时才会显示);OnEnable、Start则是在脚本被启动的情况下被调用,其中OnEnable会在脚本或者物体每次被重新启用时都会被再次调用。
- 父物体与子物体Awake、OnEnable、Start函数执行顺序:
首先同一脚本中该三个函数的执行顺序是:Awake->OnEnable->Start,然后:
* 若父子物体都是在场景中已经存在的:子物体的Awake、OnEnable全执行完毕后才会执行到父物体的Awake、OnEnable;当所有父与子物体的Awake与OnEnable全都执行完毕后才开始执行子物体的Start再执行父物体的Start。
* 若父子物体先不存在于场景中,而是通过Instantiate()动态产生的:则父与子的调用顺序与上面相反,父物体的Awake、OnEnable全执行完毕后才会执行到子物体的Awake、OnEnable;当所有父与子物体的Awake与OnEnable全都执行完毕后才开始执行父物体的Start再执行子物体的Start。
该结论是实测多次观察出来的,但unity官方没未明确说明Awake OnEnable Start存在固定顺序,故不排除有时不表现为以上所说顺序而是随机顺序,不应该依赖这些执行顺序而应尽量避免初始化的先后的要求。 - 调用Instantiate()方法动态添加GameObject时,新GameObject的Awake、OnEnable都调用结束后Instantiate()才会返回。
- 一般在新建类时会产生空的Update函数。如果代码不需要用到该函数,应该该函数进行删除。另外,尽量不要在Update函数内执行Find、FindObjectOfType、FindGameObjectsWithTag这些寻找物体的函数,面应该尽量在Start或Awake函数中执行。
- 每个脚本中实现Update()回调函数,这是一般做法,更优的做法是只有一个Manger脚本含有Update函数,遍历(Array性能优于List)调用其他脚本的OnUpdate(或其他命名)函数。Unity要维护调用的Update函数越多开销越大,详细测试见:https://blogs.unity3d.com/cn/2015/12/23/1k-update-calls/ 从评论中了解到,unity正在开发全新的一套消息机制,喜闻乐见。
另一方面,有人想到用Coroutines协程代替Update,测试证明Update比协程要快5倍,协程内部至少要处理move next和current两个调用 - 引用一个游戏对象的逻辑,可以在最开始的地方定义它。例如:
private Transform myTransform;
private Rigidbody myRigidbody;
void Start()
{
myTransform = transform;
myRigidbody = rigidbody;
} - 尽量减少使用临时变量,特别是在Update等实时调用的函数中。
- 捕捉Android返回与Home键:
//返回键
if(Application.platform == Runtimeplatform.Android
&& Input.GetKeyDown(KeyCode.Escape))
{
//...
} //Home键
if(Application.platform == Runtimeplatform.Android
&& Input.GetKeyDown(KeyCode.Home))
{
//...
} - 直接打开app store,同理根据链接不同也可打开Mail或浏览器等:
void OnRateButtonClick()
{
#if UNITY_ANDROID
Application.OpenURL("market://details?id=YOUR_APP_ID");
#elif UNITY_IPHONE
Application.OpenURL("itms-apps://itunes.apple.com/app/idYOUR_APP_ID");
#endif
} - 获取Android手机分辨率:
private float androidDensity = 1.0f;
void GetDensity()
{
//#if UNITY_ANDROID
if (Application.platform == RuntimePlatform.Android)
{
AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = player.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject wm = activity.Call<AndroidJavaObject>("getWindowManager");
if (wm != null)
{
AndroidJavaObject display = wm.Call<AndroidJavaObject>("getDefaultDisplay");
if (display != null)
{
AndroidJavaObject displayMetrics = new AndroidJavaObject("android.util.DisplayMetrics");
display.Call("getMetrics", displayMetrics);
androidDensity = displayMetrics.Get<float>("density");
}
}
}
//#endif
} - Time.timeScale设置为0时Update()仍然会继续执行,FixedUpdate()会停止调用,注意:此时协程WaitForSeconds和Invoke调用都会停止!
Time.timeScale会影响Time.deltaTime和Time.time,不会影响Time.realtimeSinceStartup, Time.unscaledDeltaTime, Time.unscaledTime;
Time.time/timeScale = unscaledTime,
Time.deltaTime / timeScale = unscaledDeltaTime;
在Update中使用Time.deltaTime,就可以使用timeScale改变运动速率
在Update中使用Time.unscaledDeltaTime,timeScale就不会影响运动速率
在后台运行(暂停)和卡顿(如加载大场景时进入场景那一刻)期间,Time.deltaTime和Time.time不会继续计时,Time.realtimeSinceStartup, Time.unscaledDeltaTime, Time.unscaledTime会继续计时,此时Time.realtimeSinceStartup更精准会在游戏恢复时立马得到正常时间,Time.unscaledDeltaTime, Time.unscaledTime则可能要等好几帧之后才会得到正常的时间(即暂停期间经过的时间过几帧才加上来)。
当手机调整了设备时间后Time.realtimeSinceStartup也同样会受影响。 - 获取当前animator播放的state时长:anim.GetCurrentAnimatorStateInfo(0).length。然而该函数需要等动画播放后才能正确获取,即使在协程中等待一帧再调用该函数得到的时间也可能是错误的,应该调用anim.Update(0)后再去获取:
m_animator.Play(animName, -1, 0);
m_animator.Update(0);
int length = m_animator.GetCurrentAnimatorStateInfo(0).length;若是在5.x版本中则可以通过指定的状态名字获取其时长:anim.runtimeAnimatorController.animationClips.First (x => x.name == "AnimationName").length;
- Animator.Play(string stateName, int layer = -1, float normalizedTime = float.NegativeInfinity):
layer:经测试0和-1是一样的。
normalizedTime:
0-1为从开始到结束之间某时间点开始播放;
负无穷时如果play的是当前状态则继续播放当前状态不做任何改变,否则跳到从头开始播目标状态;
为负数时,时间会保持增长,从负数开始至0期间为暂停的,从0之后开始正常播放;
为超过1的数时则会以小数部分的时间(等同于0-1的参数)点开始播放,忽略整数部分(实际上整数部分代表重复播放了多少遍)。 - 简单实现animator反方向播放动画:animator.speed=-1;
- 发ios包的注意点:
在用unity4.6发iOS包的时候,发现导出的xcode工程出错;其实原因是xcode太新了,为7.2, 而unity还只支持7.1,而两者兼容性不好,导致了很多error的出现。所以,发ios包时要注意xcode的版本和unity是否相符,不然会花太多的时间在上面的,切记!
图形化调试:
Unity中图形化调试主要4种
Debug.Draw
Gizmos.Draw
Graphic.DrawMesh
GL
只需在Scene窗口显示的调试图像
一直显示的 OnDrawGizmos + Gizmos.Draw
选中显示的 OnDrawGizmosSelected + Gizmos.Draw
脚本控制的 Update + Debug.Draw
需要在实际设备屏幕显示的调试图像
Update+Graphic.DrawMesh
OnRenderObject+GLGraphic.DrawMesh和Debug.Draw 调用一致,都是在Update系里
Graphic.DrawMesh和GL 显示类似,都在各个窗口显示,并且可以设置材质。
详见:http://blog.sina.com.cn/s/blog_471132920101gxzf.htmlUnity提供了命令行的接口,可以通过Shell调用。进而可以一键打包,一键打AssetBundle,接着上传SVN等操作。文档:http://docs.unity3d.com/Manual/CommandLineArguments.html
- 调试执行时间:
Stopwatch sp = new Stopwatch ();
sp.Start ();
DoSomething ();
sp.Stop ();
Debug.Log (string.Format ("Elapsed:{0} ms", (float)sp.ElapsedTicks/ Stopwatch.Frequency * 1000f)); - 写Unity编辑器控件时如何获得Unity内置的图标:Texture tex = (Texture)EditorGUIUtility.Load("PlayButton On");或
EditorGUIUtility.IconContent("PlayButton On")
这样就可以获得一个蓝色的播放图标。所有的图标名字集合请转至http://www.xuanyusong.com/archives/3777
- 您可以通过使用[MenuItem(“CONTEXT / ...”)添加自定义项目到上下文菜单,即使是内置的类
写一个继承自AssetPostporocessor的脚本可在Unity导入或更新各种资源之前或之后增加自定义处理,如更改图片或音频的格式、转换xlsx配置档为bytes文件等等。
- 在使用缓冲池等需要修改对象的父节点时,正确的顺序应该是首先禁用对象,然后将其父对象重置为对象池,而不是先修改父对象再禁用对象,这样会造成不必要的污染。
- ??和?.两个操作符表达式对于继承自UnityEngine.Object的类通常是得不到正确结果的,它是纯C#的null检查,它会绕过Unity内部自定义的==null检查,请谨慎使用或避免使用在内置组件中。
unity为了开发者方便使用调试获得更多错误细节信息,在对C++封装C#时增加了很多额外处理,如果不做这些操作,则用户看到的就是简单的空引用异常的错误,对错误原因和修改方式知之较少。
如GameObject等在C#仅仅是对引擎内部原生C++ Object的封装,C#的内存管理是GC自动处理,C++则是是仅当切换场景或手动调用UnityEngine.Object.Destroy()时清理,故存在C#引用还存在而底层原生代码已被销毁的情况。故unity重载了==操作符可以判断原生Object是否被destoryed,也因此==null的操作比你想像中更费,它要判断处理的事比较复杂:private Transform m_CachedTransform
public Transform transform
{
get
{
if (m_CachedTransform == null)
m_CachedTransform = InternalGetTransform();
return m_CachedTransform;
}
}以上代码即会看不出对transform进行缓存有多少性能提升,因==null的操作本身就比较费。
对object进行判空有两种意图,是确保已进行赋值还是检查引用的底层引擎对象生命周期,以下代码意义不明:
var go = gameObject ?? CreateNewGameObject();
当你是想判断实际引用的物体是否被destory需要显示调用==操作符:
var go = gameObject != null ? gameObject : CreateNewGameObject();
// Or use the implicit bool conversion operators for the same check
go = gameObject ? gameObject : CreateNewGameObject();当你想确保变量已被初始化赋了正确的值需要显示调用object.ReferenceEquals()(对null的检查该调用已被编译器优化,且速度快于自定义的==操作符):
return !object.ReferenceEquals(gameObject, null) ? gameObject : CreateNewGameObject();
详情:https://blogs.unity3d.com/2014/05/16/custom-operator-should-we-keep-it/
实际代码实践中发现仅如BoxCollider等内置组件不可使用??和?.表达式,自定义类及UGUI相关组件是没问题的,可能unity5或之后某版本unity已优化。
Unity3d笔记的更多相关文章
- Unity3D笔记 英保通一
一.材质和着色器 1.材质和着色器紧密的联系,其中材质相当于是一个框架,而着色器就是框架中中的内容.在材质框架中可以选择不同的Shader并调节不同的 属性 Material和Physic Mater ...
- Unity3D笔记 Collect
一.输入轴 默认输入轴: Horizontal 和 Vertical被映射到w, a, s, d键和方向键 Fire1, Fire2, Fire3被分别映射到Ctrl,Option(Alt)和Comm ...
- Unity3D笔记 GUI 三、实现选项卡二窗口
实现目标: 1.使用个性化Box控件 2.个性化Lable控件 3.添加纵向滚动条 4.新建SelectedItem样式 一.最终效果: 二.主要代码 using UnityEngine; using ...
- Unity3D笔记 GUI 一
要实现的功能: 1.个性化Windows界面 2.减少个性化的背景图片尺寸 3.个性化样式ExitButton和TabButton 4.实现三个选项卡窗口 一.个性化Windows界面 1.1.创建一 ...
- Unity3D笔记 愤怒的小鸟<七> 小鸟群准备动画
要实现的目标: 1.3只小鸟初始动画 2.完善代码slingShot.js 3.完善代码BirdMoving.js 1.实现3个准备动画:Unity3D内置的动画管理器 1.1.先选择GameObje ...
- Unity3D笔记 愤怒的小鸟<五> 小鸟动画+Unity3D如何设置断点调式
前言:实现小鸟的动画,之前吐槽过js写U3D,就改成了C#来写,没想到遇到问题了. 实现的效果 using UnityEngine; using System.Collections; /// < ...
- Unity3D笔记 愤怒的小鸟<二> 实现Play界面
创建Play界面.能个把各个图片组合成一个场景,场景组成后背景能够不停的滚动,当鼠标单击时显示图片手型鼠标 一.GUI Texture 1.创建背景.地面.树木.草 ,这里注意Z轴的排序,一层一层则第 ...
- Unity3D笔记 愤怒的小鸟<一>场景切换
新建3个场景,场景1 Start 十秒后自动切换到场景2 Splash,场景2在二秒后自动切换到场景3 Selection 一.场景一Start 二.场景2 Splash 三.场景3 Selectio ...
- Unity3D笔记六 GUI游戏界面
1.Label:标签控件,可以在游戏中用来展示文本字符串信息,不仅可以写字还可以贴图片. 2.Button:按钮控件,一般分图片按钮和普通的按钮,还有一个连续按钮RepeatButton注意,这个在W ...
- Unity3D 笔记二 3D模型基础
一.3D模型基础 1.Hierarchy 显示的是界面上的游戏对象(GameObject),每个游戏对象都有.至少要有一个Camera,点击Camera就可以在Preview中看到摄像机的视角画面.每 ...
随机推荐
- linux 设置静态IP方法
本系统使用 linux redhat 7.2 1. 修改ip vi /etc/sysconfig/network-scripts/ifcfg-eno16777736 2. 修改数据项如下 3. ...
- mongo 介绍
[介绍]:MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统.在高负载的情况下,添加更多的节点,可以保证服务器性能.MongoDB 旨在为WEB应用提供可扩展的高性能数据存 ...
- HttpModule与HttpHandler详解(转)
ASP.NET对请求处理的过程:当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给 ASPNET_ISAPI.dll,A ...
- Failed to load http://wantTOgo.com/get_sts_token/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fromHere.com' is therefore not allowed access.
Failed to load http://wantTOgo.com/get_sts_token/: No 'Access-Control-Allow-Origin' header is presen ...
- Channel (digital image) 通道 色彩深度 Color_depth
en.wikipedia.org/wiki/Channel_(digital_image) Color digital images are made of pixels, and pixels ar ...
- python cookbook第三版学习笔记三:列表以及字符串
过滤序列元素: 有一个序列,想从其中过滤出想要的元素.最常用的办法就是列表过滤:比如下面的形式:这个表达式的意义是从1000个随机数中选出大于400的数据 test=[] for i in range ...
- JavaScript判断图片是否加载完成的三种方式 (转)
一.load事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <!DOCTYPE HTML> <html> <head> ...
- ABAP 调用webservice 错误
错误:1.soamanager 配置端口错误: 调整端口后报错: java端回复: 嗯 有问题了我待会儿看看应该是数据有问题
- 【ansible】ansible部署方式以及部署包
最近研究ansible的使用,在使用pip安装的时候遇到很多奇怪的问题,为此采用了手动安装的方式,并编写了一键安装脚本. ansible要求机器必须安装python2.6以上版本,可以通过一下命令查看 ...
- PAT 乙级 1081. 检查密码 (15) 【字符串】
题目链接 https://www.patest.cn/contests/pat-b-practise/1081 思路 有一个坑点 可能会输入空格 也就是说 要用 geline 或者 gets() 然后 ...