Unity-Basic

前言

Unity Basic

Unity相关

坐标系

1, World Space(世界坐标):
我们在场景中添加物体(如:Cube),他们都是以世界坐标显示在场景中的。transform.position可以获得该位置坐标。

2, Screen Space(屏幕坐标):
以像素来定义的,以屏幕的左下角为(0,0)点,右上角为(Screen.width,Screen.height),Z的位置是以相机的世界单位来衡量的。
注:鼠标位置坐标属于屏幕坐标,Input.mousePosition可以获得该位置坐标,手指触摸屏幕也为屏幕坐标,Input.GetTouch(0).position可以获得单个手指触摸屏幕坐标。

3.ViewPort Space(视口坐标):
视口坐标是标准的和相对于相机的。相机的左下角为(0,0)点,右上角为(1,1)点,Z的位置是以相机的世界单位来衡量的。
4, 绘制GUI界面的坐标系:
这个坐标系与屏幕坐标系相似,不同的是该坐标系以屏幕的左上角为(0,0)点,右下角为(Screen.width,Screen.height)。

【四种坐标系的转换】

1、世界坐标→屏幕坐标:camera.WorldToScreenPoint(transform.position);这样可以将世界坐标转换为屏幕坐标。其中camera为场景中的camera对象。
2、屏幕坐标→视口坐标:camera.ScreenToViewportPoint(Input.GetTouch(0).position);这样可以将屏幕坐标转换为视口坐标。其中camera为场景中的camera对象。
3、视口坐标→屏幕坐标:camera.ViewportToScreenPoint();
4、视口坐标→世界坐标:camera.ViewportToWorldPoint();

参考 https://www.jianshu.com/p/9ed5f8d023ff

unity 串口通信

https://blog.csdn.net/Rick__/article/details/83743294

接口InverseTransformDirection

Traget.InverseTransformDirection(Vector3 direction):相当于先将Target的旋转到与世界坐标对齐,然后把direction附加到Target上(把direction想象成一支箭,插在Target上),最后再把Target旋转回原来的位置。此时direction的方向(以世界坐标反映)就是返回的值。

Target.TransformDirection(Vector3 direction):此时direction的值不论为多少,都视为以Target本身local坐标系下所对应的向量。这个函数相当于把direction直接横移到世界坐标系里,重新根据这个横移过来的方向给出其具体方向,作为返回值。

https://blog.csdn.net/chy555chy/article/details/79556346

Unity项目建议

0 内存占用
1 mvc设计结构,单例等
2 长期存在的对象和动态存在的加载方式
3 字典、链表的长度?的读取方式读取频率
4 mono脚本的大小,类的耦合度
5 try catch
6 数据据命令的操作频率
7 debug全部删掉
8 能用自定义方法完成的所有事情,不要根据变量放置到update等中间去检测。使用协程、多线程处理。
9 所有gameobject的存在和销毁、加载周期,序列化和反序列化周期。
10 垃圾回收,定期回收垃圾
11 使用memory profiler 进行内存分析,IL2CPP
12内存优化:
(1)字符串链接后,旧的会成为垃圾,定期清理
(2)尽量不用foreach,用for循环
(3)避免直接访问gameobject的tag属性,不用go.tag,二是go.compareTag(“haha”)
(4)使用池
(5)最好不用LINQ
13 代码优化
(1)Transfrom只访问一次
(2)循环中不要频繁使用getcomponent
(3)使用OnbecameVisible 来控制物体update里的开销
(4)使用内建数据初始化,比如Vector3.Zero而不是new vector3(0,0,0)
(5)避免复制,多用ref
14 定义事件后,使用开检测是否为空,不要注册空方法
public delegate void ClickItemdelegate(GameObject item);
​ public event ClickItemdelegate ClickItemEvent;
public void ClickItem(GameObject item)
​ {
​ ClickItemEvent(item);
​ }
​ void ClickItemTemplate(GameObject item)
​ {
​ //空的事件,不这样做的话ClickItemEvent会引发空引用异常
​ }
15 添加监听后,必须成对地注销监听
16 析构函数不要循环调用
17 没有嵌入到主线程的,去掉mono继承

移动项目的优化方法:

1.使用assetbundle,实现资源分离和共享,将内存控制到200m之内,同时也可以实现资源的在线更新
2.顶点数对渲染无论是cpu还是gpu都是压力最大的贡献者,降低顶点数到8万以下,fps稳定到了30帧左右
3.只使用一盏动态光,不是用阴影,不使用光照探头
粒子系统是cpu上的大头
4.剪裁粒子系统
5.合并同时出现的粒子系统
6.自己实现轻量级的粒子系统
animator也是一个效率奇差的地方
7.把不需要跟骨骼动画和动作过渡的地方全部使用animation,控制骨骼数量在30根以下
8.animator出视野不更新
9.删除无意义的animator
10.animator的初始化很耗时(粒子上能不能尽量不用animator)
11.除主角外都不要跟骨骼运动apply root motion
12.绝对禁止掉那些不带刚体带包围盒的物体(static collider )运动
NUGI的代码效率很差,基本上runtime的时候对cpu的贡献和render不相上下
13每帧递归的计算finalalpha改为只有初始化和变动时计算
14去掉法线计算
15不要每帧计算viewsize 和windowsize
16filldrawcall时构建顶点缓存使用array.copy
17.代码剪裁:使用strip level ,使用.net2.0 subset
18.尽量减少smooth group
19.给美术定一个严格的经过科学验证的美术标准,并在U3D里面配以相应的检查工具

三种实例化方法

挂脚本
addcomponent
运行时实例化
参考:
https://answers.unity.com/questions/653904/you-are-trying-to-create-a-monobehaviour-using-the-2.html

交互速度
用deltatime来控制,不要固定角度或者速度等,因为不同的平台和配置每帧的物理时间不一样。

Unity Shader优化思路
尽量使用低精度的数值类型;
共享某些纹理和贴图的坐标;
减少处理光源的个数;
只工作在特定渲染器上;
有个问题?优化可以被量化?

协程

协程不是线程,也不是异步执行的。协程和 MonoBehaviour 的 Update函数一样也是在MainThread中执行的。使用协程你不用考虑同步和锁的问题。
协程是一个分部执行,遇到条件(yield return 语句)会挂起,直到条件满足才会被唤醒继续执行后面的代码。Unity在每一帧(Frame)都会去处理对象上的协程。Unity主要是在LateUpdate后去处理协程(检查协程的条件是否满足)。
参考图coroutinue,是跟unity执行周期一致的。

coroutinue

两个例子:

1 使用yeld return null实现类似update的功能,代码质量更高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class dialog_yield : MonoBehaviour {
public string dialogStr = "yield return的作用是在执行到这行代码之后,将控制权立即交还给外部。yield return之后的代码会在外部代码再次调用MoveNext时才会执行,直到下一个yield return——或是迭代结束。虽然上面的代码看似有个死循环,但事实上在循环内部我们始终会把控制权交还给外部,这就由外部来决定何时中止这次迭代。有了yield之后,我们便可以利用“死循环”,我们可以写出含义明确的“无限的”斐波那契数列。";
public float speed = 5.0f;
void Start () {
StartCoroutine(ShowDialog());
}
IEnumerator ShowDialog(){
float timeSum = 0.0f;
while(guiText.text.Length < dialogStr.Length){
timeSum += speed * Time.deltaTime;
guiText.text = dialogStr.Substring(0, System.Convert.ToInt32(timeSum));
yield return null;
}
}
}

2 完全的测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class TestCoroutine : MonoBehaviour {  

private bool isStartCall = false; //Makesure Update() and LateUpdate() Log only once
private bool isUpdateCall = false;
private bool isLateUpdateCall = false;
// Use this for initialization
void Start () {
if (!isStartCall)
{
Debug.Log("Start Call Begin"); //11111111111
StartCoroutine(StartCoutine());
Debug.Log("Start Call End"); //3333333333
isStartCall = true;
}
}
IEnumerator StartCoutine()
{
Debug.Log("This is Start Coroutine Call Before"); //2
yield return new WaitForSeconds(1f);
Debug.Log("This is Start Coroutine Call After"); //10
}
// Update is called once per frame
void Update () {
if (!isUpdateCall)
{
Debug.Log("Update Call Begin"); //4
StartCoroutine(UpdateCoutine());
Debug.Log("Update Call End"); //6
isUpdateCall = true;
}
}
IEnumerator UpdateCoutine()
{
Debug.Log("This is Update Coroutine Call Before"); //5
yield return new WaitForSeconds(1f);
Debug.Log("This is Update Coroutine Call After"); //11
}
void LateUpdate()
{
if (!isLateUpdateCall)
{
Debug.Log("LateUpdate Call Begin"); //7
StartCoroutine(LateCoutine());
Debug.Log("LateUpdate Call End"); //9
isLateUpdateCall = true;
}
}
IEnumerator LateCoutine()
{
Debug.Log("This is Late Coroutine Call Before"); //8
yield return new WaitForSeconds(1f);
Debug.Log("This is Late Coroutine Call After"); //12
}
}

总结:

1.yield return 0、yield return null
等待下一帧接着执行下面的内容
2.yield return new WaitForSeconds(float secs)
等待指定秒数,接着执行下面的内容
3.yield return www;
使用WWW下载,等待www下载完成以后再执行下面代码
4.yield return StartCoroutine(“协程方法名”)
先执行协程方法,并等待,直到该协程方法执行完再执行后面的内容
5.yield break
退出协程,不执行break后面的代码

参考:
https://blog.csdn.net/huang9012/article/details/29595747
https://blog.csdn.net/qq_33337811/article/details/73608891
https://www.cnblogs.com/fly-100/p/3910515.html

Unity 粒子系统

Unity官方粒子模拟液体碰撞的一个例子
https://unity3d.com/cn/learn/tutorials/topics/scripting/particle-launcher

//ParticleLauncher Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class ParticleLauncher : MonoBehaviour {

public ParticleSystem particleLauncher;
public ParticleSystem splatterParticles;
public Gradient particleColorGradient;
public ParticleDecalPool splatDecalPool;

List<ParticleCollisionEvent> collisionEvents;

void Start ()
{
collisionEvents = new List<ParticleCollisionEvent> ();
}

void OnParticleCollision(GameObject other)
{
ParticlePhysicsExtensions.GetCollisionEvents (particleLauncher, other, collisionEvents);

for (int i = 0; i < collisionEvents.Count; i++)
{
splatDecalPool.ParticleHit (collisionEvents [i], particleColorGradient);
EmitAtLocation (collisionEvents[i]);
}

}

void EmitAtLocation(ParticleCollisionEvent particleCollisionEvent)
{
splatterParticles.transform.position = particleCollisionEvent.intersection;
splatterParticles.transform.rotation = Quaternion.LookRotation (particleCollisionEvent.normal);
ParticleSystem.MainModule psMain = splatterParticles.main;
psMain.startColor = particleColorGradient.Evaluate (Random.Range (0f, 1f));

splatterParticles.Emit (1);
}
void Update ()
{
if (Input.GetButton ("Fire1"))
{
ParticleSystem.MainModule psMain = particleLauncher.main;
psMain.startColor = particleColorGradient.Evaluate (Random.Range (0f, 1f));
particleLauncher.Emit (1);
}

}
}

//ParticleDecalData Class

1
2
3
4
5
6
7
public class ParticleDecalData
{
public Vector3 position;
public float size;
public Vector3 rotation;
public Color color;
}

// Class ParticleDecalPool

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class ParticleDecalPool : MonoBehaviour {
public int maxDecals = 100;
public float decalSizeMin = .5f;
public float decalSizeMax = 1.5f;

private ParticleSystem decalParticleSystem;
private int particleDecalDataIndex;
private ParticleDecalData[] particleData;
private ParticleSystem.Particle[] particles;

void Start ()
{
decalParticleSystem = GetComponent<ParticleSystem> ();
particles = new ParticleSystem.Particle[maxDecals];
particleData = new ParticleDecalData[maxDecals];
for (int i = 0; i < maxDecals; i++)
{
particleData [i] = new ParticleDecalData ();
}
}

public void ParticleHit(ParticleCollisionEvent particleCollisionEvent, Gradient colorGradient)
{
SetParticleData (particleCollisionEvent, colorGradient);
DisplayParticles ();
}

void SetParticleData(ParticleCollisionEvent particleCollisionEvent, Gradient colorGradient)
{
if (particleDecalDataIndex >= maxDecals)
{
particleDecalDataIndex = 0;
}
particleData [particleDecalDataIndex].position = particleCollisionEvent.intersection;
Vector3 particleRotationEuler = Quaternion.LookRotation (particleCollisionEvent.normal).eulerAngles;
particleRotationEuler.z = Random.Range (0, 360);
particleData [particleDecalDataIndex].rotation = particleRotationEuler;
particleData [particleDecalDataIndex].size = Random.Range (decalSizeMin, decalSizeMax);
particleData [particleDecalDataIndex].color = colorGradient.Evaluate (Random.Range (0f, 1f));

particleDecalDataIndex++;
}

void DisplayParticles()
{
for (int i = 0; i < particleData.Length; i++)
{
particles [i].position = particleData [i].position;
particles [i].rotation3D = particleData [i].rotation;
particles [i].startSize = particleData [i].size;
particles [i].startColor = particleData [i].color;
}

decalParticleSystem.SetParticles (particles, particles.Length);
}
}

//Class SplatOnCollision

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class SplatOnCollision : MonoBehaviour {

public ParticleSystem particleLauncher;
public Gradient particleColorGradient;
public ParticleDecalPool dropletDecalPool;

List<ParticleCollisionEvent> collisionEvents;

void Start ()
{
collisionEvents = new List<ParticleCollisionEvent> ();
}

void OnParticleCollision(GameObject other)
{
int numCollisionEvents = ParticlePhysicsExtensions.GetCollisionEvents (particleLauncher, other, collisionEvents);

int i = 0;
while (i < numCollisionEvents)
{
dropletDecalPool.ParticleHit(collisionEvents[i], particleColorGradient);
i++;
}
}
}

unity自己实现树形结构,利用UGUI

xLua热更新

鼠标和三维物体交互

射线方法

从鼠标位置映射相机,发出射线,如果射线碰撞到某物体且发生点击事件,则进行交互;
交互的结果跟射线碰撞的物体有关;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
Debug.DrawLine(ray.origin, hitInfo.point);
GameObject gameObj = hitInfo.collider.gameObject;
if(Input.GetMouseButtonDown(0))
{
Debug.Log("click object name is " + gameObj.name);
Destroy(gameObj);
}
}
}

或者:点击的时候再发射线,性能考虑。

在有collider的物体上,实现OnMouseXXX接口

更为方便的方式,使用委托:
交互物体Cube上
1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public delegate void EventHandler(GameObject e);

public event EventHandler MouseDown;//鼠标按下
public event EventHandler MouseDrag;//鼠标拖拽
public event EventHandler MouseUp;//鼠标抬起
public event EventHandler MouseOver;//鼠标悬停在物体上方时
public event EventHandler MouseExit;//鼠标离开物体时

void OnMouseDown()
{
if (MouseDown != null)
MouseDown(this.gameObject);

}

2 随便一个生效的脚本

1
2
3
4
5
6
7
8
void Start()
{
Cube.GetComponent<EventDispatcher>().MouseDown += ClickSomething;
}
private void ClickSomething(GameObject e)
{
Debug.Log("点击物体:"+e);
}

游戏物体 EventTrigger 物体动态事件监听

参考:
https://blog.csdn.net/m0_37583098/article/details/82977523

接口实现方法

https://blog.csdn.net/leemu0822/article/details/85802781

物体朝另一物体平滑运动和转向

最简单的相机跟随-始终跟随,每一帧都跟随

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CameraController : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate ()
{
transform.position = player.transform.position + offset;
}
}

在某一段时间内实现跟随,匀速跟随

比如,让一个物体从A移动到B,不考虑平滑效果,匀速运动下,一秒10帧,每秒0.1 * (b-a),那么:

t += Time.deltaTime;
UpdatePos = Origin + (1-t)* (Target-Origin)
//UpdatePos = Mathf.Lerp(Origin,Target, t);
这样,我们准确地在1s时间内实现了物体的移动。这里考虑Lerp函数的实现,很容易发现以上两者是完全等效的。

1
2
3
4
5
public static float Lerp(float a, float b, float t)
{
return (1-t)*a + t * b; // a + (b-a) * t
}
t [0,1];

无限接近的伪跟随-平滑跟随

网上你能看到的大多数跟随是unity官方给出的例子:
UpdatePos = Mathf.Lerp(UpdatePos,Target, t);
为什么是伪跟随呢,因为插值的结果是在最近的帧时刻,使物体无限靠近:
最新的位置 = 上一时刻位置 + (目标位置- 上一时刻位置) Time.Deltatime
假如start = 0,Target = 1,Time.deltatime = 0.01,物体在第一帧内移动
0+1
0.01 = 0.01
第二帧 0.01 + 0.99*0.01 ~= 0.02
这样无限逼近1.
达到了平滑的效果,但是只是理论接近,永远无法完全到达。

SmoothDamp

unity封装的实现类似弹簧阻尼效果的平滑移动,大致类似Lerp,也可以约束移动的时间:

1
2
3
4
5
6
7
8
9
10
11
12
public class ExampleClass : MonoBehaviour
{
public Transform target;
public float smoothTime = 0.3F;
private Vector3 velocity = Vector3.zero;

void Update()
{
Vector3 targetPosition = target.TransformPoint(new Vector3(0, 5, -10));
transform.position = Vector3.SmoothDamp(transform.position, targetPosition, ref velocity, smoothTime);
}
}

Canvas 的三种显示模式

https://www.jianshu.com/p/660a513e7d41

鼠标控制物体旋转、平移、缩放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
void Update()
{
float _mouseX = Input.GetAxis("Mouse X");
float _mouseY = Input.GetAxis("Mouse Y");
CameraFOV();
CameraRotate(_mouseX,_mouseY);
CameraMove(_mouseX,_mouseY);
}

public void CameraFOV()
{
float wheel = Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * 1000;
_mainCamera.transform.Translate(Vector3.forward * wheel);
}

public void CameraRotate(float _mouseX,float _mouseY)
{
//注意!!! 此处是 GetMouseButton() 表示一直长按鼠标左键;不是 GetMouseButtonDown()
if (Input.GetMouseButton(0))
{
//控制相机绕中心点(centerPoint)水平旋转
_mainCamera.transform.RotateAround(centerPoint, Vector3.up, _mouseX * rotateSpeed);

//记录相机绕中心点垂直旋转的总角度
angle += _mouseY * rotateSpeed;

//如果总角度超出指定范围,结束这一帧(!用于解决相机旋转到模型底部的Bug!)
//(这样做其实还有小小的Bug,能发现的网友麻烦留言告知解决办法或其他更好的方法)
if (angle > maxRotAngle || angle < minRotAngle)
{
return;
}

//控制相机绕中心点垂直旋转(!注意此处的旋转轴时相机自身的x轴正方向!)
_mainCamera.transform.RotateAround(centerPoint, _mainCamera.transform.right, _mouseY * rotateSpeed);
}
}

public void CameraMove(float _mouseX,float _mouseY)
{
if (Input.GetMouseButton(2))
{
//加载小手的资源图片
//Texture2D cursorTex = Utils.LoadTexture("hand");

//鼠标图标换成自定义小手
//Cursor.SetCursor(cursorTex, Vector2.zero, CursorMode.Auto);

//相机位置的偏移量(Vector3类型,实现原理是:向量的加法)
Vector3 moveDir = (_mouseX * -_mainCamera.transform.right + _mouseY * -_mainCamera.transform.up);

//限制y轴的偏移量
//moveDir.y = 0;
_mainCamera.transform.position += moveDir*5f;
}
else
{
//Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
}
}

参考:
https://blog.csdn.net/dlhcoder/article/details/85942743

多个button使用同一方法

UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject

var button = UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject;
Debug.Log(button.name);

https://blog.csdn.net/fxd1024/article/details/100737854
https://blog.csdn.net/weixin_43818160/article/details/99739265

RectTransform详细说明

https://www.jianshu.com/p/dbefa746e50d

改变某个panel/Image的位置
rect.anchoredPosition = new Vector2(temp,rect.anchoredPosition.y);

轮盘按钮

https://www.jianshu.com/p/76067db26ae0

寻找场景中的物体

1 GameOnbject.Find(“”);只能找到active的物体
2 存在物体.transform.Find(); 找到子物体

组件激活getComponent<>().Enabled = true;

其他内容

lens flare

Json

halo

https://blog.csdn.net/puppet_master/article/details/54000951

一般自适应

https://blog.csdn.net/lyh916/article/details/50865541
https://www.jianshu.com/p/ca46228e5133
https://blog.csdn.net/u010989951/article/details/52125651

网页自适应
https://blog.csdn.net/tianyongheng/article/details/78633787
https://blog.csdn.net/qq_38456478/article/details/78869971
https://www.jianshu.com/p/cb3189cce7e8

unity分辨率和比例的调整文档

http://www.aclockworkberry.com/managing-screen-resolution-and-aspect-ratio-in-unity-3d/

Unitywebservice

自己写了数据的接口,发出和响应http请求,返回和解析json数据
作为客户端需要的接口是httpclient
作为服务器可以使用httplistener接口,net基本都做好了封装
比较旧的接口是httpserver,没有进一步深入
https://csharp.hotexamples.com/examples/-/HttpListener/-/php-httplistener-class-examples.html
https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=netframework-4.8

unity-webservice
http://wiki.unity3d.com/index.php?title=Webservices_In_Unity
https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.html
https://docs.unity3d.com/Manual/UnityWebRequest.html
http://gyanendushekhar.com/2017/12/03/call-rest-web-service-unity3d-asp-net-web-api-rest-service/
https://blog.csdn.net/yimingsilence/article/details/45642243

其他
https://www.cnblogs.com/infly123/p/4032941.html
https://www.cnblogs.com/fyluyg/p/6047819.html
https://blog.csdn.net/yslflsy/article/details/45362847
https://forum.unity.com/threads/how-do-you-consume-a-web-service-from-unity-solved.311484/

unity自己实现树形结构,利用UGUI

xLua热更新开源

https://github.com/Tencent/xLua
https://www.zhihu.com/question/54344452/answer/138990189

Unity Manual相关记录

基本操作
1 移动设备输入过程中,对高频率数据信号的低通滤波(专题)
2 单个四元数不能表示任何方向超过180度的旋转
3 添加随机元素
4 设置-graphics 可编程渲染管线文档 https://docs.unity3d.com/Packages/com.unity.render-pipelines.core@latest
5 性能分析概述(专题)
6 插件有托管插件和原生插件
如果 DLL 不包含依赖于 Unity API 的代码,则可以使用适当的编译器选项将其直接编译为 DLL。如果确实想使用 Unity API,则需要将 Unity 自己的 DLL 提供给编译器;
7 低级原生插件接口(专题)
8 assetbundle (专题)
9 Scriptable Object:在editor会话期间保存数据/将数据保存为项目中的资源
10 携程功能,简单实现携程状态机(专题)
11 备份项目或将项目添加到版本控制库时,应包括 Unity 主项目文件夹,其中包含 Assets 和 ProjectSettings 文件夹。这些文件夹中的所有信息对于 Unity 的运行都至关重要。在备份时应忽略 Library 和 Temp 文件夹。
12 基于文本的场景文件:Unity 的场景格式是用 YAML 数据序列化语言实现的。
13 Unity可以用脚本修改材质、网格、物理材质的永久值。(一般修改在推出play的时候重置)
14 扩展编辑器(专题)
导入 - 基本没什么内容
2D
1 精灵图集
概念类似于assetbundle的管理思想,将不同的2D图片资源打包和分类/后期脚本加载,优化运行的性能和。
2 瓦片资源