前置知识:本教程假设你已了解 C# 基本语法(变量、方法、类)。如需回顾,可参考系列中的 C# 学习笔记文章。
4.1 创建第一个脚本
在 Project 面板中:右键 → Create → C# Script,命名为 PlayerMovement。
双击打开脚本,默认内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class PlayerMovement : MonoBehaviour { void Start() { }
void Update() { } }
|
所有 Unity 脚本都继承自 MonoBehaviour。
4.2 MonoBehaviour 生命周期
Unity 按照固定顺序自动调用以下方法:
初始化阶段
1
| Awake() → OnEnable() → Start()
|
| 方法 |
调用时机 |
用途 |
Awake() |
对象加载时立即调用(无论脚本是否启用) |
初始化引用、设置变量 |
OnEnable() |
对象每次变为启用状态时 |
注册事件、订阅消息 |
Start() |
第一次 Update 之前,且脚本已启用 |
初始化依赖其他对象的数据 |
更新阶段
1
| FixedUpdate() → Update() → LateUpdate()
|
| 方法 |
调用频率 |
用途 |
FixedUpdate() |
固定时间间隔(默认 0.02s) |
物理更新(刚体、力) |
Update() |
每帧调用,频率不固定 |
常规逻辑(输入检测、状态更新) |
LateUpdate() |
Update 之后每帧调用 |
摄像机跟随等需要在所有更新后执行的操作 |
销毁阶段
1
| OnDisable() → OnDestroy()
|
| 方法 |
调用时机 |
用途 |
OnDisable() |
对象被禁用时 |
取消订阅、释放资源 |
OnDestroy() |
对象被销毁时 |
最终清理 |
4.3 Time 相关 API
1 2 3 4 5 6 7 8 9 10 11 12
| float delta = Time.deltaTime;
float fixedDelta = Time.fixedDeltaTime;
float totalTime = Time.time;
Time.timeScale = 0; Time.timeScale = 2;
|
使用 Time.deltaTime 保证帧率独立
1 2 3 4 5
| transform.Translate(0, 0, 1);
transform.Translate(0, 0, 1 * Time.deltaTime);
|
4.4 Debug 与日志
1 2 3 4 5 6 7 8 9 10
| Debug.Log("普通日志信息"); Debug.LogWarning("警告信息"); Debug.LogError("错误信息");
Debug.DrawLine(startPos, endPos, Color.red); Debug.DrawRay(origin, direction, Color.green);
Debug.Break();
|
4.5 公开变量的序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class PlayerMovement : MonoBehaviour { public float moveSpeed = 5f; [SerializeField] private int health = 100; [HideInInspector] public int score; [Range(0, 10)] public float jumpForce = 5f; [Tooltip("角色的移动速度,单位:米/秒")] public float speed = 5f; }
|
4.6 本章小结
- Unity 脚本继承
MonoBehaviour,有固定的生命周期调用顺序
Awake → Start → Update/FixedUpdate/LateUpdate → OnDestroy
Update 不固定帧率,需乘以 Time.deltaTime 保证一致性
FixedUpdate 固定间隔,适合物理运算
- 使用
[SerializeField]、[Range]、[Tooltip] 属性美化 Inspector
练习题
- 创建一个脚本,在 Start 中输出 “Game Started”,在 Update 中每帧输出当前时间
- 将
moveSpeed 设为 public 并在 Inspector 中修改数值
- 在 Update 中使用
transform.Translate 沿 Z 轴移动,观察是否乘以 Time.deltaTime 的区别
- 尝试使用
Time.timeScale = 0 实现暂停效果