欢迎回来! 今天我们来搞定 Unity 里一个必须掌握的核心概念------生命周期函数。 很多初学者在这里卡壳,学完这篇你就彻底懂了!
一、什么是生命周期函数?
你可以把一个 Unity 脚本想象成一个员工的职业生涯:
入职第一天 → Awake() 背好工牌,认识自己的工位
开始上班 → Start() 开晨会,了解今天的任务
每天上班 → Update() 日常工作,每天都做
体检日 → FixedUpdate() 固定时间做固定的事
下班前 → LateUpdate() 收尾工作,等别人都做完再做
离职 → OnDestroy() 交接工作,离开公司
这个比喻贯穿全文,记住它,生命周期就懂了。
Awake --- "入职第一天"
cs
void Awake()
{
Debug.Log("游戏初始化")
}
Awake 做一件事:认识自己。
- 脚本一创建,立刻执行,哪怕组件是关闭状态
- 只跑一次
- 这里做什么?获取自身组件、初始化自己的变量
常见错误:
- 在 Awake 里去调用另一个脚本的数据。
- 这很危险!因为你不知道对方的 Awake 有没有跑完。
- 自己的事 Awake 做,依赖别人的事交给 Start!
Start --- "开始上班第一天"
cs
void Start()
{
Debug.Log("游戏开始,当前血量:" + hp);
}
Start 做一件事:和别人打招呼。
- 在第一帧 Update 之前执行
- 此时所有脚本的 Awake 都已经跑完了
- 只跑一次
- 这里做什么?依赖其他脚本的初始化、打印调试信息
一句话区分 Awake 和 Start:
- Awake → 管好自己
- Start → 联系别人
Update --- "每天上班"
cs
void Update()
{
float h = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * h * speed * Time.deltaTime);
}
Update 是你用得最多的函数,没有之一。
- 每帧执行一次,游戏运行期间一直循环
- 帧率是不固定的(手机可能 30fps,PC 可能 144fps)
- 所以移动必须乘
Time.deltaTime,否则帧率越高跑得越快!
Update 适合做什么:
✅ 键盘 / 鼠标输入检测
✅ 直接修改 Transform 的移动
✅ UI 数值更新
✅ 计时器
❌ 物理运算(会抖!)
Time.deltaTime 是什么?
- 就是上一帧到这一帧经过了多少秒。
- 60fps 时约等于 0.016 秒,30fps 时约等于 0.033 秒。
- 乘上它之后,不管帧率高低,每秒移动距离都一样
FixedUpdate --- "固定体检日"
cs
void FixedUpdate()
{
rb.AddForce(Vector3.forward * 10f);
}
FixedUpdate 是专门给物理引擎准备的。
- 以固定时间间隔 执行,默认 0.02秒一次(50次/秒)
- 和帧率完全无关
- 不需要乘
Time.deltaTime(用Time.fixedDeltaTime如需要)
FixedUpdate 适合做什么:
✅ Rigidbody 施力 AddForce
✅ 物理驱动的移动 MovePosition
✅ 需要和碰撞体交互的运动
❌ 输入检测(会丢帧!按键可能被跳过)
为什么输入不能放 FixedUpdate?
假设游戏跑 60fps,Update 每帧都能检测到按键。但 FixedUpdate 只有 50次/秒,有些帧根本不执行,GetKeyDown 触发的瞬间可能直接被跳过!
LateUpdate --- "下班前收尾"
cs
void LateUpdate()
{
// 等物体移动完,摄像机再跟过来
cam.position = transform.position + offset;
}
LateUpdate 是"等所有人做完我再做"。
- 每帧执行,但在所有 Update 之后
- 保证你看到的是"这帧结束时"的最终状态
LateUpdate 适合做什么:
✅ 摄像机跟随(最经典用法)
✅ 依赖其他脚本Update结果的逻辑
摄像机为什么要放 LateUpdate?
如果摄像机和角色都在 Update 里,执行顺序不确定,摄像机可能先跑 ,角色还没动,摄像机就已经跟了个寂寞。放 LateUpdate,角色动完,摄像机再跟,丝滑!
执行顺序总览
游戏启动
|
Awake()只跑一次
|
Start()只跑一次
|
游戏循环[ FixedUpdate()0.2秒执行一次,Update() 每帧执行,LateUpdate()每帧Update后]
|
OnDestroy() 销毁时,只跑一次
二、脚本实现
经过上面的所有学习之后那么我们来完成我们的脚本代码吧!
首先我们设置移动速度与跳跃高度
cs
[Header("移动参数")]
public float moveSpeed = 5f; // 移动速度
[Header("物理参数")]
public float jumpForce = 5f; // 跳跃冲量
[Header] 是 Unity 的一个特性(Attribute),作用很简单:
在 Inspector 面板里,给变量分组加上标题文字。

然后我们在定义私有变量用于获取物理组件等
cs
// 私有变量
private Rigidbody rb; // 刚体组件引用
private Vector3 inputDir; // 本帧的输入方向(Update写,FixedUpdate读)
private bool jumpRequest; // 跳跃请求标记(Update写,FixedUpdate读)
接下来我们在初始化 Awake()获取我们的刚体组件,如果获取不到就向控制台发送信息
cs
void Awake()
{
rb = GetComponent<Rigidbody>();
if (rb == null)
{
Debug.LogError("【PhysicsMoveDemo】请在该物体上添加 Rigidbody 组件!");
}
}
初始化完成后Start()我们也向控制台发送完成信息
cs
void Start()
{
Debug.Log("【Start】脚本初始化完成,初始位置:" + transform.position);
}
在每帧运行时Update()我们都要获取我们的玩家键盘键输入并且实现移动和跳跃等逻辑
cs
void Update()
{
// --- 1. 读取键盘输入 ---
float h = Input.GetAxis("Horizontal"); // A/D 左右
float v = Input.GetAxis("Vertical"); // W/S 前后
// normalized 防止斜向移动速度叠加变快(斜向本来是 √2 ≈ 1.41 倍)
inputDir = new Vector3(h, 0, v).normalized;
// --- 2. 非物理移动
transform.Translate(inputDir * moveSpeed * Time.deltaTime, Space.World);
// --- 3. 跳跃请求:GetKeyDown 必须在 Update 里检测,防止 FixedUpdate 漏帧 ---
if (Input.GetKeyDown(KeyCode.Space))
{
jumpRequest = true; // 先记录请求,在 FixedUpdate 里执行
}
}
在这里先说明一下
非物理移动:直接操作 Transform(适合无 Rigidbody 的物体)
物理驱动移动:使用 MovePosition(比直接改 position 更稳定)
如果同时有 Rigidbody,Transform 和物理会冲突,二选一即可,现在这里写的是非物理移动
接下来我们就要编写物理帧执行的代码,比如物理移动,跳跃执行等
cs
void FixedUpdate()
{
// --- 1. 物理驱动移动
// Time.fixedDeltaTime 固定为 0.02s,也可以不乘(效果一样,写上更规范)
Vector3 nextPos = rb.position + inputDir * moveSpeed * Time.fixedDeltaTime;
rb.MovePosition(nextPos);
// --- 2. 执行跳跃:ForceMode.Impulse = 瞬间冲量,适合跳跃 ---
if (jumpRequest)
{
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
jumpRequest = false; // 重置标记,防止连续跳
}
}
最后在所有 Update 执行完毕后LateUpdate()
cs
void LateUpdate()
{
// 此处预留摄像机跟随逻辑
// 示例:Camera.main.transform.position = transform.position + new Vector3(0, 5, -8);
}
接下来我们挂载脚本到物体上吧,别忘啦如果使用的是物理驱动的移动方式需要给物体加上刚体组件哦,接下来看运行结果

今天的内容就到这里! 接下来我将连续更新90天的Untiy教程从基础到一个网络部分,有兴趣的朋友们可以收藏关注,谢谢!如果有疑问,评论区见。