How to Develop a Game
MonoBehaviour
PublishDate: 2025-06-01 | CreateDate: 2025-06-01 | LastModify: 2025-06-01 | Creator:ljf12825

MonoBehaviour是Unity中最重要的基类之一,它是所有挂载到GameObject上的脚本的基础。每当在Unity编译器中创建也给C#脚本,并将其附加到一个GameObject时,这个脚本默认会继承MonoBehaviour

MonoBehaviour提供了一些非常强大的功能,尤其是在场景生命周期和事件处理方面

MonoBehaviour继承自Behaviour

Behaviour

Behaviour继承自Component,是MonoBehaviourRendererCollider等类的基类,它为所有脚本提供了一些通用的启用/禁用功能和调度机制

API

Properties

属性类型描述
enabledbool决定了当前Behaviour是否启用,当启用时,该组件会响应更新(如Update()等声明周期方法),禁用则不会
isActiveAndEnablebool是一个只读属性,返回当前组件是否被启用并且它的GameObject也启用

示例
enable用法

void Start()
{
    // 禁用这个脚本
    this.enabled = false;
}

void Update()
{
    if (this.enabled)
    {
        // 如果脚本启用,这部分代码才会执行
        Debug.Log("Script is enabled.");
    }
}

enable在继承时的行为
如果你继承自Behaviour,并且禁用该组件,那么Unity会停止调用该组件的方法。但是,如果Behaviour的父类被禁用,你仍然可以控制enable属性来启用或禁用某些组件行为

启用和禁用的实际应用

控制游戏对象的行为

例如在游戏中按下按钮时禁用某些功能或暂停某些操作

public class GameController : MonoBehaviour
{
    public GameObject player;

    void PauseGame()
    {
        // 禁用玩家脚本,暂停玩家控制
        player.GetComponent<PlayerController>().enabled = false;
    }

    void ResumeGame()
    {
        // 启用玩家脚本,恢复玩家控制
        player.GetComponent<PlayerController>().enabled = true;
    }
}
控制物体动画与行为
控制物理行为

MonoBehaviour

MonoBehaviour是Unity中最核心的类之一,它为游戏开发者提供了许多功能和特性,使得脚本能够与Unity引擎进行交互
通过继承MonoBehaviour,可以让自定义类称为Unity组件,并使用Unity引擎提供的生命周期方法、事件处理、协程支持等功能

MonoBehaviour会提供以下特性:

1.生命周期方法

MonoBehaviour提供了多个生命周期方法,让你能够在合适的时机执行代码。这些方法涵盖了Unity引擎中的许多重要事件,包括初始化、更新、碰撞检测等

生命周期函数示意图

初始化阶段(只执行一次)

初始化阶段的生命周期函数是游戏对象创建并激活后、正式开始游戏逻辑之前自动调用的一系列函数,主要用于初始化变量、加载资源、设置状态等操作

函数名调用时机用途特点
Awake()脚本实例被 加载 后立刻调用(即使对象未启用也会调用)初始化数据、引用等(最早)初始化非依赖其他组件的逻辑
OnEnable()对象启用时调用(每次启用都会调用脚本激活可以多次触发常用于注册事件
Start()所有对象的Awake()调用完后,在对象启用的第一帧调用一次初始化逻辑,如加载资源、启动协程初始化依赖其他组件/对象的逻辑

运行时循环阶段(重复执行)

函数名调用频率用途
FixedUpdate()每固定时间(如 0.02 秒)物理计算、施加力、碰撞检测等
Update()每帧常规逻辑、输入处理、状态更新
LateUpdate()每帧摄像机追踪、骨骼动画等需要晚一点处理的逻辑
OnGUI()每帧多次IMGUI 绘图接口,用于旧 GUI 系统(已不推荐)
关于Update()

在Update()中实现“时间无关”逻辑 由于帧率变化,直接写逻辑会导致游戏表现不同步
解决方法:

void Update()
{
    float moveSpeed = 5f;
    transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
}

常见用法 1.键盘输入控制移动

void Update()
{
    float h = Input.GetAxis("Horizontal");
    float v = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(h, 0, v);
    transform.Translate(dir * 5f * Time.deltaTime);
}

2.每帧检测条件触发事件

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space)) Jump();
}

性能注意事项

当关闭或禁用脚本时,Update()不会被调用,当GameObejct被禁用时,所有附加脚本的Update()都停止调用

关于LateUpdate()

典型用途

1.摄像机跟随

public class FollowTarget : MonoBehaviour
{
    public Transform target;

    void LateUpdate()
    {
        if (target != null)
        {
            transform.position = target.position + new Vector3(0, 5, -10);
        }
    }
}

2.骨骼/动画后处理

3.平滑插值(Smooth Follow)

void LateUpdate()
{
    transform.position = Vector3.Lerp(transform.position, target.position, Time.deltaTime * 5);
}

LateUpdate()是在每帧所有逻辑处理完之后调用的函数,适合做跟随、补偿、视觉同步、动画后处理等操作

关于FixedUpdate()

FixedUpdate()不一定每帧都调用,也可能在一帧内被调用多次(为了补上落后时间)

为什么物理逻辑必须放在FixedUpdate()

Unity的物理系统(Rigidbody、Collider等)是在物理引擎中执行的,它以固定步长(Fixed Timestep)计算模拟

如果你在Update()中对刚体施加力

void Update()
{
    rb.AddForce(Vector3.forward);
}

正确做法:

void FixedUpdate()
{
    rb.AddForce(Vector3.forward);
}
时间控制

默认情况下:

Time.fixedDeltaTime = 0.02f(每秒调用50次)

可以通过Edit > Project Setting > Time修改

示例:让角色持续向前移动(基于物理)

Rigidbody rb;

void Start() => rb = GetComponent<Rigidbody>();

void FixedUpdate() => rb.MovePosition(rb.position + Vector3.forward * 5f * Time.fixedDeltaTime);

注意事项 1.不要在FixedUpdate()中检测Input.GetKey()
因为输入每帧更新,可能miss

2.与物理系统交互统一放在FixedUpdate()
避免不一致和jitter

3.可能一帧内调用多次FixedUpdate() 这是为了追上物理时间进度

碰撞/触发事件

发生在物理更新阶段(即FixedUpdate()阶段)之后调用,调用频率和FixedUpdate()一致,不受帧率的影响

Rigidbody + Collider才能触发以下函数

函数名用途
OnCollisionEnter(Collision col)碰撞开始
OnCollisionStay(Collision col)碰撞持续
OnCollisionExit(Collision col)碰撞结束
OnTriggerEnter(Collider col)触发器进入
OnTriggerStay(Collider col)触发器内持续
OnTriggerExit(Collider col)触发器离开

Unity物理系统

渲染阶段

阶段用途
OnPreRender()摄像机开始渲染前
OnRenderObject()所有对象渲染时
OnPostRender()摄像机完成渲染后
OnWillRenderObject()对象将被摄像机渲染前
OnDrawGizmos() / OnDrawGizmosSelected()编辑器中画 Gizmos

禁用/销毁阶段

函数名说明
OnDisable()脚本被禁用时调用(如 enabled = falseSetActive(false)
OnDestroy()脚本被销毁前调用,用于释放资源、停止协程等

应用生命周期事件

函数名说明
OnApplicationPause(bool pause)应用暂停/恢复时调用(如手机切后台)
OnApplicationFocus(bool focus)是否获得焦点(如切到其他应用)
OnApplicationQuit()应用关闭前调用

自定义生命周期顺序

Unity默认调用顺序无法改变(例如A的Awake总在B前),但可以手动更改执行顺序

方法一:Inspector设置执行顺序

菜单栏:Edit > Project Settings > Script Execution Order
把关键脚本设置为更早或更晚执行

方法二:代码显示调用(推荐)

void Awake()
{
    manager = FindObjectOfType<GameManager>();
    manager.Register(this);
}

2.协程(Coroutine)

MonoBehaviour提供了对协程的支持,协程允许你在多个帧之间暂停执行某些代码,而不会阻塞主线程。使用协程,你可以轻松实现延迟、定时任务、动画过渡等功能 Coroutine

3.输入处理

Input-System

4.物理与碰撞

Physics-System

5.组件管理

可以使用GetComponentAddComponent等方法来访问和控制其他组件。例如,获取物体的Rigidbody`组件或添加新的组件

Rigidbody rb = GetComponent<Rigidbody>(); // 获取组件
rb.AddForce(Vector3.up * 10f); // 应用力

// 动态添加组件
gameObject.AddComponent<BoxCollider>();

6.MonoBehaviour特性

7.其他功能