基础知识
快捷键
工作原理
反射机制和游戏场景
GameObject
类对象存在于游戏场景中的所有对象里,是最最基础的对象;
向GameObject
对象添加各种各样的组件(其实就是C#脚本),来使各个对象有不同的功能;
Unity通过反射new
出挂在GameObject
上C#脚本的对象,并让脚本对象与GameObject
关联;
游戏场景本质是YAML配置文件
预设体(预制体)
预先设置好的物体,相当于模板
将场景中,由多个对象组成的单个对象,可以变为预设体
创建方法
直接将此物体(SimpleObject
)拖到Project
窗口的文件夹内就可以生成预设体
使用
可以直接拖入场景使用
修改
修改预设体后,选中预设体,在Inspector
窗口中单击Overrides
,点击Apply
或Apply All
就可以完成修改
修改过后,所有预设体实例同步更新
单独编辑
右键open
可以单独编辑预设体
脚本基础
MonoBehavior类
只有继承了这个类,才能挂载在
GameObject
上;继承了这个类的子类不能
new
;使用
DisallowMultipleComponent
特性可以使该脚本只能在同一物体上挂一次;遵循面向对象继承多态原则;
不继承Mono类
不能挂在
GameObject
上;使用时需要自己
new
;一般为单例模式的类(用于管理)或者数据结构类(用于存储数据);
执行先后顺序
脚本右上角Execution Order...
可以管理脚本执行的先后顺序
生命周期函数
一般为
private
和protected
;依附的对象取消激活后,所有的生命周期函数都会暂停;
生命周期函数可以继承,支持多态;
如果生命周期函数没有写逻辑,就不要写该生命周期函数,会造成额外开销;
Awake
当该脚本对象被创建时调用,且只调用一次,类似构造函数
void Awake()
{
}
OnEnable
依附的对象被激活时调用,当一个对象被激活时,进行逻辑处理
void OnEnable()
{
}
Start
第一次帧更新之前调用,只能调用一次,比Awake晚执行
void Start()
{
}
FixedUpdate
用于物理计算相关的处理,每帧执行,自定义每帧的间隔时间
void FixedUpdate()
{
}
Project Settings
中的Time
可以更改间隔时间(Fixed Timestep)
Update
游戏核心逻辑帧更新,晚于FixedUpdate
void Update()
{
}
LateUpdate
晚于Update的帧更新
一般用于处理摄像机位置更新相关内容,因为在Update和LateUpdate之间,Unity会进行渲染相关更新
void LateUpdate()
{
}
OnDisable
依附的对象被取消激活时调用,当一个对象被取消激活时,进行逻辑处理
void OnDisable()
{
}
OnDestory
依附的对象被销毁时调用
void OnDestroy()
{
}
辅助特性
强制序列化特性
[SerializeField]
[SerializeField] public int id;
编辑器里隐藏特性
[HideInInspector]
[HideInInspector] public string card;
分组特性
为成员分组
[Header("分组说明")]
[Header("Array value")]
public float[] floats;
public List<int> list;
[Header("Other value")]
public ETestEnum testEnum;
public GameObject obj;
悬停注释
为变量添加说明
[Tooltip("说明内容")]
[Tooltip("This is a test enum value.")] public ETestEnum testEnum;
间隔特性
让2个字段间出现间隔
[Space]
public float[] floats;
[Space]
public List<int> list;
修饰数值滑条范围
[Range(最大值,最小值)]
[Range(0, 100)]
public float[] floats;
多行显示字符串
默认显示3行,传入参数显示对应行
[Multiline(行数)]
[Multiline]
public string card;
滚动条显示字符串
默认超过3行显示滚动条
[TextArea(最少显示行数,最多显示行数“超过这个数显示滚动条”)]
[TextArea(3, 4)]
public string life;
变量添加快捷方法
为变量的右键菜单添加一个可以执行对应方法的按钮(方法必须无参无返回值,且在同一个脚本文件中)
[ContextMenuItem("显示按钮名", "方法名")]
[ContextMenuItem("Add money", "AddMoney")]
public int money;
void AddMoney()
{
money += 100;
}
添加在Inspector执行的方法
为该脚本中的某个函数添加能够在Inspector中执行的方法
[ContextMenu("显示名称")]
[ContextMenu("Debug test")]
void PrintTest()
{
Debug.Log("Test func.");
}
MonoBehavior重要内容
重要成员
获取依附的对象
gameObject
依附对象的名称
name
依附对象的位置信息
transform.position; // 位置
transform.rotation; // 旋转
transform.eulerAngles; // 角度
transform.lossyScale; // 缩放
设置脚本激活
并不会马上停止运行,还是先运行完,再停止
enabled = true;
重要方法
所有获取组件的函数,都会搜索整个父子层级,即,父对象的父对象,子对象的子对象等等
获取依附对象上的其它脚本
获取当前依附对象上,某个脚本类的单个对象
GetComponent()
根据脚本名称获取
TestEmpty testEmpty = GetComponent("TestEmpty") as TestEmpty;
根据Type获取
TestEmpty testEmpty2 = GetComponent(typeof(TestEmpty)) as TestEmpty;
根据泛型获取(推荐)
主要使用的获取方式
TestEmpty testEmpty3 = GetComponent<TestEmpty>();
获取依附对象上的所有特定脚本
获取某个类的脚本在当前依附物体上所存在的所有对象
GetComponents<>()
TestEmpty[] testEmpties = GetComponents<TestEmpty>();
foreach (var t in testEmpties)
{
Debug.Log(t);
}
获得子对象特定脚本
获取当前依附对象的子对象挂载的特定脚本(会检测当前依附对象是否挂载)
GetComponentInChildren<>(是否检测取消激活的子对象“默认为false”);
TestEmpty t = GetComponentInChildren<TestEmpty>();
获取子对象所有特定脚本
获取当前依附对象的子对象挂载的所有特定脚本(会检测当前依附对象是否挂载)
GetComponentsInChildren<>(是否检测取消激活的子对象“默认为false”);
var list = new List<TestEmpty>();
GetComponentsInChildren(true, list);();
获取父对象特定脚本
获取当前依附对象的父对象上的特定脚本对象(如果当前依附对象没有父对象,则默认检测当前依附对象是否挂载特定脚本)
GetComponentInParent<>()
TestEmpty t = GetComponentInParent<TestEmpty>();
获取父对象所有特定脚本
获取当前依附对象的父对象上所有的特定脚本对象(如果当前依附对象没有父对象,则默认检测当前依附对象是否挂载特定脚本)
GetComponentsInParent<>()
TestEmpty[] t = GetComponentsInParent<TestEmpty>();
安全获取组件
防止返回值为null
,改函数返回值为bool
类型,传入需要赋值的变量
TryGetComponent<>()
if (TryGetComponent<TestEmpty>(out var t))
{
Debug.Log(t);
}
重要组件和API
以下规定:脚本=组件
GameObject
成员变量
名称
可修改
gameObject.name
是否激活
不可修改
gameObject.activeSelf
静态
可修改
gameObject.isStatic
层级
可修改
gameObject.layer
标签
可修改
gameObject.tag
变换
可修改内部变量
gameObject.transform
transform.position = new Vector3(1, 1, 1);
静态方法
创建自带几何体
GameObject.CreatePrimitive(PrimitiveType枚举);
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
obj.name = "Create Cube";
查找对象(不推荐)
无法查找到取消激活的对象
这些方法都会影响性能,查找时会遍历所有对象,不推荐使用
对象名查找单个对象
GameObject.Find("对象名称");
var o = GameObject.Find("Cube");
if (o != null)
{
Debug.Log(o);
}
标签查找单个对象
GameObject.FindWithTag("标签名称")
GameObject.FindGameObjectWithTag("标签名称")
查找多个对象
只能通过标签查找
GameObject.FindGameObjectsWithTag("标签名称")
实例化(克隆)对象
通过传入预设体或场景中对象来进行动态创建物体(克隆一个对象)
GameObject.Instantiate(Object对象)
public Object cloneObj;
Object o = GameObject.Instantiate(cloneObj);
删除对象
不仅可以删除场景物体,还可以删除脚本(组件),资产等等
移除时不会马上移除,而是打上移除标识,在下一帧将对象从内存中移除
GameObject.Destroy(Object对象,延迟几秒删除“默认0s”);
GameObject.DestroyImmediate(Object对象); // 马上移除对象,不推荐使用
public Object cloneObj;
GameObject.Destroy(cloneObj);
过场景不删除
默认下,切换场景时,场景中的对象会被自动删除
使用函数使某个对象过场景不被删除
GameObject.DontDestroyOnLoad(Object对象);
GameObject.DontDestroyOnLoad(this.gameObject);
成员方法
创建空物体
GameObject 对象变量名 = new GameObject();
GameObject 对象变量名 = new GameObject("名称");
GameObject 对象变量名 = new GameObject("名称", typeof(脚本1), typeof(脚本2), ...);
为对象添加脚本(组件)
组件类型 组件变量名 = 对象变量名.AddComponent<组件类型>();
标签比较
对象变量名.CompareTag("标签名称")
设置激活状态
对象变量名.SetActive(是否激活);
让其它对象执行函数(不推荐)
对象变量名.SendMessage("函数名")
对象变量名.SendMessage("函数名", 传入值)
// 让自己和自己的子对象执行
对象变量名.BroadcastMessage("函数名")
// 让自己和父对象执行
对象变量名.SendMessageUpwards("函数名")
Time
时间缩放比例
默认为1
,大于1加速,小于1减速
Time.timeScale = 1;
帧间隔时间
最近的一帧用了多长时间(秒),不可修改
主要用来计算位移(路程=时间*速度)
受时间缩放比例影响
Time.deltaTime
不受时间缩放比例影响
Time.unscaledDeltaTime
游戏开始到现在的时间
主要在单机游戏中计时,不能修改
受时间缩放比例影响
Time.time
不受时间缩放比例影响
Time.unscaledTime
物理帧间隔时间
受时间缩放比例影响
Time.fixedDeltaTime
不受时间缩放比例影响
Time.fixedUnscaledDeltaTime
帧数
游戏从开始到现在跑了多少帧(执行了几次Update,游戏进行了几次循环)
可以作用于帧同步
Time.frameCount
Transform
Unity坐标系
坐标
世界坐标
相对于世界坐标系的位置
transform.position
本地坐标
相对于父对象坐标系的位置
transform.localPosition
对象朝向
面朝向
transform.forward
蓝色代表Z轴,是表示物体面朝的方向
让蓝色的Z轴围绕绿色的Y轴旋转,就是在改变物体的面朝向
将Rotation的Y设置成90
,就是改变了物体的面朝向
由此得出下表:
上下朝向
transform.up
左右朝向
transform.right
位移
假定Unity使用1毫米为一个Unity距离
路程(毫米/帧) = 方向 速度 时间
手动计算
物体根据自身坐标系的方向位移:
transform.position += -transform.right * (1 * Time.deltaTime);
物体根据世界坐标轴的方向(固定)位移:
transform.position += Vector3.left * (1 * Time.deltaTime);
Translate
transform.Translate(方向 * (速度 * 帧间隔), 坐标系)
第二个参数:
默认Space.Self
Space.Self:
基于自身的坐标系,移动的方向直接映射到自身坐标系上。
transform.Translate(Vector3.left * (1 * Time.deltaTime), Space.Self);
比如,
移动方向:长蓝色线段
映射到自身坐标系:短蓝色线段
最终移动方向:长黄色线段
Space.World:
基于世界的坐标系,移动的方向直接映射到世界坐标系上。
transform.Translate(-transform.right * (1 * Time.deltaTime), Space.World);
比如,
移动方向:短蓝色线段
映射到世界坐标系:长黄色线段
最终移动方向:长黄色线段
角度
世界(欧拉)角度
transform.eulerAngles
本地(欧拉)角度
transform.localEulerAngles
旋转
transform.Rotate(new Vector3(围绕X轴每帧转几度, 围绕Y轴每帧转几度, 围绕Z轴每帧转几度) * 帧间隔, 坐标系)
transform.Rotate(围绕坐标轴的哪个轴旋转, 每帧转几度 * 帧间隔, 坐标系)
Space.Self
绕着自身坐标轴旋转
transform.Rotate(new Vector3(0, 100, 0) * Time.deltaTime, Space.Self);
// 围绕物体自身向上的坐标轴旋转
transform.Rotate(Vector3.up, 10 * Time.deltaTime, Space.Self);
Space.World
绕着世界坐标轴旋转
transform.Rotate(new Vector3(0, 100, 0) * Time.deltaTime, Space.World);
// 围绕向上(Y)的世界坐标轴旋转
transform.Rotate(Vector3.up, 10 * Time.deltaTime, Space.World);
围绕着某点进行旋转
围绕着某点进行环形运动,类似于地球绕着太阳转
transform.RotateAround(围绕的点坐标, 围绕的轴, 每帧转几度 * 帧间隔);
// 围绕原点旋转
transform.RotateAround(Vector3.zero, Vector3.up, 100 * Time.deltaTime);
缩放
世界缩放
不能修改
transform.lossyScale
本地缩放
transform.lossyScale
手动修改
transform.localScale = Vector3.one * Time.deltaTime;
看向
物体的面朝向(+Z轴)朝向某一个点(Vector3
)或一个对象(Transform
)
transform.LookAt(坐标)
// 看向原点
transform.LookAt(Vector3.zero);
父子关系
父对象
断绝所有子类的父子关系
将与当前对象有子关系的所有对象取消与当前对象的父子关系
transform.DetachChildren();
获取子对象
transform.Find("对象名称") // 可以找到取消激活的对象,不能查找子对象的子对象
transform.GetChild(索引); // 通过索引获取子对象
获取子对象数量
取消激活的子对象也算;
查找不到子对象的子对象;
transform.childCount
子对象
获取父对象
transform.parent
设置父对象
普通赋值
transform.parent = null; // 取消父子关系 transform.SetParent(null); //设置父对象 public GameObject newParent; transform.parent = newParent.transform; transform.SetParent(newParent.transform);
API设置
第二个参数:
如果为
true
,子对象的变换(Transform)会重新计算,计算为相对于父对象的变换(Transform)。在场景中体现为,子对象的变换(Transform)还是原来设置父子关系之前的变换(Transform);
如果为
false
,不会改变子对象的变换(Transform)。在场景中体现为,子对象的变换(Transform)已经不在原来设置父子关系之前的变换(Transform);
transform.SetParent(Transform对象); transform.SetParent(Transform对象, 子对象的变换是否根据父对象变换变化“默认true”);
transform.SetParent(null); transform.SetParent(newParent.transform, false);
判断是否为某个父类的子对象
子对象Transform.IsChildOf(父对象Transform)
获取做为子对象的编号
transform.GetSiblingIndex()
设置为第一个子对象
transform.SetAsFirstSibling()
设置为最后一个子对象
transform.SetAsLastSibling()
设置指定子对象编号
索引超出当前最大或最小子对象编号时,会自动设置为最后一个子对象
transform.SetSiblingIndex(索引);
坐标转换
世界坐标=>本地坐标
将世界坐标轴上的点,转化为对象坐标轴上的点(点的位置不变,只是换了参考坐标系)
会受到缩放影响
Vector3 v = transform.InverseTransformPoint(Vector3.forward);
世界方向=>本地方向
将世界坐标轴上的方向向量,转化为对象坐标轴上的方向向量(方向向量的位置改变)
不受到缩放影响(Direction)
Vector3 v = transform.InverseTransformDirection(Vector3.forward);
会受到缩放影响(Vector)
Vector3 v = transform.InverseTransformVector(Vector3.forward);
本地坐标=>世界坐标
会受到缩放影响
transform.TransformPoint(Vector3.forward);
本地方向=>世界方向
不受到缩放影响(Direction)
Vector3 v = transform.TransformDirection(Vector3.forward);
会受到缩放影响(Vector)
Vector3 v = transform.TransformVector(Vector3.forward);
Input(推荐InputSystem)
鼠标在屏幕的位置
屏幕坐标原点在游戏画面左下角,右=+X,上=+Y
Input.mousePosition
检测鼠标输入
鼠标输入的一
左键0
,右键1
,中键2
按下
瞬间调用一次
Input.GetMouseButtonDown(鼠标按键)
抬起
瞬间调用一次
Input.GetMouseButtonUp(鼠标按键)
长按(按下和抬起)
从按下开始执行,每一帧都会执行(如果在Update中),抬起结束
Input.GetMouseButton(鼠标按键)
中键滚动
返回(X,Y),Y=-1下滚
,Y=0不动
,Y=1上滚
Input.mouseScrollDelta
检测键盘输入
按下
Input.GetKeyDown(KeyCode.W)
传入字符串
Input.GetKeyDown("小写按键名称")
抬起
Input.GetKeyUp(KeyCode.W)
长按(按下和抬起)
从按下开始执行,每一帧都会执行(如果在Update中),抬起结束
Input.GetKey(KeyCode.W)
任意按键
包括鼠标按钮
Input.anyKey()
Input.anyKeyDown()
输入字符
获取每帧按下键盘的字符
Input.inputString
检测默认轴输入
返回值是一个浮点数,在-1~1
之间,一般表示方向,没有触发时默认0
Input.GetAxis("热键配置名称");
Project Settings
里的Input Manager
可以进行热键配置
修改Size
即可增添热键
比如,左右水平热键
移动设备触摸
if (Input.touchCount > 0)
{
Touch touch = Input.touches[0];
// 位置
Vector2 pos = touch.position;
// 相对上次位置的变化
Vector2 dpos = touch.deltaPosition;
}
// 是否启用多点触控
Input.multiTouchEnabled = true;
// 开启陀螺仪
Input.gyro.enabled = true;
// 重力加速度向量
Vector3 gv = Input.gyro.gravity;
// 旋转速度
Vector3 rv = Input.gyro.rotationRate;
// 当前旋转的四元数
Quaternion rq = Input.gyro.attitude;
InputSystem
新输入系统基于事件,输入设备和动作逻辑互相分离,通过配置映射来处理输入信息。具有易用,多设备多平台协调一致的特点。
安装
在
Window
的Package Manager
选择Packages: Unity Registry
搜索Input System
即可安装
设置当前输入系统为
Input System
,重启编辑器
在Project Settings
中Player
的Other Settings
下修改
Input Actions
用来管理各种按键的集合文件,可以定义按键名称,触发方式等等
右键创建Input Actions
注意要点击Save Assets按钮或者勾选Auto-Save才能保持
Action Maps
一个按键映射的集合,包含自定义按键
Actions
按键操作,使用Binding
绑定按键
Value
是轴操作类型,Button
是按钮操作类型
Interactions
是触发条件,如,双击,按住不放等等
Player Input
Player Input
脚本用于挂载在需要输入操作的对象上
Actions
选择创建的Input Actions资产,Default Map
选择默认的按键映射
Behavior
热键触发后需要执行函数的方式
Invoke Unity Events
Events:
需要Behavior选择Invoke Unity Events
才能显示;
会出现Input Actions资产中定义的映射表(如,Player,Monster);
Device Lost Event
:表示输入设备连接丢失时触发
Device Regained Event
:表示输入设备重新连接时触发
Controls Changed Event
:表示换输入设备时触发
自定义的映射类下会出现热键函数绑定设置,选择挂载了包含执行函数组件的对象,右侧可以选择执行函数
比如,当前Sphere
类挂载了有Jump
函数的InputSystemTest
组件
InputSystemTest
组件:
没有CallbackContext判断默认会执行3次
public class InputSystemTest : MonoBehaviour
{
// 该无参函数会默认执行3次
public void Jump()
{
Debug.Log("Jump.");
}
}
执行顺序:context.started -> context.performed -> context.canceled
public void Jump(InputAction.CallbackContext context)
{
// 当按键取消后返回true
if (context.canceled)
{
Debug.Log("Jump.");
}
}
Invoke C Sharp Events
该方法需要在当前对象上挂载用于定义热键触发函数的组件
如,这里新建的InputSystemTest
组件
在组件的生命周期函数中添加热键触发事件
using UnityEngine.InputSystem;
public class InputSystemTest : MonoBehaviour
{
private PlayerInput _playerInput;
private void Awake()
{
// 获取Player Input组件对象
_playerInput = GetComponent<PlayerInput>();
// 添加热键触发事件(当有任意动作被触发时)
_playerInput.onActionTriggered += Jump;
}
private void Jump(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("Jump.");
}
}
自定义Input Actions(推荐)
用这个方法,一个被操控的对象就不用挂载多个脚本去管理输入,只需挂载一个有热键触发的执行函数组件就可以了
自动生成Input Actions类
自动生成Input Actions
类用来管理热键触发函数
不要修改这个自动生成类
在Input Actions资产面板选择Generate C# Class
自动生成类(默认在Input Actions资产的当前路径,且生成的文件名称与Input Actions资产相同)
在该生成文件的最底部,有Action的触发函数
使用Input Actions类
创建一个用来存储热键触发函数的组件(如,
InputSystemTest
)
在
InputSystemTest
的生命周期函数中添加需要的事件执行顺序:
context.started -> context.performed -> context.canceled
InputAction类对象.ActionMaps映射.Action动作.执行顺序 += 函数
private void Awake() { _sphereRigidbody = GetComponent<Rigidbody>(); // 创建一个Input Action类对象 PlayerInputController inputController = new PlayerInputController(); // 启用指定映射 inputController.Player.Enable(); // 添加跳跃事件 inputController.Player.Jump.performed += Jump; } private void Jump(InputAction.CallbackContext context) { if (context.performed) { Debug.Log("Jump."); } }
使用前需要启用特定的映射Action Maps
// 启用指定映射 InputAction类对象.ActionMaps映射.Enable();
不需要挂载Player Input组件,只需挂载存储热键触发函数的组件(这里是
InputSystemTest
)就好了
2D Vector
2D向量输入,当Action Type为Value
时才能添加
常用于wasd前进后退移动输入
使用方法
inputVector.x
:左右移动浮点数
inputVector.y
:前后移动浮点数
private void Awake()
{
// 创建一个Input Action类对象
PlayerInputController inputController = new PlayerInputController();
// 启用指定映射
inputController.Player.Enable();
// 添加移动事件
inputController.Player.Movement.performed += Movement;
}
private void Movement(InputAction.CallbackContext context)
{
// context.ReadValue读取轴值
var inputVector = context.ReadValue<Vector2>();
Vector3 v = new Vector3(inputVector.x, 0, inputVector.y);
}
热键映射不同输入设备
每个热键映射都有不同输入设备的按键设置
添加的Control Schems
是所有热键映射共享的,即每个热键映射都会有Control Schems
的按键绑定界面
使用方式
添加一个
Control Schems
选择一个/多个输入设备
勾选现有
Control Schems
即可绑定输入设备也可给同一映射添加多个
Control Scheme
来进行不同输入设备的按键绑定
显示当前所有绑定按键
All Control Schemes
可以显示当前映射所有不同输入设备绑定的按键
热键映射切换
可以动态切换热键映射,所有热键映射必须显式启用才能被触发
InputAction类对象.映射名称.Enable() // 启用
InputAction类对象.映射名称.Disable() // 禁用
private PlayerInputController _playerInputController;
private void Awake()
{
_sphereRigidbody = GetComponent<Rigidbody>();
// 创建一个Input Action类对象
_playerInputController = new PlayerInputController();
// 启用指定映射
_playerInputController.Player.Enable();
// 添加跳跃事件
_playerInputController.Player.Jump.performed += Jump;
// 添加移动事件
_playerInputController.Player.Movement.performed += Movement;
// 添加怪物热键事件
_playerInputController.Monster.Print.performed += MonsterPrint;
}
private void Update()
{
// 当键盘的P键按下时,禁用Player按键映射,启用Monster按键映射
if (Keyboard.current.pKey.wasPressedThisFrame)
{
_playerInputController.Player.Disable();
_playerInputController.Monster.Enable();
}
}
private void MonsterPrint(InputAction.CallbackContext context)
{
Debug.Log("I am monster.");
}
查看连接的输入设备
Window
->Analysis
->Input Debugger
可以查看当前连接的所有输入设备
双击设备,可以实时监控设备的输入信息
其中显示了Input System
包中相应设备的所有值,比如,当前的Keyboard
包下的某些成员变量的值
热键重新绑定
为热键设置新的触发按键,当调用此方法时,立马开始监听,按下的键就是新的触发按键
重新绑定前需要禁用相应映射
需要手动释放RebindingOperation
对象
_playerInputController.Player.Disable();
// 重新为热键分配按键
_playerInputController.Player.Jump.PerformInteractiveRebinding()
// ...还可以添加其它的修饰函数
// 无法分配鼠标按键
.WithControlsExcluding("Mouse")
// 绑定完成后
.OnComplete(callback =>
{
// 启用相应映射
_playerInputController.Player.Enable();
// 需要手动释放RebindingOperation对象
callback.Dispose();
})
.Start();
获取新绑定的按键(覆盖按键的新路径)
callback.action.bindings[0].overridePath
Screen
静态属性
当前屏幕分辨率
当前设备的整个屏幕分辨率
Screen.currentResolution
2560 x 1440 @ 240.002978124323Hz
屏幕窗口当前宽高
当前游戏程序窗口的宽高
// 宽
Screen.width;
// 高
Screen.height;
屏幕休眠模式
当游戏运行时,屏幕的休眠模式
Screen.sleepTimeout = SleepTimeout.NeverSleep; // 永不休眠
Screen.sleepTimeout = SleepTimeout.SystemSetting; // 系统设置
全屏模式
游戏运行时是否为全屏模式
Screen.fullScreen = true;
窗口模式
Screen.fullScreenMode = FullScreenMode.Windowed; // 窗口模式
Screen.fullScreenMode = FullScreenMode.MaximizedWindow; // 最大化窗口
Screen.fullScreenMode = FullScreenMode.FullScreenWindow; // 全屏窗口
Screen.fullScreenMode = FullScreenMode.ExclusiveFullScreen; // 独占全屏
移动设备屏幕转向
Screen.autorotateToPortrait = true; // 正常竖屏
Screen.autorotateToLandscapeLeft = true; // Home键在左边,摄像头在右边
Screen.autorotateToLandscapeRight = true; // Home键在右边,摄像头在左边
Screen.autorotateToPortraitUpsideDown = true; // 倒立竖屏
指定屏幕显示方向
Screen.orientation = ScreenOrientation.LandscapeLeft; // ScreenOrientation枚举
静态方法
设置分辨率(一般移动设备不使用)
Screen.SetResolution(宽, 高, 是否全屏);
Screen.SetResolution(1920, 1080, false);
Camera
组件变量参数
Clear Flags
Skybox
天空盒
Solid Color
颜色填充,针对于2d游戏,Background
可以设置填充颜色
Depth Only
只渲染当前摄像机的Depth,不渲染其它摄像机深度
用途:UI单独一个摄像机,游戏场景单独一个摄像机
示例:
Depth = -1, Clear Flags = Skybox
:
Depth = 0, Clear Flags = Depth Only
:
Game游戏场景
:
Culling Mask
该摄像机能够渲染哪些层级
层级
Projection
摄像机摄影模式
Perspective
透视模式
Orthographic
正交模式
FOV Axis
视场角
Vertical
垂直计算FOV
Horizontal
水平计算FOV
Field of View
视野范围
Physical Camera
物理摄像机,模拟现实摄像机
Clipping Planes
裁剪平面距离
Near
摄像机开始渲染的距离(离摄像机多远的距离)
Far
摄像机结束渲染的距离(最大能看见的距离)
Depth
渲染顺序上的深度
当有多个摄像机时,该值越小越先渲染,即,数字小的,会被数字大的画面遮住
示例
UI单独一个摄像机,游戏场景单独一个摄像机
Viewport Rect
视口范围(主要用于双摄像机游戏)
该摄像机渲染的图像处于屏幕中的位置
0~1
相当于宽高百分比
Rendering Path
渲染路径
Target Texture
渲染纹理(主要用来制作小地图)
将摄像机捕捉的图像渲染到Render Texture
对象上
创建Render Texture
并赋值
Render Texture
:
Occlusion Culling
是否启用剔除遮挡
如果A物体被B物体遮挡,那被遮挡部分不会被渲染,节省性能
HDR
是否允许高动态范围渲染
MSAA
是否允许抗锯齿
Allow Dynamic Resolution
是否运行多态分辨率呈现
Target Display
显示在哪个显示器上
重要静态成员
获取摄像机
主摄像机
标签必须是MainCamera
,否则无效
如果有多个主摄像机,那就会随机返回其中一个
Camera.main
所有摄像机
获取场景中所有摄像机
Camera[] cameras = Camera.allCameras;
渲染委托
摄像机剔除前
Camera.onPreCull += ...
摄像机渲染前
Camera.onPreRender += ...
摄像机渲染后
Camera.onPostRender += ...
重要成员
组件参数获取
Camera.main.depth = 0;
...
世界坐标=>屏幕坐标
返回值为Vector3
,
X
:屏幕坐标X,
Y
:屏幕坐标Y,
Z
:该世界坐标到摄像机的距离(比如,头顶血条2D显示时,利用Z实现近大远小)
摄像机对象.WorldToScreenPoint(世界坐标)
Vector3 screenPoint = mainCam.WorldToScreenPoint(transform.position);
屏幕坐标=>世界坐标
传入的屏幕坐标只有x,y,Z轴是世界坐标到摄像机的距离
摄像机对象.WorldToScreenPoint(屏幕坐标)
Vector3 worldPoint = mainCam.ScreenToWorldPoint(new Vector3(pos.x, pos.y, 10));
Light
Light组件变量参数
Type
光源类型
Spot
聚光灯
Directional
方向光(环境光)
Point
点光源
Area
面光源(仅烘焙)
Range
发光范围距离
Spot Angle
聚光灯光锥角度
Color
光照颜色
Mode
光照模式
Realtime
实时光源
Mixed
混合光源
Baked
烘焙光源(实时+混合光源)
Intensity
光照强度
Indirect Multipler
改变间接光强度
低于1
:每次反弹会使光更暗
大于1
:每次反弹会使光更亮
Shadow Type
阴影类型
No Shadows
无阴影
Hard Shadows
硬阴影
Soft Shadows
软阴影
RealtimeShadows
实时阴影
Strength
阴影暗度,0~1
,类似于阴影透明度
Resolution
阴影分辨率,越高越逼真,越消耗性能
Bias
阴影推离光源的距离
Normal Bias
阴影投射面沿法线收缩距离
Near Panel
渲染阴影的近裁剪面
Cookie
烘焙贴图
Draw Halo
光晕
Flare
耀斑
摄像机要添加Flare Layer
才能看见耀斑
Render Mode
渲染模式
Auto
运行时确定
Important
以像素为单位进行渲染,效果逼真,消耗大
Not Important
以快速模式进行渲染
Culling Mask
剔除遮罩层,决定哪些层的对象受到该光源影响
组件参数获取
light.intensity = .5f;
...
Light设置
Window
->Rednering
->Lighting
打开光照设置面板
Environment
Skybox Material
天空盒材质球
Sun Source
太阳来源
不设置会默认使用场景中最亮的方向光代表太阳
Enviroment Lighting
环境光设置
Source
:环境光光源颜色
Skybox:天空和材质作为环境光颜色
Gradient:可以为天空、地平线、地面单独选择颜色和他们之间混合
Color:指定颜色
Rigbody
刚体,用来模拟物理
组件参数
Mess
质量(默认单位千克
)
Drag
空气阻力
根据力移动对象时,影响对象的空气阻力大小
Angular Drag
根据扭矩旋转对象时,影响对象旋转的空气阻力大小
扭矩旋转:当无重力时,2个有刚体的物体互相碰撞,弹开之后,物体会飘走并旋转
Use Gravity
是否受重力影响
Is Kinematic
启用此选项,则对象不会被物理引擎驱动,只能通过Transform
对其进行操作
Interpolate
插值运算
让刚体物体移动的更平滑
None
不进行插值运算
Interpolate
根据前一帧的变换来平滑变换
Extrapolate
差值运算
根据下一帧的估计变换来平滑变换
Collision Detection
碰撞检测模式
用于防止快速移动的对象穿过其它对象而不进行碰撞检测
Discrete
离散检测
Continuous
连续检测
Continuous Dynamic
动态连续检测(性能消耗高)
Continuous Speculative
连续推测检测
性能消耗比
Discrete
<Continuous
<Continuous Speculative
<Continuous Dynamic
不同检测模式碰撞选择表
刚体加力
自带添加力方法
刚体加力:就是给物体一个有方向有速度的力(如,向后猛推物体)
获取刚体组件
Rigidbody rigidbody = GetComponent<Rigidbody>();
添加力
世界坐标:
刚体组件对象.AddForce(方向 * 力的大小);
rigidbody.AddForce(Vector3.forward * 10);
本地坐标:
刚体组件对象.AddRelativeForce(方向 * 力的大小);
rigidbody.AddRelativeForce(Vector3.forward * 100);
添加扭矩力
添加扭矩力,让其旋转
世界坐标:
刚体组件对象.AddTorque(方向 * 力的大小);
rigidbody.AddTorque(Vector3.up * 10);
本地坐标:
刚体组件对象.AddRelativeTorque(方向 * 力的大小);
rigidbody.AddRelativeTorque(Vector3.up * 100);
直接改变速度
该速度方向是世界坐标
rigidbody.velocity
rigidbody.velocity = Vector3.forward * 5;
模拟爆炸效果
相当于在一个点发生了爆炸,产生的冲击波使物体移动
刚体组件对象.AddExplosionForce(力的大小, 哪个点发生了爆炸, 爆炸半径);
rigidbody.AddExplosionForce(100, Vector3.zero, 10f);
力的模式(ForceMode)
添加力方法都可以传入ForceMode
参数,模式不同,力的计算就不同,导致最终的移速也会不同
Force
持续力模式(最符合现实物理)
给物体添加一个持续的力,与物体质量有关
Impulse
损失力模式
给物体添加一个瞬间的力,与物体质量有关,忽略时间
Acceleration
加速度模式
给物体增加一个持续的加速度,忽略其质量
VelocityChange
速度改变模式
给物体一个添加一个瞬时速度,忽略其质量和时间
力场组件(Constant Force)
相当于之前加力的可视化操作
刚体休眠
当刚体处于休眠状态时,不会进行物理计算
是否正在休眠
刚体组件对象.IsSleeping()
唤醒刚体
刚体组件对象.WakeUp();
休眠后立马唤醒
if (_rigidbody.IsSleeping())
{
_rigidbody.WakeUp();
}
Collider
碰撞器
表示物体的体积(形状),刚体会利用碰撞器的体积进行碰撞计算,模拟真实的碰撞效果,产生力的作用
碰撞器种类
3D碰撞器中除了Box Collider
、Capsule Collider
、Sphere Collider
,其它性能消耗都很高
组件参数
Is Trigger
是否是触发器
触发器:发生碰撞时,会被物理引擎忽略,并触发对应的C#事件。主要用于没有物理效果的碰撞检测。
Material
物理材质
可以确定碰撞体和其它对象碰撞时的交互(表现)方式
Center
碰撞体在对象局部空间中的中心点位置
多碰撞器组合
当一个父对象有多个子对象时,直接在父对象添加刚体,就可以将子对象中所有的碰撞器一起检测碰撞(子对象决定父对象的体积/形状)
Physic Material
物理材质
Dynamic Friction
物体移动中的摩擦力
通常在0~1
之间,
值为0时
:会像在冰面一样滑行
值为1时
:会使物体迅速停止
Static Friction
物体静止时的摩擦力
通常在0~1
之间,
值为0时
:会让物体像冰块一样
值为1时
:会让物体很难被移动
Bounciness
表面弹性,0为不反弹,1会一直弹上弹下
Friction Combine
2个碰撞对象摩擦力的组合方式
Bounce Combine
2个碰撞对象弹性的组合方式
碰撞检测函数
注意
碰撞和触发响应函数属于特殊的生命周期函数,也是通过反射调用;
与物理碰撞触发相关的响应函数处于FixedUpdate和Update生命周期函数之间;
如果是多碰撞器组合物体,检测的组件不能怪在子对象上,应该挂在刚体父对象;
碰撞和触发器函数都快写成虚函数,让子类重写逻辑
物理碰撞检测响应函数
碰撞触发接触时
碰撞触发接触时,自动触发一次
private void OnCollisionEnter(Collision other)
{
}
2个物体相互接触时
2个物体相互摩擦时,每帧调用。如果两物体接触后静止不动,就不会触发
private void OnCollisionStay(Collision other)
{
}
碰撞结束时
碰撞结束(2个物体分离时),自动触发一次
private void OnCollisionExit(Collision other)
{
}
Collision
传入的碰撞对象信息
碰撞到的对象的碰撞器信息
Collision类对象.collider
碰撞对象的依附对象
Collision类对象.gameObject
碰撞接触点
Collision类对象.contactCount
碰撞接触点坐标
ContactPoint[] contactPointos = Collision类对象.contacts;
触发器碰撞触发函数
碰撞触发接触时
碰撞触发接触时,自动触发一次
private void OnTriggerEnter(Collider other)
{
}
2个物体相互接触时
2个物体相互接触时,每帧调用。
private void OnTriggerStay(Collider other)
{
}
碰撞结束时
碰撞结束(2个物体分离时),自动触发一次
private void OnTriggerExit(Collider other)
{
}
Collider组件
音效系统
Audio Clip
音频片段,就是具体的声音文件(.mp3等等)
Load In Background
启用此选项,该Clip文件会放在单独的线程中加载,因此不会阻塞主线程
Load Type
加载的类型
Decompress On Load
该文件将在加载后立即解压缩
Compressed In Memory
保持文件的压缩状态至内存中,当播放时,才进行解压缩
Streaming
动态解码声音。
该方法使用最少的内存来缓冲从磁盘中增量读取并动态解码的压缩数据
Preload Audio Data
启用之后,此音频将会在场景加载前被预加载
Compression Format
压缩格式
Audio Source
音频源组件,用以发出声音,是连接Audio Listener和Audio Mixer的通道
Output
将Audio Clip输出到Audio Mixer
Priority
优先级
Volume
音量大小
Pitch
播放速度
Stereo Pan
2D模式下,播放音频的位置
Spatial Blend
设置声音为2D还是3D
Reverb Zone Mix
回声效果
3D Sound Settings
3D音效设置
Audio Listener
音频监听器组件,通常与Audio Source一起工作,用来接收声音,一般放在摄像机上面
Audio Mixer
混音器,游戏具有不同的音轨,使用这个可以分开进行控制