Unity知识点入门、基础、核心、进阶_unity入门
知识点来源:总结人间自有韬哥在, 唐老狮,豆包
目录
- 一、Unity入门
-
- 1 生命周期函数和打印信息
-
- 1.1. 生命周期函数详解
- 1.2. 在 Unity 中打印信息
- 2 Unity 特性
-
- 2.1变量可见性控制
- 2.2.自定义类型序列化
- 2.3辅助特性(提升可读性)
- 2.4交互增强特性
- 3.基础属性和组件的获取
-
- 3.1. 重要成员
- 3.2. 重要方法
- 4.GameObject游戏对象
-
- 4.1. GameObject 成员变量
- 4.2. GameObject 静态方法
- 4.3. GameObject 成员方法
- 4.4. 次要成员方法(不建议使用,效率低)
- 5.Time时间
- 6.Transform
-
- 6.1. Transform 概述
- 6.2. Vector3 三维向量
- 6.3. 位置
- 6.4. 朝向
- 6.5. 位移
- 6.6. 角度和旋转
- 6.7. 缩放
- 6.8. 看向
- 6.9. 父子关系
- 6.10. 坐标转换
- 7.Input 组件
-
- 7.1.鼠标输入(Update 中使用)
- 7.2.键盘输入(Update 中使用)
- 7.3虚拟轴输入(控制移动/旋转)
- 7.4触摸输入(移动设备)
- 7.5.手柄/虚拟按钮
- 7.6.重力感应(陀螺仪)
- 8.Screen屏幕
- 9.Camera摄像机
-
- 9.1Camera组件参数
- 9.2Camera参数和方法
-
- 9.2.1. 获取摄像机相关
- 9.2.2. 渲染相关委托
- 9.2.3. 重要成员
- 10.Light光面板
-
-
- 10.1光源组件
- 10.2光面板(照明设置)
-
- 11 物理系统 - 刚体
-
- 11.1.刚体组件参数
- 11.2.刚体参数和方法
- 12. 物理系统 - 碰撞体
-
- 12.1.3D 碰撞器种类
- 12.2.3D 碰撞器共同参数
- 12.3.常用碰撞器
- 12.4不常用碰撞器
- 13. 物理系统 - 物理材质
- 14. 碰撞检测函数
-
- 14.1碰撞器与触发器的核心条件对比
-
- 14.1.1.碰撞发生的必要条件
- 14.1.2.触发器触发的必要条件
- 14.2.物理碰撞检测响应函数
- 14.3触发器检测响应函数
- 15.Unity 音效系统
-
- 15.1.音频文件导入
- 15.2.音频源(AudioSource)
-
- 15.2.1.音频源组件参数
- 15.2.2.音频源参数和方法
- 15.3.麦克风录制
- 二、Unity基础
-
- 1.Mathf
-
- 1.1.常用基础方法(一般计算一次)
- 1.2.插值运算(Lerp)深度解析
- 1.3.三角函数与角度转换
- 2.坐标系
-
- 2.1.四大坐标系对比
- 2.2坐标转换核心方法
-
- 2.2.1. 世界 ↔ 本地(Transform 方法)
- 2.2.2. 世界 ↔ 屏幕(Camera 方法)
- 2.2.3. 世界 ↔ 视口(Camera 方法)
- 3.Vector3
-
- 3.1基础属性(实例成员)
- 3.2静态方法(基础运算)
- 4.Quaternion
-
- 4.1.构造与属性
- 4.2.核心方法(旋转控制)
- 5.延迟函数
-
- 5.1.核心方法
- 5.2.对象状态对延迟函数的影响
- 5.3延迟函数 vs 协程(Coroutine)
- 6.协同程序
-
- 6.1.协程方法
- 6.2.多线程与协程对比表
- 7.特殊文件夹
- 8.Resources
-
- 8.1.同步加载
- 8.2.异步加载
- 8.3.资源卸载
- 9.SceneManager
-
- 9.1.场景同步加载
- 9.2.场景异步加载
-
- 9.2.1 事件回调异步加载场景
- 9.2.2 协程异步加载场景
- 9.3常用方法和属性
- 10.LineRenderer
-
- 10.1.LineRenderer组件参数
- 10.2.LineRenderer参数和方法
- 11.物理系统-范围检测
-
- 11.1.范围检测基础
- 11.2.核心方法
- 12.射线检测
- 三、Unity核心
-
- 1.图片纹理
-
- 1.1.Unity支持的图片格式
- 1.2.纹理类型参数
- 1.3.纹理形状参数
- 1.4.纹理高级参数设置
- 1.5.纹理平铺拉伸参数
- 1.6.纹理平台打包相关参数
- 2.SpriteEditor精灵编辑器
-
- 2.1.Single 图片编辑功能
- 2.2.Multiple 图集元素分割
- 2.3.Polygon 多边形编辑
- 3.Animator
-
- 3.1.Animator 动画器组件参数说明
- 3.2.Animator 动画器代码控制
- 3.3 Animator 窗口中动画状态设置相关参数
- 3.4.Animator 窗口中动画过渡设置相关参数
- 3.5. 动画分层和遮罩
- 3.6.动画融合树
-
- 3.6.1.动画 1D 混合
- 3.6.2.动画2D 混合
- 3.7. 3D 动画其他相关知识
-
- 3.7.1. 动画子状态机
- 3.7.2.动画目标匹配
- 3.7.3.状态机行为脚本
- 3.7.4.状态机复用
- 4.模型导入
-
- 4.1.Model模型页签
-
- 4.1.1.Scene 场景相关设置
- 4.1.2.Meshes 网格相关设置
- 4.1.3.Geometry 几何体相关设置
- 4.2.Rig操纵骨骼页签
-
- 4.2.1. Animation Type(动画类型)
- 4.2 2. Muscles&Settings(肌肉与设置)
- 4.3.Animation动画页签
-
- 4.3.1.导入相关参数设置
- 4.3.2.动画剪辑选择与属性设置
- 4.4 Materials材质纹理页签
- 5.CharacterController角色控制器
-
- 5.1.角色控制器的概念
- 5.2.角色控制器的使用
- 5.3.角色控制器组件参数
- 5.4.角色控制器代码控制
- 5.5.碰撞和触发检测函数
- 6.导航寻路系统
-
- 6.1.导航网格生成
- 6.2.NavMeshAgent
-
- 6.2.1.NavMeshAgent 组件参数
- 6.2.2.NavMeshAgent 代码控制
- 6.3.OffMeshLink
- 6.4.NavMeshObstacle
- 四、Unity进阶
-
- 1.InputSystem
-
- 1.1.代码检测输入
-
- 1.1.1.键盘输入
- 1.1.2.鼠标输入
- 1.1.3.触屏输入
- 1.1.4.手柄输入
- 1.1.5.其他输入
- 1.2.InputAction
-
- 1.2.1.InputAction参数设置
- 1.2.2.InputAction输入绑定类型
- 1.2.3.InputAction使用方法
- 1.2.4.InputAction特殊设置及系统设置
- 1.2.5.InputActions输入操作配置文件
- 1.2.6.输入配置文件生成CSharp代码
- 1.3.PlayerInput
-
- 1.3.1.PlayerInput介绍
- 1.3.2.PlayerInput玩家输入管理组件
- 1.4.UGUI配合使用
- 1.5.InputDebug输入调试器
- 2.VideoPlayer
-
- 2.1.视频剪辑设置
- 2.2.VideoPlay视频播放器
-
- 2.2.1.VideoPlayer组件参数
- 2.2.2.VideoPlayer参数和方法
- 2.3.全景视频
- 3.ScriptableObject
-
- 3.1.ScriptableObject数据文件的创建
- 3.2.ScriptableObject数据文件的使用
- 3.3.ScriptableObject非持久数据和持久化
- 3.4.ScriptableObject单例
- 4.TextMeshPro
-
- 4.1.TextMeshPro UI
-
- 4.1.1.TextMeshPro UI组件参数
- 4.1.2.TextMeshPro UI参数和方法```
- 4.2. 3D 文本和 UI 文本区别:
- 4.3.字体资源
-
- 4.3.1.字体资源-基本信息设置
- 4.3.2.字体资源-生成设置和图集纹理
- 4.3.3.字体资源-字体粗细
- 4.3.4.字体资源-其他设置
- 4.4.富文本标签
- 4.5.样式表
- 4.6.图文混排
- 4.7.项目设置TextMeshPro基本设置
- 4.8.SDF材质球
- 4.9.MP_TextEventHandler
- 4.10.TMP_TextUtilities
一、Unity入门
1 生命周期函数和打印信息
1.1. 生命周期函数详解
Awake
OnEnable
Start
Awake
晚FixedUpdate
Update
LateUpdate
Update
晚执行OnDisable
OnDestroy
OnDisable
1.2. 在 Unity 中打印信息
Debug
类Log
方法Debug.Log(\"Awake Debug.Log\");
Debug
类LogWarning
方法Debug.LogWarning(\"Awake Debug.LogWarning\");
Debug
类LogError
方法Debug.LogError(\"Awake Debug.LogError\");
MonoBehaviour
类print
方法MonoBehaviour
类时,可使用该方法打印普通信息,如 print(\"Awake print\");
2 Unity 特性
2.1变量可见性控制
[SerializeField]
private
/protected
变量[SerializeField] private int value;
GameObject
等- 运行时修改会影响成员变量
[HideInInspector]
public
变量[HideInInspector] public int value;
public
变量public int value;
2.2.自定义类型序列化
public E_TestEnum enumValue;
[System.Serializable]
特性[Serializable] public struct MyStruct{...}
[System.Serializable]
特性 + 继承 UnityEngine.Object
或标记为 [CreateAssetMenu]
[Serializable] public class MyClass{...}
MonoBehaviour
需手动序列化-
ScriptableObject
需 [CreateAssetMenu]
List
)public int[] array;
public List list;
List
需初始化)2.3辅助特性(提升可读性)
[Header(\"标题\")]
\"基础属性\"
)[Header(\"战斗属性\")] public int atk;
[Tooltip(\"提示\")]
\"最大生命值\"
)[Tooltip(\"闪避率\")] public float miss;
[Space(像素)]
[Space(20)] public int crit;
[Range(Min, Max)]
0, 100
)[Range(0, 10)] public float luck;
[Multiline(行数)]
[Multiline(5)] public string tips;
[TextArea(Min, Max)]
3, 5
)[TextArea(3, 4)] public string desc;
2.4交互增强特性
[ContextMenuItem(\"按钮名\", \"方法\")]
[ContextMenuItem(\"重置\", \"ResetMoney\")] public int money;
[ContextMenu(\"按钮名\")]
[ContextMenu(\"测试逻辑\")] private void Test();
3.基础属性和组件的获取
3.1. 重要成员
gameObject
GameObject
print(gameObject.name);
transform
GameObject
的位置信息print(transform.position);
enabled
this.enabled = false;
3.2. 重要方法
GetComponent
Type
、泛型获取var script = GetComponent();
GetComponents
var scripts = GetComponents();
GetComponentInChildren
bool
:是否查找失活子对象,默认 false
var childScript = GetComponentInChildren(true);
GetComponentsInChildren
bool
:是否查找失活子对象,默认 false
可传入
List
接收结果GetComponentsInChildren(true, list);
GetComponentInParent
var parentScript = GetComponentInParent();
GetComponentsInParent
var parentScripts = GetComponentsInParent();
TryGetComponent
out
输出结果if (TryGetComponent(out var script)) { ... }
4.GameObject游戏对象
4.1. GameObject 成员变量
name
print(gameObject.name); gameObject.name = \"新名称\";
activeSelf
print(gameObject.activeSelf);
isStatic
print(gameObject.isStatic);
layer
print(gameObject.layer);
tag
print(gameObject.tag);
transform
print(gameObject.transform.position);
4.2. GameObject 静态方法
CreatePrimitive
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
Find
null
,无法找失活对象,多匹配时不确定找到哪个GameObject obj = GameObject.Find(\"对象名\");
FindWithTag
/FindGameObjectWithTag
null
,无法找失活对象GameObject obj = GameObject.FindWithTag(\"标签名\");
FindGameObjectsWithTag
GameObject[] objs = GameObject.FindGameObjectsWithTag(\"标签名\");
FindObjectOfType
null
var scriptObj = GameObject.FindObjectOfType();
Instantiate
GameObject clone = GameObject.Instantiate(original);
Destroy
GameObject.Destroy(obj, 5); // 5 秒后删除
DestroyImmediate
GameObject.DestroyImmediate(obj);
DontDestroyOnLoad
GameObject.DontDestroyOnLoad(obj);
4.3. GameObject 成员方法
GameObject obj = new GameObject(\"物体名\", typeof(脚本1), typeof(脚本2));
AddComponent
var script = obj.AddComponent();
GetComponent
var script = obj.GetComponent();
CompareTag
if (gameObject.CompareTag(\"标签名\")) { ... }
SetActive
obj.SetActive(false);
4.4. 次要成员方法(不建议使用,效率低)
SendMessage
gameObject.SendMessage(\"方法名\", 参数);
BroadcastMessage
gameObject.BroadcastMessage(\"方法名\");
SendMessageUpwards
gameObject.SendMessageUpwards(\"方法名\");
5.Time时间
timeScale
Time.timeScale = 0; // 时间停止
Time.timeScale = 2; // 2 倍速
(Update 内使用)
deltaTime
print(\"帧间隔时间: \" + Time.deltaTime);
transform.Translate(Vector3.forward * speed * Time.deltaTime);
unscaledDeltaTime
timeScale
的时间间隔(秒)print(\"不受 scale 影响的帧间隔时间: \" + Time.unscaledDeltaTime);
transform.Translate(Vector3.forward * speed * Time.unscaledDeltaTime);
time
timeScale
影响的时间(秒)print(\"受 scale 影响的游戏开始到现在的时间: \" + Time.time);
unscaledTime
timeScale
的时间,自游戏启动以来的时间(秒)print(\"不受 scale 影响的游戏开始到现在的时间: \" + Time.unscaledTime);
(FixedUpdate 内使用)
fixedDeltaTime
print(\"受 scale 影响的物理帧间隔时间: \" + Time.fixedDeltaTime);
fixedUnscaledDeltaTime
timeScale
的时间间隔(秒)print(\"不受 scale 影响的物理帧间隔时间: \" + Time.fixedUnscaledDeltaTime);
frameCount
print(\"从开始到现在游戏跑了 \" + Time.frameCount + \" 帧\");
6.Transform
6.1. Transform 概述
Transform 主要用于游戏对象(GameObject)的位移、旋转、缩放、父子关系、坐标转换等相关操作。
6.2. Vector3 三维向量
Vector3 v1 = new Vector3(); v1.x = 10; v1.y = 10; v1.z = 10;
Vector3 v2 = new Vector3(10, 10);
Vector3 v3 = new Vector3(10, 10, 10);
Vector3 v4; v4.x = 10; v4.y = 10; v4.z = 10;
Vector3 v11 = new Vector3(1, 1, 1); Vector3 v12 = new Vector3(2, 2, 2);
print(v11 + v12); // (3.0, 3.0, 3.0)
Vector3.zero
、Vector3.right
等常用向量print(Vector3.zero); // (0, 0, 0)
Distance
方法返回向量之间的距离print(Vector3.Distance(v11, v12)); // 1.732051
6.3. 位置
position
print(this.transform.position);
this.transform.position = new Vector3(10, 10, 10);
localPosition
print(this.transform.localPosition);
this.transform.localPosition = Vector3.up * 10;
6.4. 朝向
可通过 transform.forward
、transform.up
、transform.right
得到对象当前的面朝向、头顶朝向、右手边朝向。
6.5. 位移
Update
里this.transform.position += this.transform.forward * 1 * Time.deltaTime;
Translate
方法translation
的方向和距离移动变换,可指定相对坐标系this.transform.Translate(Vector3.forward * 1 * Time.deltaTime, Space.World);
6.6. 角度和旋转
rotation
print(this.transform.rotation);
eulerAngles
Vector3
赋值print(this.transform.eulerAngles);
this.transform.eulerAngles = new Vector3(10, 10, 10);
localEulerAngles
print(this.transform.localEulerAngles);
this.transform.localEulerAngles = new Vector3(10, 10, 10);
Rotate
方法Update
内this.transform.Rotate(new Vector3(0, 100, 0) * Time.deltaTime);
this.transform.Rotate(Vector3.right, 10 * Time.deltaTime, Space.World);
RotateAround
方法this.transform.RotateAround(Vector3.zero, Vector3.right, 10 * Time.deltaTime);
6.7. 缩放
lossyScale
print(this.transform.lossyScale);
localScale
Vector3
向量一起改print(this.transform.localScale);
this.transform.localScale += Vector3.one * Time.deltaTime;
6.8. 看向
LookAt
方法可让一个对象的面朝向某一个点或者某一个对象,一般写在 Update
内以持续更新。
this.transform.LookAt(Vector3.zero);
this.transform.LookAt(lookAtObj);
Transform
信息6.9. 父子关系
parent
变量transform
print(this.transform.parent);
print(this.transform.parent.name);
parent
变量this.transform.parent = null;
this.transform.parent = GameObject.Find(\"Father2\").transform;
SetParent
方法this.transform.SetParent(null);
this.transform.SetParent(GameObject.Find(\"Father2\").transform);
this.transform.SetParent(GameObject.Find(\"Father3\").transform, false);
DetachChildren
方法this.transform.DetachChildren();
Find
方法print(this.transform.Find(\"Cube (1)\").name);
childCount
变量print(this.transform.childCount);
GetChild
方法for (int i = 0; i < this.transform.childCount; i++) { print(\"儿子的名字:\" + this.transform.GetChild(i).name); }
IsChildOf
方法if (son.IsChildOf(this.transform)) { print(\"是我的儿子\"); }
GetSiblingIndex
方法print(son.GetSiblingIndex());
SetAsFirstSibling
方法son.SetAsFirstSibling();
SetAsLastSibling
方法son.SetAsLastSibling();
SetSiblingIndex
方法son.SetSiblingIndex(1);
6.10. 坐标转换
InverseTransformPoint
方法print(\"转换后的点 \" + this.transform.InverseTransformPoint(Vector3.forward));
InverseTransformDirection
方法print(\"转换后的方向(不受缩放影响)\" + this.transform.InverseTransformDirection(Vector3.forward));
InverseTransformVector
方法print(\"转换后的方向(受缩放影响)\" + this.transform.InverseTransformVector(Vector3.forward));
TransformPoint
方法print(\"本地 转 世界 点\" + this.transform.TransformPoint(Vector3.forward));
TransformDirection
方法print(\"本地 转 世界 方向\" + this.transform.TransformDirection(Vector3.forward));
TransformVector
方法print(\"本地 转 世界 方向\" + this.transform.TransformVector(Vector3.forward));
7.Input 组件
7.1.鼠标输入(Update 中使用)
mousePosition
Vector3
(x,y 像素坐标)print(Input.mousePosition);
GetMouseButtonDown(0/1/2)
int
键索引,返回 bool
if (Input.GetMouseButtonDown(0)) 射击();
GetMouseButtonUp(0/1/2)
int
键索引,返回 bool
if (Input.GetMouseButtonUp(1)) 取消();
GetMouseButton(0/1/2)
int
键索引,返回 bool
if (Input.GetMouseButton(2)) 旋转();
mouseScrollDelta
Vector2
(y=-1 下滚,y=1 上滚)float scroll = Input.mouseScrollDelta.y;
7.2.键盘输入(Update 中使用)
GetKeyDown(KeyCode.W)
KeyCode
枚举或 \"w\"
字符串,返回 bool
if (Input.GetKeyDown(KeyCode.Space)) 跳跃();
KeyCode.W
),字符串小写(如 \"w\"
)GetKeyUp(KeyCode.W)
KeyCode
,返回 bool
if (Input.GetKeyUp(\"q\")) 换弹();
GetKey(KeyCode.W)
KeyCode
,返回 bool
if (Input.GetKey(KeyCode.LeftShift)) 加速();
inputString
string
(只读)if (Input.anyKeyDown) print(Input.inputString);
anyKeyDown
帧有效anyKeyDown
bool
(只读)if (Input.anyKeyDown) 开始游戏();
7.3虚拟轴输入(控制移动/旋转)
GetAxis(\"Horizontal\")
float
(如 -0.5, 0.8)Horizontal
(A/D 或 左摇杆)transform.Translate(Vector3.right * Input.GetAxis(\"Horizontal\"));
GetAxisRaw(\"Vertical\")
float
(-1/0/1)Vertical
(W/S 或 上摇杆)if (Input.GetAxisRaw(\"Fire1\") > 0) 开火();
GetAxis(\"Mouse X/Y\")
float
(-1~1)Mouse X
(鼠标左右)camera.Rotate(0, Input.GetAxis(\"Mouse X\"), 0);
7.4触摸输入(移动设备)
touchCount
if (Input.touchCount >= 2) 缩放();
Edit > Project Settings > Input Manager > Multi Touch
touches[0].position
Vector2 pos = Input.touches[0].position;
touches[0].deltaPosition
Vector2 delta = Input.touches[0].deltaPosition;
multiTouchEnabled
Input.multiTouchEnabled = true;
true
,禁用后仅识别第一个触摸点7.5.手柄/虚拟按钮
GetButtonDown(\"Jump\")
string
按钮名(如 “Jump”)if (Input.GetButtonDown(\"Jump\")) 跳跃();
Edit > Project Settings > Input Manager
中配置GetButton(\"Fire\")
string
按钮名if (Input.GetButton(\"Fire\")) 持续射击();
7.6.重力感应(陀螺仪)
gyro.enabled
Input.gyro.enabled = true;
gyro.gravity
Vector3 gravity = Input.gyro.gravity;
gyro.rotationRate
float rotation = Input.gyro.rotationRate.z;
8.Screen屏幕
currentResolution
Resolution
类对象Resolution resolution = Screen.currentResolution;
width
、height
print(\"Game窗口的当前宽度\" + Screen.width);
print(\"Game窗口的当前高度\" + Screen.height);
sleepTimeout
Screen.sleepTimeout = SleepTimeout.NeverSleep;
Screen.sleepTimeout = SleepTimeout.SystemSetting;
fullScreen
Screen.fullScreen = true;
fullScreenMode
FullScreenMode
中的某个值Screen.fullScreenMode = FullScreenMode.Windowed;
autorotateToLandscapeLeft
Screen.autorotateToLandscapeLeft = true;
autorotateToLandscapeRight
Screen.autorotateToLandscapeRight = true;
autorotateToPortrait
Screen.autorotateToPortrait = true;
autorotateToPortraitUpsideDown
Screen.autorotateToPortraitUpsideDown = true;
orientation
Screen.orientation = ScreenOrientation.Landscape;
SetResolution
Screen.SetResolution(1920, 1080, false);
9.Camera摄像机
9.1Camera组件参数
Clear Flags
(清除标志)Background
(背景)Culling Mask
(剔除遮罩)Projection
(投影)- Field of view(视野):摄像机视角,范围在0 - 180度之间,一般默认60度
- Physical Camera(物理相机):勾选后可模拟真实世界中的摄像机
Clipping Planes
(裁剪平面)Viewport Rect
(Viewport矩形)Depth
(深度)Rendering path
(渲染路径)Target Texture
(目标纹理)Occlusion Culling
(遮挡剔除)HDR
MSAA
Allow Dynamic Resolution
(允许动态分辨率)Target Display
Target Eye
9.2Camera参数和方法
9.2.1. 获取摄像机相关
main
print(Camera.main);
print(Camera.main.name);
allCamerasCount
print(Camera.allCamerasCount);
allCameras
Camera[] allCameras = Camera.allCameras;
print(allCameras.Length);
9.2.2. 渲染相关委托
onPreCull
Camera.onPreCull += (c) => { /* 处理逻辑 */ };
onPreRender
Camera.onPreRender += (c) => { /* 处理逻辑 */ };
onPostRender
Camera.onPostRender += (c) => { /* 处理逻辑 */ };
9.2.3. 重要成员
depth
Camera.main.depth = 10;
WorldToScreenPoint
Vector3 v = Camera.main.WorldToScreenPoint(this.transform.position);
print(v);
ScreenToWorldPoint
Vector3 v = Input.mousePosition;
v.z = 5;
sphere.position = Camera.main.ScreenToWorldPoint(v);
10.Light光面板
10.1光源组件
Directional
(方向光)Spot
(聚光灯)Point
(点光源)Area
(面光源)Color
(光源颜色)Mode
(光源模式)Intensity
(光源强度)Indirect Multiplier
(间接系数)Strength
(强度)Resolution
(分辨率)Bias
(偏离)Normal Bias
(法线偏离)Near Panel
(近平面)Cookie
(剪影)Cookie Size
(剪影大小)Draw Halo
(绘制光晕)Flare(眩光)
Render Mode
Culling Mask
(剔除遮罩)intensity
(光照强度)light.intensity = 0.5f;
10.2光面板(照明设置)
Skybox Material
(天空盒材质)Sun Source
(太阳来源)Source
(环境光光源颜色)Intensity Multiplier
(环境光亮度)Ambient Mode
(环境模式)Fog
(雾开关)Color
(雾颜色)Mode
(雾计算模式)Halo Texture
(光晕材质)Halo Strength
(光晕强度)Flare Fade Speed
(炫光交叉淡化速度)Flare Strength
(炫光强度)Spot Cookie
(聚光灯剪影)11 物理系统 - 刚体
11.1.刚体组件参数
Mass
(质量)Drag
(空气阻力)Angular Drag
(角阻力,扭矩阻力)Use Gravity
(重力开关)Is Kinematic
Transform
移动。如果启用此选项,则对象将不会被物理引擎驱动,只能通过 (Transform
) 对其进行操作。对于移动平台,或者如果要动画化附加了 HingeJoint
的刚体,此属性将非常有用Interpolate
(插值运算)FixTime
,改成一秒,这样对象会很突兀的一秒移动一次,这时开启插值运算就可以让刚体对象平滑移动None
(无插值运算模式)Interpolate
(插值模式)Extrapolate
(外推模式)Collision Detection
(碰撞检测模式)Discrete
(离散检测)Continuous
(连续检测)Discrete
消耗更多的性能,但减少了穿透问题。适用于高速移动的物体,如子弹或快速飞行的物体。对动态碰撞体(具有刚体)使用离散碰撞检测,并对静态碰撞体(没有刚体)使用连续碰撞检测。设置为连续动态 (Continuous Dynamic
) 的刚体将在测试与该刚体的碰撞时使用连续碰撞检测。(此属性对物理性能有很大影响,如果没有快速对象的碰撞问题,请将其保留为 Discrete
设置)其他刚体将使用离散碰撞检测Continuous Dynamic
(连续动态检测)Continuous
和 Discrete
的优点,对高速物体进行多次检测,对慢速或静止物体进行一次检测。在保证精度的同时比 Continuous
更省性能。适用于快速移动的物体与静止或缓慢移动的物体之间的碰撞检测,如快速移动的角色或车辆。性能消耗高。对设置为连续 (Continuous
) 和连续动态 (Continuous Dynamic
) 碰撞的游戏对象使用连续碰撞检测。还将对静态碰撞体(没有刚体)使用连续碰撞检测。对于所有其他碰撞体,使用离散碰撞检测。用于快速移动的对象Continuous Speculative
(连续推测检测)Constraints
(刚体约束)Freeze Position
(冻结位置)Freeze Rotation
(冻结旋转)Info
(当前刚体的信息)11.2.刚体参数和方法
this.GetComponent()
获取刚体组件,示例:rigidBody = this.GetComponent();
rigidBody.AddForce(Vector3.forward * 10);
。若要让对象相对于自身面朝向移动,可使用rigidBody.AddForce(this.transform.forward * 10);
。若想即使有阻力也让对象一直移动,可在Update
内持续调用此方法。rigidBody.AddRelativeForce(Vector3.forward * 10);
rigidBody.AddTorque(Vector3.up * 10);
rigidBody.AddRelativeTorque(Vector3.up * 10);
rigidBody.velocity = Vector3.forward * 5;
rigidBody.AddExplosionForce(100, Vector3.zero, 10);
rigidBody.AddForce(Vector3.forward * 10, ForceMode.Acceleration);
。- Force(力模式):给物体添加持续力,与物体质量有关。
- Impulse(冲击力模式):给物体添加瞬间力,与物体质量有关,忽略时间。
- VelocityChange(瞬时速度模式):给物体添加瞬时速度,忽略质量和时间。
constant force
添加到物体上,修改其参数可实现不用代码添加力的效果,适用于保持某种力的场景。IsSleeping
方法判断刚体是否休眠,如if (rigidBody.IsSleeping())
;使用WakeUp
方法唤醒刚体,如rigidBody.WakeUp();
12. 物理系统 - 碰撞体
12.1.3D 碰撞器种类
- 盒状碰撞器 (
BoxCollider
) - 球状碰撞器 (
Sphere Collider
) - 胶囊碰撞器 (
Capsule Collider
) - 网格碰撞器 (
Mesh Collider
) - 轮胎碰撞器 (
Wheel Collider
) - 地形碰撞器 (
Terrain Collider
)
12.2.3D 碰撞器共同参数
Edit Collider
(编辑碰撞体)Is Trigger
(是否是触发器)Material
(物理材质)Center
(碰撞器中心)12.3.常用碰撞器
BoxCollider
(盒状碰撞器)Size
(大小)Sphere Collider
(球状碰撞器)Radius
(半径)Capsule Collider
(胶囊碰撞器)Radius
(半径)Height
(高度)Direction
(轴向)异形物体使用多种碰撞器组合。刚体对象的子对象碰撞器信息参与碰撞检测。比如金字塔预设体,只在金字塔最高层级对象添加刚体,子对象的所有 Cube
都会参与碰撞检测。再比如一个 Cube
添加刚体,再给他添加两个空物体,两个空物体分别添加斜着的盒型碰撞器当做支架,这样这个 Cube
下落时就会被支架撑起来,即便两个空物体连模型都没有只有碰撞器。
12.4不常用碰撞器
Mesh Collider
(网格碰撞器)Convex
才会显示绿色的碰撞器边框Convex
(凸面)Cooking Options
(烹制选项)Mesh
(网格模型选项)Wheel Collider
(轮胎碰撞器)Mass
(车轮的质量)Radius
(车轮的半径)Wheel Damping Rate
(应用于车轮的阻尼值)Suspension Distance
(车轮悬架的最大延伸距离)Force App Point Distance
(定义车轮上的受力点)Suspension Spring
(悬架尝试通过增加弹簧力和阻尼力来到达目标位置)Terrain Collider
(地形碰撞器)Terrain Data
(地形数据)Enable Tree Colliders
(选中此属性时,将启用树碰撞体)13. 物理系统 - 物理材质
Dynamic Friction
(动摩擦力)Static Friction
(静摩擦力)Bounciness
(弹性)Friction Combine
(摩擦力组合)Average
(平均值)Minimum
(最小值)Maximum
(最大值)Multiply
(相乘)Bounce Combine
(反弹组合)Friction Combine
模式相同Average
(平均值)Minimum
(最小值)Maximum
(最大值)Multiply
(相乘)14. 碰撞检测函数
14.1碰撞器与触发器的核心条件对比
14.1.1.碰撞发生的必要条件
Is Trigger
14.1.2.触发器触发的必要条件
Is Trigger
14.2.物理碰撞检测响应函数
// OnCollisionEnter方法 碰撞触发接触时会自动执行这个函数private void OnCollisionEnter(Collision collision){ // 获取碰撞到的对象的相关信息 Collider collider = collision.collider; // 碰撞到的对象的碰撞器信息 GameObject gameObject = collision.gameObject; // 碰撞到的对象 Transform transform = collision.transform; // 碰撞到的对象的位置信息 // 获取接触点数 int contactCount = collision.contactCount; ContactPoint[] pos = collision.contacts; // 返回接触点类数组,可以查看每个接触点的具体的坐标 print(this.name + \"被\" + collision.gameObject.name + \"撞到了\");}// OnCollisionExit方法 碰撞结束分离时会自动执行的函数private void OnCollisionExit(Collision collision){ print(this.name + \"被\" + collision.gameObject.name + \"结束碰撞了\");}// OnCollisionStay方法 两个物体相互接触摩擦时会不停的调用该函数 接触但静止时不会调用private void OnCollisionStay(Collision collision){ print(this.name + \"一直在和\" + collision.gameObject.name + \"接触\");}
14.3触发器检测响应函数
// OnTriggerEnter方法 触发开始的函数 当第一次接触时会自动调用protected virtual void OnTriggerEnter(Collider other){ print(this.name + \"被\" + other.gameObject.name + \"触发了\");}// OnTriggerExit方法 触发结束的函数 当水乳相融的状态结束时会调用一次private void OnTriggerExit(Collider other){ print(this.name + \"被\" + other.gameObject.name + \"结束水乳相融的状态了\");}// OnTriggerStay方法 当两个对象水乳相融的时候会不停调用private void OnTriggerStay(Collider other){ print(this.name + \"和\" + other.gameObject.name + \"正在水乳相融\");}
15.Unity 音效系统
15.1.音频文件导入
Force To Mono
(强制单声道)LoadType
(加载类型)- Compress in Memory:大音效(内存低,加载慢)
- Streaming:极长音频(内存最小,CPU 高)
Preload Audio Data
(预加载)15.2.音频源(AudioSource)
15.2.1.音频源组件参数
AudioClip
Play On Awake
Loop
Volume
PlayerPrefs
存储用户设置Priority
AudioMixer
管理Stereo Pan
Spatial Blend=0
配合使用Spatial Blend
Min/Max Distance
和衰减曲线Doppler Level
Volume Rolloff
-
Logarithmic
(真实衰减)-
Linear
(线性衰减)-
Custom
(自定义曲线)Custom
需手动绘制曲线,匹配场景距离Min/Max Distance
Bypass Effects
Output
AudioMixer
组件使用15.2.2.音频源参数和方法
Play()
audioSource.Play();
PlayDelayed(5f)
audioSource.PlayDelayed(2f); // 2 秒后播放
Pause()
/UnPause()
audioSource.Pause();
Stop()
audioSource.Stop(); // 下次从开头播放
isPlaying
if (!audioSource.isPlaying) 播放完毕逻辑;
AudioSource[] audios = GetComponents(); audios[1].Play();
15.3.麦克风录制
Microphone.devices
string[] mics = Microphone.devices; // 打印所有麦克风名称
Microphone.Start(设备名, 循环, 时长, 采样率)
audioClip = Microphone.Start(null, false, 10, 44100); // 默认设备录 10 秒
Microphone.End(设备名)
Microphone.End(null); // 停止并保存录音
AudioClip.GetData(数组, 起始样本)
float[] data = new float[clip.channels * clip.samples];
clip.GetData(data, 0);
audioSource.clip = 录音Clip; audioSource.Play();
二、Unity基础
1.Mathf
1.1.常用基础方法(一般计算一次)
Mathf.PI
float
(只读)print(Mathf.PI); // 3.141593
Mathf.Abs(float f)
f
:数值返回
:绝对值Mathf.Abs(-5f); // 5
Mathf.Clamp(float val, float min, float max)
val
:原始值min/max
:边界Mathf.Clamp(HP, 0, 100); // HP 不低于 0 不高于 100
Mathf.Lerp(float a, float b, float t)
t
0→1 时从 a
平滑过渡到 b
)a
:起始值b
:目标值t
:插值系数pos = Mathf.Lerp(startPos, endPos, 0.5f); // 中间位置
Mathf.RoundToInt(float f)
f
:浮点数返回
:整数Mathf.RoundToInt(3.6f); // 4
Mathf.Sqrt(float f)
f
:数值返回
:平方根Mathf.Sqrt(25f); // 5
Vector3.Distance
)Mathf.CeilToInt(float f)
f
的最小整数f
:浮点数返回
:整数Mathf.CeilToInt(1.3f); // 2
Mathf.FloorToInt(float f)
f
的最大整数f
:浮点数返回
:整数Mathf.FloorToInt(9.6f); // 9
Mathf.Max(params float[] values)
values
:可变长参数列表返回
:最大值Mathf.Max(1, 2, 3, 4, 5); // 5
Mathf.Min(params float[] values)
values
:可变长参数列表返回
:最小值Mathf.Min(1, 2, 3, 4, 5); // 1
Mathf.Pow(float f, float p)
f
的 p
次幂f
:底数p
:指数返回
:幂值Mathf.Pow(2, 3); // 8
Mathf.IsPowerOfTwo(int value)
value
:整数返回
:布尔值Mathf.IsPowerOfTwo(4); // true
Mathf.Sign(float f)
f
的符号,正数和 0 返回 1,负数返回 -1f
:数值返回
:1 或 -1Mathf.Sign(-10); // -1
1.2.插值运算(Lerp)深度解析
pos = Mathf.Lerp(pos, target, Time.deltaTime * speed);
t += Time.deltaTime; pos = Mathf.Lerp(start, end, t);
t
累加,匀速到达目标(t≥1
时固定为 end
)color = Color.Lerp(Color.red, Color.blue, t);
t
0→1 时红→蓝)1.3.三角函数与角度转换
Mathf.Rad2Deg
float
(只读)float deg = rad * Mathf.Rad2Deg; // 弧度转角度
Mathf.Deg2Rad
float
(只读)float rad = deg * Mathf.Deg2Rad; // 角度转弧度
Mathf.Sin(float rad)
rad
:弧度返回
:正弦值Mathf.Sin(90 * Mathf.Deg2Rad); // 1
Mathf.Cos(float rad)
rad
:弧度返回
:余弦值Mathf.Cos(0 * Mathf.Deg2Rad); // 1
Mathf.Atan2(float y, float x)
y/x
的角度)y/x
:坐标差值返回
:弧度float angle = Mathf.Atan2(y, x) * Mathf.Rad2Deg; // 目标角度
2.坐标系
2.1.四大坐标系对比
2.2坐标转换核心方法
2.2.1. 世界 ↔ 本地(Transform 方法)
InverseTransformPoint(Vector3 worldPos)
worldPos
:世界点返回
:本地点InverseTransformDirection(Vector3 worldDir)
worldDir
:世界方向返回
:本地方向TransformPoint(Vector3 localPos)
localPos
:本地点返回
:世界点TransformDirection(Vector3 localDir)
localDir
:本地方向返回
:世界方向2.2.2. 世界 ↔ 屏幕(Camera 方法)
WorldToScreenPoint(Vector3 worldPos)
worldPos
:世界点返回
:屏幕点(x,y,depth)ScreenToWorldPoint(Vector3 screenPos)
screenPos
:屏幕点(需设Z)返回
:世界点2.2.3. 世界 ↔ 视口(Camera 方法)
WorldToViewportPoint(Vector3 worldPos)
worldPos
:世界点返回
:视口点(0-1)ViewportToWorldPoint(Vector3 viewportPos)
viewportPos
:视口点(需设Z,返回:
世界点3.Vector3
3.1基础属性(实例成员)
magnitude
float
(返回长度)Vector3 dir = target - transform.position;
float distance = dir.magnitude;
Mathf.Sqrt(x²+y²+z²)
,性能略低于Distance
方法normalized
Vector3
(返回单位向量)Vector3 normDir = dir.normalized;
sqrMagnitude
float
(返回长度²)if (dir.sqrMagnitude < 25) 触发攻击;
magnitude
快约50%3.2静态方法(基础运算)
Distance(a, b)
(b-a).magnitude
)a,b:Vector3
返回:float
float dist = Vector3.Distance(A, B);
Angle(from, to)
from,to:Vector3
返回:float
float angle = Vector3.Angle(forward, dir);
Cross(a, b)
a,b:Vector3
返回:Vector3
Vector3 up = Vector3.Cross(right, forward);
Dot(a, b)
Lerp(a, b, t)
a,b:Vector3
t:float
返回:Vector3
pos = Vector3.Lerp(start, end, Time.deltaTime*3);
Slerp(a, b, t)
a,b:Vector3
t:float
返回:Vector3
dir = Vector3.Slerp(forward, targetDir, 0.1f);
MoveTowards(current, target, maxDistanceDelta)
current,target:Vector3
maxDistanceDelta:float
返回:Vector3
transform.position = Vector3.MoveTowards(pos, target, speed*dt);
Lerp
+Clamp
,更安全4.Quaternion
4.1.构造与属性
Quaternion()
Quaternion q = new Quaternion();
Quaternion.identity
AngleAxis(angle, axis)
angle:float
(度数)axis:Vector3
返回:Quaternion
Quaternion q = Quaternion.AngleAxis(90, Vector3.up);
Euler(x, y, z)
x,y,z:float
(度数)返回:Quaternion
Quaternion q = Quaternion.Euler(30, 0, 0);
eulerAngles
Vector3
(返回欧拉角)Vector3 angles = q.eulerAngles;
identity
Quaternion
(只读)transform.rotation = Quaternion.identity;
new Quaternion(0,0,0,1)
4.2.核心方法(旋转控制)
Lerp(a, b, t)
a,b:Quaternion
t:float
返回:Quaternion
q = Quaternion.Lerp(rotA, rotB, 0.5f);
Slerp
快20%,但可能“翻折”(适合非方向敏感场景)Slerp(a, b, t)
a,b:Quaternion
t:float
返回:Quaternion
transform.rotation = Quaternion.Slerp(rot, targetRot, dt*5);
LookRotation(dir, up)
dir:Vector3
(目标方向)up:Vector3
(默认Vector3.up)返回:Quaternion
Quaternion look = Quaternion.LookRotation(target - pos);
Transform.LookAt
,但更灵活(可自定义Up轴)operator * (q1, q2)
q1,q2:Quaternion
返回:Quaternion
transform.rotation *= Quaternion.AngleAxis(10, Vector3.up);
operator * (q, vec)
q:Quaternion
vec:Vector3
返回:Vector3
Vector3 newDir = q * Vector3.forward;
Transform.TransformDirection(vec)
5.延迟函数
5.1.核心方法
Invoke(method, time)
method
: 函数名(字符串)time
: 延迟时间(秒)time
秒后执行InvokeRepeating(method, time, repeat)
method
: 函数名time
: 首次延迟repeat
: 重复间隔(秒)time
秒后,之后每repeat
秒执行CancelInvoke([method])
method
: 可选(取消指定函数,不填则取消所有)IsInvoking([method])
method
: 可选(检查指定函数,不填则检查所有)bool
5.2.对象状态对延迟函数的影响
InvokeRepeating
)InvokeRepeating
)5.3延迟函数 vs 协程(Coroutine)
IEnumerator
传参)6.协同程序
6.1.协程方法
StartCoroutine(ie)
yield
控制StopCoroutine(ie/c)
Coroutine
对象)StopAllCoroutines()
清空所有yield return X
null
/数字:下一帧-
WaitForSeconds(t)
:等待t
秒-
WaitForFixedUpdate()
:物理帧-
WaitForEndOfFrame()
:渲染后X
决定恢复时机6.2.多线程与协程对比表
transform
)7.特殊文件夹
Application.dataPath
print(Application.dataPath)
发布后:只读
Resources
Resources.Load
访问)Resources.Load
可用)StreamingAssets
print(Application.streamingAssetsPath)
移动:只读
persistentDataPath
print(Application.persistentDataPath)
Plugins
Plugins/iOS
/Android
)Editor
Editor
Standard Assets
8.Resources
8.1.同步加载
Resources.Load(path)
path
: 资源路径(无扩展名)返回
: ObjectGameObject cube = Resources.Load(\"Prefabs/Cube\");
LoadAll(path)
path
: 文件夹路径返回
: Object[]Object[] textures = Resources.LoadAll(\"Textures\");
Load(path)
T
: 目标类型返回
: TAudioClip bgm = Resources.Load(\"Music/BGM\");
as
,代码更简洁Instantiate
实例化Instantiate(Resources.Load(\"Player\"));
GameObject
不实例化会占用内存,但无法卸载8.2.异步加载
LoadAsync(path)
ResourceRequest
)ResourceRequest req = Resources.LoadAsync(\"BigTex\");
req.completed += OnLoadEnd;
void OnLoadEnd(AsyncOperation op) { tex = op.asset as Texture; }
yield return req;
或 while (!req.isDone)
IEnumerator LoadCoroutine() { yield return req; 渲染纹理(); }
req.progress
(0~1,非精确)progressBar.value = req.progress;
8.3.资源卸载
UnloadAsset(asset)
Resources.UnloadAsset(tex);
GameObject
预制体(会报错)UnloadUnusedAssets()
GC.Collect
)Resources.UnloadUnusedAssets(); GC.Collect();
Destroy()
释放Destroy(instance.gameObject);
9.SceneManager
9.1.场景同步加载
- 实现方式:使用
SceneManager.LoadScene
进行场景同步加载,需引用UnityEngine.SceneManagement
命名空间。
using UnityEngine.SceneManagement;// 场景同步切换SceneManager.LoadScene(\"Lesson21_场景异步加载Test\");
- 缺点:切换场景时,Unity 会删除当前场景的所有对象,并加载下一个场景的相关信息。若当前场景或下一个场景的对象过多,该过程会非常耗时,导致玩家感受到卡顿。
9.2.场景异步加载
9.2.1 事件回调异步加载场景
- 原理:利用
SceneManager.LoadSceneAsync
方法在后台异步加载场景,通过AsyncOperation
类的completed
事件回调来处理加载完成后的逻辑。
// 封装的场景异步加载方法 private void LoadSceneAsyncWithCallback(string sceneName) { // 异步加载场景 AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(sceneName); // 加载完成回调 asyncOperation.completed += (aO) => { print(\"加载结束\"); }; asyncOperation.completed += AsynLoadOver; } // 异步加载场景回调 private void AsynLoadOver(AsyncOperation ao) { print(\"AsynLoadOver\"); }
- 注意事项:即使过场景时脚本或脚本依附的对象被销毁,异步加载的回调依然能够执行,因为回调被存储在事件中。
9.2.2 协程异步加载场景
- 原理:通过协程调用
SceneManager.LoadSceneAsync
进行异步加载,在加载过程中可以执行其他逻辑,如更新进度条。
// 异步加载场景协程函数 IEnumerator CoroutineAsynLoadScene(string name) { // 异步加载场景 AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(name); print(\"异步加载过程中打印的信息\"); // 利用场景异步加载的进度更新进度条(不太准确) while (!asyncOperation.isDone) { print(asyncOperation.progress); yield return null; } // 等待异步加载结束 yield return asyncOperation; print(\"异步加载结束后打印的信息\"); // 也可根据游戏规则自定义进度条变化条件 }}
9.3常用方法和属性
activeScene
sceneCount
sceneCountInBuildSettings
GetSceneAt(int index)
sceneCount - 1
GetSceneByName(string name)
Scene
对象GetSceneByPath(string path)
UnloadSceneAsync(int sceneBuildIndex)
UnloadSceneAsync(string sceneName)
10.LineRenderer
10.1.LineRenderer组件参数
- Mouse Position:摄像机位置创建(少用)
- Physics Raycast:射线碰撞点创建(常用)
- true:世界坐标(固定)
- false:本地坐标(随物体移动)
- View:始终朝向相机
- Transform Z:沿物体Z轴方向
- Stretch:单次拉伸
- Tile:平铺重复
10.2.LineRenderer参数和方法
AddComponent()
GameObject
添加 LineRenderer
组件lineRenderer.loop = true;
PositionCount ≥ 2
lineRenderer.startWidth = 0.02f;
lineRenderer.endWidth = 0.02f;
Update
中调用lineRenderer.startColor = Color.white;
lineRenderer.endColor = Color.red;
Update
中调用material = Resources.Load(\"火焰材质\");
lineRenderer.material = material;
lineRenderer.positionCount = 4;
lineRenderer.SetPositions(new Vector3[] { new Vector3(0,0,0),new Vector3(0,0,5), new Vector3(5,0,5)});
PositionCount
,数组长度需 ≤ PositionCount
lineRenderer.SetPosition(3, new Vector3(5, 0, 0));
index
从 0 开始,坐标基于 useWorldSpace
的设置lineRenderer.useWorldSpace = false;
lineRenderer.generateLightingData = true;
11.物理系统-范围检测
11.1.范围检测基础
- 检测代码执行时触发(非持续检测)
LayerMask
位运算(左移+或运算)1 << LayerMask.NameToLayer(\"Enemy\")
表示仅检测Enemy层QueryTriggerInteraction
枚举:-
UseGlobal
(全局设置)-
Collide
(检测触发器)-
Ignore
(忽略触发器)Edit > Project Settings > Physics > Queries Hit Triggers
11.2.核心方法
OverlapBox
中心坐标, 半尺寸, 旋转, 层掩码, 触发器模式
Collider[]
(动态数组)OverlapBoxNonAlloc
中心坐标, 半尺寸, 预分配数组, 层掩码, 触发器模式
int
(碰撞数)colliders = new Collider[10]
)减少GCAllocOverlapSphere
中心坐标, 半径, 层掩码, 触发器模式
Collider[]
(动态数组)LayerMask
过滤非目标层OverlapSphereNonAlloc
中心坐标, 半径, 预分配数组, 层掩码, 触发器模式
int
(碰撞数)OverlapCapsule
端点1, 端点2, 半径, 层掩码, 触发器模式
Collider[]
(动态数组)Vector3.ProjectOnPlane
计算地面投影OverlapCapsuleNonAlloc
端点1, 端点2, 半径, 预分配数组, 层掩码, 触发器模式
int
(碰撞数)12.射线检测
条件:目标需有碰撞器(无需刚体)
new Ray(origin, direction)
- 摄像机射线:
Camera.ScreenPointToRay(鼠标位置)
origin
:射线起点direction
:方向向量(非终点)屏幕点转射线用于UI/场景交互
Physics.Raycast
(单碰撞)参数:
(射线/起点, 方向, out 碰撞信息, 距离, 层掩码, 触发器模式)
bool
用途:检测首个碰撞目标(如射击命中)
层掩码:
1 << 层号
(如1 << 8
)Physics.RaycastAll
(多碰撞)参数:
(射线/起点, 方向, 距离, 层掩码, 触发器模式)
RaycastHit[]
(无序数组)用途:获取所有碰撞目标(如区域内敌人)
Physics.RaycastNonAlloc
(预分配)参数:
(射线/起点, 方向, 预分配数组, 距离, 层掩码, 触发器模式)
int
(碰撞数)优化:避免GCAlloc,适合高频检测(如每帧扫描)
collider
:碰撞器-
point
:交点坐标-
normal
:碰撞面法线-
distance
:起点到交点距离normal
用于特效朝向(如弹孔法线对齐)point
用于生成命中特效(如子弹痕迹)1. 射线/起点
2. 方向(非必填,重载支持)
3.
out 碰撞信息
(单碰撞)4. 距离(0=无限)
5. 层掩码
6. 触发器模式
示例:
Raycast(ray, out hit, 100, 1<<8)
QueryTriggerInteraction
枚举:-
Collide
(检测触发器)-
Ignore
(忽略)-
UseGlobal
(全局设置)Project Settings > Physics > Queries Hit Triggers
(默认检测触发器)RaycastHit[] hits = new RaycastHit[10]
- 缓存射线:避免重复创建(如
Camera.main
缓存)NonAlloc
比RaycastAll
少生成临时数组,适合高频场景(如技能检测)ScreenPointToRay
+ Raycast
(层过滤UI)2. 射线攻击:检测首个碰撞目标(
distance
限制射程)3. 视线阻挡:
Raycast
返回distance
与预设值比较if (hit.distance < 敌人距离) 被遮挡
三、Unity核心
1.图片纹理
1.1.Unity支持的图片格式
BMP
:是Windows操作系统的标准图像文件格式,特点是几乎不进行压缩,占磁盘空间大。
TIF
:基本不损失图片信息的图片格式,缺点是体积大。
JPG
:一般指JPEG格式,属于有损压缩格式,能够让图像压缩在很小的存储空间,一定程度上会损失图片数据,无透明通道。
PNG
:无损压缩算法的位图格式,压缩比高,生成文件小,有透明通道。
TGA
:支持压缩,使用不失真的压缩算法,还支持编码压缩。体积小,效果清晰,兼备BMP的图像质量和JPG的体积优势,有透明通道。
PSD
:是PhotoShop(PS)图形处理软件专用的格式,通过一些第三方工具或自制工具可以直接将PSD界面转为UI界面。
此外,Unity还支持EXR、GIF、HDR、IFF、PICT等格式。其中,在Unity中最常用的图片格式是JPG、PNG和TGA三种。
1.2.纹理类型参数
人眼看线性渐变的图片会感觉不是线性的,要用伽马控件校正,校正后的图片人眼看是线性渐变的
- Input Texture Alpha:使用输入纹理中的Alpha通道
- From Gray Scale:从输入纹理RGB值的平均值生成Alpha,一般不用
游戏中有时不使用高精度、多三角面片的模型(避免卡顿),记录高精度模型的各个点的法线做成法线贴图,在低精度模型中,通过法线贴图和一些着色器算法,在三角面片更少的低精度模型里能得到效果更好、看起来更高精度的效果
- Bumpiness:控制凹凸程度,值越大凹凸感越强
- Filtering:
- Sharp:生成比标准模式更锐利的法线贴图
- Smooth:使用标准算法生成法线贴图
- Single:按原样使用精灵图像,图片是一张图(非图集)就选这个选项
- Multiple:瓦片模式,如果是图集,使用该选项,可以在Sprite Editor编辑窗口自定义图片
- Polygon:网格精灵模式,如果图片或者图集是多边形可以选择这种模式
- Pixels Per Unit:世界空间中的一个距离单位(Unity中为一米)对应多少像素
- MeshType(只有Sprite模式是Single模式和Multiple模式才支持,因为Polygon模式可自定义多边形大小):
- Full Rect:创建四边形,将精灵显示在四边形上,若图片为三角形,渲染到3D引擎里会创建矩形做成两个三角面片来渲染
- Tight:基于像素Alpha值来生成网格,更加贴合精灵图片的形状,任何小于32*32的精灵都使用FullRect模式,即使设置成Tight模式也是,若图片为三角形,渲染到3D引擎里会把三角形切割成几个三角面片来渲染
- Extrude Edges:使用滑动条确定生成的网格中精灵周围留出的区域大小,可理解为三角形图片边的溢出渲染区域的大小
- Pivot(Single模式才有此选项):精灵图片的轴心点,对应九宫格布局的九个点,还可以自定义
- Generate Physics Shape(只有Single 和Multiple模式才可使用,因为Polygon是自己手动设置的):启用此选项,Unity会自动根据精灵轮廓生成默认物理形状,若图片要进行物理判断(如碰撞器或者物理检测),就勾选它
- Sprite Editor:编辑Sprite,需要安装2D Sprite包
- Spotlight:聚光灯类型,需要边缘纯黑色纹理,TextureShape纹理形状需设置为2D形状
- Directional:方向光,平铺纹理,需要设置TextureShape纹理形状为2D形状
- Point:点光源,需要设置TextureShape纹理形状为立方体形状
- Channel:
- Alpha:使用Alpha通道,不允许进行压缩
- Red:使用红色通道
1.3.纹理形状参数
- Auto(自动):根据纹理信息创建布局。
- 6 Frames Layout(6 帧布局(立方体环境)):纹理包含以标准立方体贴图布局之一排列的六个图像。
- Latitude-Longitude Layout(纬度精度布局(立方体)):将纹理映射到 2D 维度/经度。
- Mirrored Ball(镜面球):将纹理映射到类似球体的立方体贴图上。
- None(无):无过滤。
- Specular(镜面(光泽反射)):将立方体作为反射探针。
- Diffuse(漫反射(发光)):将纹理进行过滤表示辐照度,可作为光照探针。
作用:解决低端设备上立方体贴图过滤错误的问题。
1.4.纹理高级参数设置
- None:纹理尺寸保持不变
- ToNearest:将纹理缩放到最接近2的幂的大小(PVRTC格式要求纹理为正方形)
- ToLarger:将纹理缩放到最大尺寸值的2的幂的大小
- ToSmaller:将纹理缩放到最小尺寸值的2的幂的大小
- Box:随着尺寸减小,级别更平滑
- Kaiser:Mipmap尺寸下降时使用的锐化算法,适用于远处纹理模糊的情况
1.5.纹理平铺拉伸参数
- Repeat(重复):在区块中重复纹理
- Clamp(钳制):拉伸纹理的边缘
- Mirror(镜像):在每个整数边界上镜像纹理以创建重复图案
- Mirror Once(镜像一次):镜像纹理一次,然后将拉伸边缘纹理
- Per - axis(每轴):单独控制如何在 U 轴和 V 轴上包裹纹理
- Point(点):纹理在靠近时变为块状
- Bilinear(双线性):纹理在靠近时变得模糊,一般常用此模式
- Trilinear(三线性):与 Bilinear 类似,但纹理也在不同的 Mip 级别之间模糊
1.6.纹理平台打包相关参数
Bilinear:使用双线性插值调整大小,对于细节重要的图片,比米切尔算法保留更多细节
移动端和网页端特有格式
iOS:选择默认的纹理压缩设置 (PVRTC) 可获得更大兼容性;若应用程序不包含 OpenGL ES 2 支持,可选择 ASTC 格式,该格式质量更好、灵活性更高且压缩速度比 PVRTC 快
Android:因安卓设备众多且标准不一,一般会根据不同设备标准制作多个安装包。
- 构建以 OpenGL ES 3 为目标的 APK:访问 Android 的 Player Settings(菜单:Edit > Project Settings >Player Settings,然后选择 Android 类别),向下滚动到 Graphics APIs 部分,确保 OpenGL ES 2 不在列表中,然后构建 APK(菜单:File > Build Settings,然后单击 Build)
- 构建以 OpenGL ES 2 为目标的单独 APK:访问 Android Player Settings,向下滚动到 Graphics APIs 部分,在列表中添加 OpenGL ES 2 并删除 OpenGL ES 3 和 Vulkan,然后构建 APK
Low Quality(低质量):以低质量格式压缩纹理
Normal Quality(法线质量):以标准格式压缩纹理
High Quality(高质量):以高质量格式压缩纹理,一般选择高质量
2.SpriteEditor精灵编辑器
2.1.Single 图片编辑功能
Position:调整图片在其中的偏移位置以及宽高。
Border:设定九宫格的 4 条边。
Pivot:确定轴心(中心)点的位置。
Pivot Unit Mode:
Normalized:标准化模式,取值在 0 至 1 之间。
Pixels:像素模式,显示当前轴心在图片中的像素位置。
Custom Pivot:自定义轴心点。
Snap 捕捉:使控制点贴近最近的像素,默认选择该选项。
Outline Tolerance:控制轮廓点的复杂性和准确性,取值范围 0 至 1,值越大,轮廓点越多,越准确。
Generate:生成网格轮廓,可手动编辑点,修改后需应用。
2.2.Multiple 图集元素分割
当图片资源为图集时,需将模式设为 Multiple,借助 Sprite Editor 进行图集元素分割:
Automatic 自动分割:
Pivot 轴心:设置单张图片轴心点位置。
Custom Pivot 自定义轴心点:自定义轴心点。
Method 方法:
Delete Existing 删除现有:替换已选的任何矩形。
Smart 聪明:尝试创建新矩形并保留或调整现有矩形。
Safe 安全:添加新矩形而不改变已存在的矩形。
Grid By Cell Size 按单元格大小分割:仅适用于规范矩形图集。
Pixel Size 像素大小:设置单元格宽高。
Offset 偏移:设置左上角偏移位置。
Padding 填充:设置与边缘的偏移位置以及矩形间的偏移缝隙。
Keep Empty Rects:决定是否保留空矩形,一般不勾选。
Grid By Cell Count 按单元格数量分割:设置 Column & Row(行列数)。
Trim 剪裁:选中切片单元格,可自动去除单元格上多余的透明部分。
2.3.Polygon 多边形编辑
若使用的资源是多边形资源,可将模式设为 Polygon,在 Sprite Editor 中进行快捷设置,但实际开发中较少使用:
3.Animator
3.1.Animator 动画器组件参数说明
- Normal(正常更新):按照正常的游戏更新循环进行动画更新
- Animate Physics(物理更新):与物理系统同步更新动画,适用于动画与物理交互的场景
- Unscaled Time(不受时间缩放影响):动画更新不受 Time.timeScale 的影响,即使游戏时间被缩放,动画仍按正常速度播放
- Always Animate(始终播放动画):无论物体是否在屏幕内,动画都会持续播放,不会被剔除
- Cull Update Transforms(裁剪更新变换):当摄像机没有渲染该物体时,停止对物体位置、IK(反向运动学)的写入操作,但动画本身可能仍在运行
- Cull Completely(完全裁剪):当摄像机没有渲染物体时,整个动画被完全禁用,不进行任何计算和更新
3.2.Animator 动画器代码控制
获取 Animator 组件
//我们用代码控制状态机切换主要使用的就是Animator提供给我们的API//我们知道一共有四种切换条件 int float bool trigger//所以对应的API也是和这四种类型有关系的Animator animator = this.GetComponent<Animator>();
Animator.SetXXX 方法:通过状态机条件切换动画
//通过状态机条件切换动画//设置动画参数状态// 设置浮点数类型的动画参数animator.SetFloat(\"条件名\", 1.2f); // 设置整数类型的动画参数animator.SetInteger(\"条件名\", 5); // 设置布尔类型的动画参数animator.SetBool(\"条件名\", true); // 设置触发类型的动画参数animator.SetTrigger(\"条件名\");
Animator.GetXXX 方法:获得动画参数状态
//获得动画参数状态// 获取浮点数类型的动画参数值animator.GetFloat(\"条件名\"); // 获取整数类型的动画参数值animator.GetInteger(\"条件名\"); // 获取布尔类型的动画参数值animator.GetBool(\"条件名\"); // 直接切换动画(除非特殊情况,不然一般不使用)// 注意:状态名和动画名不一样,动画名拖进来默认名字就是状态名,但是可以修改得和动画名不一样animator.Play(\"状态名\");
3.3 Animator 窗口中动画状态设置相关参数
3.4.Animator 窗口中动画过渡设置相关参数
- None:不在添加任何过渡
- Current State:将当前状态过渡排队
- Next State:使下一个状态的过渡进行排队
- Current State Then Next State:将当前状态的过渡和下一个状态的过渡都依次排队
- Next State Thne Current State:将下一状态的过渡和当前状态的过渡依次排队
- 选中时,找到有效过渡或当前过渡时,会中断
- 不选中时,找到有效过渡,会中断
3.5. 动画分层和遮罩
- Override:覆盖方式,播放该层动画时忽略其他层信息
- Additive:叠加方式,会和其它层动画叠加播放
- 选中:采用折中方案调整同步层上的动画时长(基于权重计算)
- 不选中:动画时长将使用原始层做为母版
3.6.动画融合树
3.6.1.动画 1D 混合
- Homogeneous Speed:均匀速度
- Reset Time Scale:重置时间刻度
3.6.2.动画2D 混合
2D 混合的使用:大体上和 1D 混合相似,只是多关联了一个参数,关联的动画也多设置了一个预制。拖动蓝色框上的红点(类似 1D 混合的红色指针)或混合树的进度条可修改参数值查看效果。
3.7. 3D 动画其他相关知识
3.7.1. 动画子状态机
概念:子状态机是在状态机里包含的另一个状态机。当某一个状态由多个动作状态组合成复杂状态时,如角色技能由跳起、攻击、落下三段动作组成,可将这些动作放在子状态机中。
创建方法:在 Animator Controller 窗口中右键选择 Create Sub-State Machine 来创建。
3.7.2.动画目标匹配
概念:当游戏中角色以某种动作移动后,其手或脚需落在特定位置,如跳过踏脚石、跳跃抓住房梁等。以跳跃动作为例,可使角色跳到实际游戏中不同高度的平面。
实现方式:利用 Unity 中 Animator 的 MatchTarget 函数。步骤为找到动作关键点位置信息(如起跳点、落地点)并传入该函数。
代码示例
if( Input.GetKeyDown(KeyCode.Space) ){ animator.SetTrigger(\"Jump\"); //Animator中的MatchTarget方法 //自动调整 GameObject 的位置和旋转。 //参数一:目标位置 //参数二:目标角度 //参数三:匹配的骨骼位置 //参数四:位置和角度权重 //参数五:开始位移动作的百分比 这个参数要观察起跳瞬间动画播放了百分之多少 //参数六:结束位移动作的百分比 这个参数要观察落地瞬间动画播放了百分之多少 animator.MatchTarget(targetPos.position, targetPos.rotation, AvatarTarget.RightFoot, new MatchTargetWeightMask(Vector3.one, 1), 0.4f, 0.64f);}
3.7.3.状态机行为脚本
状态机行为脚本使用方法:新建脚本继承 StateMachineBehaviour 基类,实现特定方法进行状态行为监听,包括 OnStateEnter(进入状态时,第一个 Update 中调用)、OnStateExit(退出状态时,最后一个 Update 中调用)、OnStateIK(OnAnimatorIK 后调用)、OnStateMove(OnAnimatorMove 后调用)、OnStateUpdate(除第一帧和最后一帧,每个 Update 上调用)、OnStateMachineEnter(子状态机进入时调用,第一个 Update 中调用)、OnStateMachineExit(子状态机退出时调用,最后一个 Update 中调用)。
代码示例
// 重写该函数,当进入指定状态时调用public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){ // 当前状态名称与所需状态名称相同时输出日志 if (stateInfo.IsName(stateName)) Debug.Log(\"进入HumanoidIdle状态\");}// 重写该函数,当退出指定状态时调用public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){ // 当前状态名称与指定名称相同时输出日志 if (stateInfo.IsName(\"HumanoidIdle\")) Debug.Log(\"退出HumanoidIdle状态\");}// 重写该函数,当进行动画 IK 计算时调用public override void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){ base.OnStateIK(animator, stateInfo, layerIndex);}// 重写该函数,当进行动画更新时每帧调用public override void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){ base.OnStateMove(animator, stateInfo, layerIndex);}// 重写该函数,当进行动画更新时每帧调用public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){ base.OnStateUpdate(animator, stateInfo, layerIndex); // 当前状态名称为指定名称时输出日志 if (stateInfo.IsName(\"HumanoidIdle\")) Debug.Log(\"处于HumanoidIdle状态\");}// 重写该函数,当进入状态机时调用public override void OnStateMachineEnter(Animator animator, int stateMachinePathHash){ base.OnStateMachineEnter(animator, stateMachinePathHash);}// 重写该函数,当退出状态机时调用public override void OnStateMachineExit(Animator animator, int stateMachinePathHash){ base.OnStateMachineExit(animator, stateMachinePathHash);}
3.7.4.状态机复用
概念:游戏开发中,多个对象(如多个玩家和怪物)动画状态机行为一致但动作不同时,为避免重复创建状态机浪费时间,状态机复用用于为不同对象使用共同的状态机行为,减少工作量,提升开发效率。
选择依据:状态机行为脚本相对动画事件更准确,但使用稍麻烦,可根据实际需求选择。
状态机复用:在 Project 窗口右键选择 Create -> Animator Override Controller,为 Animator Override Controller 文件在 Inspector 窗口关联基础的 Animator Controller 文件,再关联需要的动画。
`
4.模型导入
4.1.Model模型页签
4.1.1.Scene 场景相关设置
-
.fbx
、.max
、.jas
= 0.01-
.3ds
= 0.1-
.mb
、.ma
、.lxo
、.dxf
、.blend
、.dae
= 1- 导入混合形状需 FBX 文件有平滑组
- 若导入有法线的混合形状,需将 Blend Shape Normals 属性设为 Import 用 FBX 法线信息,或设为 Calculate 让 Unity 计算法线
4.1.2.Meshes 网格相关设置
- Low:低压缩比
- Medium:中等压缩比
- High:高压缩比
- 需要在代码中读写网格数据
- 需要运行时合并网格
- 需要使用网格碰撞器
- 需要运行时用 NavMesh 构建组件烘焙 NavMesh 等
- Everything:对顶点及多边形顶点索引重新排序
- Polygon Order:仅对多边形重新排序
- Vertex Order:仅对顶点重新排序
4.1.3.Geometry 几何体相关设置
- Calculate:根据 Normals Mode、Smoothness Source 和 Smoothing Angle 属性计算
- None:不计算法线
- Unweighted:法线不加权重
- Area Weighted:法线按图面面积加权重
- Angle Weighted:法线按每个图面上的顶角加权重
- Area And Angle Weighted:法线按图面面积和顶角加权重,默认选项
- From Smoothing Groups:仅用模型文件中的平滑组
- From Angle:用 Smoothing Angle 值确定平滑边
- None:不拆分硬边的任何顶点
- Calculate Legacy:用旧版算法计算切线
- Calculate Legacy With Split Tangents:用旧版算法计算切线并在 UV 图表上拆分,网格接缝影响法线贴图光照时使用
- Calculate Mikktspace:用米克特空间计算切线
- None:不导入顶点切线,无切线则无法用法线贴图着色器
4.2.Rig操纵骨骼页签
4.2.1. Animation Type(动画类型)
- Avatar Definition(选择获取 Avatar 定义的位置):
- No Avatar:没有化身系统信息。
- Create From This Model:根据此模型创建 Avatar 化身信息。
- Copy from Other Avatar:指向另一个模型上设置的 Avatar 化身信息,需指定 Source(复制另一个具有相同骨架的 Avatar 化身信息以导入其动画剪辑)。
- Skin Weights(蒙皮权重):设置影响单个顶点的最大骨骼数量。
- Standard(4 Bones)标准:使用最多 4 个骨骼产生影响,出于性能考虑,建议使用此设置。
- Custom 自定义:可设置自定义的最大骨骼数,选择后会出现以下选项:
- Max Bones/Vertex:定义每个顶点的最大骨骼个数,值越大性能消耗越大。
- Max Bone Weight:设置考虑骨骼权重的最低阈值,权重计算时将忽略小于此值的内容。
- Optimize Game Objects(优化游戏对象):在 Avatar 化身系统和 Animator 动画组件中删除和存储所导入角色的游戏对象骨骼层级信息。启用后会出现 Extra Transforms to Expose 选项,角色将使用 Unity 动画系统的内部骨架,可提高动画角色的性能,一般不勾选。
- Extra Transforms to Expose(要暴露的额外变换):要公开的骨骼层级,可在下方打钩公开该骨骼层级信息。有放大镜(通过名称搜索对应骨骼信息)、Toggle All(全选或者反选)、Collapse All(全部折叠)、Expand All(全部展开)等操作。
4.2 2. Muscles&Settings(肌肉与设置)
- Muscle Group Preview(肌肉群预览):可预览不同姿势的旋转变化,观察之前的关联映射关系是否合理,主要起预览作用,可拖拽关节点查看关节旋转效果。
- Per - Muscle Settings(肌肉设置):用于设置各骨骼在旋转时的范围限制,避免在极限角度出现奇怪效果,可单独设置限制范围。
- Additional Settings(高级设置):可以设置手脚的扭转和伸展值,一般不修改。其中 Translation DoF 比较重要:
- 如果启用,将启用人形角色的移动动画,可进行骨骼的位置移动,但可能导致其他骨骼拉长。
- 如果禁用,Unity 仅使用旋转对骨骼进行动画化。启用后会提升性能消耗,因为动画需要执行额外步骤来重定向人形动画,除非动画包含角色某些骨骼的动画式移动,否则一般禁用。
- Muscles 肌肉下拉框:可重置所有设置。
4.3.Animation动画页签
4.3.1.导入相关参数设置
- Off:禁用动画压缩,导入时 Unity 不会减少关键帧数量,效果最好但性能低、文件大、运行时内存占用大,通常不建议使用
- Keyframe Reduction:减少冗余关键帧,仅适用于 Generic 通用动画类型,一般选择此项
- Keyframe Reduction and Compression:减少关键帧并在存储动画时压缩关键帧,影响文件大小,内存大小与 Keyframe Reduction 相同,仅适用于 Legacy 旧版动画类型
- Optimal:让 Unity 决定如何压缩,仅适用于 Generic 通用和 Humanoid 人形动画类型
4.3.2.动画剪辑选择与属性设置
- Start:动画剪辑的开始帧
- End:动画剪辑的结束帧
- Bake Into Pose(烘焙成动作):将根旋转烘焙到骨骼移动,禁用此选项将存储为根运动,不勾选会影响根对象的旋转,勾选则不会
- Based Upon(依据):
- Original:保持源文件中的原始旋转
- Root Node Rotation:使用根节点的旋转(仅适用于 Generic 通用动画类型)
- Body Orientation:保持上半身朝前(仅适用于 Humanoid 人形动画类型)
- Offset(偏移):根旋转偏移(单位:度)
- Bake Into Pose(烘焙成的动作):将垂直根运动烘焙到骨骼移动,禁用此选项将会存储为根运动,如走路动作不勾选根对象会上下移动,勾选则更平稳
- Based Upon(at Start)(依据(开始时)):
- Original:保持源文件中的垂直位置
- Root Node Position:使用垂直根位置(仅适用于 Generic 通用动画类型)
- Center Of Mass:保持质心与根位置对齐(仅适用于 Humanoid 人形动画类型)
- Feet:保持双脚与根变换位置对齐(仅适用于 Humanoid 人形动画类型)
- Offset(偏移):垂直根位置偏移
- Bake Into Pose(烘焙成的动作):将水平根运动烘焙到骨骼移动,禁用此选项将会存储为根运动,不勾选根对象会水平运动,勾选则只会播放动画根对象不会水平运动
- Based Upon(依据(开始时)):
- Original:保持源文件中的水平位置
- Root Node Position:使用水平根位置(仅适用于 Generic 通用动画类型)
- Center Of Mass:保持与根位置对齐(仅适用于 Humanoid 人形动画类型)
- 附加动画层:在动画控制器(状态机)中可添加新的动画层
- Pose Frame(动画帧):当启用参考姿势帧时,该项用于选择具体的帧
4.4 Materials材质纹理页签
- None:不使用此模型中嵌入的任何材质,改用 Unity 的默认漫反射材质
- Standard:导入时,Unity 使用默认规则来生成材质
- Import via MaterialDescription(Experimental):导入时,Unity 使用 FBX 文件中嵌入的材质描述来生成材质。与 Standard 相比,该方法结果更准确,并且支持更广泛的材质类型
- Use Embedded Materials:将导入的材质保持在导入的资源中
- Use External Materials(Legacy):将导入的材质提取为外部资源。这是旧版材质处理方式,适用于 2017.1 或更早的 Unity 版本创建的项目
- By Base Texture Name:使用导入材质的漫反射纹理名称来命名材质。若未将漫反射纹理分配给材质,Unity 将使用导入材质的名称
- From Model’s Material:使用导入材质的名称来命名材质
- Model Name + Model’s Material:使用模型文件的名称与导入材质的名称相结合来命名材质
- Local Materials Folder:在本地 Materials 材质子文件夹(模型文件所在的同一文件夹)中查找现有材质
- Recursive-Up:在所有父文件夹(一直向上追溯到 Assets 文件夹)中所有 Materials 子文件夹中查找现有材质
- Project-Wide:在所有 Unity 项目文件夹中查找现有材质
5.CharacterController角色控制器
5.1.角色控制器的概念
角色控制器是一种用于控制角色的组件,它使角色受制于碰撞,但不会像刚体那样产生一些奇怪的表现。例如,使用刚体判断碰撞时,角色可能在斜坡上往下滑动,或者在碰撞时被撞飞等,而角色控制器能让角色表现得更加稳定。Unity 提供了专门的角色控制器组件来实现这一功能。
注意:添加角色控制器后,无需再添加刚体,并且它能检测碰撞函数和触发器函数。
5.2.角色控制器的使用
使用角色控制器时,建议取消 Animator 组件上的根运动,以避免与角色控制器的控制产生冲突,确保角色运动的稳定性和可控性。
5.3.角色控制器组件参数
5.4.角色控制器代码控制
CharacterController.isGrounded 变量:用于判断在上次移动期间 CharacterController 是否接触地面。
//CharacterController中的isGrounded变量 是否接触了地面//在上次移动期间 CharacterController 是否接触地面?if ( characterController.isGrounded ){ print(\"接触地面了\");}
CharacterController.SimpleMove 方法:使角色受重力作用进行移动,以指定的速度移动角色。
//CharacterController中的SimpleMove方法 受重力作用的移动//以 speed 移动该角色。characterController.SimpleMove(Vector3.forward * 10 * Time.deltaTime);
CharacterController.Move 方法:让角色进行不受重力作用的移动,为 GameObject 的移动提供附加的 CharacterController 组件。
//CharacterController中的Move方法 不受重力作用的移动//为 GameObject 的移动提供附加的 CharacterController 组件。characterController.Move(Vector3.forward * 10 * Time.deltaTime);
5.5.碰撞和触发检测函数
OnControllerColliderHit 函数:当角色控制器与别的碰撞器产生碰撞时调用该函数。
//当角色控制器想要判断和别的碰撞器产生碰撞时 使用该函数private void OnControllerColliderHit(ControllerColliderHit hit){ print(\"角色碰撞器发生碰撞\"+hit.collider.gameObject.name);}
OnCollisionEnter 方法:对于角色控制器无效,不会被调用。
//OnCollisionEnter方法对角色控制器没用 //private void OnCollisionEnter(Collision collision)//{// print(\"碰撞触发\");//}
OnTriggerEnter 方法:角色控制器可以检测触发器,当进入触发器时该方法会被调用。
private void OnTriggerEnter(Collider other){ print(\"触发器触发\");}
6.导航寻路系统
6.1.导航网格生成
Object 场景对象设置页签:设置参与寻路烘焙的对象。
- All:显示场景上所有对象
- MeshRenderers:显示挂载的网格渲染器的对象
- Terrains:显示挂载了地形脚本的对象
- Manual Voxel Size(手动设置立体像素大小):开启后可设置立体像素大小,控制烘焙的准确度,立体像素大小描述了生成的导航网格表示场景几何体的准确程度。注意立体像素大小减半会使内存使用量增加 4 倍,构建时间也增加 4 倍,一般情况下不需要修改,除非想要极其准确的导航网格
- Voxel Size(像素大小):配合 Manual Voxel Size 使用
- Min Region Area(最小区域面积):当面积小于此处值的导航网格区域会被移除
- Height Mesh(高度网格构建开关):主要用来解决楼梯烘焙为斜坡时,希望在楼梯表面的位置准确放置在楼梯平面上,而不是斜坡上,启用它会增加烘焙时间
Areas 导航地区页签:设置对象的寻路消耗,配合 Object 页签使用。
Agents 代理页签:设置寻路代理信息,可单独设置寻路对象。
6.2.NavMeshAgent
6.2.1.NavMeshAgent 组件参数
Agent Type(代理类型):配合 Agents 页签使用。
Base Offset(基础偏移值):相对对象轴心点的高度偏移,即改变圆柱体位置。
Steering(转向 移动设置)
Obstacle Avoidance(障碍躲避 避障设置)
Path Finding(寻路 路径寻找规则)
6.2.2.NavMeshAgent 代码控制
常用内容
navMeshAgent.SetDestination()
navMeshAgent.isStopped = true;
不常用内容
print(navMeshAgent.speed);
print(navMeshAgent.acceleration);
print(navMeshAgent.angularSpeed);
if ( navMeshAgent.hasPath ) { }
print(navMeshAgent.destination);
print(navMeshAgent.path);
if ( navMeshAgent.pathPending ) { }
print(navMeshAgent.pathStatus);
navMeshAgent.updatePosition = true;
navMeshAgent.updateRotation = true;
print(navMeshAgent.velocity);
NavMeshPath navMeshPath = new NavMeshPath();if(navMeshAgent.CalculatePath(Vector3.zero, navMeshPath) ){}
if (navMeshAgent.SetPath(navMeshPath)) { }
navMeshAgent.ResetPath();
navMeshAgent.Warp(Vector3.zero);
6.3.OffMeshLink
6.4.NavMeshObstacle
- Capsule:胶囊
- Box:盒装
四、Unity进阶
1.InputSystem
开启方法:File——>Build Setting——>Player Setting——>Other——>Active Input Handling
1.1.代码检测输入
1.1.1.键盘输入
using UnityEngine.InputSystem;
Keyboard keyBoard = Keyboard.current;
keyBoard.具体按键.wasPressedThisFrame
判断,如if (Keyboard.current.spaceKey.wasPressedThisFrame)
可检测空格键按下keyBoard.具体按键.wasReleasedThisFrame
,例如if (Keyboard.current.dKey.wasReleasedThisFrame)
检测D键抬起keyBoard.具体按键.isPressed
,像if (Keyboard.current.spaceKey.isPressed)
检测空格长按状态keyBoard.onTextInput += (c) => {print(\"通过lambda表达式\" + c);};
普通函数:先定义
private void TextInput(char c)
,再keyBoard.onTextInput += TextInput;
if (Keyboard.current.anyKey.wasPressedThisFrame)
,但无法得知具体按下的键1.1.2.鼠标输入
Mouse mouse = Mouse.current;
if (Mouse.current.leftButton.wasPressedThisFrame)
判断左键按下if (Mouse.current.leftButton.wasReleasedThisFrame)
检测左键抬起if (Mouse.current.rightButton.isPressed)
检测右键长按Mouse.current.position.ReadValue()
,原点是左下角,值为屏幕最大分辨率Mouse.current.delta.ReadValue()
,获取鼠标两帧间移动向量Mouse.current.scroll.ReadValue()
,往上滚大于0,往下滚小于01.1.3.触屏输入
Touchscreen touchscreen = Touchscreen.current;
使用前判空:
if (touchscreen == null) return;
print(touchscreen.touches.Count)
输出当前触屏手指数量touchscreen.touches[0]
获取指定索引的手指信息foreach (var item in touchscreen.touches)
遍历所有触屏手指if (touchControl.press.wasPressedThisFrame)
,touchControl
为指定手指对象if (touchControl.press.wasReleasedThisFrame)
检测手指抬起if (touchControl.press.isPressed)
判断手指长按状态if(touchControl.tap.isPressed)
检测手指点击print(touchControl.tapCount)
输出手指连续点击次数print(touchControl.position.ReadValue())
获取当前手指位置print(touchControl.startPosition.ReadValue())
得到手指第一次接触时位置touchControl.radius.ReadValue()
读取手指接触区域半径大小touchControl.delta.ReadValue()
获取手指偏移位置UnityEngine.InputSystem.TouchPhase touchPhase = touchControl.phase.ReadValue();
通过
switch
语句判断:switch (touchPhase)
{
//无
case UnityEngine.InputSystem.TouchPhase.None:
break;
//开始接触
case UnityEngine.InputSystem.TouchPhase.Began:
break;
//移动
case UnityEngine.InputSystem.TouchPhase.Moved:
break;
//结束
case UnityEngine.InputSystem.TouchPhase.Ended:
break;
//取消
case UnityEngine.InputSystem.TouchPhase.Canceled:
break;
//静止
case UnityEngine.InputSystem.TouchPhase.Stationary:
break;
default:
break;
}
希望这个更新后的表格能满足你的需求。如果你还有其他问题,请随时告诉我。
1.1.4.手柄输入
Gamepad gamePad = Gamepad.current;
使用前判空:
if (gamePad == null) return;
print(gamePad.leftStick.ReadValue())
,右和上是正方向print(gamePad.rightStick.ReadValue())
if (gamePad.leftStickButton.wasPressedThisFrame)
判断左摇杆按下if (gamePad.leftStickButton.wasReleasedThisFrame)
检测左摇杆抬起if (gamePad.leftStickButton.isPressed)
检测左摇杆长按if (gamePad.dpad.left.wasPressedThisFrame)
抬起:
if (gamePad.dpad.left.wasReleasedThisFrame)
长按:
if (gamePad.dpad.left.isPressed)
gamePad.buttonNorth
,按下检测如if (Gamepad.current.buttonNorth.wasPressedThisFrame)
,也可按具体名字如gamePad.triangleButton
等监听gamePad.startButton
,按下检测if (Gamepad.current.startButton.wasPressedThisFrame)
gamePad.selectButton
,按下检测if (Gamepad.current.selectButton.wasPressedThisFrame)
gamePad.leftShoulder
,按下检测if (Gamepad.current.leftShoulder.wasPressedThisFrame)
gamePad.leftTrigger
,按下检测if (Gamepad.current.leftTrigger.wasPressedThisFrame)
1.1.5.其他输入
UnityEngine.InputSystem.Gyroscope
)、重力传感器等UnityEngine.InputSystem.Gyroscope gyroscope = UnityEngine.InputSystem.Gyroscope.current; gyroscope.angularVelocity.ReadValue();
,查看类内部成员使用1.2.InputAction
以下是对上述“InputAction”相关内容整理的表格,涵盖了InputAction的定义、参数设置、不同类型的输入绑定、使用方法以及相关设置等方面:
1.2.1.InputAction参数设置
Value
:用于状态连续更改的输入,多个设备绑定时只发送最受控制设备的输入Button
:每次按下时触发的ActionPass Through
:和Value
类似,多个设备绑定时发送所有设备的输入Vector2
只能选返回Vector2
变量类型的设备(手柄摇杆、鼠标位置等),Button
只能选按钮返回值设备(鼠标左键、手柄按键等),包括Any
、Analog
、Axis
、Bone
、Digital
、Double
、Dpad
、Eyes
、Integer
、Quaternion
、Stick
、Touch
、Vector2
、Vector3
等started
(开始)、performed
(触发)、canceled
(结束)三个事件Hold
:长按操作,按下触发started
,按住时间大于等于Hold Time
触发performed
,否则触发canceled
Tap
:点击操作,按下触发started
,在Max Tap Duriation
时间内松开触发performed
,否则触发canceled
SlowTap
:类似Hold
,按住时间大于等于Max Tap Duriation
,松开时触发performed
MultiTap
:多次点击操作,Tap Count
为点击次数,Max Tap Spacing
为点击间隔,Max Tap Duration
为每次点击持续时间,满足条件触发performed
Press
:类似按钮操作,Trigger Behavior
有Press Only
(按下触发started
和performed
,不触发canceled
)、Release Only
(按下触发started
,松开触发performed
)、Press And Release
(按下和松开都触发started
和performed
,不触发canceled
)、Press Point
(利用按钮浮点值区分按下状态)Clamp
:将输入值钳制到[min..max]
范围Invert
:反转控件值(乘以-1)Invert Vector 2
:反转Vector2
轴的值Invert Vector 3
:反转Vector3
轴的值Normalize
:将输入值规格化为[0..1]
或[-1..1]
Normalize Vector 2
:将输入向量规格化为单位长度Normalize Vector 3
:将输入向量规格化为单位长度Scale
:将输入值乘以系数Scale Vector 2
:沿x
、y
轴乘以相应值Scale Vector 3
:沿x
、y
、z
轴乘以相应值Axis Deadzone
:缩放控件值,使绝对值小于最小值为0,大于最大值为1或-1,避免无意输入和确保最大值Stick Deadzone
:缩放Vector2
控件值,幅值小于最小值为(0,0)
,大于最大值规格化为长度11.2.2.InputAction输入绑定类型
Negative
(负面按键)、Positive
(正向按键)、Composite Type
(复合类型)、MinValue
(最小值)、MaxValue
(最大值)、Which Side Wins
(同时按下处理方式,Neither
:取中间值,Positive
:取maxValue
,Negative
:取minValue
)Vector
的x
、y
表示两个轴),参数有Up
、Down
、Left
、Right
、Composite Type
(复合类型)、Mode
(处理模式,Analog
:模拟值,Digital Normalized
:单位化向量,Digital
:未单位化向量)Ctrl+C
),参数有Modifier
(复合输入内容)、Button
(输入内容)Ctrl+K+U
),参数有Modifier
(两个复合输入内容)、Button
(输入内容)1.2.3.InputAction使用方法
move.Enable();
move.started += StartedTestFun;
private void StartedTestFun(InputAction.CallbackContext context) { print(\"开始事件调用\"); }
move.performed += (context) => { print(\"触发事件调用\"); }
move.canceled += (context) => { print(\"结束事件调用\"); }
context.phase
,如Disabled
、Waiting
、Started
、Performed
、Canceled
)、动作行为信息(context.action.name
)、控件(设备)信息(context.control.name
)、获取值(context.ReadValue
)、持续时间(context.duration
)、开始时间(context.startTime
)1.2.4.InputAction特殊设置及系统设置
Interactions
中为整个动作或单个设备设置特殊输入条件,如长按时间等;可点击创建InputSystem
默认值设置文件并修改UpdateMode
:更新模式(Process Events In Dynamic Update
、Process Events In Fixed Update
、Process Events Manually
)Background Behavior
:后台行为(Reset And Disable Non Background Devices
、Reset And Disable All Devices
、Ignore Focus
、Filter Noise on .current
、Compensate Orientation
)Default Deadzone Min
:默认死区最小值Default Deadzone Max
:默认死区最大值Default Button Press Point
:默认按钮按下点Button Release Threshold
:按钮释放阈值Default Tap TIme
:默认点击时间Default Slow Tap Time
:默认慢速点击时间Default Hold Time
:默认保持时间Tap Radius
:点击半径MultTap Delay TIme
:多次点击延迟时间Supported Devices
:可设置支持的设备,不设置则支持所有可识别设备,设置后缩小编辑器显示范围并避免无关设备输入Motion Usage
:动作使用Description
:描述Play Mode Input Behavior
:播放模式输入行为(Pointers And Keyboards Respect Game View Focus
、All Devices Respect Game View Focus
、All Device Input Always Goes To Game View
)1.2.5.InputActions输入操作配置文件
InputAction
的集合,记录想要处理的行为和动作(InputAction
相关信息),可自定义 InputAction
(如开火、移动、旋转等)并关联对应的输入动作,与 PlayerInput
关联后,PlayerInput
自动解析文件,触发输入动作时以分发事件形式通知执行行为Project
窗口右键选择 Create
创建 InputActions
配置文件,文件后缀为 .inputactions
,本质是 json
文件Actions 输入动作窗口:在此可通过加号或右键创建各种
InputAction
,无需在代码中声明变量,可直接添加键盘配置Properties 输入操作绑定的输入属性:与普通
InputAction
点击齿轮的选项相同工具栏:提供保存、搜索等功能按键
Gamepad
(手柄)、Joystick
(摇杆)、KeyboardMouse
(键盘鼠标)、Touch
(触屏)、XR
(VR/AR 等)、All Devices
(设备选择)作用:切换控制方案后,若该方案由多个设备配合控制,可进一步筛选对应设备,如切换键盘鼠标方案后可二次筛选
搜索栏:可搜索对应动作行为
2. 在每个绑定设备中选择设备的控制方案
3. 左上角选择控制方案可筛选设备,选择后还可二次筛选设备
InputSystem中专门用于任意键按下的方案
InputSystem.onAnyButtonPress.CallOnceInputSystem.onAnyButtonPress.CallOnce((control) =>{ print(\"InputSystem中专门用于任意键按下的方案 路径\" + control.path); print(\"InputSystem中专门用于任意键按下的方案 名字\" + control.name);});
通过Json数据加载配置文件
string json = Resources.Load<TextAsset>(\"PlayerInputTest\").text;// 使用 InputActionAsset 类的静态方法 FromJson 解析 json 字符串,返回解析后的 InputActionAsset 对象,并将其存储在变量 asset 中InputActionAsset asset = InputActionAsset.FromJson(json);// 将解析后的 InputActionAsset 对象赋值给 input 对象的 actions 属性input.actions = asset;
1.2.6.输入配置文件生成CSharp代码
InputActions
文件,勾选 Generate C# Class
2. 在
Inspector
窗口设置生成路径(如 Assets/Scripts/GeneratedInputCode
)、类名(如 CustomInputActions
)、命名空间(如 MyGame.Input
)3. 应用后生成代码,生成的代码根据
InputAction
配置文件解析 Json
生成类并提供一些方法MyInputActions.inputactions
的配置文件,选中它后在 Inspector 窗口勾选 Generate C# Class
,设置生成路径为 Assets/Scripts/InputCode
,类名为 GameInputActions
,命名空间为 GameProject.Input
,点击应用后,在指定路径下生成对应的 C# 代码文件GameInputActions input;
声明一个用于监听输入的配置文件对象(这里以 GameInputActions
为例,对应前面生成的类名)Start
方法input = new GameInputActions();
实例化配置文件对象 2. 激活配置文件的输入:
input.Enable();
启用输入 3. 添加事件监听:
input.Action1.Fire.performed += (context) => { print(\"鼠标点击 开火\"); };
input.Action2.Space.performed += (context) => { print(\"空格按下 跳跃\"); };
假设
Action1
是战斗操作行为组,Fire
是其中的开火输入动作;Action2
是移动跳跃行为组,Space
是其中的跳跃输入动作Update
方法print(\"wasd移动\" + input.Action1.Move.ReadValue());
监听输入并打印相关信息 假设
Move
是 Action1
行为组中用于控制角色移动的输入动作,通过 ReadValue
获取移动的向量值并打印1.3.PlayerInput
1.3.1.PlayerInput介绍
PlayerInput
定义InputSystem
提供的用于接受玩家输入并处理自定义逻辑的组件PlayerInput
工作原理InputActions
文件)2. 通过
PlayerInput
关联配置文件,自动解析3. 关联响应函数,处理对应逻辑
PlayerInput
好处2. 通过配置文件配置监听行为
3. 专注于输入事件触发后的逻辑处理
PlayerInput
组件PlayerInput
组件PlayerInput
参数SendMessage
:逻辑脚本挂载在与PlayerInput
同一对象上,通过SendMessage
通知执行函数BroadcastMessage
:逻辑脚本可挂载在自身或子对象上,通过BroadcastMessage
通知执行函数Invoke UnityEvent Actions
:在Inspector
窗口通过拖拽关联函数,响应函数参数类型为InputAction.CallbackContext
,可关联其他对象的脚本函数Invoke CSharp Events
:通过获取PlayerInput
进行事件监听,可得到对应行为的值,如input.currentActionMap[\"Move\"].ReadValue()
SendMessage
示例:在自定义脚本中声明名为“On+行为名”的函数,无参数或参数类型为InputValue
,挂载到PlayerInput
依附对象上。代码如下:
public void OnMove(InputValue value){ print(\"Move\"); print(\"Move\" + value.Get<Vector2>());}public void OnFire(InputValue value){ print(\"Fire\"); if (value.isPressed) { print(\"Fire按下\"); }}
BroadcastMessage
示例:基本规则同SendMessage
,自定义脚本还可挂载在子对象上
Invoke Unity Events
示例|在脚本中声明函数,如:
public void MyFire(InputAction.CallbackContext context){ print(\"开火1\");}public void MyMove(InputAction.CallbackContext context){ print(\"移动1\");}public void MyLook(InputAction.CallbackContext context){ print(\"Look1\");}
在Inspector
窗口通过拖拽关联函数|
Invoke C Sharp Events
示例|
(1). 获取PlayerInput
组件:
PlayerInput input = this.GetComponent<PlayerInput>();
(2). 添加委托函数:
input.onDeviceLost += OnDeviceLost;input.onDeviceRegained += OnDeviceRegained;input.onControlsChanged += OnControlsChanged;input.onActionTriggered += OnActionTrigger;
(3). 处理事件:
public void OnActionTrigger(InputAction.CallbackContext context){ print(\"触发OnActionTrigger\"); switch (context.action.name) { case \"Fire\": if (context.phase == InputActionPhase.Performed) print(\"开火\"); break; case \"Look\": print(\"看向\"); print(context.ReadValue<Vector2>()); break; case \"Move\": print(\"移动\"); print(context.ReadValue<Vector2>()); break; }}
1.3.2.PlayerInput玩家输入管理组件
inputValue.isPressed
获取
Vector2
类型值:inputValue.Get()
Vector2
类型值的x
和y
属性:callbackContext.ReadValue().x
、callbackContext.ReadValue().y
获取输入行为名字:
callbackContext.action.name
获取输入控件名字:
callbackContext.control.name
获取输入控件所属设备名字:
callbackContext.control.device.name
获取输入阶段枚举值:
callbackContext.phase
获取输入阶段字符串表示:
callbackContext.phase.ToString()
PlayerInputManager
作用PlayerInputManager
组件参数PlayerInputManager
通知关联对象的方式,与PlayerInput
工作方式相同Join Players When Button Is Pressed
:新设备加入或无玩家时按下任意键加入Join Players When Join Action Is Triggered
:新设备加入时按下指定按键触发加入,一般选择此项Join Players Manually
:手动加入玩家PlayerInput
组件的游戏对象JoinBehavior
规则加入,默认勾选Max Player Count
为允许的最大玩家数Maintain Aspect Ratio
:控制分屏区域纵横比与实际屏幕分辨率匹配Set Fixed Number
:大于零时,始终将屏幕分割为固定数量矩形Screen Rectangle
:用于分配玩家分屏的规范化屏幕矩形PlayerInputManager
使用示例:
(1). 创建预制体方块,添加PlayerInput
组件和脚本,创建配置文件并关联到预制体的PlayerInput
组件,再关联到PlayerInputManger
的玩家预制体上(预制体需有PlayerInput
组件)
(2). 调整方块预制体对象输入行为为手动关联模式,关联脚本上的Move
函数,代码如下:
private Vector3 dir;void Update(){ this.transform.Translate(dir * 10 * Time.deltaTime);}public void Move(InputAction.CallbackContext context){ dir = context.ReadValue<Vector2>(); dir.z = dir.y; dir.y = 0;}
(3). 选择模式(如按A
键和手柄开始键创建新预制体),PlayerInputManager
自动处理输入控制
(4). 让方块预制体挂载摄像机,勾选分屏选项实现分屏效果
(5). 使用单例获取PlayerInputManager
并添加玩家加入和离开事件:
//获取PlayerInputManager//PlayerInputManager.instance//玩家加入时PlayerInputManager.instance.onPlayerJoined += (playerInput) =>{ print(\"创建了一个玩家\");};//玩家离开时PlayerInputManager.instance.onPlayerLeft += (playerInput) =>{ print(\"离开了一个玩家\");};
1.4.UGUI配合使用
OnGUI
中输入判断内容不触发,让OnGUI
内容有效需选“Both”或只激活老输入系统InputManager
;支持UGUI,需用新输入系统的输入模块(Input System UI Input Module
)处理相关输入false
可防止自动取消选择Single Unified Pointer:所有指针输入统一为一个指针,只有帧中最后一个输入生效
All Pointers As Is:UI输入模块不统一指针输入,每个设备输入都是独立指针,可能出现多个指针同时指向多个对象的情况
DefaultInputActions
内置资产,可创建自定义资源并在此分配,编辑器会根据命名约定自动映射操作到UI输入Canvas
对象上添加Tracked Device Raycaster
组件EventSystem
中的EventSystem
组件替换为Multiplayer Event System
组件(先移除InputSystemUIInputModule
和EventSystem
组件再添加);可同时激活多个MultiplayerEventSystem
,每个玩家有自己的InputSystemUIInputModule
和MultiplayerEventSystem
组件及操作来驱动UI;若使用PlayerInput
组件,可设置其自动配置玩家的InputSystemUIInputModule
;MultilayerEventSystem
组件属性与事件系统中属性相同,还添加了playerRoot
属性,可设为包含此事件系统应处理的所有UI可选择项的游戏对象On - Screen Button
用于按钮交互,On - Screen Stick
用于摇杆交互,关联之前输入配置文件设置好逻辑和关联设备的小球输入,如On - Screen Stick
关联手柄摇杆可像手柄摇杆一样控制小球移动,On - Screen Button
关联空格键可像按空格键一样控制小球跳跃1.5.InputDebug输入调试器
InputDebug
定义InputDebug
窗口的方式Window
(窗口)-> Analysis
(分析)-> Input Debugger
(输入调试器)2. 通过
PlayerInput
组件:点击PlayerInput
组件上的Open Input Debugger
InputDebug
窗口信息 - 未运行状态InputDebug
窗口信息 - 运行状态2.VideoPlayer
2.1.视频剪辑设置
以下是将上述内容整理为表格的形式,方便你更清晰地了解视频剪辑设置的相关知识:
1.
Original
:保持原始大小2.
Three Quarter Res
:调整为原始宽高的四分之三3.
Half Res
:调整为原始宽高的一半4.
Quarter Res
:调整为原始宽高的四分之一5.
Square(1024x1024)
:调整为 1024x1024 正方形图像,宽高比可控6.
Square(512x512)
:调整为 512x512 正方形图像,宽高比可控7.
Square(256x256)
:调整为 256x256 正方形图像,宽高比可控8.
Custom
:调整为自定义分辨率,宽高比可控,可设置Width
(生成图像的宽)、Height
(生成图像的高)9.
Aspect Ratio
:调整图像大小时的宽高比,有No Scaling
(添加黑色区域保留原始宽高比)、Stretch
(拉伸原始内容填充目标分辨率)1.
Auto
:为目标平台选择最合适的视频编解码器2.
H264
:MPEG–4 高级视频编码 (AVC) 视频编解码器,受大多数平台硬件支持3.
H265
:MPEG-H Part 2 或高效视频编码 (HEVC) 视频编解码器,受某些平台硬件支持4.
VP8
:VP8 视频编解码器,受大多数平台软件支持,部分平台(如 Android 和 WebGL)硬件支持1.
Low Spatial Quality
:转码时图像大小显著减小(通常为原始尺寸的四分之一),播放时扩展回原始大小,节省存储空间但播放时模糊度最大2.
Medium Spatial Quality
:转码时图像大小适度减小(通常为原始尺寸的一半),播放时扩展回原始大小,图像更清晰,存储空间有所减少3.
High Spatial Quality
:不调整大小,保持视频原始视觉清晰度1.
Off
:源文件没有隔行扫描,不进行隔行扫描2.
Even
:采用每个帧的偶数行,插入创建缺失内容,丢弃奇数行3.
Odd
:采用每个帧的奇数行,插入创建缺失内容,丢弃偶数行隔行扫描和逐行扫描区别:
隔行扫描:每一帧被分割为两场,包含奇数或偶数扫描行,交替显示,存在闪烁,人眼易疲劳
逐行扫描:每次显示整个扫描帧,画面更平滑,闪烁较小
2.2.VideoPlay视频播放器
2.2.1.VideoPlayer组件参数
2.2.2.VideoPlayer参数和方法
参数设置:
// 是否自动播放,设置为 false 表示不自动播放videoPlayer.playOnAwake = false; // 设置渲染模式为在摄像机的远平面上渲染videoPlayer.renderMode = VideoRenderMode.CameraFarPlane; // 设置目标渲染贴图为 renderTexture(需提前定义)videoPlayer.targetTexture = renderTexture; // 设置目标摄像机为名为 \"Main Camera\" 的摄像机videoPlayer.targetCamera = GameObject.Find(\"Main Camera\"); // 设置目标摄像机的透明度为 0.5videoPlayer.targetCameraAlpha = 0.5f; // 以 Over-Under3D 格式呈现视频videoPlayer.targetCamera3DLayout = Video3DLayout.OverUnder3D; // 设置视频源模式为使用视频剪辑videoPlayer.source = VideoSource.VideoClip; videoPlayer.clip = videoClip; // 或者设置视频源模式为使用 URL 路径// videoPlayer.source = VideoSource.Url; // videoPlayer.url = Application.streamingAssetsPath + \"/Video.mp4\"; // 设置视频不循环播放videoPlayer.isLooping = false;
视频状态输出:
// 输出视频总时长,单位为秒print(videoPlayer.length); // 输出当前视频播放的时长,单位为秒print(videoPlayer.time); // 输出视频的总帧数print(videoPlayer.frameCount); // 输出当前视频播放到的帧print(videoPlayer.frame);
方法:
// 播放视频videoPlayer.Play(); // 停止视频,再次播放时会从头开始videoPlayer.Stop(); // 暂停视频播放videoPlayer.Pause(); // 为视频准备数据,提前调用可避免播放时卡顿videoPlayer.Prepare();
事件:
// 准备完成事件,当视频准备完成后触发,可用于避免播放卡顿videoPlayer.prepareCompleted += (v) =>{ print(\"准备完成\"); isPrepareCompleted = true;};// 开始事件,当执行 videoPlayer.Play() 方法后调用videoPlayer.started += (v) =>{ print(\"当执行 player 播放方法后 会调用的事件\");};// 结尾事件,当视频播放到结尾处时调用videoPlayer.loopPointReached += (v) =>{ print(\"视频播放到结尾处时会调用的事件\");};
2.3.全景视频
Unity 支持两种类型的全景视频:
- 等距圆柱投影布局:也被称为球面投影、简化圆柱投影、矩形投影或普通圆柱投影。这种布局的全景视频,其宽高比通常为 2:1(对应 360 度内容)或 1:1(对应 180 度内容)。
- 立方体贴图布局:由六个正方形纹理的集合构成。该布局的全景视频宽高比包括 1:6、3:4、4:3、6:1 等。可以通过视频分辨率的比值来判断该全景视频属于哪种布局类型。
在 Unity 中使用全景视频
(1). 导入等距圆柱投影布局的视频文件时,可以通过观察其分辨率是否为 2:1 来进行初步判定。
(2). 使用 Video Player 组件,将其渲染模式设置为以 Render Texture(渲染纹理)来播放视频。
(3). 设置接受渲染纹理的天空盒材质,具体操作为将天空盒材质的着色器设置为 Skybox>Panoramic。
(4). 配置场景,使其使用所设置的天空盒材质。
(5). 运行测试,尝试旋转摄像机的角度,查看全景视频的播放效果。
需要注意的是,为了获得更好的视觉效果,尽量使用较高分辨率的全景视频,如 4K 或 8K 分辨率。但对于一些老旧设备或者移动设备,由于性能限制,可能最多只能支持 2K 分辨率,具体情况需根据实际设备性能来确定。
** 使用全景视频时的注意事项**
(1). Render Texture(渲染纹理)方面:确保 Render Texture 的 Size(尺寸)与视频的尺寸保持一致,可以在视频预览窗口中选择 Source Info(源信息)来查看视频的分辨率。同时,将渲染纹理的 Depth Buffer(深度缓冲区)设置为 No depth buffer(无深度缓冲区)。
(2). 天空盒材质方面:
- 对于等距圆柱投影布局,在天空盒材质中将 Mapping(映射)设置为 Latitude Longitude Layout(经纬度布局),然后根据视频是 180 视图还是 360 视图,相应地选择 360 degree(360 度)或者 180 degree(180 度)。
- 对于立方体贴图布局,将 Mapping 设置为 6 Frames Layout(6 帧布局)。
- 如果视频是 VR 视频:
- 当视频内容分为左右双眼显示时,需要将天空盒材质的 3D Layout(3D 布局)设置为 Side by Side(并排)。
- 当左右侧内容在视频中呈上下分布时,3D Layout 应设置为 Over Under(上下)。
3.ScriptableObject
3.1.ScriptableObject数据文件的创建
注意:需要继承ScriptableObject类
(1)为类添加CreateAssetMenu通过菜单创建资源特性 [CreateAssetMenu(fileName = “默认文件名”, menuName = “在Asset/Create菜单中显示的名字”, order = 再Asset/Create菜单中的位置(多个时可以通过它来调整顺序))]
[CreateAssetMenu(fileName =\"MrTangData\", menuName =\"ScriptableObject/我的数据\", order = 0)]public class MyData : ScriptableObject{}
(2)利用ScriptableObject的静态方法创建数据对象,然后将数据对象保存在工程目录下
// 调用ScriptableObject的静态方法CreateInstance,创建一个继承自ScriptableObject的MyData类型的实例// 这里的MyData是自定义的数据类,必须继承自ScriptableObjectMyData myDataAsset = ScriptableObject.CreateInstance<MyData>(); // 使用Unity编辑器的API AssetDatabase的CreateAsset方法,根据创建的实例myDataAsset// 在指定路径\"Assets/Unity进阶ScriptableObject教程/Lesson02_ScriptableObject数据文件的创建/MyDataTest.asset\"创建一个数据资源文件AssetDatabase.CreateAsset(myDataAsset, \"Assets/Unity进阶ScriptableObject教程/Lesson02_ScriptableObject数据文件的创建/MyDataTest.asset\");// 调用AssetDatabase的SaveAssets方法,保存当前创建的所有资源文件到项目中AssetDatabase.SaveAssets();// 调用AssetDatabase的Refresh方法,刷新Unity编辑器的界面,使新创建的资源在编辑器中及时显示出来AssetDatabase.Refresh();
3.2.ScriptableObject数据文件的使用
方法一:通过Inspector中的public变量进行关联
方法二:通过资源加载的信息关联
myData = Resources.Load(\"MyDataTest\");
3.3.ScriptableObject非持久数据和持久化
MyData myData = ScriptableObject.CreateInstance();
csharp
myData.PrintInfo();
myData.i = 9999;
myData.f = 6.6f;
myData.b = true;
//将数据对象序列化为json字符串:
string str = JsonUtility.ToJson(myData);
print(str);
//把数据序列化后的结果存入指定路径当中:
File.WriteAllText(Application.persistentDataPath + \"/testJson.json\", str);
print(Application.persistentDataPath);
csharp
//从本地读取Json字符串:
str = File.ReadAllText(Application.persistentDataPath + \"/testJson.json\");
//根据json字符串反序列化出数据将内容覆盖到数据对象中:
JsonUtility.FromJsonOverwrite(str, myData);
// FromJsonOverwrite方法是将JSON数据覆盖到现有对象
// FromJson方法JSON数据转换为新的对象实例用一个新对象来接(就算用老对象来接 也是引用新的实例)
myData.PrintInfo();
3.4.ScriptableObject单例
实现单例模式化获取数据
实现单例模式化获取数据需要运用到面向对象、单例模式、泛型等知识。我们可以创建一个ScriptableObject
数据单例模式基类,这样一来,只要让子类继承这个基类,就可以直接获取到数据,而无需再使用public
关联或者资源动态加载的方式。
我们定义了一个名为SingleScriptableObject
的泛型类,它继承自ScriptableObject
。这个类的作用是实现单例模式的ScriptableObject
对象。在类中,定义了一个私有静态字段instance
,用于存储单例对象;还定义了一个公共静态属性Instance
,用于获取单例对象,该属性的类型为泛型参数T
。
在Instance
属性的get
访问器中,首先检查单例对象instance
是否为空。如果为空,就尝试从资源路径下加载对应的数据资源文件。按照约定,数据资源文件的路径为Resources/ScriptableObject/
,并且文件名与类名相同。如果没有找到对应的数据资源文件,为了保证程序的正常运行,会直接创建一个新的数据对象。最后,返回单例对象。具体代码如下:
public class SingleScriptableObject<T> : ScriptableObject where T : ScriptableObject{ private static T instance; public static T Instance { get { // 如果为空 首先应该去资源路径下加载 对应的 数据资源文件 if (instance == null) { // 我们定两个规则 // 1.所有的 数据资源文件都放在 Resources文件夹下的ScriptableObject中 // 2.需要复用的 唯一的数据资源文件名 我们定一个规则:和类名是一样的 instance = Resources.Load<T>(\"ScriptableObject/\" + typeof(T).Name); } // 如果没有这个文件 为了安全起见 我们可以在这直接创建一个数据 if (instance == null) { instance = CreateInstance<T>(); } // 甚至可以在这里 从json当中读取数据,但是我不建议用ScriptableObject来做数据持久化 return instance; } }}
例如,让RoleInfo
类继承SingleScriptableObject
:
public class RoleInfo : SingleScriptableObject<RoleInfo>
或者创建TestData
类继承SingleScriptableObject
:
[CreateAssetMenu]public class TestData : SingleScriptableObject<TestData>{ public int i; public bool b;}
这样,就可以直接使用Instance
单例来获取数据文件了。无论Resource/ScriptableObject
路径下有没有对应的数据文件都可以正常获取。如果没有,程序会动态生成默认的数据。使用示例如下:
print(RoleInfo.Instance.roleList[0].id);print(RoleInfo.Instance.roleList[1].tips);print(TestData.Instance.i);print(TestData.Instance.b);
4.TextMeshPro
4.1.TextMeshPro UI
4.1.1.TextMeshPro UI组件参数
C1、C2、C3:颜色级别,区分文本颜色
Quote:引用文本样式
Link:超链接文本格式样式
Title:标题样式
Normal:普通正文文本样式
Material Preset:TMP字体显示基于材质球,切换材质球改变渲染效果(因Shader着色器不同),可调整材质球参数(如边缘线)
Font Style:B:加粗(Bold);I:斜体(Italic);U:下划线(Underline);S:删除线(Strikethrough);ab:小写文本(Small Caps Lowercase);AB:大写文本(All Caps);SC:大写文本,按实际输入字母大小显示(Small Caps)
Auto Size:勾选后有更多设置选项,消耗大少用。Auto Size Options:Min:最小字体大小(Minimum Size);Max:最大字体大小(Maximum Size);WD%:水平挤压字符(Width Percentage);Line:减少行间距(负数)(Line Spacing Reduction,negative value)
Color Preset:颜色预设(Color Preset)
Color Mode:Single:与顶点颜色叠加(Overlay with Vertex Color);Horizontal Gradient:双色水平渐变(Two-Color Horizontal Gradient);Vertical Gradient:双色垂直渐变(Two-Color Vertical Gradient);Four Corners Gradient:四色四角渐变(Four-Color Four-Corners Gradient)
Colors:依颜色模式设置多个颜色值
居中对齐:文本居中对齐(Center Align)
右对齐:文本靠右对齐(Right Align)
拉伸左对齐:增加间距填满行,最后一行不拉伸(Justify Left,last line not justified)
拉伸齐平:类似拉伸左对齐,最后一行也拉伸(Justify Full)
网格居中:按网格居中文本,效果更细致(Mesh Center,more delicate effect)
中部对齐:文本垂直居中对齐(Middle Align Vertically)
底部对齐:文本靠底部对齐(Bottom Align)
基线对齐:第一行基线与显示区域中间对齐,适用于单行文本(Baseline Align,suitable for single-line text)
中线对齐:类似中部对齐,依文本网格边界垂直放置,适合狭小空间(Middle Line Align,placed vertically according to text mesh boundary,suitable for narrow spaces)
卡普赖恩对齐:第一行中间与显示区域中间对齐(Cap Height Align,align the middle of the first line with the middle of the display area)
Enabled:控件大小变化时文本自动换行(Text wraps automatically when the control size changes)
Ellipsis:超出部分用省略号代替(Replace the overflowing part with an ellipsis)
Masking:类似Overflow,隐藏显示区域外内容(Similar to Overflow, hide the content outside the display area)
Truncate:超出内容直接截断不显示(Truncate the overflowing content and do not display it)
Scroll Rect:仅用于旧版TextMesh Pro项目兼容,新项目建议用遮罩模式(Only used for compatibility with legacy TextMesh Pro projects. It is recommended to use the masking mode for new projects)
Page:文本切分为多个页面,可选择显示具体页面内容(Divide the text into multiple pages, and you can select the specific page content to display)
Linked:文本扩展到指定TextMesh Pro游戏对象,当前对象溢出内容在关联对象显示(Extend the text to the specified TextMesh Pro game object, and the overflowing content of the current object will be displayed in the associated object)
Line:在每条线宽度上水平拉伸纹理(Stretch the texture horizontally across the entire width of each line)
Paragraph:在整个文本中水平拉伸纹理(Stretch the texture horizontally across the entire text)
Match Aspect:水平缩放纹理,保持纵横比不变(Scale the texture horizontally while maintaining the aspect ratio)
Line:在每条线高度上垂直拉伸纹理(Stretch the texture vertically across the entire height of each line)
Paragraph:在整个文本中垂直拉伸纹理(Stretch the texture vertically across the entire text)
Match Aspect:垂直缩放纹理,保持纵横比不变(Scale the texture vertically while maintaining the aspect ratio)
Reverse:按相反顺序绘制四边形,重叠时远离摄像机的在前面(Draw quadrilaterals in the opposite order. When they overlap, the ones farther from the camera are in the front)
4.1.2.TextMeshPro UI参数和方法```
TextMeshPro UI 组件常用属性
textMeshProUGUI.text = \"123123adfasdklf545454564654654646454564654132156465424\";
textMeshProUGUI.font = ...; // 获取或设置字体
textMeshProUGUI.fontSize = 10;
textMeshProUGUI.color = Color.black;
textMeshProUGUI.alignment = TextAlignmentOptions.Center;
textMeshProUGUI.lineSpacing = 50;
textMeshProUGUI.richText = false;
TextMeshPro UI 组件常用方法
textMeshProUGUI.SetText(\"Hello, World!\");
textMeshProUGUI.Rebuild(UnityEngine.UI.CanvasUpdate.Prelayout);
textMeshProUGUI.ForceMeshUpdate();
print(textMeshProUGUI.text.Length);
CanvasUpdate
枚举
Prelayout
:布局前调用Layout
:布局时调用PostLayout
:布局后调用PreRender
:渲染前调用LatePreRender
:渲染后调用MaxUpdateValue
:最后调用
** UI 事件监听**
若要为 TMP UI 添加交互事件,可使用 UGUI 中的 EventTrigger
组件。
4.2. 3D 文本和 UI 文本区别:
TextMeshPro
组件TextMeshProUGUI
组件EventTrigger
TextMeshPro
,将其视为 3D 物体进行处理TextMeshProUGUI
,将其视为 UI 组件处理using TMPro;using UnityEngine;public class Lesson09_3D 文本 : MonoBehaviour{ public TextMeshProUGUI textMeshProUGUI; // UI 文本组件
public TextMeshPro textMeshPro; // 3D 文本组件}
4.3.字体资源
4.3.1.字体资源-基本信息设置
Optimum:尽可能合理利用纹理中的空间,保持字符最大可能的字体大小,正式确定字体时使用
Extended ASCII:拓展 ASCII 字符集(增加了许多特殊字符和符号)
ASCII Lowercase:仅包含小写字母字符(a~z)
ASCII Uppercase:仅包含大写字母字符(A-Z)
Numbers + Symbols:包含数字(0-9)和常见的符号(如 !, @, #, $, % 等)
Custom Range:允许用户定义一个自定义字符范围,用户可以指定要包含的 Unicode 范围
Unicode Range(Hex):允许用户输入 Unicode 范围的十六进制值
Custom Characters:用户可以手动输入要包含的具体字符,可以是任何字符(如字母、符号等)
Characters from File:从文本文件中读取字符,允许用户根据文件内容自动生成字符集,适合大量字符的处理
SMOOTH:采用抗锯齿效果,提供平滑的边缘,适合大多数情况下的文本显示
COLOR_HINTED:基于颜色的抗锯齿效果,强调颜色的呈现,适合需要突出颜色的文本
COLOR:不使用抗锯齿,直接渲染文本的颜色,适合在高对比度或需要清晰边缘的场景中使用
RASTER_HINTED:位图渲染,通常用于较小字体,能够提供较高的清晰度
RASTER:位图渲染,不进行抗锯齿处理,提供快速渲染,但在边缘可能出现锯齿现象
SDF:使用带符号的距离场技术渲染,能够在缩放时保持清晰度
SDF8:使用 8 位 SDF 渲染,支持更小的纹理,适合资源受限的环境
SDF16:使用 16 位 SDF 渲染,提供更高的清晰度和更细腻的边缘
SDF32:使用 32 位 SDF 渲染,具有最高的细节和清晰度
SDFAA_HINTED:使用抗锯齿的 SDF 渲染,提供平滑的边缘和清晰的字符显示
SDFAA:使用 SDF 渲染,但不进行抗锯齿处理,快速渲染
4.3.2.字体资源-生成设置和图集纹理
Static(静态模式):字体集在创建时需要一个固定的纹理图集,适用于字符已知且不需要动态变化的情况,如仅有少量英文字符时。
Dynamic(动态模式):字体纹理图集会在运行时根据需要动态生成,能够显示更多字符,适合中文项目或多语言项目
SMOOTH_HINTED:抗锯齿位图,字符像素和纹理像素对齐,适合小字体或精确对齐的场景。
SMOOTH:提供平滑边缘,适用于大多数文本显示,兼顾清晰度和性能。
COLOR_HINTED:基于颜色的抗锯齿,突出颜色效果。
COLOR:不使用抗锯齿,适用于高对比度或需要清晰边缘的场景。
RASTER_HINTED:位图渲染,适合较小字体,但放大时可能模糊。
RASTER:快速渲染模式,但边缘可能出现锯齿。
SDF:带符号距离场技术,支持缩放时保持清晰。
SDF8:8 位 SDF 渲染,适用于资源受限环境。
SDF16:16 位 SDF 渲染,提供更高清晰度。
SDF32:32 位 SDF 渲染,适合需要极高质量的文本。
SDFAA_HINTED:抗锯齿的 SDF 渲染,提供平滑边缘和清晰字符显示。
SDFAA:SDF 渲染但无抗锯齿,快速渲染但可能出现锯齿
Auto Sizing:使用尽可能大的字体大小(推荐)。
Custom Size:自定义字体大小
4.3.3.字体资源-字体粗细
4.3.4.字体资源-其他设置
4.4.富文本标签
这是文本加粗示例。
这是文本斜体示例。
这是加下划线示例。
这是改变大小示例。
这是改变颜色示例。
这是左对齐示例。
这是背景高亮示例。
这是透明度示例。
这是全部大写示例。
123 这是改字体和材质示例。
正常这是加上标示例。
正常这是加下标示例。
这是超链接示例。
4.5.样式表
标签包裹文字应用样式,本质是对富文本标签的复用,能避免重复书写冗余的富文本样式编码4.6.图文混排
1. 图片名称。
2. 图片位置和宽度相关参数,配合全局偏移和缩放参数设置。
关键参数:
BX、BY:相对于基线的原点的左上角。
AD:放置下一个内容时向右前进的位置
1.
2.
3.
1.
2.
4.7.项目设置TextMeshPro基本设置
4.8.SDF材质球
Texture:为文本添加贴图
Tiling:平铺(缩放)
Offset:偏移
Speed:移动速度(可实现滚动效果,配合 UV 配置)
Softness:边缘柔和度,使文字边缘模糊
Dilate:拓展,类似改变字体粗细
Texture:边缘线纹理,与轮廓颜色相乘叠加
Thickness:轮廓粗细,值越大越粗
None:无阴影
Normal:标准底图样式
Inner:反转底图,用原始文本遮罩它
Color:底图阴影颜色
Offset X:X 轴偏移
Offset Y:Y 轴偏移
Dilate:拓展,改变粗细
Softness:边缘柔和度,使阴影边界模糊
Outer Bevel:外斜面,字体有倾斜侧面的凸起效果
Inner Bevel:内斜面,字体轮廓向内凹陷
Amount:陡峭程度
Offset:位置偏移
Width:斜面大小
Roundness:使斜面更平滑
Clamp:限制斜面最大高度
Specular Color:镜面反射颜色
Specular Power:镜面反射强度
Reflectivity Power:反射强度
Diffuse Shadow:漫反射阴影
Amblent Shadow:环境阴影
Face:凹凸影响程度
Outline:凹凸贴图对文本轮廓的影响程度
Outline Color:立方体贴图对轮廓颜色的影响
Texture:环境立方体贴图
Rotation:旋转环境贴图
Offset:发光效果中心偏移值
Inner:发光效果向内延伸距离
Outer:发光效果向外延伸距离
Power:发光强度
Gradient Scale:渐变比例
Texture Width/Height:纹理宽高
Scale X/Y:SDF 比例乘数
Sharpness:清晰度
Perspective Filter:透视过滤器,使文本在透视摄像机下更柔和
Offset X/Y:每个字符顶点位置的偏移量
Mask:
关闭蒙版
硬蒙版
柔和蒙版
Clip Rect:剪辑矩形,设置遮罩矩阵范围
Stencil ID:模板 ID
Stencil Comp:模板成分
Uset Ratios:使用率
Cull Mode:裁剪模式
4.9.MP_TextEventHandler
TMP_TextEventHandler
onLinkSelection
string linkInfo
:超链接的相关信息;string linkText
:超链接显示的文本;int index
:超链接在文本中的索引位置TMP_TextEventHandler
onCharacterSelection
char charInfo
:被点击或悬停的字符;int i
:字符在文本中的索引位置TMP_TextEventHandler
onSpriteSelection
char spirteInfo
:与精灵图片相关的字符信息;int i
:精灵图片在文本中的索引位置TMP_TextEventHandler
onWordSelection
string word
:被点击或悬停的单词;int i1
:单词在文本中的起始索引位置;int i2
:单词在文本中的结束索引位置TMP_TextEventHandler
onLineSelection
string lineInfo
:被点击或悬停的行文本内容;int i1
:行在文本中的起始索引位置;int i2
:行在文本中的结束索引位置4.10.TMP_TextUtilities
int FindIntersectingLink(TMP_Text text, Vector3 position, Camera camera)
获取单词索引:
int FindIntersectingWord(TMP_Text text, Vector3 position, Camera camera)
获取单字符索引:
int FindIntersectingCharacter(TMP_Text text, Vector3 position, Camera camera)
获取行索引:
int FindIntersectingLine(TMP_Text text, Vector3 position, Camera camera)
int FindNearestLink(TMP_Text text, Vector3 position, Camera camera)
获取单词索引:
int FindNearestWord(TMP_Text text, Vector3 position, Camera camera)
获取单字符索引:
int FindNearestCharacterOnLine(TMP_Text text, Vector3 position, Camera camera)
获取行索引:
int FindNearestLine(TMP_Text text, Vector3 position, Camera camera)
using TMPro;using UnityEngine;using UnityEngine.EventSystems;public class Lesson22_TMP_TextUtilities : MonoBehaviour, IPointerClickHandler{ public TextMeshProUGUI textMeshProUGUI; public void OnPointerClick(PointerEventData eventData) { print(\"OnPointerClick TextMeshProUGUI\"); // 获取链接索引,传入 TMP、鼠标位置、UI 摄像机(默认可以传 null) int linkIndex = TMP_TextUtilities.FindIntersectingLink(textMeshProUGUI, eventData.position, null); // 如果不为 -1,则证明点击到了一个超链接信息 if (linkIndex != -1) { // 获取超链接显示的文本信息,例如 \"百度\" print(textMeshProUGUI.textInfo.linkInfo[linkIndex].GetLinkText()); // 获取富文本标签 中的? 具体地址信息,例如 \"谷歌\" print(textMeshProUGUI.textInfo.linkInfo[linkIndex].GetLinkID()); } // 获取单字符索引,传入 TMP、鼠标位置、UI 摄像机(默认可以传 null)、是否检测可见性 int charIndex = TMP_TextUtilities.FindIntersectingCharacter(textMeshProUGUI, eventData.position, null, true); // 如果索引不为 -1,打印点击到的字符 if (charIndex != -1) { print(textMeshProUGUI.textInfo.characterInfo[charIndex].character); } }}