1.脚本完整声明周期:
Awake > OnEnable > Start > Update > FixedUpdate > LateUpdate > OnGUI > OnDisable > OnDestroy
2.更新函数:
- Update(逻辑帧):执行次数取决于运行电脑的帧率。
- FixedUpdate(渲染帧):每0.02s执行一次,一般进行物理模拟计算,跟随每帧渲染,可以调整执行的时间间隔。
注:例如在联机游戏中,我们希望不同的玩家无论使用什么样的电脑,所产生的物理效果是一致的,比如《人类一败涂地》等游戏。
- LateUpdate:在所有Update执行完成后调用,一般处理摄像头移动等依赖其他对象逻辑。
3.初始化函数
- Awake:在脚本**整个生命周期(active = true)**调用一次,一般用来设置脚本间的引用。
- Start:在对象第一次被激活(active&enable = true(因此可以延迟调用,控制激活时间))在Awake后,第一帧前会触发。
- OnEnable:在每次对象被激活或脚本(active/enabled = true)被启动时调用。
4.动态资源加载方式:
-
Instantiate:最基础的动态加载,仅负责复制 实例。
csGameObject Obj = Instantiate(Prefab, Vector3.zero, Quaternion.identity); -
AssetBundle:资源放在服务器,www模块获取,从Bundle中下载资源,可**【热更新】**的资源打包方案。
-
Resource.Load:通过固定路径 直接加载资源。
csGameObject itemPrefab = Resources.Load<GameObject>(resourcePath); -
AssetDatabase.LoadAsset:仅编辑器模式下调试,无法在打包游戏中运行。
5.四元数与欧拉角
- 欧拉角:直观,unity编辑器中使用的旋转方式是以欧拉角的方式呈现,但是欧拉角存在万向死锁问题 和插值错误的不可避免的问题。
- 四元数:不直观但能解决欧拉角的问题。
- 万向死锁问题:旋转时x,y,z需要有先后顺序不然变换的结果不一,当旋转时可能出现轴重合。变换不存在过程,只有初始与结果,例如:先绕x轴旋转10°,再绕y轴旋转90°,最后绕x轴旋转35°,但是因为不存在过程,因此实际计算是先绕x轴旋转45°,最后绕y轴旋转90°。
注:Transform组件里的Rotation是四元数,但是以欧拉角(Vector3)的形式展现的。
6.Cnaves渲染模式
- Screen Space-Overlay:与摄像机无关,显示在屏幕的2D空间,且永远在3D物体前面渲染。
- Screen Space-Camera:指定一个摄像机,UI会渲染在相机的投射范围内。
- World Space:UI相当于场景中的一个物品,可以在场景中随意移动位置。
注:World Space可以用作敌人血条显示或者VR开发等。
7.Cnaves Scaler 的 UI 缩放模式
- Constant Pixel Size:保持UI自身像素大小(1Pixel)不变。
- Scale With Screen Size:根据指定比例显示在屏幕上。
- Constant Physical Size:使UI元素保持物理单位(厘米,英寸等)大小不变。
注:1.Constant Pixel Size与Constant Physical Size都是与屏幕分辨率无关。
2.UI在不同分辨率下的一致性:需要考虑UI的位置与尺寸,因此使用Rect Transfrom的锚点位置与Cnaves Scaler组件的Scale With Screen Size模式。
8.UGUI布局
1)锚点(Anchors)与轴心(Pivot)
- 锚点:四个值(小三角)分别表示相对于父物体左下角的比例,相对于父容器的缩放比例与位置。
理解:可以将父容器左下角看作原点,若Min与Max中X或Y相同(例如Min X与Max X都为0.6),则不随父容器缩放,只是位置会发生改变,是相对父容器比例的位置。若Min与Max中X或Y不相同,也就是三角分开,可以看右下角图片,每个小三角都与本身缩放(蓝点)呈现映射关系。


- 轴心:定义元素自身旋转与缩放中心,可以理解为绕轴旋转与缩放。
2)布局组件
- Horizontal / Vertical Layout Group:自动排列子元素。
- Content Size Fitter:根据内容动态调整大小。
- Aspect Ratio Fitter:保持宽高比。
9.协程
- 本质:运行在主线程之上,通过迭代器 实现,模拟 异步行为,协程之间是顺序执行,而不是多线程并发,在每帧update之后检查yied条件是否满足,通过yield return暂停协程后,主线程继续处理其他操作(如渲染),待条件满足时,Unity将协程的后续代码重新加入主线程队列。协程本身不涉及多线程,但能避免主线程阻塞。
- 过程:(Update > 协程处理 > LateUpdate)
1.启动协程,Unity会将协程的迭代器加入"待处理队列"
2.每帧Unity会遍历队列中的所有协程,满足条件就继续执行后续,否则跳过该协程。
-
使用方式:
csvoid Start() { //启动协程 myCoroutine = StartCoroutine(DelayedAction(2.0f)); //停止协程 StopCoroutine(myCoroutine); StopAllCoroutines(); } IEnumerator DelayedAction(float delayTime) { Debug.Log("协程开始,将延迟" + delayTime + "秒"); yield return new WaitForSeconds(delayTime); Debug.Log("延迟结束,执行动作!"); }注: 1.A脚本的协程,无法在B脚本中通过引用停止该协程。
2.如果对象被销毁,依附的协程也会停止。若不希望协程停止,将其挂在例如:
DontDestroyOnLoad 对象等持久化对象上。
3.避免频繁开启停止协程,会产生GC压力。
- 实际应用:黑屏颜色渐变,异步加载,延迟执行生成物品等
10.异步加载
1.基本概念
- 作用:可以在不阻塞游戏主线程的情况下加载资源。
- 好处:加载资源的同时,游戏继续运行,提高性能,加载大型场景时可以实现平滑转换。
- 使用方式:Resources.LoadSceneAsync(index) 或者 使用Addressables工具实现。
注:需要使用协程来完成异步加载操作,协程作为调度工具使用,将耗时的I/O或计算任务交给后台线程,主线程只检查进度。
2.语法使用
1)async与await
- async:修饰方法的关键词,用来编写异步代码。方法返回类型通常为void,Task,Task<T>。
- await:等待一个Task或者Awaitable对象完成,期间不会阻塞主线程。
2)Awaitable(可等待对象):是一套规则,await后面需要是Awaitable类型,而Task是Awaitable的一种而已。

3)SceneManager:场景管理的核心类,用于加载,卸载与切换场景。
11.事件系统
注:事件(event)是对委托的封装,并且更加安全(外部必须注册和取消订阅来触发事件)
12.单例模式
1.分类:饿汉式(提前创建好,线程安全 )与懒汉式(用到才创建,延迟加载)
2.作用:只存在一个实例 ,并提供全局唯一的访问入口。
3.缺点:违反了依赖倒置原则。
13.六大设计原则
1.单一职责原则:一个类只干一件事。
2.开闭原则:对扩展开放,对修改关闭(增加而不是修改)。
3.里氏替换原则:子类必须完全替换父类,且不破坏原有逻辑。
4.接口隔离原则:接口需要小而专,不强迫类实现用不到的方法。
5.依赖倒置原则:依赖抽象,不依赖具体实现。
6.迪米特法则:一个对象应该尽量不干涉其他对象。
13.垃圾回收(GC)
14.C#特性关键词
-
Serializable\] :序列化自定义类
-
Flags\]:枚举组合
-
Range(Min,Max)\]:可视化并限制数值范围
-
RequireComponent(组件名)\]:强制添加组件(一般写在类前)
-
作用:
1.避免频繁创建与销毁对象导致GC压力与内存碎片化。
2.重复利用已经创建的对象,降低CPU和内存开销。
3.统一管理生成与回收,避免代码冗余。
-
使用方式:
csvar objectPool = new ObjectPool<T>( createFunc: () => new T(), // 创建新对象的委托 actionOnGet: (obj) => obj.SetActive(true), // 取出时的操作 actionOnRelease: (obj) => obj.SetActive(false), // 放回时的操作 actionOnDestroy: (obj) => Destroy(obj), // 销毁对象的委托 collectionCheck: true, // 防止重复放回的检查(调试用) defaultCapacity: 10, // 默认池容量 maxSize: 100 // 池最大容量(超限时销毁对象) ); void UsePool(){ GameObject obj = objectPool.Get(); //获取对象 objectPool.Release(obj); //放回对象池 objectPool.Dispose(); //清空对象池,并销毁所有对象 objectPool.Clear(); //清空对象池中空闲对象 }注:此种使用匿名函数的写法,需要另外有类似UsePool这样使用对象池的函数,才能被其他脚本使用;也可以写在冒号之后写具体函数名,就可以直接使用了。actionOnGet等其实本质是委托,写的函数会添加到各委托中。
-
注意事项:
1.根据需求分配足够的对象给予初始容量;超出最大容量自动销毁多余对象。
2.激活/禁用代替销毁;在获取对象时重置属性;保证每个Get()都有对应的Release()。
16.常见架构
1)MonoBehaviour 架构(面向对象)
- 核心思想:通过继承Mono的脚本挂载到GameObject上,使得每个对象独立处理逻辑。
- 优势:小规模项目(UI交互和角色操控等)。
- 劣势:大量Obj的Update逐个执行,导致主线程卡顿。
2)MVC架构
- 核心思想:数据(Model),显示(View)与逻辑(Controller)分离。
- 使用方式
1.Model:存储玩家数据
2.View:处理玩家输入与数据显示
3.Controller:协调两者(其实就是调用其中的变量与方法,进行整合)
- 优势:UI交互与网络同步。
- 劣势:严格的分层会导致增加代码复杂度。
3)Event - Driven架构
- 核心思想:通过事件解耦模块通信
- 优势:低耦合系统(成就系统和音效触发等)
- 劣势:过度使用会导致调试(修改与)困难。
4)分层架构
- 核心思想:按照功能划分层级。
- 优势:大型项目严格模块划分使用。
17.Unity DOTS
18.Image与RawImage
1.支持资源类型
- Image:仅支持Sprite,一般用在固定形状且适配缩放的静态UI元素。
- RawImage:支持Texture,一般用在动态加载或者实时渲染的图像。
2.功能特性
- Image:Sliced(边缘保持固定比例缩放),Tiled(平铺重复显示)与Filled(径向或线性填充),并且不支持UV调整。
- RawImage:UV Rect(裁切或平移显示区域,例如:仅显示左半部分或缩放纹理的某一区域),支持动态纹理(网络图片)。
3.性能
- Image:可与Sprite Packer(图集打包)结合使用可优化渲染性能,与UI事件系统深度集成。
- RawImage:轻量级,直接操作原始纹理。
4.材质与渲染
- Image:使用UI/Default材质,支持透明度混合和UI遮罩。
- RawImage:使用UI/Unlit/Transparent材质,支持无光照的纹理显示。
- 注:两者均可绑定自定义Shader,,而RawImage常用于复杂纹理(例如:扭曲效果)。
19.Unity多线程
1)自动多线程
- Job System
- Burst Compiler
- Addressables/AssetBundle
- 物理引擎:默认在子线程处理碰撞检测与刚体模拟。
- 批处理导入:在导入资源时,Unity会使用多线程加速出力。
2)手动多线程
- 自定义子线程任务
cs
void Start() {
Thread thread = new Thread(() => {
// 子线程中执行耗时操作
Debug.Log("子线程ID: " + Thread.CurrentThread.ManagedThreadId);
});
thread.Start();
}
注:子线程不能调用Unity API,否则会直接崩溃。
- Task(异步编程模型)
cs
async Task LoadData() {
string data = await Task.Run(() => {
// 子线程中读取文件
return System.IO.File.ReadAllText("data.txt");
});
// 回到主线程更新 UI
Debug.Log("数据加载完成: " + data);
}
注:await会暂停当前方法的执行,等待Task.Run中的操作完成,同时不阻塞主线程。UI事件返回值需要是void,并且await无法等待async void方法完成并且其中异常也不会捕获。
- 多线程使用限制与注意事项
1.主线程独占操作:创建/销毁Obj,修改组件属性,调用Debug.log与Time.deltaTime,访问Physics.Raycast。
2.线程同步:使用UnityMainThreadDispatcher(第三方工具)或MainThreadQueue将子线程结果传回主线程。
cs
Thread thread = new Thread(() => {
int result = HeavyCalculation();
UnityMainThreadDispatcher.Instance.Enqueue(() => {
textUI.text = "结果: " + result; // 在主线程更新 UI
});
});
3.竞态条件:多线程修改共享 数据需用lock或Mutex同步。
cs
private object obj = new object();
private int _counter = 0;
private void ThreadSafeIncrement() {
lock (obj) {
_counter++;
}
}
20.序列化(与反序列化)
1.概念:将对象状态(变量值,引用关系等)转换为可存储或可传输的格式。
2.应用:
- 场景与预制体保存:Unity将场景中的GameObject及其组件序列化为.unity或.prefab文件。
- Inspector面板显示:公共变量或者[SerializeField]的私有变量显示在Inspector面板。
- ScriptableObject数据存储:创建重复使用的配置数据。
- 数据持久化:将数据转换为JSON字符串保存到文件。
- 网络数据传输:通过序列化将游戏状态发送到服务器或其他客户端。
3.Unity可序列化对象:
- 基本数据类型:int,float,string,bool等。
- Unity类型:Vector3.Quaternion,Color等。
- 自定义的类或结构体(需标记[System.Serializable])
4.控制序列化字段
-
HideInInspector\]:避免显示在Inspector窗口,但仍可序列化。
5.自定义序列化
- ISerializationCallbackReceiver接口:
cs
public class DataVersioning : MonoBehaviour, ISerializationCallbackReceiver
{
public void OnAfterDeserialize()
{
//序列化后的特殊处理
}
public void OnBeforeSerialize()
{
// 序列化前的特殊处理
}
}
- SO与SP(SerializedProperty)管理复杂数据
cs
[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor {
//定义inspector面板显示UI内容与交互逻辑
public override void OnInspectorGUI() {
SerializedProperty dataProp = serializedObject.FindProperty("data");
//根据dataProp类型生成对应UI控件
EditorGUILayout.PropertyField(dataProp);
//用户修改该值需调用此方法应用在实际MyComponent对象上
serializedObject.ApplyModifiedProperties();
}
}
注:SP是操作序列化字段的工具类,SO是存储数据的容器。
21.Unity点击交互的实现方式
1)射线检测
cs
private void Update()
{
mousePosition = Mouse.current.position.ReadValue();
// 从相机发射一条指向鼠标位置的射线
pos = mainCamera.ScreenToWorldPoint(mousePosition);
pos.z = 0;
ray = mainCamera.ScreenPointToRay(mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray.origin , ray.direction, maxDistance, targetLayer);
// 执行射线检测
if (Physics2D.Raycast(ray.origin,ray.direction ,maxDistance, targetLayer))
{
// 射线命中物体,使用命中点作为世界位置
CurrentWorldPosition = hit.point;
Debug.Log($"射线命中: {hit.collider.gameObject.name},世界位置: {CurrentWorldPosition}");
}
else
{
Debug.Log($"未命中物体,使用 fallback 位置: {CurrentWorldPosition}");
}
}
注:目标物体需要有Collider。
2)物理碰撞检测
cs
public class SimpleClick : MonoBehaviour
{
private void OnMouseDown()
{
Debug.Log("点击了: " + gameObject.name);
}
}
注:目标物体需要有Collider,并且不适用于UI元素。
3)事件系统
1.UI控件
cs
public class UIClickHandler : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("点击了 UI 物体: " + gameObject.name);
}
}
2.3D与2D物体
cs
public class ObjectClickHandler : MonoBehaviour
{
private void Start()
{
//给当前物体添加EventTrigger组件
EventTrigger trigger = gameObject.AddComponent<EventTrigger>();
//创建一个事件条目
EventTrigger.Entry entry = new EventTrigger.Entry();
//设置事件类型为"PointerClick"
entry.eventID = EventTriggerType.PointerClick;
entry.callback.AddListener((data) => OnClick());
//将条目添加到EventTrigger的事件列表中
trigger.triggers.Add(entry);
}
private void OnClick()
{
Debug.Log("点击了场景物体: " + gameObject.name);
}
}
4)新输入系统
优点:支持多设备输入,高度可配置化。
22.相机基本设置
1.Clear Flags(清除屏幕方式)
- SkyBox:用天空盒填充未渲染区域
- Solid Color:用纯色填充(适合 2D 游戏)
- Depth Only:仅清除深度信息(用于多相机叠加)
- Don't Clear:不自动清除(需手动处理,慎用)
2.Projection(投影模式)
- Perspective(透视):3D效果,物体近大远小。
- Orthographic(正交):2D 效果,无视距离,适合2D游戏。
3.Clipping Planes(剪裁平面)
- Near:渲染的最近距离
- Far:渲染的最远距离(过大会影响性能)
4.Viewport Rect:定义相机渲染的屏幕区域
例如:设置x=0.5,y=0.5让相机渲染右半屏幕
5.Culling Mask:选择渲染的Layer物体。
6.Target Texture:将相机画面渲染到Render Texture上。
23.NavMesh寻路//TODO:修改,增加vr寻路里面地内容
1.烘培导航网格
- 场景中标记可行走区域(静态物体)
- 打开Window/AI/Navigation(若没有则需要导包),调整烘焙参数。
- 点击Bake,即可生成NaveMesh。
2.脚本控制NavMeshAgent
cs
private void Update()
{
if (!playerNav.hasPath && !playerNav.pathPending)
{
//开启寻路
playerNav.SetDestination(target.position);
}
if (!playerNav.pathPending && playerNav.remainingDistance <= playerNav.stoppingDistance && !playerNav.hasPath)
{
//关闭寻路
playerNav.ResetPath();
}
}
注:pathPending表示路径计算完毕, hasPath表示路径是否存在(当到达或者重置则不存在路径),remainingDistance表示剩余距离,stoppingDistance表示停止距离。
3.动态物体处理
- 为动态障碍物添加NavMeshObstacle组件。
- 设置组件中Carve属性(实时更新NavMesh)。
24.数据持久化
1.PlayerPerfs:存储数据是全局共享,高耦合性且安全性低,因此只适合存储少量基本数据。
cs
int highScore = 1000;
//存储highScore,设置变量为HighScore
PlayerPrefs.SetInt("HighScore", highScore);
//获取Score,如果没有返回默认值(3)
int score = PlayerPrefs.GetInt("Score", 3);
PlayerPrefs.Save();
2.Json:轻量,易用的数据持久化方案。
cs
// 保存数据
string json = JsonUtility.ToJson(data);//对象转成JSON字符串
System.IO.File.WriteAllText(SavePath(fileName), json);//写入本地文件
// 读取数据
string json = System.IO.File.ReadAllText(path);//读取Json字符串
SomeClass loadedPlayer = JsonUtility.FromJson<T>(json);//Json字符串转成对象
注:公开的变量以及[SerializeField]修饰的私有变量可以储存。
25.DoTween插件使用
1.初始化:可以自动初始化,也可以手动。
cs
DOTween.Init(bool recycleAllByDefault = false, bool useSafeMode = true, LogBehaviour logBehaviour = LogBehaviour.ErrorsOnly)
DOTween.Init();
注:recycleAllByDefault = true(动画使用完会放入对象池,不会直接销毁)
useSafeMode = true(动画性能慢一些,但更安全)
logBehaviour(根据模式,会记录不同信息)
2.timeScale对动画的影响
在创建的动画后加上.SetUpdate(true)方法就可以,这样在游戏暂停(Time.timeScale = 0)的时候动画依旧在运行,知道动画结束。
3.动画返回值:Tween
4.移动过渡
cs
//to:目标点;duration:持续时间;snapping = true:每次移动整数值。
transform.DOMove(Vector3 to, float duration, bool snapping);
transform.DOMoveX(10, 2f, false);
transform.DOLocalMove(new Vector3(10f, 2f, 0), 10f, false);
transform.DOLocalMoveX(10, 2f, false);
//endValue:跳跃目标点;jumpPower:跳跃强度,决定跳跃高度;
transform.DOJump(Vector3 endValue, float jumpPower, int numJumps, float duration, bool snapping));
transform.DOLocalJump(new Vector3(10, 0, 0), 10, 3, 2f, false);
5.旋转过渡
cs
//to:目标值;duration:过渡时间;mode:旋转模式(fast:最短路径(旋转不会超过360度),FastByond360:旋转会超过360度)
transform.DORotate(Vector3 to, float duration, RotateMode mode);//欧拉角
transform.DORotateQuaternion(Quaternion to, float duration)//四元数
//towards:目标点;duration:过渡时间;axisConstraint:旋转的约束轴(只旋转此轴);up:默认为Vector.up
transform.DOLookAt(Vector3 towards, float duration, AxisConstraint axisConstraint = AxisConstraint.None, Vector3 up = Vector3.up)
6.缩放过渡
cs
transform.DOScale(float/Vector3 to, float duration)
transform.DOScaleX/DOScaleY/DOScaleZ(float to, float duration)
7.文本动画
cs
//打字机效果,会覆盖原先的文字,显示新的文字。
GetComponent<Text>().DOText(string str, float duration);
8.震动效果
cs
//持续时间,强度(在哪个轴上震动)
transform.DOShakePosition(1,Vector3 vector);
9.冲击效果
cs
//punch:被打击的目标点;duration:过渡时间;vibrato:振动频率;elasticity:震荡效果(0-1)
transform.DOPunchPosition(Vector3 punch, float duration, int vibrato, float elasticity, bool snapping)
transform.DOPunchRotation(Vector3 punch, float duration, int vibrato, float elasticity)
transform.DOPunchScale(Vector3 punch, float duration, int vibrato, float elasticity)
26.进程,线程与协程
1.进程:操作系统进行资源分配和管理的最小单位,是"独立程序的实例",例如:打开一个浏览器就会创建一个线程。
2.线程:一个进程中包含多个进程,是CPU调度 的基本单位。
3.协程:一种轻量级的线程,完全在unity主线程中执行,而例如Addressable的异步操作是在后台线程中进行的。