Skip to content

unity-script-system

基础概念

Unity 的脚本系统,你可以先理解成:

脚本就是你写的 C# 组件,用来控制 GameObject 的行为。

Unity 里不是“写一个 main 函数,然后程序从 main 开始跑”。 Unity 的逻辑是:你把脚本挂到某个 GameObject 上,Unity 在合适的时机自动调用脚本里的函数。

1. 脚本本质上也是 Component

比如你写一个脚本:

c
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    void Update()
    {
        Debug.Log("玩家正在运行逻辑");
    }
}

这个 PlayerController 继承了 MonoBehaviour,所以它就可以挂到 GameObject 上。

挂上去后,它就变成这样:

c
Player
├─ Transform
├─ SpriteRenderer
├─ Rigidbody2D
├─ Collider2D
└─ PlayerController

也就是说: 脚本不是独立运行的代码文件,而是一个挂在对象身上的行为组件。

2. MonoBehaviour 是 Unity 脚本的核心基类

大多数 Unity 脚本都会这样写:

c
public class MyScript : MonoBehaviour
{
}

MonoBehaviour 给了你很多 Unity 特有能力,比如:

  • 可以挂到 GameObject 上
  • 可以使用 Start()
  • 可以使用 Update()
  • 可以访问 transform
  • 可以使用 GetComponent
  • 可以启用/禁用脚本
  • 可以接收碰撞、触发、鼠标、生命周期事件

如果一个类没有继承 MonoBehaviour,它通常就不能直接挂到 GameObject 上。

3. 脚本生命周期:Unity 自动调用这些函数

这是脚本系统最重要的部分。

常用生命周期顺序大概是:

c
Awake()

OnEnable()

Start()

Update()

LateUpdate()

OnDisable()

OnDestroy()

再加一个物理专用的:

c
FixedUpdate()

你可以这样理解:

函数什么时候执行常见用途
Awake()对象加载时最早执行初始化内部变量、获取组件
OnEnable()脚本/对象启用时执行监听事件、重置状态
Start()第一次 Update 前执行一次依赖其他对象初始化后的逻辑
Update()每帧执行一次输入、普通逻辑、计时
FixedUpdate()固定时间间隔执行物理移动、Rigidbody 操作
LateUpdate()Update 后执行摄像机跟随、收尾逻辑
OnDisable()脚本/对象禁用时执行取消监听、暂停逻辑
OnDestroy()对象销毁时执行清理资源

最常见的新手组合是:

c
void Awake()
{
    // 获取组件
}

void Start()
{
    // 初始化游戏开始状态
}

void Update()
{
    // 每帧检查输入
}

void FixedUpdate()
{
    // 处理物理移动
}

4. Update 和 FixedUpdate 的区别

这个特别重要。

Update() 是每一帧执行一次。 如果电脑性能高,一秒可能执行 120 次;性能低,可能一秒执行 30 次。

适合放:

  • 键盘输入
  • 鼠标输入
  • UI 检查
  • 普通逻辑
  • 动画状态判断
  • 倒计时

例如:

c
void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        Debug.Log("按下空格");
    }
}

FixedUpdate() 是固定时间执行,默认大约每秒 50 次。 适合放物理相关逻辑。

比如:

c
void FixedUpdate()
{
    rb.linearVelocity = new Vector2(moveX * speed, rb.linearVelocity.y);
}

简单记:

输入放 Update,物理放 FixedUpdate。

5. transform 是最常用的内置引用

只要脚本挂在某个 GameObject 上,你就可以直接用:

c
transform

它代表当前对象的 Transform 组件。

例如:

c
void Update()
{
    transform.position += new Vector3(1, 0, 0) * Time.deltaTime;
}

这表示:当前对象每秒往右移动一点。

注意这里用了:

c
Time.deltaTime

它表示上一帧到这一帧经过了多少秒。 移动、计时、平滑变化时经常要用它,否则不同帧率下速度会不一样。

6. Inspector 参数:让脚本变得可调

比如:

c
public float speed = 5f;

这个字段会出现在 Inspector 面板里。

更推荐这样写:

c
[SerializeField] private float speed = 5f;

意思是: 代码里保持 private,但 Unity Inspector 里仍然能调。

完整例子:

c
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private float speed = 5f;

    void Update()
    {
        float x = Input.GetAxisRaw("Horizontal");
        transform.position += new Vector3(x, 0, 0) * speed * Time.deltaTime;
    }
}

这样你不用改代码,就可以在 Unity 里调整玩家速度。

7. 脚本怎么访问组件

假设 Player 身上有 Rigidbody2D,脚本也挂在 Player 上。

c
Player
├─ Rigidbody2D
└─ PlayerController

脚本里可以这样拿到它:

c
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Rigidbody2D rb;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }
}

核心是:

c
GetComponent<Rigidbody2D>();

意思是: 从当前 GameObject 身上找到 Rigidbody2D 组件。

常用方式:

c
GetComponent<T>()              // 找自己身上的组件
GetComponentInChildren<T>()    // 找子对象里的组件
GetComponentInParent<T>()      // 找父对象里的组件

新手更推荐 Inspector 拖拽引用:

c
[SerializeField] private Rigidbody2D rb;

然后在 Inspector 里把对象拖进去。

8. 一个完整的玩家移动脚本

2D 示例:

c
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private float speed = 5f;

    private Rigidbody2D rb;
    private float moveX;

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        moveX = Input.GetAxisRaw("Horizontal");
    }

    void FixedUpdate()
    {
        rb.linearVelocity = new Vector2(moveX * speed, rb.linearVelocity.y);
    }
}

这里发生了什么:

c
Awake       获取 Rigidbody2D
Update      读取键盘输入
FixedUpdate 控制物理速度

这就是比较标准的脚本分工。

9. 碰撞和触发事件

如果对象身上有 Collider,Unity 可以自动调用碰撞函数。

3D 常用:

c
void OnCollisionEnter(Collision collision)
{
    Debug.Log("撞到了:" + collision.gameObject.name);
}

2D 常用:

c
void OnCollisionEnter2D(Collision2D collision)
{
    Debug.Log("撞到了:" + collision.gameObject.name);
}

如果 Collider 勾选了 Is Trigger,用触发函数:

c
void OnTriggerEnter2D(Collider2D other)
{
    Debug.Log("进入触发区:" + other.gameObject.name);
}

简单区别:

类型是否会挡住物体常见用途
Collision会真实碰撞地面、墙、箱子
Trigger不阻挡,只检测进入金币、传送门、检测区

10. 实例化和销毁对象

脚本可以动态创建对象,比如生成子弹、敌人、特效。

c
[SerializeField] private GameObject bulletPrefab;
[SerializeField] private Transform firePoint;

void Shoot()
{
    Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
}

销毁对象:

c
Destroy(gameObject);

其中:

c
gameObject

代表当前脚本挂着的那个 GameObject。

11. 协程 Coroutine:延迟和分步骤执行

如果你想“等 2 秒后再做某事”,可以用协程。

c
using System.Collections;
using UnityEngine;

public class Example : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(WaitAndPrint());
    }

    IEnumerator WaitAndPrint()
    {
        Debug.Log("开始等待");
        yield return new WaitForSeconds(2f);
        Debug.Log("2 秒后执行");
    }
}

协程常用于:

  • 延迟执行
  • 技能冷却
  • 波次刷怪
  • 渐隐渐现
  • 分阶段动画逻辑

12. 脚本之间怎么通信

常见方式有三种:

第一种:直接拖引用。

c
[SerializeField] private Health health;

void Attack()
{
    health.TakeDamage(10);
}

第二种:GetComponent

c
Health health = GetComponent<Health>();
health.TakeDamage(10);

第三种:事件系统。

适合稍微进阶后学习,比如玩家死亡通知 UI、音效、任务系统。

新手阶段先掌握前两种就够了。

13. 常见脚本分类

做游戏时,脚本通常会分成几类:

脚本类型例子负责什么
控制脚本PlayerController玩家输入、移动、跳跃
状态脚本Health血量、死亡
生成脚本EnemySpawner刷怪、生成道具
管理脚本GameManager游戏流程、胜负
UI 脚本UIManager血条、分数、按钮
数据脚本ItemData道具、技能、配置
摄像机脚本CameraFollow跟随玩家

一个好习惯是: 一个脚本只负责一类清晰的事情。

14. 新手最容易犯的错误

第一,脚本文件名和类名不一致。

文件叫:

c
PlayerController.cs

类名也应该是:

c
public class PlayerController : MonoBehaviour

第二,脚本没有挂到 GameObject 上。 只写了代码,但没有拖到对象上,Unity 不会执行。

第三,把物理移动写在 Update 里。 物理对象建议用 Rigidbody,并在 FixedUpdate 中处理。

第四,到处使用 Find()GameObject.Find() 能用,但频繁使用会乱、慢、难维护。

第五,一个脚本写太多功能。 比如 PlayerController 里同时写移动、血量、背包、UI、存档,后面会很难改。

15. 建议你的学习顺序

你可以按这个路线练:

  1. 写一个脚本,让 Cube 每秒向右移动。
  2. [SerializeField] 把速度显示到 Inspector。
  3. 用键盘控制 Cube 左右移动。
  4. GetComponent 获取 Rigidbody2D
  5. FixedUpdate 控制物理移动。
  6. 写碰撞检测,碰到金币后销毁金币。
  7. Instantiate 生成子弹。
  8. Destroy 销毁子弹。
  9. 写一个 Health 脚本控制血量。
  10. 写一个 GameManager 管理胜利和失败。

你可以把 Unity 脚本系统记成这句话:

脚本系统 = MonoBehaviour 生命周期 + Inspector 参数 + 组件访问 + 输入/物理/碰撞/生成逻辑。

掌握这几个,你就能开始真正控制游戏世界了。

参考链接

脚本系统

文章评价

读完这篇,留下你的看法

暂无审核通过的评价。

登录账号后才能评价。

本站访客数0总站访问量0本页访问量0