Skip to content

Unity脚本

L edited this page Sep 7, 2019 · 15 revisions

脚本是附加在游戏物体上用于定义游戏对象行为的指令代码
unity脚本在执行时是单线程的
Unity支持三种高级编程语言:C#/JavaScript

语法结构

using UnityEngine;
using 其他命名空间;

public class 类名 : MonoBehaviour
{
    void 方法名()
    {
        Debug.Log("调试显示信息");
    }
}

文件名和类名必须一致
写好的脚本必须附加在物体上才执行,物体会创建一个这个脚本的类对象
附加到游戏物体的脚本类必须从MonoBehaviour类继承

Unity模板脚本

C:\Program Files\Unity\Editor\Data\Resources\ScriptTemplates
可以进行编辑
比如 81-C# Script-NewBehaviourScript.cs.txt

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class #SCRIPTNAME# : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        #NOTRIM#
    }

    // Update is called once per frame
    void Update()
    {
        #NOTRIM#
    }
}

脚本与Unity编辑器

1.脚本里面的public变量会显示在编辑器里面
1
2
tips:在类文件中设置Test=100;在Unity编辑器中设置Test=200,最终得到Test=200
因为Test是对象的字段,在Unity编辑器中操作的是对象
2.脚本中的private变量,可以通过[SerializeField]可以被Unity编辑器访问
即该变量希望被Unity编辑器访问,不希望被其他类访问
6
7
3.希望脚本中的public变量不被编辑器访问
使用[HideInInspector]特性
4.希望给变量加范围

[Range(0,120)]
public int Test4;

规范

1.编辑器不区分首字母大小写,在编辑器中不显示属性
不建议使用私有字段和属性结合的方式写,直接写字段
2.不能在子线程中访问主线程成员->构造函数中不能访问Unity提供的功能->在脚本中通常不写构造函数
而且Unity会调用两次构造函数,不符合预期

挂载多个脚本

当挂载多个脚本,且脚本之间有依赖关系,使用[RequireComponent]

public RequireComponent(Type requiredComponent);

QQ图片20190907091330
这样在Inspector里面只用挂载最后一个依赖脚本,其他的脚本自动挂载
链接

脚本生命周期

Unity脚本从唤醒到销毁的过程
消息/必然事件:当满足某条件Unity引擎自动调用的函数
生命周期=消息/必然事件
视频链接
完整的生命周期,看官网
生命周期图
20190427103124813
下面是比较重要的生命周期

初始阶段

初始化,用Awake和Start代替构造函数
1.Awake 唤醒 当物体载入时立即调用1次,常用于在游戏开始前进行初始化
执行时机:游戏物体创建->立即执行Awake(早于Start)
禁用物体时,不执行Awake;不禁用物体,禁用脚本时,会执行Awake 可以判断当满足某条件时启动当前脚本

//关系是否启动该脚本,是否执行Start和OnEnable    
this.enabled = true;

2.Start 物体载入且脚本对象启用时被调用1次,常用于数据或者游戏逻辑初始化
执行时机:游戏物体创建->脚本启动->执行Start
禁用物体时,不执行Start;不禁用物体,禁用脚本时,不执行Start
tips:
a.先执行Awake再执行Start
在所有物体的Awake执行完成后,再执行所有物体的Start
->初始化游戏数据,可以通过Awake和Start方法来区分先后顺序
b.仅初始化的时候执行一次,脚本从禁用到启动不再执行Awake和Start
3.OnEnable
执行时机:每当脚本对象启用时执行

物理阶段

1.FixedUpdate 固定更新
执行时机:脚本启用后,每隔固定时间被调用 适用性:适用于对游戏对象做物理操作,比如移动等
不会受到渲染影响(渲染时间不固定:每帧渲染工作量不同、机器性能不同)
设置更新频率:Edit->Project Setting->Time->Fixed Timespan
默认值为0.02s,不建议修改,改大了失真,改小了增大消耗
2.OnCollisionXXX 碰撞
当满足碰撞条件时调用
3.OnTriggerXXX 触发
当满足触发条件时调用

游戏逻辑

1.Update 脚本启用后,每次渲染场景时调用,频率和设备性能与渲染量有关
执行时机:渲染帧执行,执行间隔不固定
适用性:处理游戏逻辑(有些游戏也会把FixedUpdate的工作放到Update中执行)
tips:注意与FixedUpdate的区别
2.LateUpdate 延迟更新
在Update函数被调用后执行,适用于跟随逻辑
LateUpdate与Update在同一帧执行,在Update后面执行
eg.人物移动(Update),摄像机跟随(LateUpdate)

输入事件

注意物体必须有Collider(碰撞器)

OnMouseEnter 鼠标移入

鼠标移入当前Collider时调用

OnMouseOver 鼠标经过

鼠标经过当前Collider时调用

OnMouseExit 鼠标离开

鼠标离开当前Collider时调用

OnMouseDown 鼠标按下

鼠标按下当前Collider时调用

OnMouseUp 鼠标抬起

鼠标在当前Collider抬起时调用

Input类

链接
包装了输入功能的类,可以读取输入管理器中设置的按键,以及访问移动设备的多点触控或加速感应数据
建议在Update()中监控用户的输入(建议用事件机制替换在Update()中判断的方式)
1.获得键盘输入

//button:0-左键,1-右键,2-中键

//指定的鼠标按钮被按下时返回true(持续)
public static bool GetMouseButton(int button);
//用户按下指定鼠标按钮的第一帧返回true
public static bool GetMouseButtonDown(int button);
//用户释放指定鼠标按钮的第一帧返回true
public static bool GetMouseButtonUp(int button);

//eg.
bool result= Input.GetMouseButton(0);

2.获得键盘输入

//类似GetMouseButton/GetMouseButtonDown/GetMouseButtonUp
public static bool GetKey(KeyCode key);
public static bool GetKeyDown(KeyCode key);
public static bool GetKeyUp(KeyCode key);
public static bool GetKey(string name);
public static bool GetKeyDown(string name);
public static bool GetKeyUp(string name);

注意键盘左右两边的重复按键在KeyCode中有区分

KeyCode.LeftControl
KeyCode.RightControl

两个按键同时检测,取&&

场景渲染

前提是该物体必须有Mesh Render
1.OnBecameVisible 当可见
当Mesh Render在任何相机上可见时调用
2.OnBecameInvisible 当不可见
当Mesh Render在任何相机上不可见时调用

结束阶段

1.OnDisable 当不可用
对象变为不可用或者附属游戏对象非激活状态时此函数被调用
每次物体被禁用都会调用OnDisable
2.OnDestroy 当销毁
当脚本销毁或附属的游戏对象被销毁时被调用
3.OnApplicationQuit 当程序结束
应用程序退出时被调用

/// <summary>
/// 生命周期/消息/必然事件
/// </summary>
public class Lifecycle : MonoBehaviour
{
    /******************************************初始化阶段****************************************************/
    //执行时机:游戏物体创建->立即执行Awake(早于Start)
    //作用:初始化,代替构造函数 
    //仅初始化的时候执行一次
    private void Awake()
    {
        //可以判断当满足某条件时启动当前脚本
        //关系是否启动该脚本,是否执行Start和OnEnable       
        //this.enabled = true;
        //Debug.Log($"Awake:{Time.time} {this.name}");
    }

    //执行时机:游戏物体创建->脚本启动->执行Start
    //作用:初始化,代替构造函数 
    //仅初始化的时候执行一次
    private void Start()
    {
        Debug.Log($"Start:{Time.time} {this.name}");
    }

    //执行时机:每当脚本对象启用时执行  
    private void OnEnable()
    {
        //Debug.Log($"OnEnable:{Time.time} {this.name}");
    }

    /******************************************************物理阶段*************************************************/
    //执行时机:每隔固定时间执行一次(时间可修改)
    //适用性:适合对物体做物理操作(移动、旋转等),不会受到渲染影响(渲染时间不固定:每帧渲染工作量不同、机器性能不同) 
    private void FixedUpdate()
    {
        //Debug.Log($"FixedUpdate:{Time.time} {this.name}");
    }

    //碰撞事件
    private void OnCollisionEnter(Collision collision)
    {

    }

    //触发事件
    private void OnTriggerEnter(Collider other)
    {
        
    }

    /******************************************************游戏逻辑阶段*************************************************/
    //执行时机:渲染帧执行,执行间隔不固定
    //适用性:处理游戏逻辑
    private void Update()
    {
        
    }

    //在Update函数被调用后执行,适用于跟随逻辑
    private void LateUpdate()
    {
        
    }

    /******************************************************输入阶段*************************************************/
    //鼠标移入
    private void OnMouseEnter()
    {
        
    }
    //鼠标经过
    private void OnMouseOver()
    {
        
    }
    //鼠标离开
    private void OnMouseExit()
    {
        
    }
    //鼠标按下
    private void OnMouseDown()
    {
        Debug.Log("OnMouseDown");
    }
    //鼠标抬起
    private void OnMouseUp()
    {
        
    }

    /******************************************************场景渲染阶段*************************************************/
    //当Mesh Render在任何相机上可见时调用
    private void OnBecameVisible()
    {
        
    }
    //当Mesh Render在任何相机上不可见时调用
    private void OnBecameInvisible()
    {
        
    }

    /******************************************************结束阶段*************************************************/
    //对象变为不可用或者附属游戏对象非激活状态时此函数被调用
    //每次物体被禁用都会调用OnDisable
    private void OnDisable()
    {
        
    }
    //当脚本销毁或附属的游戏对象被销毁时被调用
    private void OnDestroy()
    {
        
    }
    //应用程序退出时被调用
    private void OnApplicationQuit()
    {
        
    }
}

调试

将程序投入实际运行中,通过开发工具进行测试,修正逻辑错误的过程

使用Unity编辑器

1.控制台调试

Debug.Log("");
print("");

2.定义共有变量(前端显示的变量),程序运行后在监测面板(Inspector)查看数据
适用于数据变化快的,想查看规律的变量
tips:最后发布游戏前,记住删除Debug.Log/Debug变量
3.创建按钮在界面上点击调用

private void OnGUI()
{
    if (GUILayout.Button("按钮"))
    {
        //调用测试方法
    }
}

使用VS

链接
准备工作
1.安装VS,Unity
2.在Unity项目面板中导入VS Tools
调试步骤
1.打断点
2.VS中启动调试(Attach to Unity)
3.在Unity中Play场景

Clone this wiki locally