Unity 小技巧总结

定时重复处理,比如, 启动0.5秒后每隔1秒执行一次 DoSomeThing 函数:
1.用InvokeRepeating 函数实现
void Start() { InvokeRepeating(“DoSomeThing”, 0.5, 1.0); }
CancelInvoke(“你调用的方法”); 停止InvokeRepeating

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Start()
{
StartCoroutine("Repeating");开始调用
StopCoroutine("Repeating");停止调用
}
IEnumerator Repeating()
{
yield return new WaitForSeconds(0.5f);

while (true)
{
yield return new WaitForSeconds(1f);
DoSomeThing();
}
}

尽量避免每帧处理,可以每隔几帧处理一次
比如:
void Update() { DoSomeThing(); }

可改为每5帧处理一次:
void Update() { if(Time.frameCount % 5 == 0) { DoSomeThing(); } }

主动回收垃圾
给某个 GameObject 绑上以下的代码:
void Update() { if(Time.frameCount % 50 == 0) { System.GC.Collect(); } }

不要使用SendMessage之类的方法,他比直接调用方法慢了100倍,你可以直接调用或通过C#的委托来实现。

关于渲染队列和Batch的非官方经验总结是,一帧的渲染队列的生成,依次决定于每个渲染物体的:
Shader的RenderType tag,
Renderer.SortingLayerID,
Renderer.SortingOrder,
Material.renderQueue(默认值为Shader里的”Queue”),
Transform.z(ViewSpace)(默认为按z值从前到后,但当Queue是“Transparent”的时候,按z值从后到前)。
这个渲染队列决定了之后(可能有dirty flag的机制?)渲染器再依次遍历这个渲染队列,“同一种”材质的渲染物体合到一个Batch里。

Unity渲染路径(Rendering Path)种类
概述
开发者可以在Unity工程的PlayerSettings设置对渲染路径进行3选1:
Deferred Lighting,延迟光照路径。3者中最高质量地还原光照阴影。光照性能只与最终像素数目有关,光源数量再多都不会影响性能。
Forward Rendering,顺序渲染路径。能发挥出Shader全部特性的渲染路径,当然也就支持像素级光照。最常用、功能最自由,性能与光源数目*受光照物体数目有关,具体性能视乎其具体使用到的Shader的复杂度。
Vertex Lit,顶点光照路径。顶点级光照。性能最高、兼容性最强、支持特性最少、品质最差。

unity 点击2D物体
1.给物体添加对应的2D碰撞体,例如Box Collider 2D;
2.Update检测鼠标是否点下;
3.如果鼠标点下,创建一条射线,通过Physics2D.Raycast获取点击时鼠标处的对象;

1
2
3
4
5
6
7
8
9
10
11
12
13
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition;
Ray ray = Camera.main.ScreenPointToRay(mousePos);
RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);
if (hit.collider != null)
{
Debug.Log(hit.collider.name);
}
}
}

从游戏开始到当前帧经历的时间 Time.realtimeSinceStartup;
从游戏开始到当前帧经历的帧总数 Time.frameCount;

计算FPS:

1
2
3
4
5
6
7
8
9
10
11
12
_countFrame += 1
void Update()
{
float time = Time.realtimeSinceStartup;
if (time - _lastTime >= 1.0f)
{
_fps = (float)(_countFrame/(time - _lastTime));
Debug.Log("FPS: " + _countFrame);
_countFrame = 0;
_lastTime = time;
}
}

得到当前帧鼠标的位移量:Input.GetAxis()

1
2
3
4
5
6
7
8
9
void Update()
{
if (Input.GetMouseButton(0) && _isRotation){
float x = Input.GetAxis("Mouse X")*10;
float y = Input.GetAxis("Mouse Y")*10;
Debug.Log("x: " + x + " y: " + y);

}
}

对象跟随鼠标运动:

1
2
3
4
5
6
7
8
Vector3 wp = Camera.main.WorldToScreenPoint(transform.position);
Vector3 sp = Input.mousePosition;
sp.z = wp.z;

if (Input.GetMouseButton(0))
{
transform.position = Camera.main.ScreenToWorldPoint(sp);
}

协同程序的开启与终止:
在Unity3D中,使用MonoBehaviour.StartCoroutine方法即可开启一个协同程序,也就是说该方法必须在MonoBehaviour或继承于MonoBehaviour的类中调用。
在Unity3D中,使用StartCoroutine(string methodName)和StartCoroutine(IEnumerator routine)都可以开启一个线程。区别在于使用字符串作为参数可以开启线程并在线程结束前终止线程,相反使用IEnumerator 作为参数只能等待线程的结束而不能随时终止(除非使用StopAllCoroutines()方法);另外使用字符串作为参数时,开启线程时最多只能传递一个参数,并且性能消耗会更大一点,而使用IEnumerator 作为参数则没有这个限制。
在Unity3D中,使用StopCoroutine(string methodName)来终止一个协同程序,使用StopAllCoroutines()来终止所有可以终止的协同程序,但这两个方法都只能终止该MonoBehaviour中的协同程序。
还有一种方法可以终止协同程序,即将协同程序所在gameobject的active属性设置为false,当再次设置active为ture时,协同程序并不会再开启;如是将协同程序所在脚本的enabled设置为false则不会生效。这是因为协同程序被开启后作为一个线程在运行,而MonoBehaviour也是一个线程,他们成为互不干扰的模块,除非代码中用调用,他们共同作用于同一个对象,只有当对象不可见才能同时终止这两个线程。然而,为了管理我们额外开启的线程,Unity3D将协同程序的调用放在了MonoBehaviour中,这样我们在编程时就可以方便的调用指定脚本中的协同程序,而不是无法去管理,特别是对于只根据方法名来判断线程的方式在多人开发中很容易出错,这样的设计保证了对象、脚本的条理化管理,并防止了重名。

UGUI空格导致换行:将空格转换为全角空格,半角空格会使Text自动换行。

实现text显示不同颜色的字,如我是程序员小白,其中程序员为红色,其余自为黑色。使用透明颜色标签<color=#0000ff00>111,其中的111不会显示在Text上但会占据格子,作用类似于空格,通过这个标签的颜色值可以改变相应的字体颜色。

unity 编辑状态下暂停:

1.Debug.Break();或者UnityEditor.EditorApplication.isPaused = false;

2.使用编辑器类:EditorApplication.ExecuteMenuItem(“Edit/Play”);
3.UnityEditor.EditorApplication.isPlaying = false;

问题:
unity中通过Application.dataPath + “/Resources/Config/xxx”)作为将要读取文件的路径时,在编辑器上正常运行,但在打包后却无法正确读取文件
解决:
这是因为不同平台Application.dataPath所指定的路径不一样,editor模式下代表的是Asset,打包后对应的路径是打包时生成的文件夹“xxx_data”,这是需要把对应的文件拷贝到“xxx_data”文件夹下,例如打包后文件路径“E:\Unity\TowerDefense\Build\塔防_Data\Resources\Config”对应编辑器下的“E:\Unity\TowerDefense\Assets\Resources\Config”。

问题:
UNITY 无法导入视频解决方法
解决
1.unity 导入视频时无法转换成movieTexture, 这时候unity会提示影片导入失败,这时候需要安转QuickTime Player,这个软件可以把unity的影片转换成unity能用的材质。
2.QuickTime 无法正常运行时并且提示 “please install apple application support”时,打开下载的QuickTime安装包,选择安装“apple application support.msi”,安装选择“修复”。
3.unity支持的影片格式有.mov .mpg .mpeg .mp4 .avi .asf。
4.成功导入的影片会生成一个对应的Movie Audio,这个文件是该影片的声音文件。

问题:Scroll Rect中滑动事件是通过EventTrigger响应,所以当item也是通过EventTrigger响应点击事件时,就会遮挡住后面的Scroll Rect的滑动事件。
UGUI的ScrollRect组件会和放在它上面的button或者toggle等组件有事件响应的冲突,具体体现为上面的组件会遮挡下面的响应,在button或者toggle等组件上出现只能点击不能滑动的效果,要想滑动必须点旁边才行。
解决:
(1).Button: Button.onClick.AddListener(delegate () {ButtonOnClick(Button.gameObject); }); onClick回调函数 是继承自UnityEngine.Events.UnityAction.委托。由于同一个点击事件通过不同的事件模块去响应,很好的处理了item挡住Scroll Rect 事件的问题。委托格式为不带任何参数和返回的函数。
这里的Button是指你要按下的那个按钮,ButtonOnClick是该按钮按下时要触发的事件。
第二种解决方案是:不用按钮,1.新建一个继承MonoBehaviour和IPointerClickHandler接口的脚本(例如ClickObject),2.这个脚本实现public void OnPointerClick(PointerEventData eventData)方法:3.创建一个名为Panel_IPointer的空对象,这个空对象就是你的按钮。并且将ClickObject脚本附加到对象上。这时候点击这个对象就会调用OnPointerClick方法。
第三种:创建一个Image(例如名为Btn),Btn对象添加EventTrigger组件,” Add New” -> 选择” PointerClick”。将Btn对象拖拽到触发者位置。然后点击”No Function”选择我们要触发的OnTestClick事件。
(2)toggle:使用isOn的方法,例如if(toggle.ison){debug.log(“click”)};