# Unity3d脚本

脚本是附加在游戏物体上用于定义游戏对象行为指令的代码,需要继承自 MonoBehaviour 类,Unity3d中文件名与类名必须一致。

在Unity3d中要创建脚本,需要把C#脚本转换成CLS(Common Language Specification),然后再经过Mono运行时转换为机器码。下面是C#用来打印调试信息的示例脚本:

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

public class TestDebug : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("调试信息1");
        print("调试信息2");
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 脚本生命周期

Unity3d官方对脚本声明周期有详细的介绍,可参考Unity3d脚本生命周期 (opens new window)

从Unity3d的周期图中看,它大体分为:

  1. 初始化阶段
  2. 物理碰撞处理
  3. 输入事件
  4. 游戏逻辑
  5. 场景渲染
  6. Gizmo渲染
  7. GUI渲染
  8. 帧结束
  9. 暂停
  10. 销毁处理

# 初始化阶段

该阶段主要包含四个函数:

  1. Awake:物体上挂载的脚本不管有没有被Enabled都会调用该函数,主要用于满足条件时激活脚本(this.enable=true)。
  2. OnEnable:该脚本被Enabled时调用该函数。
  3. Reset:在编辑器不运行时,当脚本被挂载时调用。
  4. Start:物体上挂载的脚本仅在被Enabled时调用该函数,常用于游戏逻辑初始化。

# 物理碰撞处理

如果固定Update时间小于每一帧的Update时间,物理碰撞处理会运行不只一轮。

  1. FixedUpdate:固定Update,可在Edit-->Project Setting-->Time-->Fixed Timestep来设置更新时间,默认为0.02s。
  2. 动画更新。
  3. OnTriggerXXX:满足触发条件时运行。
  4. OnCollisionXXX:满足碰撞条件时运行。
  5. yield WaitForFixedUpdate。

# 输入处理

这个阶段主要处理输入,比如:

  • OnMouseEnter:鼠标移入物体Collider时调用。
  • OnMouseOver:鼠标在物体Collider内时会一直调用。
  • OnMouseExit:鼠标离开Collider时调用。
  • OnMouseDown:鼠标按键按下时调用。
  • OnMouseUp:鼠标按键抬起时调用。

# 游戏逻辑

  1. Update:游戏每帧调用,每帧之间间隔时间不固定,它跟当前平台的帧数有关,而FixedUpdate是固定时间,在处理物理逻辑的时候应该放在FixedUpdate中。
  2. 协程处理:
    • yield null
    • yield WaitForSeconds
    • yield WWW
    • yield StartCoroutine
  3. 动画更新。
  4. LateUpdate:该函数在所有Update函数调用后调用,可用于跟随逻辑,比如一个摄像机跟随一个物体,这个摄像机的逻辑就可以放在这里面。

# 场景渲染

下面是场景渲染时运行的方法:

  1. OnWillRenderObject:如果对象可见,每个相机都会调用它。
  2. OnPreCull:在相机消隐场景之前被调用。
  3. OnBecameVisible:当Mesh Renderer在任何相机上可见时调用。
  4. OnBecameInvisible:当Mesh Renderer在任何相机上都不可见时调用。
  5. OnPreRender:在相机渲染场景之前被调用。
  6. OnRenderObject:在相机场景渲染完成后被调用。
  7. OnPostRender:在相机完成场景渲染之后被调用。
  8. OnRenderImage:当完成所有渲染图片后被调用,用来渲染图片后期效果。

# 其他处理

  1. OnDrawGizmos:Gizmo渲染
  2. OnGUI:GUI渲染
  3. yield WaitForEndOfFrame:每一帧结束
  4. OnApplicationPause:在帧的结尾处调用此函数(在正常帧更新之间有效检测到暂停)。在调用 OnApplicationPause 之后,将发出一个额外帧,从而允许游戏显示图形来指示暂停状态。

# 销毁处理

主要有三个方法:

  1. OnApplicationQuit:程序退出时调用。
  2. OnDisable:只在物体被Disabled时调用,再次被Enabled时调用OnEnable。
  3. OnDestroy:游戏对象或脚本被销毁时调用。

# 常用API

这里涉及到的几个类及其常用属性方法有:

  • Component
    • 常用属性:gameObject,transform,collider
    • 常用方法:GetComponent,GetComponentInChildren,GetComponentInParent
  • Transform
    • 常用属性:position,localPosition,parent,forward
    • 常用方法:Translate,Rotate,TransformPoint,Find,SetSiblingIndex
  • GameObject
    • 常用属性:transform,activeInHierarchy,activeSelf,tag
    • 常用方法:AddComponent,Find,FindGameObjectsWithTag
  • Object
    • 常用属性:name
    • 常用方法:FindObjectOfType,Instantiate,Destroy,FindObjectsOfType
  • Time,它的常用属性有:
    • time:从游戏开始运行到现在的时间
    • timeScale:时间缩放
    • deltaTime:每帧的间隔时间
    • unscaledDeltaTime:不受缩放的每帧间隔时间

# 脚本调试

有三种方法进行调试:

  1. 控制台打印:

    Debug.Log(var) print(var)

  2. 定义脚本共有变量,程序运行时在Inspector查看。

  3. Visual Studio 调试,在VS中设置断点,启动调试,在Unity3d中Play,进行调试。

# 预制件

预制件Prefab算是一种资源类型,可多次在场景中进行实例。使用它的好处是对预制件的修改能同步到所有实例,从而提高开发效率。

注意,如果单独修改实例的属性值,该实例的值将不再随着预制件变化而变化。

# Animation相关

可在Window->Animation打开动画视图,通过该视图可直接创建和修改动画片段(Animation Clips)。

# 录制动画

录制动画的步骤如下:

  1. 点击录制按钮,开始录制动画。
  2. 添加关键帧 Add Property,选择组件类型。
  3. 选择关键帧,调整时间点。
  4. 在 Scene 或 Inspector 面板设置属性。
  5. 点击录制按钮,结束录制动画。

注意:

  1. 任何组件以及材质的属性都可进行动画处理,即使是自定义脚本组件的公共变量。
  2. 时间线上数字显示为秒数和帧数,1:30表示1秒30帧。

# Animation组件

常用属性为:

  1. Animation:当前动画
  2. Animations:可从脚本访问的动画列表
  3. PlayAutomatically:是否启动游戏时自动播放动画

# Animation片段

在Debug模式下,Animation片段能设置动画结束的处理方式,就是WrapMode属性:

  • 默认 Default,使用动画剪辑中的处理方法;
  • 播放一次 Once,播放到头后停止;
  • 循环播放 Loop,播放到头后再重头播放;
  • 乒乓播放 PingPong,播放到头后再反向播放;
  • 固定永久 Clamp Forever,播放到头后永远播放最后一帧;

# API相关

下面是动画相关的常用API:

bool isPlay=animation.isPlaying;
bool isPlay=animation.IsPlaying("动画名");
animation.Play("动画名");
animation.PlayQueued("动画名");
animation.CrossFade ("动画名");
animation["动画名"].speed = 5;
animation["动画名"].wrapMode=WrapMode.PingPong;
animation["动画名"].length;
animation["动画名"].time;
1
2
3
4
5
6
7
8
9

# 输入相关

# InputManager

输入管理器可在Edit—>Project Settings—>Input处打开。使用脚本通过虚拟轴名称获取自定义键的输入,在游戏启动时可根据个人喜好对虚拟轴进行修改。

每个虚拟轴都有如下几个参数:

  • Descriptive Name :游戏加载界面中,正向按键的详细描述。
  • Descriptive Negative Name:游戏加载界面中,反向按键的详细描述。
  • Negative Button :该按钮会给轴发送一个负值 。
  • Positive Button:该按钮会给轴发送一个正值 。
  • Alt Negative Button:给轴发送负值的另一个按钮。
  • Alt Positive Button:给轴发送正值的另一个按钮。
  • Gravity:输入复位的速度,仅用于类型为 键/鼠标 的按键。
  • Dead:任何小于该值的输入值(不论正负值)都会被视为0,用于摇杆。
  • Sensitivity:灵敏度,对于键盘输入,该值越大则响应时间越快,该值越小则越平滑。对于鼠标输入,设置该值会对鼠标的实际移动距离按比例缩放。
  • Snap:如果启用该设置,当轴收到反向的输入信号时,轴的数值会立即置为0,否则会缓慢的应用反向信号值。仅用于键/鼠标输入。
  • Invert:启用该参数可以让正向按钮发送负值,反向按钮发送正值。
  • Type类型:
    1. 键/鼠标 (Key / Mouse)
    2. 鼠标移动和滚轮 (Mouse Movement)
    3. 摇杆 (Joystick Axis)
  • Axis:设备的输入轴(摇杆,鼠标,手柄等)。
  • Joy Num:设置使用哪个摇杆。默认是接收所有摇杆的输入。仅用于输入轴和非按键。

常用的API有:

bool result=Input.GetButton("虚拟轴名");
bool result=Input.GetButtonDown("虚拟轴名");
bool result=Input.GetButtonUp("虚拟轴名");
float value=Input.GetAxis("虚拟轴名");
float value=Input.GetAxisRaw("虚拟轴名");
1
2
3
4
5

# Input类

该类包装了输入功能的类,可以判断Input Manager中设置的按键,以及移动设备上的多点触控操作,加速感应数据。

# 鼠标相关

下面的数字中,0对应左键,1对应右键,2对应中键。

  • 当指定的鼠标按钮被按下时返回true:

    bool result=Input.GetMouseButton(0);

  • 在用户按下指定鼠标按键的第一帧返回true

    bool result= Input.GetMouseButtonDown(0);

  • 在用户释放指定鼠标按键的第一帧返回true

    bool result= Input.GetMouseButtonUp(0);

# 键盘相关

  • 当通过名称指定的按键被用户按住时返回true

    bool result=Input.GetKey(KeyCode.A);

  • 当用户按下指定名称按键时的那一帧返回true

    bool result=Input.GetKeyDown(KeyCode.A);

  • 在用户释放给定名称按键的那一帧返回true

    bool result=Input.GetKeyUp(KeyCode.A);