Unity 安装 安装 Unity Hub
下载链接: https://unity.cn/releases
选择长期支持版本, 进行下载
下载完成后进行安装
设置安装目录: D:\Program Files\Unity\Unity Hub
开始安装
安装 Unity 编辑器
打开 Unity Hub, 在界面选择 installs
然后选择 Install Editor, 选择想要的版本
设置安装位置: D:\Program Files\Unity\Editor
开始安装
获取许可证
许可证 → 添加 → 获取个人许可证
编辑器设置 中文界面
打开 Unity Hub → 安装 → 找到要汉化的 Unity 编辑器 → 点击齿轮图标 → 添加模块 → 选择语言包( 这里注意, 要把安装开发工具那个勾选取消掉) → 开始安装
打开项目 → Edit → Preferenges → Language → 简体中文 → 等待加载
如果没有直接更改为中文, 重启一下编辑器就好了
基本组件 项目文件夹 💗💗 每个项目的结构可能会有所不同, 具体取决于开发者的需求和个人偏好。
文件夹 描述
Assets
这是Unity项目的核心文件夹, 包含了所有可以被导入到Unity编辑器中的资源文件。
这些资源包括但不限于模型、 纹理、 脚本、 音频文件等。
在Assets文件夹内, 你可以根据需要进一步划分子文件夹来组织你的资源。
Library
该文件夹包含了 Unity 生成的所有缓存文件和中间构建结果。
这些文件不会被包含在最终的构建输出中, 但对编辑器来说非常重要。
一般情况下, 你不应该手动修改这个文件夹里的内容。
Logs
存放Unity编辑器的日志文件, 可以帮助开发者追踪错误或警告信息。
Packages
用于存放Unity的包管理器所安装的各种包, 这些包可以是Unity官方提供的, 也可以是第三方开发者制作的。
ProjectSettings
包含项目的各种设置文件, 比如渲染设置、 物理系统设置等。 这些文件控制着整个项目的全局行为。
Temp
用于存放临时文件, 在构建过程中可能会用到。
构建完成后, 这些文件可以被安全删除。
UserSettings
用来存储与用户设置相关的配置文件的一个特殊文件夹。
这些配置文件通常包含了用户的偏好设置、 游戏进度等非图形资源的数据。
Plugins
用于放置平台特定的插件库文件( 例如.dll, .so, .dylib等) 。
插件库可以扩展Unity的功能, 提供额外的能力。
StreamingAssets
这个文件夹中的文件会被包含在最终的构建输出中, 并且可以在运行时访问。
通常用于存放一些不希望被Unity资源加载系统处理的文件, 如文本文件、 配置文件等。
Editor
如果你的项目包含了一些自定义编辑器工具或者脚本, 可以将它们放在这个文件夹下。
只有在编辑器模式下这些脚本才会被编译和执行。
Resources
用于存放那些需要通过Resources.Load方法加载的资源文件。
通常用于存放一些小文件或者需要频繁访问的资源。
面板视图 💗💗 Unity 编辑器各个面板视图的作用
/ 视图 描述 快捷键
Project
项目视图
显示项目中的所有文件和资源, 如脚本、 材质、 纹理、 模型等。 可以通过双击文件将其导入到场景中。
Ctrl + D 复制文件
Scene
场景视图
展示当前场景中的所有对象, 并允许在其中进行交互操作。 可以移动相机视角、 选择物体、 调整物体位置等。
W: 移动、 E: 旋转、 R: 缩放
Hierarchy
层级视图
列出场景中的所有 GameObject( 游戏对象) , 并显示它们之间的层次关系。 可以在此处创建新对象、 删除对象或改变它们的父子关系。
Ctrl + D 复制选中的 GameObject
Inspector
检查器视图
显示当前选中 GameObject 的属性和组件。 可以在这里修改对象的变换信息( 位置、 旋转、 缩放) 、 添加组件、 编辑组件属性等。
Ctrl + Shift + I 选中 Inspector 视图
Console
控制台视图
显示编辑器和运行时的日志信息, 包括警告和错误消息。
Ctrl + Shift + C 打开 Console 视图
Game
游戏视图
模拟游戏在目标平台上运行的情况。
Ctrl + G 切换 Game View 的焦点
Animator
动画器视图
用于创建和编辑角色动画。 可以创建动画状态机、 设置过渡条件等。
可通过 Window > Animation 打开
Asset Store
资源商店
一个内置的市场, 可以在其中搜索和下载各种免费或付费的资源, 如模型、 材质、 脚本等。
可通过 Window > Asset Store 打开
Package Manager
包管理器
管理 Unity 的附加包, 可以安装、 更新或卸载各种扩展包, 这些扩展包提供了额外的功能或工具。
可通过 Window > Package Manager 打开
Profiler
分析器视图
用于性能分析, 可以帮助了解游戏中哪些部分最耗性能, 并找出优化方向。
可通过 Window > Profiler 打开
Timeline
时间线视图
用于创建复杂的音频和视频剪辑, 适用于制作游戏内的过场动画或交互式叙事内容。
可通过 Window > Timeline 打开
Scripting Definition Editor
脚本定义编辑器
用于定义和管理 C# 脚本的元数据, 如事件函数、 属性等。
可通过 Window > Scripting Definition Editor 打开
Preferences
偏好设置
设置 Unity 编辑器的行为和外观, 例如界面颜色方案、 键盘布局等。
可通过 Edit > Preferences 打开
Layouts
窗口布局
保存和加载编辑器的窗口布局, 以便快速切换至预先设置好的工作空间。
可通过 Window > Layouts 打开
Scene Dock
场景停靠
允许将场景视图固定在一个位置, 即使在编辑器中导航其他窗口也不会改变场景视图的位置。
可通过拖拽场景视图到编辑器边缘来启用
构建物体 Unity 支持创建多种基本形状( Primitives) , 如立方体、 球体、 圆柱体等。
💗💗 创建示例
创建文件夹: 在 Project 视图, Assets 文件夹中, 点击右键 → Create → Folder → 对文件夹进行命令
创建场景 : 点击进入新创建的文件夹中, 点击右键 → Create → Scene → 对场景进行命令
创建物体 : 点击进入新创建场景
创建空对象: 在 Hierarchy 视图中点击右键 → Create Empty → 对空对象进行命令
创建物体: 右键点击空对象 → 3D Object → 选择想要创建的基本形状( 比如 Cube, Sphere, Cylinder 等) 。
组合物体: 可以使用多个物体进行拼合, 拼合的物体就是一个对象。
几何基本体 几何基本体( Primitives) 是最简单的三维模型, 通常由Unity这样的游戏引擎内置提供。 它们可以快速创建场景的基础结构, 例如墙壁、 地面、 天空盒等。
Primitives 物体 描述
Cube
立方体
可以作为墙壁或地面的基本形状
Sphere
球体
可以用作角色头部或者小行星等圆形物体
Cylinder
圆柱体
适合制作树木的树干或灯杆
Capsule
胶囊体
可以用来创建简单的角色模型或障碍物
Plane
平面
作为地面或者墙壁的表面
Quad
四边形
适合制作UI元素或贴图
Ring
环形
可以用作装饰性物体或特殊效果
其他物体
/ 物体 操作
Material
材质
在Assets文件夹内, 右键点击 → Create → Material → 为材质命名
Light
光源
在Hierarchy 视图中点击右键 → Light → 选择一种光源类型( Directional Light, Point Light, Spot Light 等)
Camera
摄像机
在 Hierarchy 视图中点击右键 → Camera
UI
按钮、 文本、 图像等
在 Hierarchy 视图中点击右键 -> UI -> 选择一个 UI 元素类型( Button, Text, Image 等)
坐标系 💗💗 局部坐标系 局部坐标系是指相对于父对象( 如果有) 的坐标系。 如果没有父对象, 则局部坐标系就是物体自己的坐标系。
局部坐标系的原点通常是物体的中心位置, 也可以通过变换组件 (Transform) 来移动这个原点。
物体的旋转和缩放也都是基于局部坐标系来进行的。
X 轴: 通常表示物体的宽度方向, 即物体左右的方向。
Y 轴: 通常表示物体的高度方向, 即物体上下方向。
Z 轴: 通常表示物体的深度方向, 即物体前后方向。
💗💗 世界坐标系 世界坐标系是全局坐标系, 它定义了场景中的绝对位置。 无论物体如何移动或旋转, 其世界坐标始终是相对于场景的原点( 通常是场景的左下角) 而言的。
X 轴: 场景中的水平方向, 通常从左向右。
Y 轴: 垂直向上, 通常表示高度方向。
Z 轴: 指向屏幕外的方向, 即从屏幕向后。
💗💗 局部与世界坐标系的区别
位置: 物体的局部位置 (transform.localPosition) 是相对于其父物体的位置; 而物体的世界位置 (transform.position 或 transform.position) 是相对于世界原点的位置。
旋转: 物体的局部旋转 (transform.localRotation) 是相对于其父物体的旋转; 而物体的世界旋转 (transform.rotation) 是相对于世界坐标系的旋转。
缩放: 物体的局部缩放 (transform.localScale) 是相对于其父物体的缩放; 而物体的世界缩放 (transform.lossyScale) 是考虑了父物体缩放后的最终比例。
属性和组件 Inspector 面板是 Unity 编辑器中非常重要的一个组成部分, 它允许你查看和编辑当前选中 GameObject 的属性和组件。 每一种不同的物体都有其对应的属性, 可以通过修改属性, 改变物体的位置和外观。
视图调整 视图操作快捷键
平移视图: 默认情况下, 按住鼠标中键( 或同时按下左键和右键) 并拖动鼠标可以平移视图。
缩放视图: 滚动鼠标滚轮可以缩放视图。
旋转视图: 按住 Alt 键并拖动鼠标可以旋转视图。
切换视图类型
透视视图( Perspective) : 按 P 键。
正交视图( Orthographic) : 按 O 键。
工具切换快捷键
选择工具( Select Tool) : 按 Q 键。 这是默认的选择工具, 用于选择和移动游戏对象。
平移工具( Move Tool) : 按 W 键。 用于在场景视图中移动游戏对象。
旋转工具( Rotate Tool) : 按 E 键。 用于在场景视图中旋转游戏对象。
缩放工具( Scale Tool) : 按 R 键。 用于在场景视图中缩放游戏对象。
调整工具( Rect Tool) : 按 T 键。 用于在场景视图中调整游戏对象。
整合( Transform Tool) : 按 Y 键。 上述的功能的整合体工具。
其他常用快捷键
捕捉模式: 按 . 键可以启用捕捉模式, 使游戏对象的移动、 旋转和缩放更加精确。
取消捕捉模式: 再次按 . 键可以取消捕捉模式。
全选游戏对象: 按 Ctrl + A( Windows/Linux) 或 Cmd + A( Mac) 可以全选场景中的所有游戏对象。
保存场景: 按 Ctrl + S( Windows/Linux) 或 Cmd + S( Mac) 可以保存当前场景。
脚本函数 生命周期
生命周期 函数 描述
初始化阶段
Awake
此方法在任何初始化之前调用
OnEnable
当脚本启用时调用。 如果脚本在场景启动时就是启用状态, 则 OnEnable 会在 Awake 方法之后立即调用。
Start
在脚本第一次被启用, 并且所有依赖组件加载完成之后调用。 这是初始化脚本的常用位置。
更新阶段
OnAnimatorIK
如果脚本绑定了一个 Animator 组件, 那么在每次 Update 之前会调用此方法。 用于设置动画 IK 和身体遮挡。
OnAnimatorMove
如果脚本绑定了一个 Animator 组件, 那么在每次 Physics.Update 之前会调用此方法。 用于改变动画的状态。
FixedUpdate
在每一帧的固定时间间隔内调用。 通常用于物理模拟, 因为它保证了固定的更新率, 即使帧速率变化也不会影响物理效果。
Update
在每一帧调用。 通常用于处理用户输入、 移动物体等。
LateUpdate
在所有 Update 方法完成后调用。 常用于调整相机位置或执行其他依赖于 Update 方法中已更新的数据的操作。
OnPostRender
在渲染每一帧之后调用。 通常用于绘制额外的图形或调试信息。
清理阶段
OnDisable
在脚本被禁用时调用。
OnDestroy
在脚本被销毁前调用。 通常是用于释放资源。
💗💗 注意事项 💗💗
1. Update 和 FixedUpdate 的调用顺序取决于 Unity 的版本以及是否启用了 Deterministic Update Order。
2. Awake 总是在 Start 之前调用, 但 Start 不一定会在 FixedUpdate 或 Update 之前调用。
3. OnEnable 和 OnDisable 可以用来处理脚本启用和禁用时的事件, 比如注册或取消注册事件监听器。
4. OnAnimatorIK 和 OnAnimatorMove 只在绑定 Animator 组件时才有效。
常见的类 在 Unity 中, 有许多类构成了游戏开发的核心部分。 这些类主要集中在 UnityEngine 命名空间中, 并且它们为创建游戏对象、 处理物理、 动画等提供了必要的功能。
功能 类名 描述
对象管理
Object
一切的基础类, 所有 Unity 中的对象都继承自这个类。
GameObject
表示场景中的一个实体, 可以附加组件。
Component
GameObject 的组件, 负责处理特定的功能, 如渲染或物理。
渲染
Renderer
负责渲染的基类。
MeshRenderer
渲染网格模型。
SpriteRenderer
渲染精灵图。
SkinnedMeshRenderer
渲染蒙皮网格模型。
变换
Transform
控制 GameObject 的位置、 旋转和缩放。
物理
Rigidbody
提供刚体物理模拟。
Rigidbody2D
2D 刚体物理模拟。
Collider
物理碰撞器基类。
BoxCollider
SphereCollider
CapsuleCollider
不同形状的碰撞器。
BoxCollider2D
CircleCollider2D
EdgeCollider2D
2D 碰撞器。
动画
Animator
控制角色动画状态机。
Animation
较旧的动画系统, 用于控制动画剪辑的播放。
用户界面 (UI)
Canvas
UI 元素的容器。
Image
Text
Button
Slider
Toggle
UI 控件。
输入
Input
获取用户输入的静态类。
Touch
触摸输入的信息。
音频
AudioSource
播放音频剪辑。
AudioClip
包含音频数据的类。
时间
Time
访问时间相关数据的静态类。
场景管理
SceneManager
加载、 卸载和切换场景。
Scene
表示一个 Unity 场景。
资源管理
Resources
加载资源文件。
AssetBundle
加载外部资源包。
网络
NetworkManager
管理网络连接和玩家。
NetworkIdentity
标记具有网络同步功能的游戏对象。
这些类只是 Unity 提供的一部分核心类, 实际上还有很多其他类和功能可用于更复杂的任务。 如果你需要了解更详细的列表或者具体的类信息, 可以查阅
Unity 官方文档 。
GameObject 类 GameObject 类是场景中最基本的构建单元。 每个可见的对象或可交互的元素都是一个GameObject实例, 包括3D模型、 灯光、 摄像机等。 GameObject类本身并不具备任何功能, 它的作用主要是作为组件的容器。
基本属性
属性 描述
name
GameObject的名字, 用于在编辑器中识别。
transform
GameObject的位置、 旋转和缩放信息, 通过Transform组件来表示。
activeSelf
返回或设置GameObject是否处于激活状态。
tag
用于快速分类GameObject, 比如“ Player” 、 “ Enemy” 等。
layer
GameObject所在的图层, 可以用来控制渲染顺序或者碰撞检测。
基本方法
方法 描述
AddComponent()
向GameObject添加指定类型的组件。
GetComponent()
获取GameObject上指定类型的组件。
GetComponents()
获取GameObject上所有指定类型的组件。
SetActive(bool value)
设置GameObject是否激活。
CompareTag(string tag)
检查GameObject的标签是否与给定的字符串匹配。
Find(string name)
查找具有指定名称的第一个 GameObject。
CreatePrimitive(PrimitiveType primitiveType)
创建一个具有指定类型的原始几何体 GameObject。
Instantiate
克隆一个 GameObject, 并设置其位置、 旋转和父物体。
Destroy(GameObject obj)
销毁指定的 GameObject, 可选延迟销毁。
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 public class AddComponentExample : MonoBehaviour { void Start () { MeshRenderer renderer = gameObject.AddComponent<MeshRenderer>(); renderer.material = new Material(Shader.Find("Standard" )); Debug.Log("MeshRenderer 组件已添加." ); } } public class GetComponentExample : MonoBehaviour { void Start () { MeshRenderer renderer = GetComponent<MeshRenderer>(); if (renderer != null ) { Debug.Log("找到了 MeshRenderer 组件." ); } else { Debug.Log("没有找到 MeshRenderer 组件." ); } } } public class GetComponentsExample : MonoBehaviour { void Start () { MeshRenderer[] renderers = GetComponents<MeshRenderer>(); foreach (MeshRenderer renderer in renderers) { Debug.Log("找到了一个 MeshRenderer 组件." ); } } } public class SetActiveExample : MonoBehaviour { void Update () { if (Input.GetKeyDown(KeyCode.Space)) { gameObject.SetActive(!gameObject.activeSelf); } } } public class CompareTagExample : MonoBehaviour { void OnTriggerEnter (Collider other ) { if (other.CompareTag("Player" )) { Debug.Log("Player 进入了触发区域!" ); } } } public class CreatePrimitiveExample : MonoBehaviour { void Start () { GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.transform.position = new Vector3(10f , 0f , 0f ); } } public class FindGameObjectExample : MonoBehaviour { void Start () { GameObject player = GameObject.Find("Player" ); if (player != null ) { Debug.Log("找到了 Player: " + player.name); } else { Debug.Log("没有找到名为 'Player' 的 GameObject" ); } } } public class InstantiateExample : MonoBehaviour { public GameObject prefab; void Start () { GameObject clone = GameObject.Instantiate(prefab, new Vector3(5f , 0f , 0f ), Quaternion.identity, transform); } } public class DestroyExample : MonoBehaviour { public GameObject target; void Start () { GameObject.Destroy(target, 2f ); } }
Transform类是所有游戏对象的核心组件之一, 它负责管理游戏对象的位置、 旋转和缩放等属性。 Transform组件对于场景中的物体定位至关重要, 并且它是每个游戏对象默认就有的一个组件。
基本属性
属性 描述
Position
代表了游戏对象在世界空间中的位置坐标, 是一个Vector3类型的变量。
Rotation
代表了游戏对象的旋转角度, 通常以四元数(Quaternion)形式表示, 也可以通过 .eulerAngles 属性转换为欧拉角表示。
Scale
代表了游戏对象的缩放比例, 也是一个Vector3类型, 用于控制对象的大小。
常用方法
方法 描述
Translate
将游戏对象沿指定方向移动指定的距离。
Rotate
使游戏对象绕指定轴旋转指定的角度。
Scale
: 改变游戏对象的尺寸。
LookAt
使游戏对象面向指定的目标或世界坐标。
SetParent
设置此游戏对象的父级。 如果worldPositionStays设置为true, 则保持当前的世界位置不变。
GetParent
返回当前游戏对象的父Transform。
Find
在子对象中寻找具有指定名称的游戏对象。
InverseTransformPoint
将世界坐标转换为本地坐标。
TransformPoint
将本地坐标转换为世界坐标。
InverseTransformDirection
从世界坐标系转换到本地坐标系。
TransformDirection
从本地坐标系转换到世界坐标系。
InverseTransformDirection
从源物体坐标系到目标物体坐标系的变换。
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 public class MoveObject : MonoBehaviour { public float speed = 1.0f ; Transform transform; void Start () { transform = GameObject.Find("ObjectName" ).transform; } } public class MoveObject : MonoBehaviour { public float speed = 1.0f ; void Update () { Transform transform = GameObject.Find("ObjectName" ).transform; transform.Translate(new Vector3(speed * Time.deltaTime, 0 , 0 )); } } public class RotateObject : MonoBehaviour { public float rotationSpeed = 360.0f ; void Update () { transform.Rotate(new Vector3(0 , rotationSpeed * Time.deltaTime, 0 )); } } public class ScaleObject : MonoBehaviour { private Vector3 originalScale; private float timeElapsed = 0f ; private float duration = 2f ; void Start () { originalScale = transform.localScale; } void Update () { timeElapsed += Time.deltaTime; float scaleFactor = Mathf.Lerp(1.0f , 1.5f , (timeElapsed % duration) / duration); transform.localScale = originalScale * scaleFactor; } } public class LookAtCursor : MonoBehaviour { void Update () { Vector3 mousePos = Input.mousePosition; mousePos.z = Camera.main.nearClipPlane; Vector3 worldMousePos = Camera.main.ScreenToWorldPoint(mousePos); Vector3 direction = worldMousePos - transform.position; transform.LookAt(new Vector3(worldMousePos.x, transform.position.y, worldMousePos.z)); } } public class ParentingExample : MonoBehaviour { public Transform newParent; void Start () { Debug.Log("Current parent: " + transform.parent); transform.SetParent(newParent); Debug.Log("New parent: " + transform.parent); } } public class FindChildExample : MonoBehaviour { void Start () { Transform childTransform = transform.Find("ChildObject" ); if (childTransform != null ) { Debug.Log("Found child object: " + childTransform.name); } else { Debug.Log("Child object not found." ); } } } public class CoordinateConversionExample : MonoBehaviour { public Transform targetTransform; void Update () { Vector3 localPosition = transform.InverseTransformPoint(targetTransform.position); Debug.Log("Local position of target: " + localPosition); Vector3 worldPosition = transform.TransformPoint(localPosition); Debug.Log("World position of target: " + worldPosition); } } public class VectorTransformationExample : MonoBehaviour { public Transform targetTransform; void Update () { Vector3 inverseDirection = transform.InverseTransformDirection(worldDirection); Debug.Log("Inverse direction: " + inverseDirection); Vector3 localDirection = new Vector3(1 , 0 , 0 ); Vector3 worldDirection = transform.TransformDirection(localDirection); Debug.Log("World direction: " + worldDirection); } } public class VectorTransformationBetweenObjects : MonoBehaviour { public Transform sourceTransform; public Transform targetTransform; void Update () { Vector3 sourceDirection = new Vector3(1 , 0 , 0 ); Vector3 targetDirection = targetTransform.InverseTransformDirection( sourceTransform.TransformDirection(sourceDirection)); Debug.Log("Target direction: " + targetDirection); } }
Vector3 类 在Unity中, Vector3 类是一个非常重要的结构体, 用于表示三维空间中的点或向量。 这个类定义了几个常量、 属性和方法, 可以帮助你在游戏中处理各种与位置、 方向和速度有关的操作。
基本结构 Vector3 是一个结构体( struct) , 它包含三个浮点数成员: x, y 和 z, 分别对应三维空间中的三个坐标轴。
常用属性
属性 描述
zero
返回一个新的 Vector3(0, 0, 0)
one
返回一个新的 Vector3(1, 1, 1)
up
返回一个新的 Vector3(0, 1, 0), 表示正y轴方向
down
返回一个新的 Vector3(0, -1, 0), 表示负y轴方向
left
返回一个新的 Vector3(-1, 0, 0), 表示负x轴方向
right
返回一个新的 Vector3(1, 0, 0), 表示正x轴方向
forward
返回一个新的 Vector3(0, 0, 1), 表示正z轴方向
back
返回一个新的 Vector3(0, 0, -1), 表示负z轴方向
magnitude
返回向量的长度
sqrMagnitude
返回向量长度的平方, 通常用于性能敏感的场合, 避免开方运算
normalized
返回单位向量, 即原向量的方向但长度为1
x, y, z
分别获取或设置向量的 x, y, z 坐标值
常用方法
方法 描述
Normalize
将当前向量归一化为单位向量
Scale
按照提供的向量对当前向量进行缩放
Set
设置向量的 x, y, z 值
Dot
计算与另一个向量的点积
Cross
计算与另一个向量的叉积
Distance
计算与另一个向量的距离
Lerp
在两个向量之间进行线性插值
MoveTowards
向目标向量移动, 最大移动距离受限制
Reflect
根据法线反射一个向量
Angle
计算与另一个向量之间的角度
Min
返回一个新向量, 其各分量为当前向量与另一个向量相应分量的较小值
Max
返回一个新向量, 其各分量为当前向量与另一个向量相应分量的较大值
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 Vector3 vector = new Vector3(3 , 4 , 0 ); Vector3 normalizedVector = vector.normalized; Debug.Log("Normalized Vector: " + normalizedVector); Vector3 vector = new Vector3(1 , 2 , 3 ); Vector3 scale = new Vector3(2 , 2 , 2 ); vector.Scale(scale); Debug.Log("Scaled Vector: " + vector); Vector3 vector = new Vector3(); vector.Set(1 , 2 , 3 ); Debug.Log("Set Vector: " + vector); Vector3 vector1 = new Vector3(1 , 2 , 3 ); Vector3 vector2 = new Vector3(4 , 5 , 6 ); float dotProduct = Vector3.Dot(vector1, vector2);Debug.Log("Dot Product: " + dotProduct); Vector3 vector1 = new Vector3(1 , 0 , 0 ); Vector3 vector2 = new Vector3(0 , 1 , 0 ); Vector3 crossProduct = Vector3.Cross(vector1, vector2); Debug.Log("Cross Product: " + crossProduct); Vector3 vector1 = new Vector3(1 , 2 , 3 ); Vector3 vector2 = new Vector3(4 , 5 , 6 ); float distance = Vector3.Distance(vector1, vector2);Debug.Log("Distance: " + distance); Vector3 from = new Vector3(0 , 0 , 0 ); Vector3 to = new Vector3(10 , 10 , 10 ); float t = 0.5f ; Vector3 interpolated = Vector3.Lerp(from , to, t); Debug.Log("Interpolated Vector: " + interpolated); Vector3 current = new Vector3(0 , 0 , 0 ); Vector3 target = new Vector3(10 , 10 , 10 ); float maxDistanceDelta = 5 ; Vector3 moved = Vector3.MoveTowards(current, target, maxDistanceDelta); Debug.Log("Moved Vector: " + moved); Vector3 inDirection = new Vector3(1 , -1 , 0 ); Vector3 normal = new Vector3(0 , 1 , 0 ); Vector3 reflected = Vector3.Reflect(inDirection, normal); Debug.Log("Reflected Vector: " + reflected); Vector3 vector1 = new Vector3(1 , 0 , 0 ); Vector3 vector2 = new Vector3(0 , 1 , 0 ); float angle = Vector3.Angle(vector1, vector2);Debug.Log("Angle: " + angle); Vector3 vector1 = new Vector3(1 , 2 , 3 ); Vector3 vector2 = new Vector3(4 , 1 , 2 ); Vector3 minVector = Vector3.Min(vector1, vector2); Vector3 maxVector = Vector3.Max(vector1, vector2); Debug.Log("Min Vector: " + minVector); Debug.Log("Max Vector: " + maxVector);
游戏应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 void Update (){ Vector3 direction = Input.mousePosition - Camera.main.ScreenToWorldPoint(new Vector3(Screen.width / 2 , Screen.height / 2 )); direction.Normalize(); transform.forward = direction; } void ScalePosition (){ Vector3 currentPosition = transform.position; Vector3 scale = new Vector3(2 , 2 , 2 ); currentPosition.Scale(scale); transform.position = currentPosition; } void SetPosition (){ Vector3 newPosition = new Vector3(); newPosition.Set(10 , 20 , 30 ); transform.position = newPosition; } bool IsFacingTarget (Transform target ){ Vector3 directionToTarget = target.position - transform.position; directionToTarget.Normalize(); float dotProduct = Vector3.Dot(transform.forward, directionToTarget); return dotProduct > 0.9f ; } Vector3 CalculateNormal (Vector3 a, Vector3 b, Vector3 c ) { Vector3 ab = b - a; Vector3 ac = c - a; return Vector3.Cross(ab, ac).normalized; } void CheckDistanceToPlayer (Transform player ){ float distanceToPlayer = Vector3.Distance(player.position, transform.position); if (distanceToPlayer < 10.0f ) { } } void SmoothlyMoveToTarget (Transform target, float speed ){ Vector3 newPos = Vector3.Lerp(transform.position, target.position, Time.deltaTime * speed); transform.position = newPos; } void MoveTowardsTarget (Transform target, float maxSpeed ){ Vector3 newPos = Vector3.MoveTowards(transform.position, target.position, maxSpeed * Time.deltaTime); transform.position = newPos; } void ReflectLightRay (Vector3 rayDirection, Vector3 surfaceNormal ){ Vector3 reflectedRay = Vector3.Reflect(rayDirection, surfaceNormal); } float CalculateAngleBetweenPlayers (Transform player1, Transform player2 ){ Vector3 direction = player2.position - player1.position; return Vector3.Angle(player1.forward, direction); } void LimitPosition (Vector3 minLimit, Vector3 maxLimit ){ Vector3 clampedPosition = Vector3.Clamp(transform.position, minLimit, maxLimit); transform.position = clampedPosition; }
Time 类 在Unity中, Time类提供了一系列的属性和方法来帮助开发者处理游戏中的时间相关功能。 这对于实现游戏逻辑、 动画、 物理模拟等非常重要。
常用属性
属性 描述
deltaTime
表示从上一帧到当前帧的时间差( 以秒为单位)
time
从游戏开始到现在经过的总时间( 以秒为单位)
timeSinceLevelLoad
自从加载当前场景以来经过的时间( 以秒为单位)
fixedDeltaTime
固定时间步长, 即从上一个固定更新到当前固定更新之间的时间差
fixedTime
自游戏启动以来经过的总时间, 按照固定时间步长计算
fixedUpdatePeriod
物理引擎和其他固定更新系统的更新频率
unscaledTime
从游戏开始到现在经过的真实时间, 不受时间缩放的影响
unscaledDeltaTime
上一帧和当前帧之间的真实时间差, 同样不受时间缩放的影响
unscaledTimeSinceLevelLoad
自从加载当前场景以来的真实时间
timeScale
游戏世界时间的缩放系数, 默认值为1.0, 表示正常速度
smoothDeltaTime
返回一个平滑的deltaTime值, 可以避免突然的时间跳跃影响游戏体验
captureFramerate
获取目标帧率
targetFramerate
设置目标帧率
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 public class SmoothMovement : MonoBehaviour { public float speed = 5f ; void Update () { transform.Translate(Vector3.right * speed * Time.deltaTime); } } public class GameTimer : MonoBehaviour { private float startTime; void Start () { startTime = Time.time; } void Update () { float elapsedTime = Time.time - startTime; Debug.Log("Elapsed Time: " + elapsedTime); } } public class LevelTimer : MonoBehaviour { void Update () { float timeSinceLevelLoad = Time.timeSinceLevelLoad; Debug.Log("Time Since Level Load: " + timeSinceLevelLoad); } } public class PhysicsUpdateExample : MonoBehaviour { public Rigidbody rb; void FixedUpdate () { rb.AddForce(Vector3.up * 5f * Time.fixedDeltaTime); } } public class FixedTimeExample : MonoBehaviour { private float startTime; void Start () { startTime = Time.fixedTime; } void FixedUpdate () { float elapsedTime = Time.fixedTime - startTime; Debug.Log("Fixed Elapsed Time: " + elapsedTime); } } public class FixedUpdatePeriodExample : MonoBehaviour { void Start () { Debug.Log("Fixed Update Period: " + Time.fixedUpdatePeriod); } } public class RealTimeTracker : MonoBehaviour { private float startTime; private float totalPlayTime; void Start () { startTime = Time.unscaledTime; } void Update () { totalPlayTime = Time.unscaledTime - startTime; Debug.Log("Total Play Time: " + totalPlayTime); } } public class UnscaledDeltaTimeExample : MonoBehaviour { private float elapsedTime = 0f ; void Update () { elapsedTime += Time.unscaledDeltaTime; if (elapsedTime > 5f ) { Debug.Log("Unscaled Delta Time Elapsed: " + elapsedTime); elapsedTime = 0f ; } } } public class UnscaledTimeSinceLevelLoadExample : MonoBehaviour { private float startTime; void Start () { startTime = Time.unscaledTimeSinceLevelLoad; } void Update () { float timeSinceLevelLoad = Time.unscaledTimeSinceLevelLoad - startTime; Debug.Log("Unscaled Time Since Level Load: " + timeSinceLevelLoad); } } public class SlowMotion : MonoBehaviour { public float normalSpeed = 1f ; public float slowMotionSpeed = 0.2f ; private bool isSlowMotion = false ; void Update () { if (Input.GetKeyDown(KeyCode.Space)) { isSlowMotion = !isSlowMotion; Time.timeScale = isSlowMotion ? slowMotionSpeed : normalSpeed; } } } public class SmoothTimeExample : MonoBehaviour { private float elapsedTime = 0f ; void Update () { elapsedTime += Time.smoothDeltaTime; if (elapsedTime > 5f ) { Debug.Log("Smooth Delta Time Elapsed: " + elapsedTime); elapsedTime = 0f ; } } }
游戏应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 public class SmoothDeltaTimeExample : MonoBehaviour { private float elapsedTime = 0f ; void Update () { elapsedTime += Time.smoothDeltaTime; if (elapsedTime > 5f ) { Debug.Log("Smooth Delta Time Elapsed: " + elapsedTime); elapsedTime = 0f ; } } } public class FramerateMonitor : MonoBehaviour { void OnGUI () { GUI.Label(new Rect(10 , 10 , 200 , 20 ), "Current Framerate: " + Time.captureFramerate); } } public class FramerateControl : MonoBehaviour { private const int TARGET_FRAMERATE = 60 ; void Start () { SetTargetFramerate(TARGET_FRAMERATE); } private void SetTargetFramerate (int targetFramerate ) { QualitySettings.vSyncCount = targetFramerate <= 30 ? 1 : 0 ; if (QualitySettings.vSyncCount == 1 ) { Application.targetFrameRate = targetFramerate; } else { Application.targetFrameRate = targetFramerate; } } void OnGUI () { GUI.Label(new Rect(10 , 10 , 200 , 20 ), "Current Framerate: " + Time.captureFramerate); } } public class TargetFramerateExample : MonoBehaviour { [SerializeField ] private int targetFramerate = 60 ; private GUIStyle labelStyle; private void Start () { SetTargetFramerate(targetFramerate); labelStyle = new GUIStyle(); labelStyle.fontSize = 20 ; labelStyle.normal.textColor = Color.white; } private void SetTargetFramerate (int targetFramerate ) { QualitySettings.vSyncCount = targetFramerate <= 30 ? 1 : 0 ; Application.targetFrameRate = targetFramerate; } private void OnGUI () { GUI.Label(new Rect(10 , 10 , 200 , 20 ), $"Current Framerate: {Time.captureFramerate} " , labelStyle); } }
在Unity中, Input类是一个非常重要的工具, 用于处理来自用户的输入, 包括键盘、 鼠标和游戏手柄等。 这个类提供了许多静态属性和方法来检测这些输入设备的状态。
基本概念
轴( Axes) : Unity中的轴用来表示连续输入, 比如移动或旋转。 轴值范围通常在-1到+1之间。
按键( Keys) : 表示特定键是否被按下, 例如Input.GetKey(KeyCode.A)检查A键是否被持续按下。
触发( Triggers) : 表示键或按钮从未按下变为按下的瞬间。
释放( Releases) : 表示键或按钮从按下变为未按下的瞬间。
常用属性
属性 描述
Input.anyKeyDown
返回一个布尔值, 表示是否有任何键被按下
Input.mousePosition
返回一个Vector3, 表示鼠标在屏幕上的位置
Input.mouseScrollDelta
返回一个Vector2, 表示鼠标滚轮的滚动量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void Update (){ if (Input.anyKeyDown) { Debug.Log("Any key is down." ); } } void Update (){ Vector3 mousePos = Input.mousePosition; Debug.Log("Mouse Position: " + mousePos); } void Update (){ Vector2 scrollDelta = Input.mouseScrollDelta; if (scrollDelta.y != 0 ) { Debug.Log("Mouse Scroll Delta: " + scrollDelta); } }
键盘输入
方法 描述
Input.GetKeyDown(KeyCode)
检查键是否被按下
Input.GetKey(KeyCode)
检查键是否被持续按下
Input.GetKeyUp(KeyCode)
检查键是否被释放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void Update (){ if (Input.GetKeyDown(KeyCode.Space)) { Debug.Log("Space key was pressed." ); } } void Update (){ if (Input.GetKey(KeyCode.W)) { Debug.Log("W key is being held down." ); } } void Update (){ if (Input.GetKeyUp(KeyCode.Escape)) { Debug.Log("Escape key was released." ); } }
鼠标输入
方法 描述
Input.GetMouseButtonDown(int button)
检查鼠标按钮是否被按下
Input.GetMouseButton(int button)
检查鼠标按钮是否被持续按下
Input.GetMouseButtonUp(int button)
检查鼠标按钮是否被释放
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void Update (){ if (Input.GetMouseButtonDown(0 )) { Debug.Log("Left mouse button was pressed." ); } } void Update (){ if (Input.GetMouseButton(1 )) { Debug.Log("Right mouse button is being held down." ); } } void Update (){ if (Input.GetMouseButtonUp(2 )) { Debug.Log("Middle mouse button was released." ); } }
轴输入
方法 描述
Input.GetAxis(string axisName)
获取指定轴的值
Input.GetAxisRaw(string axisName)
获取指定轴的原始值, 不经过平滑处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void Update (){ float horizontal = Input.GetAxis("Horizontal" ); if (horizontal != 0 ) { Debug.Log("Horizontal axis value: " + horizontal); } } void Update (){ int verticalRaw = (int )Input.GetAxisRaw("Vertical" ); if (verticalRaw != 0 ) { Debug.Log("Vertical axis raw value: " + verticalRaw); } }
GUI 类 GUI 类是 Unity 引擎中的一个核心组件, 它允许开发者直接在屏幕上绘制用户界面元素, 如按钮、 滑块、 文本框等。 GUI 类属于 UnityEngine 命名空间, 并且它的功能主要通过 OnGUI 回调函数在运行时进行绘制。 尽管 OnGUI 方法在 Unity 中仍然可用, 但现代 Unity 开发更倾向于使用 UGUI( 用户图形界面) 系统, 因为它提供了更好的性能和更丰富的功能集。
常用属性
属性 描述
color
设置或获取当前 GUI 的绘制颜色
contentColor
设置或获取 GUI 内容的颜色
depth
设置或获取 GUI 绘制的深度。 具有较高深度值的对象会覆盖较低深度值的对象。
enabled
设置或获取 GUI 控件是否响应用户输入
skin
设置或获取当前 GUI 皮肤
cursor
设置或获取鼠标光标的样式
常用方法
方法 描述
Button
创建一个按钮, 可以检测用户是否点击了该按钮
Label
创建一个标签, 用于显示文本
TextField
创建一个文本输入框, 允许用户输入文本
PasswordField
创建一个密码输入框, 输入的字符会被隐藏
Slider
创建一个滑动条, 允许用户通过拖动来选择一个值
HorizontalSlider
创建一个水平滑动条
Toggle
创建一个开关按钮, 用户可以选择开启或关闭
Box
创建一个带有边框的矩形区域
DrawTexture
在屏幕上绘制一个纹理
DrawTextureWithTexCoords
使用指定的 UV 坐标绘制纹理
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 using UnityEngine;public class GUIExamples : MonoBehaviour { private string textInput = "初始文本" ; private bool toggleState = false ; private float sliderValue = 0.5f ; private float horizontalSliderValue = 0.5f ; private int dropdownSelection = 0 ; private string [] dropdownOptions = new string [] { "选项 A" , "选项 B" , "选项 C" }; private Texture2D textureToDraw; void Start () { textureToDraw = Resources.Load<Texture2D>("Textures/MyTexture" ); } void OnGUI () { textInput = GUI.TextField(new Rect(10 , 10 , 150 , 30 ), textInput); if (GUI.Button(new Rect(10 , 50 , 100 , 30 ), "点击我" )) { Debug.Log("按钮被点击! " ); } GUI.Label(new Rect(10 , 90 , 150 , 30 ), "这是标签文本" ); sliderValue = GUI.VerticalSlider(new Rect(10 , 130 , 30 , 100 ), sliderValue, 0.0f , 1.0f ); horizontalSliderValue = GUI.HorizontalSlider(new Rect(50 , 130 , 150 , 30 ), horizontalSliderValue, 0.0f , 1.0f ); toggleState = GUI.Toggle(new Rect(10 , 240 , 100 , 30 ), toggleState, "切换" ); dropdownSelection = GUI.SelectionGrid(new Rect(10 , 280 , 150 , 30 ), dropdownSelection, dropdownOptions, 1 ); if (textureToDraw != null ) { GUI.DrawTexture(new Rect(10 , 320 , textureToDraw.width, textureToDraw.height), textureToDraw); } } }
游戏应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 using UnityEngine;using UnityEngine.UI;public class HealthBarExample : MonoBehaviour { public Transform target; public float health; public float maxHealth; private void Start () { maxHealth = health; } private Vector3 ScreenPosition (Transform transform ) { Vector3 screenPos = Camera.main.WorldToScreenPoint(transform.position); return screenPos; } private void OnGUI () { if (target == null ) return ; Vector3 screenPos = ScreenPosition(target); if (screenPos.z > 0 ) { Rect healthBarRect = new Rect(screenPos.x - 25 , Screen.height - screenPos.y + 25 , 50 , 5 ); GUI.Box(healthBarRect, "" ); float fillRatio = Mathf.Clamp01(health / maxHealth); Rect fillRect = new Rect(healthBarRect.x, healthBarRect.y, healthBarRect.width * fillRatio, healthBarRect.height); GUI.Box(fillRect, "" ); } } }
SceneManager 类 SceneManager 类是 Unity 引擎中的一个核心组件, 用于管理和操作场景。 在 Unity 中, 游戏是由一个或多个场景组成的, 而 SceneManager 提供了加载、 卸载、 切换场景等功能。
枚举类 LoadSceneMode 枚举定义了场景加载的不同模式
属性 描述
Single
新场景将替换当前正在运行的场景
Additive
新场景将被添加到当前正在运行的场景列表中
AdditiveWithUnloading
新场景被加载后, 旧场景会被卸载
常用方法
方法 描述
LoadScene
同步加载场景
LoadSceneAsync(string sceneName)
异步加载指定名称的场景
LoadSceneAsync(int sceneBuildIndex)
异步加载指定构建索引的场景
LoadSceneAsync(Scene scene, LoadSceneMode mode)
按照指定模式异步加载场景对象
UnloadSceneAsync(int sceneBuildIndex)
异步卸载指定构建索引的场景
UnloadSceneAsync(Scene scene)
异步卸载指定的场景对象
GetActiveScene
获取当前活动的场景
GetSceneByBuildIndex
通过构建索引来获取场景
GetSceneByName
通过场景名称来获取场景
MoveGameObjectToScene
将游戏对象移动到指定的场景中
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 public class SceneLoader : MonoBehaviour { public void LoadScene (string sceneName ) { SceneManager.LoadScene(sceneName); } } public class AsyncSceneLoader : MonoBehaviour { public void LoadSceneAsync (string sceneName ) { SceneManager.LoadSceneAsync(sceneName); } public void LoadSceneWithProgress (string sceneName ) { AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName); while (!asyncLoad.isDone) { float progress = asyncLoad.progress; Debug.Log("Loading progress: " + progress); } } } public class AsyncSceneUnloader : MonoBehaviour { public void UnloadSceneAsync (string sceneName ) { Scene scene = SceneManager.GetSceneByName(sceneName); if (scene != null && scene.isLoaded) { SceneManager.UnloadSceneAsync(scene); } } } public class ActiveSceneGetter : MonoBehaviour { private void Start () { Scene activeScene = SceneManager.GetActiveScene(); Debug.Log("Current active scene is: " + activeScene.name); } } public class SceneByBuildIndex : MonoBehaviour { public void GetSceneByIndex (int index ) { Scene scene = SceneManager.GetSceneByBuildIndex(index); Debug.Log("Scene at build index " + index + " is named: " + scene.name); } } public class SceneByName : MonoBehaviour { public void GetSceneByName (string sceneName ) { Scene scene = SceneManager.GetSceneByName(sceneName); Debug.Log("Scene with name " + sceneName + " has state: " + scene.state); } } public class GameObjectMover : MonoBehaviour { public GameObject gameObjectToMove; public string targetSceneName; public void MoveGameObjectToScene () { Scene targetScene = SceneManager.GetSceneByName(targetSceneName); if (targetScene.isLoaded) { SceneManager.MoveGameObjectToScene(gameObjectToLoad, targetScene); } else { Debug.LogError("Target scene is not loaded." ); } } } public class SceneLoaderWithMode : MonoBehaviour { public void LoadSceneAdditive (string sceneName ) { SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); } }
游戏应用 💗💗 游戏关卡切换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class LevelSwitcher : MonoBehaviour { public void NextLevel (string nextLevelName ) { SceneManager.LoadScene(nextLevelName); } } public class LevelCompletedTrigger : MonoBehaviour { public string nextLevelName; private void OnTriggerEnter (Collider other ) { if (other.gameObject.CompareTag("Player" )) { LevelSwitcher levelSwitcher = FindObjectOfType<LevelSwitcher>(); if (levelSwitcher != null ) { levelSwitcher.NextLevel(nextLevelName); } } } }
💗💗 游戏菜单系统 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class MenuManager : MonoBehaviour { public void LoadMainMenu () { SceneManager.LoadScene("MainMenu" ); } public void LoadSettingsMenu () { SceneManager.LoadScene("SettingsMenu" , LoadSceneMode.Additive); } public void QuitGame () { Application.Quit(); } }
💗💗 复活点和检查点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class PlayerRespawner : MonoBehaviour { public string respawnSceneName; private void OnEnable () { PlayerDeathEventSystem.PlayerDied += OnPlayerDied; } private void OnDisable () { PlayerDeathEventSystem.PlayerDied -= OnPlayerDied; } private void OnPlayerDied () { SceneManager.LoadScene(respawnSceneName); } }
💗💗 动态加载内容 1 2 3 4 5 6 7 8 9 10 11 12 13 public class DynamicContentLoader : MonoBehaviour { public void LoadNewArea (string areaName ) { AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(areaName, LoadSceneMode.Additive); asyncLoad.completed += (AsyncOperation op) => { Debug.Log("New area loaded successfully!" ); }; } }
💗💗 资源管理与优化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ResourceOptimizer : MonoBehaviour { public void UnloadUnusedScenes () { for (int i = 0 ; i < SceneManager.sceneCount; i++) { Scene scene = SceneManager.GetSceneAt(i); if (scene.name != "ActiveScene" && scene.isLoaded) { SceneManager.UnloadSceneAsync(scene); } } } }
💗💗 场景之间的数据传递 1 2 3 4 5 6 7 8 9 public class DataPasser : MonoBehaviour { public void PassDataToNextScene () { PlayerPrefs.SetInt("Score" , 100 ); SceneManager.LoadScene("NextLevel" ); } }
AudioSource 类 AudioSource 是 Unity 引擎中用于播放音频的基础组件。 在 Unity 中, 如果你想要在场景中播放声音, 无论是背景音乐、 音效还是语音, 都需要将 AudioSource 组件添加到游戏对象上。
基本属性
属性 描述
Mute
是否静音
Volume
音量大小, 范围从 0 到 1, 其中 1 表示原始音量
Pitch
音调, 可以改变声音的高低, 通常用来模拟远离或靠近的声音效果
Playback Mode
播放模式:
Looping: 循环播放
Play Once: 只播放一次
Stop: 停止播放
Clip
指定要播放的音频剪辑
属性示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public void ToggleMute (){ audioSource.mute = !audioSource.mute; } public void SetVolume (float volume ){ audioSource.volume = volume; } public void UpdatePitch (float speedFactor ){ audioSource.pitch = 1.0f + speedFactor; } void Start (){ audioSource.loop = true ; audioSource.clip = backgroundMusicClip; audioSource.Play(); } public void PlayJumpSound (){ audioSource.clip = jumpSoundClip; audioSource.Play(); }
常用方法
方法 描述
Play
开始播放音频
Stop
停止播放音频
Pause
暂停播放音频
UnPause
取消暂停状态, 继续播放音频
方法示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void Start (){ audioSource.clip = themeSongClip; audioSource.Play(); } public void OnGamePaused (){ audioSource.Stop(); } public void EnterMenu (){ audioSource.Pause(); } public void ReturnToGame (){ audioSource.UnPause(); }
其他属性
属性 描述
Pan Stereo
立体声的左右平衡, 可以在-1( 全左) 到1( 全右) 之间设置
Bypass Effects
是否绕过音频效果
Bypass Listener Effects
是否绕过监听器效果
Bypass Reverb Zones
是否绕过混响区域
Doppler Level
多普勒效应的强度, 影响音调变化
Rolloff Mode
声音衰减模式, 决定了声音如何随着距离的增加而减弱
Min Distance 和 Max Distance
定义了声音从开始减弱的距离( 最小距离) 和完全不可听的距离( 最大距离)
其他属性示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public void SetPanStereo (float panValue ){ audioSource.panStereo = panValue; } public void DisableEffects (){ audioSource.bypassEffects = true ; } public void IgnoreListenerEffects (){ audioSource.bypassListenerEffects = true ; } public void IgnoreReverbZones (){ audioSource.bypassReverbZones = true ; } public void SetDopplerLevel (float level ){ audioSource.dopplerLevel = level; } public void SetRolloffMode (AudioRolloffMode mode ){ audioSource.rolloffMode = mode; } public void SetMinMaxDistance (float min, float max ){ audioSource.minDistance = min; audioSource.maxDistance = max; }
游戏应用 💗💗 背景音乐 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class BackgroundMusic : MonoBehaviour { public AudioClip musicClip; private AudioSource audioSource; void Start () { audioSource = GetComponent<AudioSource>(); audioSource.clip = musicClip; audioSource.loop = true ; audioSource.Play(); } }
💗💗 角色动作音效 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class PlayerController : MonoBehaviour { public AudioClip jumpSound; private AudioSource audioSource; void Start () { audioSource = GetComponent<AudioSource>(); } public void Jump () { if (audioSource && jumpSound) { audioSource.clip = jumpSound; audioSource.Play(); } } }
💗💗 UI 交互音效 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class UIButtonSound : MonoBehaviour { public AudioClip clickSound; private AudioSource audioSource; void Start () { audioSource = GetComponent<AudioSource>(); } public void OnButtonClick () { if (audioSource && clickSound) { audioSource.clip = clickSound; audioSource.Play(); } } }
💗💗 动态音调变化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class EnemySound : MonoBehaviour { public AudioClip enemySound; private AudioSource audioSource; void Start () { audioSource = GetComponent<AudioSource>(); audioSource.clip = enemySound; } public void UpdatePitch (float distanceFactor ) { if (audioSource.isPlaying) { audioSource.pitch = Mathf.Lerp(0.8f , 1.2f , distanceFactor); } } }
💗💗 3D 音效定位 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class SoundEmitter : MonoBehaviour { public AudioClip soundClip; private AudioSource audioSource; void Start () { audioSource = GetComponent<AudioSource>(); audioSource.spatialBlend = 1f ; audioSource.clip = soundClip; } public void PlaySound () { audioSource.Play(); } }
💗💗 动态音量调整 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class IndoorSound : MonoBehaviour { public AudioClip indoorAmbience; private AudioSource audioSource; void Start () { audioSource = GetComponent<AudioSource>(); audioSource.clip = indoorAmbience; audioSource.Play(); } public void AdjustVolume (bool isIndoor ) { audioSource.volume = isIndoor ? 0.5f : 1.0f ; } }
💗💗 多个音频源管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class AudioManager : MonoBehaviour { public AudioSource bgmSource; public AudioSource sfxSource; public void PlayBGM (AudioClip clip ) { bgmSource.clip = clip; bgmSource.Play(); } public void PlaySFX (AudioClip clip ) { sfxSource.clip = clip; sfxSource.Play(); } }
Rigidbody 类 Rigidbody 是 Unity 中的一个重要组件, 它为游戏对象提供了物理特性。 通过给游戏对象添加 Rigidbody 组件, 你可以让这个对象受到重力的影响、 与其他带有 Rigidbody 的对象发生碰撞, 并且可以使用力和扭矩来改变其运动状态。
ForceMode 枚举
属性 描述
Force
应用线性力
Acceleration
应用加速度
Impulse
应用瞬时冲量
VelocityChange
直接改变速度
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class ApplyForceOnJump : MonoBehaviour { public float jumpForce = 500f ; private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { if (Input.GetKeyDown(KeyCode.Space)) { rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse); } } } public class SetVelocity : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { rb.velocity = new Vector3(10 , 0 , 0 ); } } public class RotateObject : MonoBehaviour { public float torqueStrength = 10f ; private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void FixedUpdate () { rb.AddTorque(Vector3.up * torqueStrength); } }
主要属性
属性 描述
Mass
物体的质量, 影响物体如何响应外力的作用
Drag
一个系数, 决定了物体在空气中移动时受到的阻力大小
Angular Drag
一个系数, 决定了物体旋转时受到的阻力大小
Use Gravity
如果启用, 则该物体将受到重力的影响
Is Kinematic
如果启用, 则该物体不会受到物理引擎的影响, 可以被脚本精确控制
Constraints
可以限制物体沿某些轴移动或旋转
Sleep Mode
当物体静止一段时间后, 物理引擎会将其设置为休眠状态以节省计算资源
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 public class ChangeMass : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); rb.mass = 20f ; } } public class IncreaseAirResistance : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); rb.drag = 0.5f ; } } public class IncreaseAngularResistance : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); rb.angularDrag = 0.5f ; } } public class DisableGravity : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); rb.useGravity = false ; } } public class MakeKinematic : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); rb.isKinematic = true ; } }
常用方法
方法 描述
AddForce
向刚体施加力
AddTorque
向刚体施加扭矩
MovePosition(Vector3 position)
在非物理模拟的情况下直接移动刚体的位置( 仅当 IsKinematic 为 true 时可用)
MoveRotation(Quaternion rotation)
直接改变刚体的旋转( 仅当 IsKinematic 为 true 时可用)
velocity
读取或设置刚体的速度
angularVelocity
读取或设置刚体的角速度
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 public class JumpOnSpace : MonoBehaviour { public float jumpForce = 500f ; private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { if (Input.GetKeyDown(KeyCode.Space)) { rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse); } } } public class RotateObject : MonoBehaviour { public float torqueStrength = 10f ; private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void FixedUpdate () { rb.AddTorque(Vector3.up * torqueStrength); } } public class TeleportObject : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { if (Input.GetKeyDown(KeyCode.T)) { rb.MovePosition(transform.position + Vector3.forward * 5f ); } } } public class RotateInstantly : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { if (Input.GetKeyDown(KeyCode.R)) { Quaternion newRotation = Quaternion.Euler(0 , 90 , 0 ); rb.MoveRotation(newRotation); } } } public class SetVelocityExample : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { rb.velocity = new Vector3(10 , 0 , 0 ); } } public class RotateObjectExample : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { rb.angularVelocity = new Vector3(0 , 10 , 0 ); } }
游戏应用 💗💗 创建一个简单的弹跳球
在 Unity 中创建一个新的空场景。
添加一个球体 GameObject (GameObject > 3D Object > Sphere)。
为球体添加 Mesh Collider 和 Rigidbody 组件。
在 Rigidbody 组件中设置 Mass 为 1.0, Use Gravity 为勾选状态, Is Kinematic 不勾选。
创建一个 C# 脚本并附加到球体 GameObject 上。 这个脚本将控制球体的初始位置和速度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using UnityEngine;public class BouncingBall : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); transform.position = new Vector3(0 , 5 , 0 ); rb.AddForce(Vector3.down * 500 , ForceMode.Force); } }
💗💗 创建一个简单的推箱子游戏
创建一个立方体 GameObject (GameObject > 3D Object > Cube)。
为立方体添加 Box Collider 和 Rigidbody 组件。
在 Rigidbody 组件中设置 Mass 为 1.0, Use Gravity 为勾选状态, Is Kinematic 不勾选。
创建一个 C# 脚本并附加到箱子 GameObject 上。 这个脚本将控制玩家点击时箱子的移动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 using UnityEngine;public class PushableBox : MonoBehaviour { private Rigidbody rb; void Start () { rb = GetComponent<Rigidbody>(); } void Update () { if (Input.GetMouseButtonDown(0 )) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { if (hit.collider.gameObject == gameObject) { Vector3 direction = (hit.point - transform.position).normalized; rb.AddForce(direction * 100 , ForceMode.Impulse); } } } } }
碰撞检测 基础概念
Collider( 碰撞器) : 是 Unity 中用于碰撞检测的组件。 它们可以附加到 GameObject 上, 并定义了 GameObject 在物理世界中的形状。 例如 Box Collider、 Sphere Collider 和 Capsule Collider 等。
Rigidbody( 刚体) : 使 GameObject 具有物理属性, 如质量、 摩擦力等, 并允许它参与物理模拟。 没有 Rigidbody 的 GameObject 不会受到重力或碰撞的影响。
回调函数
类型 回调函数 描述
碰撞回调函数
OnCollisionEnter
当两个带有 Rigidbody 的 GameObject 第一次碰撞时调用
OnCollisionStay
当两个带有 Rigidbody 的 GameObject 仍然接触时每一帧调用
OnCollisionExit
当两个带有 Rigidbody 的 GameObject 不再接触时调用
触发器回调函数
OnTriggerEnter
当另一个 Collider 进入触发器区域时调用
OnTriggerStay
当另一个 Collider 仍然在触发器区域内时每一帧调用
OnTriggerExit
当另一个 Collider 完全离开触发器区域时调用
碰撞检测 💗💗 回调函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CollisionDetectionExample : MonoBehaviour { private void OnCollisionEnter (Collision collision ) { Debug.Log("Collision detected with: " + collision.gameObject.name); } } public class TriggerDetectionExample : MonoBehaviour { private void OnTriggerEnter (Collider other ) { Debug.Log("Trigger entered by: " + other.gameObject.name); } }
💗💗 射线投射 射线投射是一个非常有用的碰撞检测技术, 它可以用来检测玩家的视线前方是否有障碍物。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class RaycastExample : MonoBehaviour { private void Update () { RaycastHit hit; if (Physics.Raycast(transform.position, transform.forward, out hit, 10f )) { Debug.Log("Hit object: " + hit.transform.name); Debug.DrawRay(transform.position, transform.forward * 10f , Color.green); } else { Debug.DrawRay(transform.position, transform.forward * 10f , Color.red); } } }
💗💗 形状投射 形状投射可以用来检测不同形状的对象是否与其他对象碰撞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class SphereCastExample : MonoBehaviour { private void Update () { RaycastHit hit; if (Physics.SphereCast(transform.position, 0.5f , transform.forward, out hit, 10f )) { Debug.Log("Hit object: " + hit.transform.name); Debug.DrawRay(transform.position, transform.forward * 10f , Color.green); } else { Debug.DrawRay(transform.position, transform.forward * 10f , Color.red); } } }
💗💗 形状重叠 形状重叠可以用来检测一个形状是否与场景中的其他 Collider 重叠。
1 2 3 4 5 6 7 8 9 10 11 12 public class OverlapSphereExample : MonoBehaviour { private void Update () { Collider[] colliders = Physics.OverlapSphere(transform.position, 1.0f ); foreach (var collider in colliders) { Debug.Log("Overlap with: " + collider.gameObject.name); } } }
💗💗 触发器 触发器是一种特殊的 Collider, 当其他 Collider 进入或离开时, 不会产生碰撞, 但会触发回调函数。
1 2 3 4 5 6 7 8 9 10 11 public class TriggerSetupExample : MonoBehaviour { public Collider myCollider; private void Start () { myCollider.isTrigger = true ; } }
游戏应用 💗💗 回调函数: 玩家与敌人的碰撞检测 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using UnityEngine;public class PlayerController : MonoBehaviour { public int health = 100 ; private void OnCollisionEnter (Collision collision ) { if (collision.gameObject.CompareTag("Enemy" )) { Debug.Log("Player collided with an enemy!" ); health -= 10 ; if (health <= 0 ) { Debug.Log("Game Over!" ); } } } }
💗💗 射线投射: 射击游戏中的命中检测 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 using UnityEngine;public class BulletScript : MonoBehaviour { private void Update () { if (Input.GetMouseButtonDown(0 )) { Vector3 mousePosition = Input.mousePosition; Ray ray = Camera.main.ScreenPointToRay(mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, 100f )) { if (hit.collider.CompareTag("Enemy" )) { Debug.Log("Bullet hit an enemy at: " + hit.point); } } } } }
💗💗 形状重叠: 检测玩家是否踩到了地板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 using UnityEngine;public class GroundCheck : MonoBehaviour { public Transform groundCheckPoint; public float checkRadius = 0.2f ; public LayerMask whatIsGround; private bool isGrounded; private void Update () { isGrounded = Physics.OverlapSphere(groundCheckPoint.position, checkRadius, whatIsGround).Length > 0 ; if (isGrounded) { Debug.Log("Player is on the ground." ); } else { Debug.Log("Player is in the air." ); } } }
💗💗 形状投射: 检测玩家是否进入某个区域 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using UnityEngine;public class AreaTrigger : MonoBehaviour { public LayerMask playerLayer; private bool isInArea = false ; private void Update () { Collider[] colliders = Physics.OverlapSphere(transform.position, 2f , playerLayer); if (colliders.Length > 0 && !isInArea) { isInArea = true ; Debug.Log("Player entered the special area." ); } else if (colliders.Length == 0 && isInArea) { isInArea = false ; Debug.Log("Player left the special area." ); } } }
💗💗 触发器: 假设我们有一扇门, 当玩家穿过门时, 门会关闭 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 using UnityEngine;public class DoorController : MonoBehaviour { public GameObject door; private void OnTriggerEnter (Collider other ) { if (other.CompareTag("Player" )) { Debug.Log("Player entered the door trigger." ); door.SetActive(false ); } } }
相机跟随 第一人称视角 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 void shijiao1 () { camera.transform.position = tank.position + tank.forward * -1 + new Vector3(0 , 1 , 0 ); camera.transform.LookAt(SJ.transform); } using System.Collections;using System.Collections.Generic;using UnityEngine;public class FirstPersonCamera : MonoBehaviour { public float mouseSensitivity = 100.0f ; private float xRotation = 0.0f ; void Start () { Cursor.lockState = CursorLockMode.Locked; } void Update () { float mouseX = Input.GetAxis("Mouse X" ) * mouseSensitivity * Time.deltaTime; float mouseY = Input.GetAxis("Mouse Y" ) * mouseSensitivity * Time.deltaTime; xRotation -= mouseY; xRotation = Mathf.Clamp(xRotation, -90f , 90f ); transform.localRotation = Quaternion.Euler(new Vector3(xRotation, 0 , 0 )); transform.parent.Rotate(new Vector3(0 , mouseX, 0 )); } }
第三人称视角 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 using System.Collections;using System.Collections.Generic;using UnityEngine;public class ThirdPersonCamera : MonoBehaviour { public Transform target; public Vector3 offset = new Vector3(-3f , 0f , -5f ); public float smoothTime = 0.3f ; private Vector3 velocity = Vector3.zero; void LateUpdate () { if (target == null ) return ; Vector3 targetPosition = target.position + offset; Vector3 smoothedPosition = Vector3.SmoothDamp(transform.position, targetPosition, ref velocity, smoothTime); transform.position = smoothedPosition; transform.LookAt(target); } }
鼠标行为 回调函数
函数 描述
OnMouseEnter
当鼠标进入一个 Collider 或 Canvas 的边界时被调用
OnMouseExit
当鼠标离开一个 Collider 或 Canvas 的边界时被调用
OnMouseDown
当鼠标按钮在一个 Collider 或 Canvas 上被按下时被调用
OnMouseUp
当鼠标按钮在一个 Collider 或 Canvas 上被释放时被调用
OnMouseDrag
当鼠标被按下并移动时被调用
OnMouseOver
只要鼠标在一个 Collider 或 Canvas 上方, 每一帧都会被调用
OnMouseUpAsButton
当鼠标按钮在一个 GUI 元素上被释放时被调用, 类似于点击按钮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 using UnityEngine;public class ClickableObject : MonoBehaviour { void OnMouseDown () { Debug.Log("GameObject was clicked!" ); } void OnMouseUp () { Debug.Log("Mouse button released on GameObject." ); } void OnMouseDrag () { Debug.Log("Dragging object with mouse." ); } void OnMouseEnter () { Debug.Log("Mouse entered the GameObject." ); } void OnMouseExit () { Debug.Log("Mouse exited the GameObject." ); } }
事件触发器
事件 描述
OnPointerClick
当用户点击一个 UI 元素时触发
OnPointerEnter
当鼠标进入一个 UI 元素时触发
OnPointerExit
当鼠标离开一个 UI 元素时触发
1 2 3 4 5 6 7 8 9 10 11 using UnityEngine;using UnityEngine.EventSystems;public class UIButtonHandler : MonoBehaviour , IPointerClickHandler { public void OnPointerClick (PointerEventData eventData ) { Debug.Log("Button was clicked!" ); } }
鼠标输入
输入 描述
Input.mousePosition
返回屏幕坐标系中的鼠标位置( 以像素为单位) , 其中 (0, 0) 通常表示屏幕左下角。
Input.GetMouseButtonDown(int button)
检查鼠标按钮是否按下, 0( 左键) , 1( 右键) , 2( 中键)
Input.GetMouseButton(int button)
检查鼠标按钮是否被持续按下, 0( 左键) , 1( 右键) , 2( 中键)
Input.GetMouseButtonUp(int button)
检查鼠标按钮是否释放, 0( 左键) , 1( 右键) , 2( 中键)
Input.GetAxis("Mouse ScrollWheel")
返回鼠标滚轮的滚动值, 正数表示向上滚动, 负数表示向下滚动
Input.GetAxis("Mouse X")
返回水平方向上的鼠标移动量
Input.GetAxis("Mouse Y")
分别垂直方向上的鼠标移动量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 Vector3 mousePosition = Input.mousePosition; Debug.Log("Mouse Position: " + mousePosition); if (Input.GetMouseButtonDown(0 )){ Debug.Log("Left mouse button down." ); } if (Input.GetMouseButton(1 )){ Debug.Log("Right mouse button held." ); } if (Input.GetMouseButtonUp(2 )){ Debug.Log("Middle mouse button up." ); } float scroll = Input.GetAxis("Mouse ScrollWheel" );if (scroll > 0f ){ Debug.Log("Scroll Up." ); } else if (scroll < 0f ){ Debug.Log("Scroll Down." ); } float mouseX = Input.GetAxis("Mouse X" );float mouseY = Input.GetAxis("Mouse Y" );if (mouseX != 0f || mouseY != 0f ){ Debug.Log("Mouse moved: (" + mouseX + ", " + mouseY + ")" ); } void Update (){ if (Input.GetMouseButtonDown(0 )) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { Debug.Log("Hit object: " + hit.transform.name); } } }
对象池 对象池( Object Pooling) 是一种设计模式, 通常用于游戏开发中以提高性能和减少内存分配的压力。 在Unity中, 对象池可以有效地管理预制体实例的创建、 销毁和重用, 尤其在处理大量短暂存在的游戏对象时非常有用, 比如子弹、 粒子效果或敌人等。
基本原理 对象池维护了一个对象列表, 这些对象预先被创建, 并且在需要使用的时候从池中取出, 不需要时再放回池中而不是直接销毁。 这样做的好处是避免了频繁的创建和销毁对象所带来的性能开销, 因为创建新对象涉及到内存分配, 而销毁对象则可能涉及垃圾回收, 这两者都会对性能产生影响。
实现步骤
预生成对象: 在游戏开始时或者加载关卡时, 根据预期的需求预先创建一定数量的对象, 并将它们存储在一个列表中。
获取对象: 当游戏运行时需要某个对象时, 从池中取出一个对象并激活它。 如果池中没有可用的对象, 则可以根据需要创建新的对象。
释放对象: 当对象不再需要时, 将其放回池中而不是销毁。 这通常伴随着重置对象的状态, 以便于下次使用。
实现方法
单例模式: 通常会使用单例模式来管理对象池, 确保游戏中只有一个对象池实例。
使用队列或列表: 使用一个队列或列表来存储所有的空闲对象。
预制体和实例化: 使用Unity的GameObject预制体系统, 通过Instantiate方法来生成对象, 并通过SetActive(false)来隐藏对象而不销毁它, 当需要时再通过SetActive(true)激活它。
池化策略: 可以设定最大池大小, 动态调整池的大小, 或者使用不同的策略来决定何时释放对象回到池中。
注意事项
内存管理: 虽然对象池可以减少频繁的创建和销毁带来的开销, 但如果管理不当也可能导致内存泄漏。 例如, 忘记从池中移除不再使用的对象。
对象状态: 在将对象返回到池中之前, 确保对象的状态被正确地重置, 否则可能会导致意外的行为。
性能考虑: 对于非常短生命周期的对象, 如果创建销毁的成本较低, 可能不需要使用对象池。
简单示例 创建一个子弹对象池, 并在需要时从池中获取子弹。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 using System.Collections.Generic;using UnityEngine;public class ObjectPoolManager : MonoBehaviour { public static ObjectPoolManager Instance { get ; private set ; } [System.Serializable ] public class Pool { public string tag; public GameObject prefab; public int size; } public List<Pool> pools; public Dictionary<string , Queue<GameObject>> poolDictionary = new Dictionary<string , Queue<GameObject>>(); private void Awake () { Instance = this ; foreach (Pool poolData in pools) { Queue<GameObject> objectPool = new Queue<GameObject>(); for (int i = 0 ; i < poolData.size; i++) { GameObject obj = Instantiate(poolData.prefab); obj.SetActive(false ); objectPool.Enqueue(obj); } poolDictionary.Add(poolData.tag, objectPool); } } public GameObject SpawnFromPool (string tag, Vector3 position, Quaternion rotation ) { if (!poolDictionary.ContainsKey(tag)) { Debug.LogError("Pool with tag " + tag + " not found." ); return null ; } GameObject obj = poolDictionary[tag].Dequeue(); obj.transform.position = position; obj.transform.rotation = rotation; obj.SetActive(true ); obj.GetComponent<Bullet>().OnObjectUseComplete(OnObjectUseComplete); return obj; } private void OnObjectUseComplete (GameObject obj ) { obj.SetActive(false ); string tag = obj.tag; if (poolDictionary.ContainsKey(tag)) { poolDictionary[tag].Enqueue(obj); } } } using UnityEngine;using System.Collections;public class Bullet : MonoBehaviour { public float lifeTime = 2f ; public void OnObjectUseComplete (System.Action<GameObject> callback ) { StartCoroutine(DestroyAfterLifetime(callback)); } private IEnumerator DestroyAfterLifetime (System.Action<GameObject> callback ) { yield return new WaitForSeconds (lifeTime ) ; callback?.Invoke(this .gameObject); } } void Shoot (){ Vector3 spawnPosition = transform.position + transform.forward * 1f ; Quaternion spawnRotation = transform.rotation; ObjectPoolManager.Instance.SpawnFromPool("Bullet" , spawnPosition, spawnRotation); }
数学应用 Mathf 类 Mathf 是 Unity 中的一个静态类, 用于提供各种数学函数和常量, 主要用于处理浮点数。 这个类包含了许多常用数学运算的方法, 如三角函数、 指数函数、 取整函数等, 这些方法对于游戏开发中的各种计算非常有用。
属性 / 方法 描述
Clamp(float value, float min, float max)
限制 value 在 min 和 max 之间
Clamp01(float value)
限制 value 在 0 和 1 之间
Abs(float f)
返回 f 的绝对值
Sign(float f)
返回 f 的符号( -1, 0 或 1)
Floor(float f)
返回不大于 f 的最大整数
Ceil(float f)
返回不小于 f 的最小整数
Round(float f)
将 f 四舍五入到最近的整数
SmoothStep(float edge0, float edge1, float x)
平滑地插值从 0 到 1 的范围
Lerp(float a, float b, float t)
线性插值从 a 到 b
Sin(float f)
返回 `f` 弧度的正弦值
Cos(float f)
返回 `f` 弧度的余弦值
Tan(float f)
返回 `f` 弧度的正切值
Acos(float f)
返回 `f` 的反余弦值
Asin(float f)
返回 `f` 的反正弦值
Atan(float f)
返回 `f` 的反正切值
Atan2(float y, float x)
根据坐标 `(x, y)` 返回角度
Pow(float f, float power)
返回 `f` 的 `power` 次幂
Sqrt(float f)
返回 `f` 的平方根
Log(float f)
返回 `f` 的自然对数
Log10(float f)
返回 `f` 的以 10 为底的对数
Mathf.PI
π 的近似值
Mathf.Deg2Rad
用于将角度转换为弧度
Mathf.Rad2Deg
用于将弧度转换为角度
Mathf.Epsilon
一个非常小的正数, 用于比较浮点数时避免除零错误
角度与弧度 角度和弧度是处理旋转和方向时常用的两种单位。 角度通常用于直观地描述旋转量, 一个完整的圆周被分为360度。 弧度是另一种测量角的单位, 它是国际单位制( SI) 中的标准单位。 一个完整的圆周包含2π( 约等于6.283185) 弧度。
角度与弧度之间的转换
角度转弧度: 弧度 = π / 180 × 角度 弧度转角度: 角度 = 180 / π × 弧度
游戏应用 💗💗 使用角度和弧度来计算物体的旋转 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 using System.Collections;using UnityEngine;public class CirclePath : MonoBehaviour { public float radius = 1.0f ; public float speed = 1.0f ; private float angleInRadians = 0.0f ; void Update () { angleInRadians += Time.deltaTime * speed; Vector3 newPosition = new Vector3(radius * Mathf.Cos(angleInRadians), 0 , radius * Mathf.Sin(angleInRadians)); transform.position = newPosition; } }
💗💗 使用角度来设置物体的方向 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;public class PlayerRotation : MonoBehaviour { public float turnSpeed = 100.0f ; void Update () { float horizontalInput = Input.GetAxis("Horizontal" ); float verticalInput = Input.GetAxis("Vertical" ); float angleInDegrees = Mathf.Atan2(verticalInput, horizontalInput) * Mathf.Rad2Deg; transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(0 , angleInDegrees, 0 ), turnSpeed * Time.deltaTime); } }
💗💗 使用弧度来计算物体的旋转速度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using UnityEngine;public class RotateTowardsTarget : MonoBehaviour { public Transform target; public float maxAngularSpeed = 100.0f ; void Update () { float angleDifferenceInDegrees = Vector3.SignedAngle(transform.forward, target.position - transform.position, Vector3.up); float angleDifferenceInRadians = angleDifferenceInDegrees * Mathf.Deg2Rad; float angularSpeed = angleDifferenceInRadians / Time.deltaTime; if (Mathf.Abs(angularSpeed) > maxAngularSpeed) { angularSpeed = Mathf.Sign(angularSpeed) * maxAngularSpeed; } transform.Rotate(Vector3.up, angularSpeed * Time.deltaTime * Mathf.Rad2Deg); } }
三角函数 三角函数是数学中一类重要的函数, 它们在几何、 物理、 工程学等领域都有广泛的应用。 最基本的三个三角函数是正弦( sine) 、 余弦( cosine) 和正切( tangent) 。
圆周定义
正弦值 sin(θ): 是该角对应的终边与单位圆交点的 y 坐标。
余弦值 cos(θ): 是该角对应的终边与单位圆交点的 x 坐标。
正切值 tan(θ): 定义为 sin(θ) / cos(θ), 当 cos(θ) ≠ 0 时有效。
直角三角形定义 对于直角三角形中的一个锐角 θ
正弦 sin(θ): 定义为对边与斜边的比值。
余弦 cos(θ): 定义为邻边与斜边的比值。
正切 tan(θ): 定义为对边与邻边的比值。
游戏应用 在游戏开发中, 三角函数是非常重要的数学工具, 它们被广泛应用于许多方面。 以下是一些使用三角函数在 Unity 游戏开发中的典型应用场景。
💗💗 物体移动 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using UnityEngine;using System;public class CircularMotion : MonoBehaviour { public float radius = 5.0f ; public float speed = 1.0f ; private float angle = 0.0f ; void Update () { angle += Time.deltaTime * speed; float x = Mathf.Cos(angle) * radius; float y = Mathf.Sin(angle) * radius; transform.position = new Vector3(x, 0 , y); } }
💗💗 物体旋转 1 2 3 4 5 6 7 8 9 10 11 12 13 14 using UnityEngine;public class LookAtTarget : MonoBehaviour { public Transform target; void Update () { Vector3 direction = (target.position - transform.position).normalized; Quaternion lookRotation = Quaternion.LookRotation(direction); transform.rotation = Quaternion.Lerp(transform.rotation, lookRotation, Time.deltaTime * 5.0f ); } }
💗💗 投影和光照 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using UnityEngine;public class LightProjection : MonoBehaviour { public Light lightSource; public Material surfaceMaterial; void OnRenderImage (RenderTexture source, RenderTexture destination ) { Vector3 lightDirection = lightSource.transform.forward; float dotProduct = Vector3.Dot(lightDirection, transform.up); surfaceMaterial.SetFloat("_LightAngle" , dotProduct); Graphics.Blit(source, destination, surfaceMaterial); } }
💗💗 摄像机摇摆 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using UnityEngine;public class CameraShake : MonoBehaviour { public float amplitude = 0.1f ; public float frequency = 2.0f ; void Update () { float time = Time.time; float offsetX = Mathf.Sin(time * frequency) * amplitude; float offsetZ = Mathf.Cos(time * frequency) * amplitude; transform.position = new Vector3(offsetX, 0 , offsetZ); } }
💗💗 物理模拟 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 using UnityEngine;public class PhysicsSimulation : MonoBehaviour { public Rigidbody rb; public float gravityStrength = 9.81f ; void FixedUpdate () { Vector3 gravityDirection = new Vector3(0 , -1 , 0 ); Vector3 gravityForce = gravityDirection * gravityStrength; rb.AddForce(gravityForce, ForceMode.Acceleration); } }
💗💗 AI 行为 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using UnityEngine;public class AIBehavior : MonoBehaviour { public Transform target; public float maxSpeed = 5.0f ; void Update () { Vector3 direction = (target.position - transform.position).normalized; float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; transform.rotation = Quaternion.Euler(0 , 0 , angle); Vector3 velocity = direction * maxSpeed; transform.Translate(velocity * Time.deltaTime); } }
线性插值 线性插值( Linear Interpolation, 简称 Lerp) 是一种在两个已知值之间找到一个未知值的数学方法。 在游戏开发和计算机图形学中, 线性插值常用于平滑地改变物体的位置、 旋转或缩放等属性。 在Unity中, 线性插值被广泛应用于动画、 移动物体以及平滑过渡效果。 Unity提供了多种Lerp函数来处理不同的数据类型, 如位置、 颜色、 向量等。
基本概念
起点 (startValue): 起始值。
终点 (endValue): 目标值。
t: 时间参数, 通常是一个介于0到1之间的值, 表示从起点到终点的进度百分比。 当t=0时, 结果等于startValue; 当t=1时, 结果等于endValue。
Lerp函数
Unity中提供了一系列Lerp函数来处理不同类型的数据
函数 描述
Vector3.Lerp
用于向量的线性插值
Color.Lerp
用于颜色的线性插值
Quaternion.Lerp
用于四元数( 旋转) 的线性插值
Mathf.Lerp
用于浮点数值的线性插值
游戏应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 using UnityEngine;public class MoveObject : MonoBehaviour { public Vector3 startPosition; public Vector3 endPosition; public float duration = 2.0f ; private float startTime; void Start () { startTime = Time.time; } void Update () { float t = (Time.time - startTime) / duration; t = Mathf.Clamp01(t); transform.position = Vector3.Lerp(startPosition, endPosition, t); if (t >= 1 ) { startTime = Time.time; } } } using UnityEngine;using UnityEngine.UI;public class ChangeColor : MonoBehaviour { public Color startColor; public Color endColor; public float duration = 2.0f ; private float startTime; void Start () { startTime = Time.time; GetComponent<Renderer>().material.color = startColor; } void Update () { float t = (Time.time - startTime) / duration; t = Mathf.Clamp01(t); GetComponent<Renderer>().material.color = Color.Lerp(startColor, endColor, t); if (t >= 1 ) { startTime = Time.time; } } } using UnityEngine;public class RotateObject : MonoBehaviour { public Quaternion startRotation; public Quaternion endRotation; public float duration = 2.0f ; private float startTime; void Start () { startTime = Time.time; transform.rotation = startRotation; } void Update () { float t = (Time.time - startTime) / duration; t = Mathf.Clamp01(t); transform.rotation = Quaternion.Lerp(startRotation, endRotation, t); if (t >= 1 ) { startTime = Time.time; } } } using UnityEngine;using UnityEngine.UI;public class ChangeHealthBar : MonoBehaviour { public float startHealth; public float endHealth; public float duration = 2.0f ; private float startTime; private Slider healthSlider; void Start () { startTime = Time.time; healthSlider = GetComponent<Slider>(); healthSlider.value = startHealth; } void Update () { float t = (Time.time - startTime) / duration; t = Mathf.Clamp01(t); float currentHealth = Mathf.Lerp(startHealth, endHealth, t); healthSlider.value = currentHealth; if (t >= 1 ) { startTime = Time.time; } } }
向量 在数学中, 向量是一个非常重要的概念, 它不仅在几何学中有广泛的应用, 在物理学、 工程学以及计算机科学等领域也扮演着核心角色。
基本定义
向量可以被看作是有方向和大小( 长度或模) 的量
在平面或空间中, 一个向量可以用一条带有箭头的线段来表示, 箭头指示向量的方向, 而线段的长度代表向量的大小。
表示方法
在二维坐标系中, 向量可以通过一对坐标 (x, y) 来表示, 其中 x 和 y 分别是该向量沿 x 轴和 y 轴的分量。
在三维坐标系中, 向量则通过三元组 (x, y, z) 来表示。
向量的运算 💗💗 向量加法
如果有两个向量 \( \overrightarrow{A} = (A1, A2) \) 和 \( \overrightarrow{B} = (B1, B2) \) , 那么它们的和 \( \overrightarrow{A} + \overrightarrow{B} \) 定义为 \( (A1 + B1, A2 + B2) \)。
💗💗 向量减法
向量 \( \overrightarrow{A} - \overrightarrow{B} \) 可以理解为 \( \overrightarrow{A} + (-\overrightarrow{B}) \) , 即\( \overrightarrow{B} \) 的相反向量与 \( \overrightarrow{A} \) 相加。
💗💗 数乘
当一个向量与一个标量 \( K \) 乘时, 结果是一个新的向量, 其方向与原向量相同 \( (当 K > 0) \), 相反 \( (当 K < 0) \), 且长度是原向量长度的 \( |k| \)倍。
💗💗 点乘( 内积)
对于两个向量 \( \overrightarrow{A} \) 和 \( \overrightarrow{B} \), 它们的内积定义为 \( \overrightarrow{A} · \overrightarrow{B} = |\overrightarrow{A}| × |\overrightarrow{B}| × cosθ \) , 其中 \( θ \) 是两向量之间的夹角。
内积也可以通过分量来计算: 如果 \( \overrightarrow{A} = (A1, A2) \) 和 \( \overrightarrow{B} = (B1, B2) \), 那么 \( \overrightarrow{A} · \overrightarrow{B} = A1 × B1 + A2 × B2 \)
💗💗 叉乘( 外积)
在三维空间中, 两个向量 \( \overrightarrow{A} \) 和 \( \overrightarrow{B} \) 的外积是一个新向量 \( \overrightarrow{C} \), 其方向垂直于 \( \overrightarrow{A} \) 和 \( \overrightarrow{B} \) 所确定的平面, 并且满足右手定则。
外积的大小等于这两个向量构成的平行四边形的面积。
💗💗 向量的模
向量的模( 或长度) 定义为 \( \sqrt{x^2 + y^2} \) (在二维空间) 或 \( \sqrt{x^2 + y^2 + z^2} \) (在三维空间)。
二维向量 在 Unity 中 Vector2 是一个二维向量, 通常用于2D游戏或3D游戏中的一些特定用途( 如纹理坐标) 。
💗💗 常用属性
zero: 返回一个所有元素都为0的新向量。
one: 返回一个所有元素都为1的新向量。
up: 返回一个y值为1的新向量 (0, 1)。
down: 返回一个y值为-1的新向量 (0, -1)。
left: 返回一个x值为-1的新向量 (-1, 0)。
right: 返回一个x值为1的新向量 (1, 0)。
normalized: 返回一个单位长度的新向量。
magnitude: 返回向量的长度。
sqrMagnitude: 返回向量长度的平方。
💗💗 常用方法
Normalize(): 将当前向量归一化。
Scale(Vector2 scale): 按照scale参数缩放当前向量。
Dot(Vector2 other): 计算与另一个向量的点积。
Lerp(Vector2 a, Vector2 b, float t): 线性插值。
MoveTowards(Vector2 current, Vector2 target, float maxDistanceDelta): 移动到目标位置, 但不会超过最大移动距离。
💗💗 应用场景
2D 游戏角色移动
用于表示2D游戏角色的位置、 速度和加速度。
例如, 通过键盘输入控制角色在二维平面上移动。
UI 元素定位
用于确定 UI 元素( 如按钮、 文本框等) 在屏幕上的位置。
也可以用于表示 UI 元素的尺寸。
粒子系统
用于定义粒子的初始速度、 方向和加速度。
例如, 在雨滴效果中, 每个雨滴的初始速度可以是一个 Vector2。
碰撞检测
用于表示矩形碰撞体的大小和位置。
在2D游戏中, 碰撞检测经常使用 Vector2 来实现。
纹理坐标
用于表示贴图在 UV 空间中的位置。
这对于2D精灵来说非常重要。
💗💗 游戏应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 using UnityEngine;public class PlayerController2D : MonoBehaviour { public float speed = 5.0f ; private Vector2 velocity; void Update () { float horizontalInput = Input.GetAxis("Horizontal" ); velocity = new Vector2(horizontalInput * speed, 0 ); transform.Translate(velocity * Time.deltaTime); } }
三维向量 在 Unity 中 Vector3 是一个三维向量, 最常用于3D游戏中。
💗💗 常用属性
zero: 返回一个所有元素都为0的新向量。
one: 返回一个所有元素都为1的新向量。
up: 返回一个y值为1的新向量 (0, 1, 0)。
down: 返回一个y值为-1的新向量 (0, -1, 0)。
left: 返回一个x值为-1的新向量 (-1, 0, 0)。
right: 返回一个x值为1的新向量 (1, 0, 0)。
forward: 返回一个z值为1的新向量 (0, 0, 1)。
back: 返回一个z值为-1的新向量 (0, 0, -1)。
normalized: 返回一个单位长度的新向量。
magnitude: 返回向量的长度。
sqrMagnitude: 返回向量长度的平方。
💗💗 常用方法
Normalize(): 将当前向量归一化。
Scale(Vector3 scale): 按照scale参数缩放当前向量。
Dot(Vector3 other): 计算与另一个向量的点积。
Cross(Vector3 other): 计算与另一个向量的叉积。
Lerp(Vector3 a, Vector3 b, float t): 线性插值。
MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta): 移动到目标位置, 但不会超过最大移动距离。
💗💗 应用场景
3D 游戏对象的位置
用于表示3D游戏世界中物体的位置。
例如, 一个玩家角色在游戏世界中的坐标。
物体的旋转
用于表示3D物体绕某轴旋转的角度。
例如, 飞机绕X轴、 Y轴和Z轴的旋转角度。
光照方向
用于表示光源的方向。
例如, 太阳光的方向可以用一个 Vector3 表示。
力的作用
用于表示施加在物体上的力的方向和大小。
例如, 风力或爆炸力。
摄像机位置和方向
用于表示摄像机的位置和朝向。
例如, 设置摄像机跟随玩家角色。
💗💗 游戏应用 1 2 3 4 5 6 7 8 9 10 11 12 13 using UnityEngine;public class RotateObject : MonoBehaviour { public Vector3 rotationSpeed = new Vector3(10 , 20 , 30 ); void Update () { transform.Rotate(rotationSpeed * Time.deltaTime); } }
四维向量 在 Unity 中 Vector4 是一个四维向量, 通常用于表示颜色或者在某些图形计算中。
💗💗 常用属性
zero: 返回一个所有元素都为0的新向量。
one: 返回一个所有元素都为1的新向量。
normalized: 返回一个单位长度的新向量。
magnitude: 返回向量的长度。
sqrMagnitude: 返回向量长度的平方。
💗💗 常用方法
Normalize(): 将当前向量归一化。
Scale(Vector4 scale): 按照scale参数缩放当前向量。
Dot(Vector4 other): 计算与另一个向量的点积。
💗💗 应用场景
颜色表示
用于表示带有透明度的颜色。
例如, 一个颜色值可以表示为 RGBA( 红绿蓝透明度) 格式。
变换矩阵
用于表示4x4变换矩阵的一列或一行。
在图形编程中, Vector4 经常用于表示矩阵向量乘法的结果。
光线追踪
用于表示光线的方向和起点。
在光线追踪算法中, Vector4 可以表示光线的方向和起点。
光照颜色
用于表示光源的颜色和强度。
例如, 一个光源的颜色和强度可以通过 Vector4 表示。
投影平面
用于表示投影平面的法线和平面方程。
在某些图形算法中, Vector4 可以表示一个平面的方程。
💗💗 游戏应用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;public class ColorBlender : MonoBehaviour { public Color colorA = new Color(1 , 0 , 0 , 1 ); public Color colorB = new Color(0 , 0 , 1 , 1 ); public float blendFactor = 0.5f ; void OnGUI () { Color blendedColor = Color.Lerp(colorA, colorB, blendFactor); GUI.color = blendedColor; GUI.Label(new Rect(10 , 10 , 100 , 30 ), "Blended Color" ); } }
欧拉角 欧拉角是一种用于描述三维空间中刚体或坐标系相对于某个参考坐标系的旋转或姿态的方法。 具体来说, 欧拉角是指通过沿着三个互相垂直的轴进行连续旋转来达到特定姿态所需的三个角度。 这三个轴通常是固定的( 相对于参考坐标系) , 或者是随刚体一起旋转的。
在Unity中, 欧拉角( Euler angles) 是一种表示物体三维空间旋转的方法。 它们由三个角度组成, 分别代表沿x轴、 y轴和z轴的旋转。 在不同的上下文中, 这些轴可以有不同的名称, 比如横滚( roll) 、 俯仰( pitch) 和偏航( yaw) 。
横滚( Roll) : 绕着物体自身的X轴旋转, 通常与飞机的翻滚动作相对应。
俯仰( Pitch) : 绕着物体自身的Y轴旋转, 通常与飞机抬头或低头的动作相对应。
偏航( Yaw) : 绕着物体自身的Z轴旋转, 通常与飞机向左或向右转弯的动作相对应。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 using UnityEngine;public class EulerRotationExample : MonoBehaviour { public float rollSpeed = 10.0f ; public float pitchSpeed = 10.0f ; public float yawSpeed = 10.0f ; private void Update () { transform.Rotate(Vector3.right * rollSpeed * Time.deltaTime); transform.Rotate(Vector3.up * pitchSpeed * Time.deltaTime); transform.Rotate(Vector3.forward * yawSpeed * Time.deltaTime); } }
物体旋转
设置物体的旋转角度: 你可以直接使用 transform.eulerAngles 属性来设置物体的旋转角度。
获取物体的旋转角度: 同样地, 你可以读取 transform.eulerAngles 来得到物体当前的旋转角度。
1 2 3 4 5 6 7 8 9 10 11 12 using UnityEngine;public class RotateObject : MonoBehaviour { public Vector3 rotationAngles = new Vector3(0 , 45 , 0 ); void Start () { transform.eulerAngles = rotationAngles; } }
动画和骨骼
在动画中, 欧拉角常用于表示关节的旋转角度。
例如, 在角色动画中, 手臂或腿部的关节旋转通常会用欧拉角来表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 using UnityEngine;using UnityEngine.AI;public class CharacterController : MonoBehaviour { public Animator animator; public NavMeshAgent agent; private void Update () { float horizontalInput = Input.GetAxis("Horizontal" ); float verticalInput = Input.GetAxis("Vertical" ); animator.SetFloat("Speed" , horizontalInput * horizontalInput + verticalInput * verticalInput); if (agent != null ) { agent.speed = verticalInput * 5f ; } if (verticalInput != 0 || horizontalInput != 0 ) { Vector3 moveDirection = new Vector3(horizontalInput, 0 , verticalInput).normalized; transform.rotation = Quaternion.LookRotation(moveDirection, Vector3.up); } } }
摄像机控制
第一人称视角: 你可以使用欧拉角来控制第一人称摄像机的俯仰和偏航。
第三人称视角: 同样适用于第三人称摄像机, 以保持摄像机相对于玩家角色的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;public class FirstPersonCamera : MonoBehaviour { public float mouseSensitivity = 100.0f ; private float xRotation = 0.0f ; void Update () { float mouseX = Input.GetAxis("Mouse X" ) * mouseSensitivity * Time.deltaTime; float mouseY = Input.GetAxis("Mouse Y" ) * mouseSensitivity * Time.deltaTime; xRotation -= mouseY; xRotation = Mathf.Clamp(xRotation, -90f , 90f ); transform.localRotation = Quaternion.Euler(xRotation, 0 , 0 ); transform.Rotate(Vector3.up * mouseX); } }
物理模拟
在物理引擎中, 欧拉角可用于初始化刚体的旋转角度。
例如, 你可以设置一个刚体的初始旋转角度, 以便它以特定的角度开始运动。
1 2 3 4 5 6 7 8 9 10 11 using UnityEngine;public class RigidbodyInitialRotation : MonoBehaviour { public Vector3 initialRotation = new Vector3(0 , 90 , 0 ); void Start () { GetComponent<Rigidbody>().transform.eulerAngles = initialRotation; } }
用户界面
当使用 Unity 的 UI 系统时, 欧拉角也可以用于调整 UI 元素的位置和方向。
例如, 你可能需要根据用户的输入动态旋转 UI 元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 using UnityEngine;using UnityEngine.UI;public class RotatableUIButton : MonoBehaviour { public float rotationSpeed = 10.0f ; public bool rotateOnHover = true ; public bool rotateOnClick = true ; private Image buttonImage; private void Start () { buttonImage = GetComponent<Image>(); } private void Update () { if (rotateOnHover && IsPointerOverGameObject()) { transform.Rotate(new Vector3(0 , 0 , rotationSpeed) * Time.deltaTime); } if (rotateOnClick && Input.GetMouseButtonDown(0 )) { if (IsPointerOverGameObject()) { transform.Rotate(new Vector3(0 , 0 , 180 )); } } } private bool IsPointerOverGameObject () { PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current); eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y); List<RaycastResult> results = new List<RaycastResult>(); EventSystem.current.RaycastAll(eventDataCurrentPosition, results); foreach (RaycastResult result in results) { if (result.gameObject == gameObject) { return true ; } } return false ; } }
游戏逻辑
在游戏逻辑中, 欧拉角可以用来表示物体的方向, 比如炮塔指向敌人的方向。
例如, 你可以计算出两个物体之间的相对角度, 并使用欧拉角来调整炮塔的方向。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using UnityEngine;public class TurretRotation : MonoBehaviour { public Transform target; public float rotationSpeed = 10.0f ; void Update () { if (target) { Vector3 direction = target.position - transform.position; Quaternion lookRotation = Quaternion.LookRotation(direction); transform.rotation = Quaternion.Lerp(transform.rotation, lookRotation, rotationSpeed * Time.deltaTime); } } }
四元数 四元数( Quaternion) 是一种用于表示物体旋转的数学结构。 相比于使用欧拉角( Euler angles) , 四元数提供了更高效、 更稳定的方式来处理旋转问题, 尤其是在涉及多个轴的旋转和插值时。
四元数由四个部分组成: 一个实部和三个虚部。 一般形式为 q = w + xi + yj + zk, 其中 w 是实部, 而 x, y, 和 z 分别对应于三个虚部。
在Unity中, 四元数是通过 Quaternion 类来表示的。 Quaternion 类提供了一系列方法和属性来帮助你操作四元数。 通常用来表示物体的旋转, 其形式简化为 (x, y, z, w), 其中 (x, y, z) 表示旋转轴的方向, w 表示旋转角度的余弦值的一半。
常用属性
属性 描述
identity
表示没有旋转的四元数
eulerAngles
获取或设置四元数对应的欧拉角
常用方法
方法 描述
Quaternion.LookRotation(Vector3 forward, Vector3 upwards)
返回一个指向指定方向的四元数
Quaternion.FromToRotation(Vector3 fromDir, Vector3 toDir)
从一个方向向另一个方向旋转
Quaternion.Euler(float x, float y, float z)
根据欧拉角创建四元数
Quaternion.Slerp(Quaternion a, Quaternion b, float t)
使用球面线性插值来平滑地从一个四元数插值到另一个四元数。
Quaternion.Lerp(Quaternion a, Quaternion b, float t)
线性插值两个四元数
Quaternion.Inverse(Quaternion rotation)
计算四元数的逆
Quaternion.Normalize(Quaternion q)
归一化四元数
应用场景
旋转物体:
使用 transform.rotation = new Quaternion(x, y, z, w); 可以直接设置物体的旋转。
使用 transform.Rotate(Vector3 axis, float angle, Space relativeTo) 可以绕着某个轴旋转一定的角度。
插值:
在动画和游戏逻辑中经常需要使用 Quaternion.Slerp 或 Quaternion.Lerp 来实现平滑的旋转效果。
组合旋转:
可以使用 * 运算符来组合两个旋转, 例如 Quaternion result = q1 * q2;。
游戏应用 💗💗 使用四元数实现物体绕轴旋转 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 using UnityEngine;public class RotateObject : MonoBehaviour { public float rotationSpeed = 45.0f ; private void Update () { Quaternion rotation = Quaternion.Euler(0 , rotationSpeed * Time.deltaTime, 0 ); transform.rotation = transform.rotation * rotation; } }
💗💗 使用四元数实现物体旋转的平滑过渡 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 using UnityEngine;public class SmoothRotation : MonoBehaviour { public Transform target; public float smoothTime = 0.3f ; private Quaternion targetRotation; private float timeSinceLastUpdate = 0.0f ; private void Start () { targetRotation = target.rotation; } private void Update () { if (target != null ) { targetRotation = target.rotation; transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, smoothTime * Time.deltaTime); } } }
💗💗 使用四元数实现物体看向目标 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 using UnityEngine;public class LookAtTarget : MonoBehaviour { public Transform target; private void Update () { if (target != null ) { Quaternion lookRotation = Quaternion.LookRotation(target.position - transform.position); transform.rotation = lookRotation; } } }
💗💗 使用四元数实现随机旋转 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 using UnityEngine;public class RandomRotation : MonoBehaviour { public float maxAngle = 10.0f ; private void Update () { Vector3 randomAxis = Random.insideUnitSphere; float randomAngle = Random.Range(-maxAngle, maxAngle); Quaternion randomRotation = Quaternion.AngleAxis(randomAngle, randomAxis); transform.rotation = transform.rotation * randomRotation; } }
加速度 加速度是速度的变化率, 通常表示为单位时间内速度的改变量。
使用Rigidbody组件 如果你正在使用Unity的物理引擎, 可以给游戏对象添加一个Rigidbody组件, 并通过施加力( Force) 来改变其运动状态。
1 2 3 4 5 6 7 8 9 void FixedUpdate (){ Rigidbody rb = GetComponent<Rigidbody>(); Vector3 force = new Vector3(10f , 0f , 0f ); rb.AddForce(force, ForceMode.Force); }
不使用Rigidbody组件 如果你不使用物理引擎, 而是手动控制物体的位置和速度, 可以在Update或FixedUpdate方法中手动计算加速度并更新速度和位置。
1 2 3 4 5 6 7 8 9 10 float speed = 0f ; float acceleration = 10f ; float deltaTime = Time.deltaTime; void Update (){ speed += acceleration * deltaTime; transform.Translate(Vector3.forward * speed * deltaTime); }
万有引力 在Unity中模拟万有引力可以用于创建更加真实的游戏场景, 特别是在涉及天体物理学、 行星运动或者任何需要模拟重力影响的场景时。
定义引力常数: 在Unity中, 我们可能不需要使用真实的万有引力常数, 而是可以根据游戏的需求调整这个值。
定义物体的质量: 为每个游戏对象分配一个质量属性。
计算引力: 编写一个函数来计算两个物体之间的引力大小。
施加引力: 使用计算出的引力来施加力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using UnityEngine;public class GravitySimulation : MonoBehaviour { public float gravityConstant = 1f ; public float mass; void FixedUpdate () { GravitySimulation[] simulations = FindObjectsOfType<GravitySimulation>(); foreach (GravitySimulation other in simulations) { if (other != this ) { ApplyGravitationalForce(other); } } } void ApplyGravitationalForce (GravitySimulation other ) { Vector3 direction = other.transform.position - transform.position; float distance = direction.magnitude; float forceMagnitude = gravityConstant * mass * other.mass / (distance * distance); Vector3 force = direction.normalized * forceMagnitude; Rigidbody myRigidbody = GetComponent<Rigidbody>(); Rigidbody otherRigidbody = other.GetComponent<Rigidbody>(); myRigidbody.AddForce(-force, ForceMode.Force); otherRigidbody.AddForce(force, ForceMode.Force); } }
动量定理 在Unity中, 动量定理是物理学中的一个重要概念, 它描述了力对物体动量变化的影响。 动量定理可以表述为: 作用在一个物体上的外力对该物体动量的变化率等于力的大小。 换句话说, 动量的变化等于力与时间的乘积, 即冲量。 在Unity中, 可以通过不同的方式来应用动量定理, 具体取决于你是在使用Unity的物理引擎还是自己手动控制物体的运动。
使用Rigidbody组件 当你使用Unity的物理引擎时, 可以通过施加力来改变物体的动量。 Unity的Rigidbody组件允许你施加力, 并且它会根据动量定理自动更新物体的状态。
1 2 3 4 5 6 7 8 9 10 void FixedUpdate (){ Rigidbody rb = GetComponent<Rigidbody>(); Vector3 force = new Vector3(10f , 0f , 0f ); rb.AddForce(force, ForceMode.Force); }
手动控制物体的动量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 float mass = 1f ; Vector3 momentum = Vector3.zero; void Update (){ Vector3 force = new Vector3(10f , 0f , 0f ); float deltaTime = Time.deltaTime; momentum += force * deltaTime; Vector3 velocity = momentum / mass; transform.Translate(velocity * deltaTime); }
高级组件 本地持久化 在Unity开发中, 有时候我们需要让游戏数据在关闭应用后仍然保留, 这就需要用到本地持久化存储技术。
PlayerPrefs 类 PlayerPrefs 是Unity提供的一个简单的键值对存储系统, 非常适合存储一些轻量级的数据, 如玩家的分数、 设置选项等。 它会自动保存数据到用户的设备上, 并且会在下次启动游戏时自动加载这些数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 PlayerPrefs.SetInt("PlayerScore" , 100 ); PlayerPrefs.Save(); int score = PlayerPrefs.GetInt("PlayerScore" , 0 ); PlayerPrefs.SetInt("PlayerScore" , 150 ); PlayerPrefs.Save(); PlayerPrefs.DeleteKey("PlayerScore" ); PlayerPrefs.Save();
文件系统 Unity允许开发者直接访问设备的文件系统, 可以用来读写文件。 通过 System.IO 命名空间中的类( 如 FileStream, StreamReader, StreamWriter 等) , 你可以创建、 读取、 更新和删除文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 string filePath = Application.persistentDataPath + "/player_score.txt" ;using (StreamWriter writer = new StreamWriter(filePath, true )){ writer.WriteLine("PlayerScore:100" ); } if (File.Exists(filePath)){ using (StreamReader reader = new StreamReader(filePath)) { string line; while ((line = reader.ReadLine()) != null ) { if (line.StartsWith("PlayerScore:" )) { int score = int .Parse(line.Substring(11 )); } } } } File.WriteAllText(filePath, "PlayerScore:150" ); if (File.Exists(filePath)){ File.Delete(filePath); }
JSON/XML 如果你需要存储结构化的数据, 可以考虑使用JSON或XML格式。 这两种格式易于解析, 并且可以通过序列化库( 如 Unity 自带的 System.Text.Json 或第三方库如 Json.NET) 轻松地将C#对象转换为JSON/XML字符串, 然后将其保存到文件中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 [System.Serializable ] public class PlayerData { public int Score; } void SavePlayerData (PlayerData data ){ string json = JsonUtility.ToJson(data); File.WriteAllText(Application.persistentDataPath + "/playerdata.json" , json); } PlayerData LoadPlayerData () { string path = Application.persistentDataPath + "/playerdata.json" ; if (File.Exists(path)) { string json = File.ReadAllText(path); return JsonUtility.FromJson<PlayerData>(json); } return null ; } PlayerData playerData = new PlayerData { Score = 100 }; SavePlayerData(playerData); PlayerData playerData = LoadPlayerData(); if (playerData != null ){ int score = playerData.Score; } PlayerData playerData = LoadPlayerData(); if (playerData != null ){ playerData.Score = 150 ; SavePlayerData(playerData); } string path = Application.persistentDataPath + "/playerdata.json" ;if (File.Exists(path)){ File.Delete(path); }
SQLite 对于更复杂的应用程序, 可能需要使用数据库来存储数据。 SQLite是一个轻量级的数据库, 非常适合用于移动设备和桌面应用程序。 Unity支持SQLite, 并且有许多插件可以帮助你在Unity中集成SQLite数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 using (IDbConnection conn = new SQLiteConnection("Data Source=" + databasePath)){ conn.Open(); IDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "INSERT INTO Players (Score) VALUES (@score)" ; cmd.Parameters.Add(new SQLiteParameter("@score" , 100 )); cmd.ExecuteNonQuery(); } using (IDbConnection conn = new SQLiteConnection("Data Source=" + databasePath)){ conn.Open(); IDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "SELECT Score FROM Players WHERE ID = @id" ; cmd.Parameters.Add(new SQLiteParameter("@id" , 1 )); IDataReader reader = cmd.ExecuteReader(); if (reader.Read()) { int score = reader.GetInt32(0 ); } } using (IDbConnection conn = new SQLiteConnection("Data Source=" + databasePath)){ conn.Open(); IDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "UPDATE Players SET Score = @score WHERE ID = @id" ; cmd.Parameters.Add(new SQLiteParameter("@score" , 150 )); cmd.Parameters.Add(new SQLiteParameter("@id" , 1 )); cmd.ExecuteNonQuery(); } using (IDbConnection conn = new SQLiteConnection("Data Source=" + databasePath)){ conn.Open(); IDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "DELETE FROM Players WHERE ID = @id" ; cmd.Parameters.Add(new SQLiteParameter("@id" , 1 )); cmd.ExecuteNonQuery(); }
资源加载 Unity 是一个非常流行的游戏开发引擎, 它提供了丰富的功能来帮助开发者创建交互式内容和游戏。 在 Unity 中, 资源管理是非常重要的一个方面, 因为游戏中的各种元素如模型、 纹理、 声音等都需要被正确地加载和使用。
Resources Unity 提供了一个特殊的 Resources 文件夹, 用于存储在运行时需要访问的资产。 任何放置在这个文件夹内的资源都可以通过 Resources.Load 方法来加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 using UnityEngine;public class LoadFromResources : MonoBehaviour { void Start () { GameObject myPrefab = Resources.Load("Prefabs/myPrefab" ) as GameObject; if (myPrefab != null ) { GameObject instance = Instantiate(myPrefab, Vector3.zero, Quaternion.identity); } } }
AssetBundles AssetBundles 是一组被打包在一起的资源, 它们可以被异步加载到游戏中。 这对于大型游戏特别有用, 因为它允许开发者按需加载资源, 从而减少初始加载时间和内存占用。
构建 AssetBundles: 首先你需要选择哪些资源应该被打包成 AssetBundles, 并构建这些包。
加载 AssetBundles: 你可以从本地磁盘或者远程服务器加载 AssetBundles。
卸载 AssetBundles: 不再需要时, 可以释放 AssetBundles 占用的内存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 using UnityEngine;using UnityEngine.Networking;public class LoadFromAssetBundles : MonoBehaviour { private const string _baseDownloadURL = "file:/path/to/your.assetbundle" ; void Start () { StartCoroutine(LoadAssetBundle()); } IEnumerator LoadAssetBundle () { UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(_baseDownloadURL); yield return www.SendWebRequest(); if (www.isNetworkError || www.isHttpError) { Debug.LogError("Error loading asset bundle: " + www.error); } else { AssetBundle myAssetBundle = DownloadHandlerAssetBundle.GetContent(www); GameObject myObject = myAssetBundle.LoadAsset<GameObject>("assetNameInBundle" ); if (myObject != null ) { GameObject instance = Instantiate(myObject, Vector3.zero, Quaternion.identity); } myAssetBundle.Unload(false ); } } }
StreamingAssets StreamingAssets 文件夹包含的内容在打包过程中不会被修改, 并且可以在运行时直接读取。 这个文件夹通常用来存放一些不需要 Unity 引擎解析的数据文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using UnityEngine;using System.IO;public class LoadFromStreamingAssets : MonoBehaviour { void Start () { string path = Application.streamingAssetsPath + "/example.txt" ; string fileContent = File.ReadAllText(path); Debug.Log("File content: " + fileContent); } }
灯光组件 Unity 是一个非常流行的跨平台游戏开发引擎, 它支持多种类型的灯光组件来帮助开发者创建丰富多样的光照效果。 在 Unity 中, 你可以添加不同种类的光源到场景中以模拟现实世界中的各种光照情况。
Directional Light( 定向光)
定向光也被称为太阳光, 因为它模仿了太阳照射地球的效果。 所有从定向光源发出的光线都平行, 并且在整个场景中保持相同的方向。 这种光通常用来模拟远距离的大光源, 比如太阳。
Point Light( 点光源)
点光源是从一个点向各个方向均匀发射光线的光源。 它们可以用来模拟像灯泡这样的小光源。 点光源的光照强度会随着距离增加而衰减。
Spot Light( 聚光灯)
聚光灯有一个明确的方向, 并且在指定的角度范围内发射光线, 类似于手电筒或舞台上的聚光灯。 你可以设置聚光灯的锥角来控制光照的范围。
Area Light( 区域光/面光源)
区域光在 Unity 中是指具有特定形状( 如矩形或圆形) 并从该形状表面发射光线的光源。 在实时渲染中, Unity 使用称为“ 烘焙” 的技术来模拟面积光源的效果, 因为直接计算面积光需要较高的计算资源。
面板属性
属性 描述
Color
光源的颜色
Intensity
光源的强度
Range
光源影响的最大距离
Spot Angle
仅在转换为聚光灯时可见, 表示光束的角度
Spot Transition Angle
光束过渡角度, 定义光束边缘到完全衰减的过渡区域
Use Realtime Global Illumination
是否启用实时全局光照
Shadow Type
阴影类型
Shadow Bias
阴影偏移量
Shadow Normal Bias
用于减少自阴影现象的偏移值
Shadow Softness
阴影柔和度
Shadow Radius
用于计算阴影的采样半径
Shadow Resolution
阴影贴图的分辨率
Shadow Contrast Threshold
阴影对比度阈值
Draw Distance
绘制距离
相机组件 摄像机( Camera) 组件是一个核心组件, 它负责捕捉场景中的图像并将其显示给用户。
基本概念
摄像机: 在 Unity 中代表一个观察者的眼睛, 它决定了用户看到的场景部分。
场景: 由多个游戏对象组成的虚拟世界。
视口: 屏幕上显示的最终渲染结果的区域。
工作模式
Perspective: 透视投影, 模拟人眼视觉效果, 远处物体看起来更小。
Orthographic: 正交投影, 所有物体大小一致, 不会随距离改变而变化, 适合 2D 游戏。
基本属性
属性 描述
Clear Flags
清除标志, 用于设置背景颜色或使用天空盒等
Background
背景色, 当 Clear Flags 设置为 Solid Color 时, 摄像机会用这个颜色来填充背景
Field of View (FOV)
视野角度, 控制摄像机的视角宽度。 通常用于 3D 摄像机
Orthographic
正交投影, 如果启用, 则摄像机使用正交投影而不是透视投影。 适用于 2D 游戏
Orthographic Size
正交尺寸, 设置摄像机可见区域的高度( 在 2D 模式下有效)
Near Clip Plane
近裁剪平面, 定义了离摄像机最近的可见点
Far Clip Plane
远裁剪平面, 定义了离摄像机最远的可见点
Depth
深度值, 决定了摄像机绘制顺序。 值越大, 摄像机越后绘制
Rendering Path
渲染路径, 决定了渲染物体的方式
Target Texture
目标纹理, 可将摄像机输出定向到一个纹理上, 这对于实现某些效果如 UI 镜头很有用
应用示例 💗💗 主视角与 UI 摄像机 在很多游戏中, 你需要一个摄像机来显示游戏的主要画面, 同时需要另一个摄像机来专门处理用户界面( UI) 。 这样可以确保 UI 元素总是清晰地显示在屏幕的正确位置, 而不受主摄像机变换的影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class MainCameraController : MonoBehaviour { public Transform target; void LateUpdate () { transform.position = new Vector3(target.position.x, target.position.y, -10 ); } } public class UICamera : MonoBehaviour { void Start () { Camera.main.targetTexture = new RenderTexture(Screen.width, Screen.height, 24 ); GetComponent<Camera>().targetTexture = null ; } }
💗💗 第三人称视角与过肩视角 在第三人称游戏中, 你可能希望有一个固定的过肩视角摄像机来展示玩家角色的行动, 同时可能还有一个自由移动的摄像机来提供更广阔的视角。
1 2 3 4 5 6 7 8 9 10 11 public class OverTheShoulderCamera : MonoBehaviour { public Transform player; public Vector3 offset; void LateUpdate () { transform.position = player.position + offset; transform.LookAt(player); } }
💗💗 分屏多人游戏 在分屏多人游戏中, 你需要为每个玩家分配一个摄像机, 每个摄像机显示各自玩家的视角。 这可以通过调整摄像机的裁剪区域或者使用多个摄像机来实现。
1 2 3 4 5 6 7 8 9 10 11 12 public class SplitScreenCamera : MonoBehaviour { public Camera player1Cam; public Camera player2Cam; void Start () { player1Cam.rect = new Rect(0 , 0.5f , 1 , 0.5f ); player2Cam.rect = new Rect(0 , 0 , 1 , 0.5f ); } }
💗💗 2D 与 3D 混合视角 在一些游戏中, 可能会结合 2D 与 3D 视角。 例如, 一个 3D 摄像机显示游戏世界, 而另一个 2D 摄像机则显示某个特定的 2D 场景或迷你地图。
1 2 3 4 5 6 7 8 9 10 11 public class MixedDimensionCamera : MonoBehaviour { public Camera mainCam; public Camera miniMapCam; void Start () { mainCam.orthographic = false ; miniMapCam.orthographic = true ; } }
💗💗 录像与回放 在一些竞技游戏中, 可能会使用额外的摄像机来录制游戏过程, 以便之后进行回放分析。 这些摄像机通常会记录整个场景或特定区域的视角。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class ReplayCamera : MonoBehaviour { public Camera replayCam; private RenderTexture renderTexture; void Start () { renderTexture = new RenderTexture(Screen.width, Screen.height, 24 ); replayCam.targetTexture = renderTexture; } void Update () { } }
线渲染器 Line Renderer 是 Unity 中用于绘制一系列相连点的组件, 常用于创建轨迹、 路径或者任何需要线性图形的应用场景, 比如激光束、 绳索效果等。
基本概念
Position Points: Line Renderer 通过一系列位置点来定义线条的形状。 这些点可以手动设置, 也可以在运行时通过脚本动态更改。
Materials and Shaders: Line Renderer 支持使用材质和着色器来自定义线条的外观, 包括颜色、 宽度等属性。
Start Width / End Width: 定义了线条起点和终点的宽度, 可以创建锥形或其他变化宽度的效果。
Start Color / End Color: 设置线条起点和终点的颜色, 支持颜色渐变。
Sorting Layer & Sorting Order: 对于2D线条, 可以设置排序层和排序顺序来控制线条的渲染层级。
组件属性
属性 描述
Position Count
当前 Line Renderer 中的位置点数量
Use World Space
如果启用, 则位置点是在世界空间中定义的; 如果禁用, 则位置点相对于 Line Renderer 所属 GameObject 的局部空间。
Width Curve
可以使用曲线来控制整个线条宽度的变化
Color Gradient
使用颜色渐变来定义线条的颜色变化
Align With Direction
启用后, 线条的方向将会对齐到其位置点之间的方向
Loop
如果启用, 则第一个位置点与最后一个位置点将被连接起来形成闭合的环
Optimize Start Frame
优化开始帧, 减少不必要的计算
Width Multiply
宽度乘数, 用于缩放线条宽度
Material
指定用于渲染线条的材质
应用示例 创建一个简单的Unity脚本示例, 展示如何使用 LineRenderer 来模拟玩家发射激光的效果。 在这个例子中, 当玩家点击鼠标时, 将从玩家的位置发射一条激光线, 直到鼠标释放为止。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 using UnityEngine;public class LaserEmitter : MonoBehaviour { public LineRenderer lineRenderer; public float maxLaserLength = 100f ; private bool isFiring = false ; private Vector3 startLaserPosition; private Vector3 lastPosition; void Start () { InitializeLineRenderer(); } void Update () { if (Input.GetMouseButtonDown(0 )) { isFiring = true ; startLaserPosition = transform.position; lastPosition = startLaserPosition; } if (isFiring) { Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition); mouseWorldPos.z = 0 ; Vector3 newPosition = Vector3.Lerp(startLaserPosition, mouseWorldPos, 1f ); if ((newPosition - startLaserPosition).magnitude > maxLaserLength) { newPosition = startLaserPosition + (newPosition - startLaserPosition).normalized * maxLaserLength; } AddPosition(newPosition); if (Input.GetMouseButtonUp(0 )) { isFiring = false ; } } } private void InitializeLineRenderer () { Material mat = new Material(Shader.Find("Sprites/Default" )); lineRenderer.material = mat; lineRenderer.startWidth = 0.1f ; lineRenderer.endWidth = 0.1f ; lineRenderer.startColor = Color.red; lineRenderer.endColor = Color.red; } private void AddPosition (Vector3 position ) { int oldPositionCount = lineRenderer.positionCount; lineRenderer.positionCount = oldPositionCount + 1 ; lineRenderer.SetPosition(oldPositionCount, position); lastPosition = position; } }
轨道渲染器 Trail Renderer 是一个用于模拟连续轨迹或路径的组件, 常用于创建如粒子尾迹、 物体拖尾效果( 例如火箭推进器的火焰轨迹) 、 角色移动路径等视觉效果。
组件介绍 当你在游戏中添加一个 GameObject, 并附上 Trail Renderer 组件后, 你可以通过调整各种属性来控制轨迹的表现形式。
Position Count: 设置轨迹上记录的位置数量。 这决定了轨迹的长度。
Time (在 Trail Renderer 的 Emission 模块中): 控制轨迹的持续时间和生命周期。
Width Multiplier: 调整轨迹的宽度。
Gradient: 用于定义轨迹的颜色渐变。 可以设置开始点、 中间点和结束点的颜色。
Sorting Layer & Sorting Order: 这两个选项主要用于 2D 游戏中, 确定轨迹渲染层的顺序。
Simulation Speed: 控制轨迹模拟的速度。
Optimization: 提供了一些优化选项, 比如是否启用碰撞检测等。
使用方法
创建 Trail: 在 GameObject 上添加 Trail Renderer 组件。
配置属性: 根据需要调整 Trail 的颜色、 宽度、 位置计数等属性。
发射点控制: 如果你想要 Trail 跟随某个移动对象, 你需要在该对象上附加 Rigidbody 或其他移动机制, 并确保 Trail Renderer 正确地跟随它的运动。
动画与交互: 可以使用脚本来控制 Trail 的开启和关闭, 或者改变其属性值, 从而实现更复杂的动态效果。
应用示例 💗💗 粒子尾迹 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 using UnityEngine;public class ParticleTrail : MonoBehaviour { public TrailRenderer trailRenderer; private void Start () { trailRenderer.emitting = false ; } private void OnTriggerEnter (Collider other ) { if (other.gameObject.CompareTag("TriggerArea" )) { trailRenderer.emitting = true ; } } private void OnTriggerExit (Collider other ) { if (other.gameObject.CompareTag("TriggerArea" )) { trailRenderer.emitting = false ; } } }
💗💗 物体拖尾 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 using UnityEngine;public class RocketTrail : MonoBehaviour { public TrailRenderer trailRenderer; public float speedThreshold = 5f ; private Rigidbody rb; private void Start () { rb = GetComponent<Rigidbody>(); trailRenderer.emitting = false ; } private void Update () { if (rb.velocity.magnitude > speedThreshold) { trailRenderer.emitting = true ; } else { trailRenderer.emitting = false ; } } }
💗💗 角色移动路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 using UnityEngine;public class PlayerMovementTrail : MonoBehaviour { public TrailRenderer trailRenderer; private void Start () { trailRenderer.emitting = false ; } private void Update () { if (Input.GetAxis("Vertical" ) != 0 || Input.GetAxis("Horizontal" ) != 0 ) { trailRenderer.emitting = true ; } else { trailRenderer.emitting = false ; } } }
网格渲染器 Mesh Renderer是一个重要的组件, 它负责将网格( Mesh) 渲染到场景中。 这个组件与Mesh Filter和网格资源一起工作来显示3D对象的外观。
基本概念
Mesh Renderer 组件用于定义物体的表面如何被渲染。 它决定了模型的颜色、 纹理以及如何响应光照。
Mesh Filter 组件关联一个网格数据到游戏对象。 网格数据定义了物体的几何形状。
网格本身是一个资源文件, 包含了顶点的位置信息以及其他细节如UV坐标等。
使用方法
添加Mesh Renderer组件: 在Unity编辑器中创建一个空的游戏对象后, 你可以通过在Inspector面板中添加Mesh Renderer组件来开始渲染一个网格。 如果你想要渲染一个具体的形状, 比如一个立方体或者球体, 你也需要添加一个Mesh Filter组件, 并且给它分配一个相应的网格资源。
材质( Material) : Mesh Renderer组件需要一个材质( Material) , 这是一个包含了渲染物体所需的所有信息的容器, 包括颜色、 贴图( Textures) 、 着色器( Shader) 等。 材质决定了物体如何根据光照条件改变其外观。
着色器( Shader) : 着色器是控制物体渲染方式的脚本。 它们可以非常简单, 例如仅使用颜色或基础纹理; 也可以非常复杂, 例如实现高级光照效果或物理渲染( PBR) 。 材质中定义了要使用的着色器。
阴影模式( Shadows Mode) : Mesh Renderer允许你配置物体是否接收阴影, 以及是否投射阴影。 这可以通过设置阴影模式选项来完成, 有多种选择如“ Casting Shadows” 、 “ Receiving Shadows” 。
Layer( 层) : 层是一种组织和过滤场景中的物体的方法。 你可以为Mesh Renderer指定一个或多个层, 这对于光照、 碰撞检测和其他基于层的操作非常有用。
应用示例 MeshRenderer组件可以让你动态地更改物体的外观, 例如改变颜色、 切换材质等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 using UnityEngine;public class ChangeMaterialExample : MonoBehaviour { public Material newMaterial; private MeshRenderer meshRenderer; void Start () { meshRenderer = GetComponent<MeshRenderer>(); if (meshRenderer == null ) { Debug.LogError("MeshRenderer component not found on this game object." ); return ; } if (newMaterial == null ) { Debug.LogWarning("No new material assigned in the inspector." ); return ; } ChangeMaterial(); } void ChangeMaterial () { Material[] currentMaterials = meshRenderer.materials; for (int i = 0 ; i < currentMaterials.Length; i++) { currentMaterials[i] = newMaterial; } meshRenderer.materials = currentMaterials; } }
协程 协程( Coroutine) 是 Unity 中一种非常有用的功能, 它允许你编写可以暂停执行的函数, 并在稍后的时间点恢复执行。 协程在 Unity 中常用于实现动画、 延迟执行任务、 简单的时间间隔操作等。
基本概念
定义: 协程是一个可以暂停执行的方法, 当它被暂停时, 可以恢复执行其他代码, 然后在适当的时候恢复协程的执行。
声明: 协程方法必须返回 IEnumerator 类型, 并且通常以 IEnumerator 开头。
启动: 要启动一个协程, 你需要调用 StartCoroutine 方法, 并传递协程方法的引用。
停止: 你可以通过调用 StopCoroutine 方法来停止一个正在进行的协程。
生命周期: 协程在其所属的 MonoBehaviour 对象存活期间可以持续运行。 如果该对象被销毁, 则所有正在运行的协程也会被自动停止。
yield 表达式 💗💗 yield return null; 暂停协程直到下一帧开始。 这可以用来实现每一帧执行一次的逻辑。
1 2 3 4 5 6 7 8 IEnumerator ExampleCoroutine () { while (true ) { Debug.Log("Current frame: " + Time.frameCount); yield return null ; } }
💗💗 yield return new WaitForEndOfFrame(); 类似于 yield return null;, 但确保当前帧的所有渲染操作完成后再继续执行。
1 2 3 4 5 6 7 8 IEnumerator ExampleCoroutine () { while (true ) { Debug.Log("After rendering completes: " + Time.frameCount); yield return new WaitForEndOfFrame () ; } }
💗💗 yield return new WaitForSeconds(float seconds); 让协程暂停指定的秒数。 这是最常见的暂停方式之一。
1 2 3 4 5 6 7 8 9 IEnumerator ExampleCoroutine () { while (true ) { Debug.Log("Waiting for 1 second..." ); yield return new WaitForSeconds (1f ) ; Debug.Log("Done waiting." ); } }
💗💗 yield return new WaitUntil(System.Func condition); 让协程暂停, 直到提供的委托函数返回 true。
1 2 3 4 5 6 7 8 IEnumerator ExampleCoroutine () { while (true ) { Debug.Log("Waiting for game object to reach position..." ); yield return new WaitUntil (( ) => gameObject.transform.position.x >= 5f ); } }
💗💗 yield return new WaitWhile(System.Func condition); 让协程暂停, 只要提供的委托函数返回 true。
1 2 3 4 5 6 7 8 9 10 11 IEnumerator ExampleCoroutine () { bool isWaiting = true ; while (true ) { Debug.Log("Waiting until condition becomes false..." ); yield return new WaitWhile (( ) => isWaiting); Debug.Log("Condition became false." ); isWaiting = true ; } }
💗💗 yield return StartCoroutine(IEnumerator routine); 让当前协程等待另一个协程的完成。
1 2 3 4 5 6 7 8 9 10 11 IEnumerator ExampleCoroutine () { yield return StartCoroutine (AnotherCoroutine( )) ; } IEnumerator AnotherCoroutine () { Debug.Log("Starting another coroutine..." ); yield return new WaitForSeconds (2f ) ; Debug.Log("Another coroutine finished." ); }
💗💗 yield break; 立即退出当前协程。
1 2 3 4 5 6 7 8 IEnumerator ExampleCoroutine () { if (!someCondition) { yield break ; } Debug.Log("Continuing..." ); }
简单示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 using UnityEngine;public class CoroutineExample : MonoBehaviour { private void Start () { StartCoroutine(MyCoroutine()); } private IEnumerator MyCoroutine () { Debug.Log("协程开始" ); yield return new WaitForSeconds (2f ) ; Debug.Log("等待 2 秒后" ); while (!IsSomeConditionTrue()) { yield return null ; } Debug.Log("条件满足" ); yield return new WaitForEndOfFrame () ; Debug.Log("下一帧开始" ); yield break ; } private bool IsSomeConditionTrue () { return Input.GetKeyDown(KeyCode.Space); } public void StopMyCoroutine () { StopCoroutine("MyCoroutine" ); } }
动画组件 Animation Clips 💗💗 概念
定义: 动画剪辑是Unity中用于存储动画数据的一种资源类型。 它由一系列关键帧组成, 每个关键帧记录了一个时间点上的骨骼位置、 旋转和缩放信息。
创建: 可以在Unity的“ Animation Window” 中创建动画剪辑, 也可以直接导入已经存在的FBX或BVH文件。
编辑: 使用Unity的动画编辑器, 可以添加、 删除或修改关键帧, 调整曲线, 实现平滑的动画过渡。
💗💗 应用场景 动画剪辑: 在游戏中为角色创建各种动作, 如行走、 跳跃、 攻击等。
💗💗 操作步骤
创建一个新的Unity项目。
导入你的角色模型, 并确保模型带有骨骼。
打开Animation窗口 (Window > Animation > Animation)。
在Hierarchy视图中选择你的角色模型。
在Inspector视图中点击“ Create” 按钮创建新的动画剪辑。
为动画剪辑命名, 例如 Jump。
使用Timeline添加关键帧, 定义跳跃的起始、 最高点和落地的姿态。
调整曲线以获得平滑过渡。
Animator Controller 💗💗 概念
定义: Animator Controller是一个脚本, 用于管理动画状态机, 定义动画状态之间的过渡规则。
使用: 在Unity的Animator窗口中创建Animator Controller, 并将其分配给游戏对象。 通过拖拽动画剪辑到Animator Controller中, 可以创建动画状态。
状态机: 每个状态可以代表一个动画剪辑, 状态之间的过渡可以基于特定条件或参数的变化。
💗💗 应用场景 控制角色在不同状态之间的转换, 例如从静止到行走再到攻击。
💗💗 操作步骤
在Assets视图中右键点击, 选择 Create > Animator Controller。
将新创建的Animator Controller拖到你的角色模型上。
在Animator窗口 (Window > Animation > Animator) 中打开这个Animator Controller。
添加状态, 例如 Idle, Walk, Attack。
设置状态之间的过渡, 例如从 Idle 到 Walk 当速度大于某个阈值时触发。
将相应的动画剪辑分配给每个状态。
State Machines 💗💗 概念
定义: 动画状态机是一种组织动画的方式, 它将动画划分为多个状态, 并定义了这些状态之间的转换规则。
工作原理: 每个状态通常对应于一个动画剪辑, 而状态间的转换则依赖于Animator Controller中的条件判断。
层次结构: 状态机可以有层次结构, 允许嵌套子状态机, 以便更好地管理和组织复杂的动画逻辑。
💗💗 应用场景 动画状态机: 管理角色的动画状态, 例如从闲逛状态到战斗状态。
💗💗 操作步骤
在Animator窗口中, 通过拖动状态来构建状态机。
为状态机添加层次结构, 例如主状态机可以包含 Combat 和 NonCombat 子状态机。
在每个子状态机内部再添加具体的动画状态, 如 Combat 下可以有 Attack, Defend 等。
Parameters 💗💗 概念
定义: 参数是用来控制动画状态机中状态切换的变量, 可以是布尔型、 整型或浮点型。
用途: 通过改变参数值, 可以触发状态机中的状态转换, 从而播放不同的动画序列。
动态更改: 可以在运行时通过脚本动态更改参数值, 以响应用户输入或游戏逻辑。
💗💗 应用场景 控制角色动画的动态切换, 例如当玩家按下攻击键时切换到攻击动画。
💗💗 操作步骤
在Animator窗口中, 点击 + 添加一个布尔参数 isAttacking。
设置 Attack 状态只有当 isAttacking 为 true 时才进入。
在脚本中, 当玩家按下攻击键时, 设置 animator.SetBool(“isAttacking”, true)。
Blend Trees 💗💗 概念
定义: 混合树是一种特殊的动画状态, 它允许将多个动画按照一定的权重混合在一起播放。
类型: 混合树可以是一维的, 也可以是二维的, 取决于需要混合的动画数量和维度。
应用: 常用于实现角色在不同速度下的移动动画, 或者是基于两个变量( 如水平和垂直速度) 的动画混合。
💗💗 应用场景 混合树: 根据角色的速度混合不同的行走动画。
💗💗 操作步骤
在Animator窗口中, 创建一个一维混合树状态。
添加至少两个动画剪辑作为混合树的输入, 例如 Idle 和 Run。
设置混合轴为 Speed, 并关联到角色的速度。
在脚本中更新角色的速度参数。
Avatar 和骨骼绑定 💗💗 概念
定义: Avatar是一个配置文件, 它定义了Unity如何将动画数据映射到特定角色的骨骼上。
作用: 确保动画数据与角色模型匹配, 即使角色模型来自不同的来源。
创建: 通过将模型导入Unity并标记骨骼关节来创建Avatar。
💗💗 应用场景 确保不同来源的角色模型能够正确播放相同的动画。
💗💗 操作步骤
导入新的角色模型。
在Inspector视图中, 检查模型的 Humanoid 属性是否已正确映射。
如果需要调整, 可以手动设置 Humanoid 骨骼映射。
使用脚本控制动画 💗💗 概念
定义: 通过编写C#脚本, 可以控制Animator Controller中的参数, 从而控制动画的播放。
示例: 可以检测玩家输入的方向键, 并相应地更改Animator Controller中的速度参数来播放行走或跑步动画。
💗💗 应用场景 响应玩家输入来改变动画状态。
💗💗 操作步骤
创建一个脚本附加到角色上。
在脚本中, 根据玩家输入改变Animator参数, 例如 animator.SetFloat(“Speed”, speed);。
Animation Events 💗💗 概念
定义: 动画事件是在动画的特定时刻触发的事件, 可以用来执行代码。
设置: 在Unity的动画编辑器中为动画剪辑设置事件, 指定触发时间和要调用的方法。
用途: 用于同步动画与其他游戏元素, 如音效、 粒子效果等。
💗💗 应用场景 动画事件: 在动画的特定时刻触发声音效果或粒子效果。
💗💗 操作步骤
在Animation窗口中, 为动画剪辑添加一个动画事件。
设置事件触发的时间点。
在脚本中实现事件方法, 例如播放音效。
Animation Notifications 💗💗 概念
定义: 类似于动画事件, 但在动画剪辑播放期间发送消息而不是直接执行代码。
用途: 用于在动画播放的不同阶段通知其他系统执行某些操作。
💗💗 应用场景 动画通知: 在动画播放期间发送消息, 例如通知UI系统显示伤害数值。
💗💗 操作步骤
在Animation窗口中, 为动画剪辑添加一个动画通知。
设置通知发送的时间点。
在脚本中监听这些通知, 并执行相应逻辑。
Inverse Kinematics 💗💗 概念
定义: IK允许你直接控制角色肢体的末端( 如手或脚) , 即使这些肢体在动画剪辑中处于不同的姿势。
应用: 对于实现角色与环境互动非常重要, 例如让角色的手抓住物体或脚踏实地。
配置: 在Animator窗口中启用IK, 并指定IK目标和权重。
💗💗 应用场景 动画IK: 让角色的手臂自然地抓取物品。
💗💗 操作步骤
在Animator窗口中, 为相关状态启用IK。
设置IK的目标, 例如角色的手部。
在脚本中更新IK目标的位置, 使其靠近物品。
自动寻路 Unity 中的自动寻路( Pathfinding) 功能通常通过其内置的导航系统来实现。 这个系统允许你在场景中定义可行走区域, 并为AI角色计算出从一个点到另一个点的最佳路径。
Navigation Mesh (NavMesh)
NavMesh Build Settings: 用于配置如何构建导航网格。 你可以指定哪些层是可行走的, 设置代理的高度、 半径等参数, 以及定义障碍物的跨越高度。
NavMesh Obstacle: 可以添加到阻挡导航网格构建的对象上, 如移动的障碍物或敌对AI, 这样它们就不会影响到导航网格的构建, 而是作为动态障碍处理。
💗💗 操作步骤
选择场景视图: 打开Unity编辑器, 选择你的场景。
打开Navigation窗口: 在菜单栏选择 Window > AI > Navigation。
配置Build Settings:
在Navigation窗口中点击 Settings 按钮。
在弹出的 NavMesh Build Settings 窗口中, 你可以设置哪些层是可以行走的( Layers) , 定义代理的尺寸( Agent Radius, Agent Height) 等。
构建NavMesh:
回到Navigation窗口, 点击 Build 按钮来构建导航网格。
你可以看到场景中的物体表面变成了蓝色, 表示这是可行走区域。
NavMesh Agent
这是一个组件, 你可以将其附加到需要进行自动寻路的GameObject上。 它负责处理移动逻辑, 比如速度、 加速度、 旋转方式等。
Destination: 目标位置, 可以通过脚本或者Inspector面板来设定。
Is On NavMesh: 确保代理在导航网格上, 如果不在, 则会试图找到最近的可行走区域。
Obstacle Avoidance: 根据环境中的其他代理或动态障碍物来调整路径。
💗💗 操作步骤
选择GameObject: 在Hierarchy视图中选择你需要自动寻路的游戏对象。
添加NavMesh Agent组件: 在Inspector面板中点击 Add Component, 然后搜索 NavMesh Agent 并添加。
配置Agent参数:
调整 Speed 来设置代理的最大移动速度。
设置 Acceleration 来控制加速和减速的速度。
使用 Angular Speed 来设置转向速度。
你可以设置目标位置 Destination, 这可以通过脚本来动态更改。
Navigation Area
Navigation Static: 标记物体为静态导航对象, 其变化不会影响到已经构建好的导航网格。
Navigation Dynamic: 动态导航区域, 这些区域可以在运行时改变, 比如桥塌陷后的水面。
💗💗 操作步骤
创建Navigation Static/Dynamic区域: 选择需要定义为导航区域的对象, 在Inspector面板中找到 Navigation 部分。
设置Area Type: 选择合适的类型, 如 Walkable 表示可行走区域, Not Walkable 表示不可行走区域。
Off-Mesh Link 当两个NavMesh之间没有直接连接但是可以通过某些特定路径( 例如跳跃、 攀爬、 使用绳索等) 到达时, 可以使用此组件来创建这种“ 非网格链接” 。
💗💗 操作步骤
创建Off-Mesh Link: 选择需要创建链接的对象, 然后在Inspector中添加 OffMeshLink 组件。
设置起始和结束位置: 通过 Position 属性来指定链接的起点和终点。
配置属性: 可以设置 Travel Cost 来改变经过此链接的成本, 从而影响AI的选择。
Path 寻路结果会被存储在一个Path对象中, 这个对象包含了从起点到终点的一系列点。 NavMesh Agent可以读取这个路径并跟随它。
💗💗 操作步骤 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 using UnityEngine;using UnityEngine.AI;public class PathExample : MonoBehaviour { public Transform target; private NavMeshAgent agent; void Start () { agent = GetComponent<NavMeshAgent>(); if (agent != null ) { agent.destination = target.position; } } void Update () { if (agent != null && agent.pathStatus == NavMeshPathStatus.PathComplete) { Debug.Log("路径已计算完成" ); } } }
NavMesh Modifier 可以修改局部导航网格属性的对象, 比如降低某个区域的通行成本, 使得AI更倾向于或避免通过该区域。
💗💗 操作步骤
添加NavMesh Modifier组件: 选择需要修改局部导航网格属性的对象, 添加 NavMeshModifierVolume 组件。
配置属性:
设置 Shape 为 Box, Capsule, Sphere 或者 Cylinder。
调整 Size 和 Offset 来确定影响范围。
设置 Area 类型和 Cost Modifier 来改变代理经过该区域的成本。
用户界面 在Unity中, UI( 用户界面) 系统允许开发者创建交互式且美观的界面, 以增强游戏或应用的用户体验。
画布 Canvas 组件是所有 UI 元素的容器, 它决定了 UI 元素在屏幕上的呈现方式。 画布是创建用户界面的基础, 所有的 UI 控件( 如按钮、 文本、 图像等) 都必须放置在画布之下。
创建画布
创建一个新的 Canvas: 在 Unity 编辑器的 Hierarchy 视图中, 选择 GameObject > UI > Canvas 来创建一个新的 UI 画布。
默认结构: 创建后, Unity 会自动为你创建一个包含几个子物体的 Canvas 对象, 包括一个 Event System、 一个 Stencil( 如果启用了Pixel Perfect) 、 一个 Content Scale Factor( 用于 DPI 缩放) 以及一个 Rect Transform。
主要属性
Render Mode: 画布的渲染模式, 决定了画布相对于相机的位置。
Screen Space - Overlay: 默认模式, 将 UI 元素直接渲染到屏幕之上, 与场景中的 3D 物体无关。
Screen Space - Camera: 将 UI 元素渲染到指定的摄像机上, 可以实现更高级的效果, 如 UI 元素跟随摄像机移动。
World Space: 将 UI 元素作为世界空间中的对象渲染, 可以将 UI 元素放置在 3D 场景中的任意位置。
Pixel Perfect: 如果勾选, Unity 会尝试让 UI 在不同分辨率的屏幕上看起来相同大小。 对于需要精确像素的艺术风格来说非常有用。
Root Canvas: 如果勾选, 则该画布将成为根画布。 通常情况下, 每个场景只有一个根画布, 它是所有其他画布的父级。
Raycast Target: 如果启用, 那么该画布下的 UI 元素可以接收到用户输入( 如点击) 。 如果禁用, 则无法接收到用户输入。
Additional Canvas Properties: 包括一些额外的属性, 如模糊效果、 透明度等。
子物体
Event System: 处理用户输入事件, 如鼠标点击、 触摸屏输入等。
Canvas Scaler: 控制 UI 元素在不同屏幕尺寸下的缩放。
Graphic Raycaster: 用于检测用户输入并触发相应的 UI 事件。
RectTransform Tool: 用于精确调整 UI 元素的位置和大小。
Canvas Scaler 组件 Canvas Scaler 组件对于适配不同分辨率的屏幕非常重要, 它具有以下几种模式:
Constant Pixel Size: 保持 UI 元素的像素大小一致。
Scale With Screen Size: 根据屏幕宽度的比例缩放 UI 元素。
Constant Physical Size: 保持 UI 元素的实际物理尺寸一致。
Graphic Raycaster 组件 Graphic Raycaster 组件用于检测用户输入并将其传递给相应的 UI 元素。 你可以根据需要添加多个 Raycaster, 以支持不同的输入类型( 如鼠标、 触摸屏等) 。
字体 这是最基本的UI组件之一, 用于在屏幕上显示文本。 当你在Hierarchy视图中创建一个UI Canvas, 并添加一个新的UI Text对象时, 就会自动附带Text组件。 在Inspector视图中, 你可以设置文本的内容、 字体大小、 颜色等属性。
属性
Text: 显示的文本内容。
Font Size: 文本字体的大小。
Font Data: 设置使用的字体文件。
Color: 文本的颜色。
Alignment: 文本对齐方式, 如左对齐、 居中、 右对齐等。
Line Spacing: 行间距。
Rich Text: 如果启用此选项, 可以使用富文本标签来格式化文本, 例如加粗、 斜体等。
字体设置 在Unity中, 字体是通过材质来定义的。 你可以使用Unity自带的字体, 也可以导入自己的TTF或OTF格式的字体文件。 一旦导入了字体, 可以在“ Font” 面板中调整字符间距、 行高和其他相关设置。
字体材质 为了使用自定义字体, 你需要创建一个字体材质。 这通常是通过在Unity编辑器中将字体文件拖到项目窗口来完成的。 Unity会自动创建一个字体材质资源。
富文本 启用了Text组件上的Rich Text选项, 那么可以在文本字符串中使用特殊的标签来改变文本的外观。
<b> 和 </b> 可以用来加粗文本。
<i> 和 </i> 可以用来斜体化文本。
<color=#rrggbb> 可以用来改变文本的颜色。
<size=值> 可以用来改变字体大小。
文本描边 描边是一个可选的效果, 可以用来增加文本的可读性或者美感。 描边是在文本边缘添加的一种颜色效果, 通常与文本本身的颜色不同。
文本溢出 当文本长度超过分配给其的区域时, Unity提供了几种处理文本溢出的方式, 比如截断或换行。
图片 在Unity中, UI图片组件是用来显示图像的一个重要元素, 广泛应用于游戏和应用程序的用户界面设计中。 UI图片组件不仅限于静态图像展示, 还可以用于实现动态效果、 响应用户输入等。
创建Image对象: 在Hierarchy视图中创建一个UI Canvas后, 在Canvas下创建一个新的Image对象。
设置Source Image: 在Inspector视图中, 找到Image组件并设置其Source Image属性。 这里可以选择从项目资源中选择一个图像文件作为源图像。
属性
Source Image: 指定要显示的图像。 可以选择Sprite、 Texture或者不指定任何图像( None) 。
Type: 图像的类型, 包括Simple、 Sliced、 Tiled和Filled四种模式。
Simple: 最简单的显示模式, 图像按照原样显示。
Sliced: 用于显示有边框和角落的图像, 可以设置四个角的像素宽度和高度来保持图像的拉伸不变形。
Tiled: 重复显示图像, 常用于创建纹理效果。
Filled: 显示填充效果, 可以设置填充的角度、 方向和填充比例。
Color: 调整图像的颜色。 即使没有选择任何图像, 也可以通过这个属性显示纯色块。
Fill Method: 当Type设置为Filled时有效, 可以选择从中心向外填充、 从左向右等不同的填充方法。
Preserve Aspect: 如果勾选, 则在调整图像大小时会保持原始图像的宽高比。
Raycast Target: 如果启用, 那么该图像可以接收用户的输入事件, 例如点击、 触摸等。
Sprite Mask 除了基本的Image组件之外, 还可以使用Sprite Mask组件来创建剪裁效果。 Sprite Mask可以用来遮罩其子物体, 只有位于遮罩区域内的子物体才能显示出来。
遮罩 遮罩组件( Mask) 是一种用来限制其他 UI 元素可见范围的技术, 可以用来创建各种视觉效果, 如圆形菜单、 异形按钮等。 遮罩组件主要有两种形式: Sprite Mask 和 Graphic Mask。 这两种遮罩组件都可以用来隐藏其子物体超出遮罩范围的部分, 从而实现特定形状的显示效果。
Sprite Mask 组件 Sprite Mask 是一种遮罩组件, 它允许你使用 Sprite 来定义遮罩的形状。 Sprite Mask 组件通常用于创建具有复杂形状的 UI 元素, 如不规则形状的按钮、 图标等。
创建 Sprite Mask
创建一个新的 GameObject: 在 Hierarchy 视图中创建一个新的空 GameObject。
添加 Sprite Mask 组件: 选择 GameObject 并在 Components 菜单下添加 UI > Mask > Sprite Mask。
设置 Sprite: 在 Inspector 视图中, 为 Sprite Mask 组件选择一个合适的 Sprite 作为遮罩的形状。
属性
Source Image: 用于定义遮罩形状的 Sprite。
Show Outer Contour: 如果勾选, 将显示遮罩的轮廓, 这对于调试遮罩效果很有帮助。
Use Triggers: 如果勾选, 遮罩将使用触发器( Trigger) 来定义其边界。 这意味着遮罩将影响其所有的子物体, 而不仅仅是直接的子物体。
Graphic Mask 组件 Graphic Mask 是另一种类型的遮罩组件, 它允许你使用任何 Graphic 类型的对象( 如 Image、 Raw Image 等) 来定义遮罩的形状。 Graphic Mask 可以用来创建更加灵活的遮罩效果。
创建 Graphic Mask
创建一个新的 GameObject: 在 Hierarchy 视图中创建一个新的 GameObject。
添加 Image 或其他 Graphic 组件: 为 GameObject 添加一个 Image 组件或其他类型的 Graphic 组件。
添加 Graphic Mask 组件: 在 Components 菜单下添加 UI > Mask > Graphic Mask。
设置 Graphic Mask: 在 Inspector 视图中, 可以设置 Graphic Mask 的属性。
属性
Target Graphic: 选择一个 Graphic 组件作为遮罩的形状来源。
Rect Mask: 如果勾选, 遮罩将基于目标 Graphic 的矩形边界来定义。
Use Triggers: 同 Sprite Mask 的 Use Triggers 属性。
使用示例 遮罩组件通常与 Canvas 的 Maskable Graphics 一起使用, 以达到最佳效果。 Maskable Graphics 是指那些支持遮罩的 UI 元素, 如 Image、 TextMesh、 Text、 RawImage 等。
创建一个圆形的按钮
创建一个 Image GameObject: 用于显示按钮的背景。
创建一个 Sprite Mask GameObject: 用于定义按钮的形状。
设置 Sprite Mask 的 Source Image: 选择一个圆形的 Sprite。
将 Image GameObject 拖动到 Sprite Mask GameObject 下作为子物体: 这样 Image 就会被圆形的 Sprite Mask 限制在其范围内显示。
按钮 Button 组件是一个UI元素, 用于响应用户的点击事件。 它可以绑定到脚本中的函数, 从而执行特定的操作。
创建按钮
在Hierarchy视图中创建一个Canvas。
在Canvas下创建一个新的Button对象。
在Inspector视图中, 你会看到一个带有默认文本的Button对象, 它已经包含了Button组件。
主要属性
On Click(): 这是一个事件列表, 可以在这里添加脚本的方法引用或其他脚本的函数, 当用户点击按钮时, 这些方法会被调用。
Transition: 按钮状态变化的过渡方式, 默认是None, 表示没有过渡效果。 其他选项包括:
Color Tint: 改变按钮颜色来显示不同的状态。
Sprite Swap: 使用不同的Sprite来显示不同的状态。
Animation: 使用Unity动画系统来播放动画。
Colors: 定义按钮在不同状态下的颜色设置, 包括正常状态、 高亮状态、 按下状态和禁用状态。
Sprites: 当Transition设置为Sprite Swap时, 这里可以指定不同状态下的Sprite。
Animations: 当Transition设置为Animation时, 这里可以指定不同状态下的动画。
添加事件
在On Click()事件列表中, 你可以通过点击“ +” 按钮来添加一个新的事件条目。
选择“ Object” 来选择一个游戏对象, 并选择该对象上的一个脚本方法。
也可以直接添加预设的方法, 如Print Log, 用于测试按钮是否有效。
高级用法
动画: 可以为按钮添加动画效果, 使其在点击时产生动画反馈。
禁用按钮: 可以通过脚本或直接在Inspector中禁用按钮, 使其不可点击。
条件响应: 根据某些条件来决定按钮是否响应用户的点击。
自定义样式 通过Sprite Mask和Sprite Shapes来创建复杂的按钮样式。 此外, 还可以通过脚本来动态地改变按钮的外观和行为。
示例代码 1 2 3 4 5 6 7 8 9 10 11 using UnityEngine;using UnityEngine.UI;public class ButtonScript : MonoBehaviour { public void OnButtonClick () { Debug.Log("Button was clicked!" ); } }
选框 Toggle 组件是一个常用的 UI 元素, 通常用于表示二元状态的选择, 如开启/关闭、 是/否等。 Toggle 组件可以用来创建复选框、 开关等用户界面元素, 并且可以方便地与脚本结合来实现各种功能。
创建 Toggle
创建一个新的 Toggle: 在 Unity 编辑器的 Hierarchy 视图中, 选择 GameObject > UI > Toggle 来创建一个新的 Toggle 对象。
默认结构: 创建后, Unity 会自动为你创建一个包含 Toggle Group( 如果之前已有 Toggle Group) 以及 Toggle Button 和 Toggle Label 的 Toggle 对象。
主要属性
Is On: 初始状态下 Toggle 是否被激活。 默认值为 true, 表示初始状态为打开。
Group: Toggle 所属的 Toggle Group。 如果 Toggle 是一个组的一部分, 那么一次只能有一个 Toggle 处于活动状态。 这对于实现单选按钮功能非常有用。
On Value Changed: 一个回调函数列表, 当 Toggle 的状态发生改变时( 即从开启变为关闭, 或从关闭变为开启) , 这些函数会被调用。 可以在这里添加脚本中的方法来响应 Toggle 状态的变化。
Toggle Button 是 Toggle 的图形表示, 当 Toggle 被激活或关闭时, 它的外观会发生变化。 Toggle Button 通常由一个 Image 组件构成, 可以通过设置不同的 Sprite 或者改变颜色来表示不同的状态。
Toggle Label Toggle Label 是 Toggle 旁边显示的文本标签, 用于描述 Toggle 的功能或用途。 Label 通常由一个 Text 组件构成, 可以设置文本的内容、 字体大小、 颜色等属性。
Toggle Group Toggle Group 是一个可选的组件, 用于将多个 Toggle 组件组合在一起, 使得它们之间可以互相排斥, 即一次只能有一个 Toggle 处于活动状态。 这对于创建单选按钮功能非常有用。
创建 Toggle Group
在 Hierarchy 视图中创建一个新的空 GameObject。
将此 GameObject 命名为 ToggleGroup。
为其添加 Toggle Group 组件。
将想要成为一组的 Toggle 对象拖拽到 ToggleGroup 下作为子物体。
在每个 Toggle 的 Toggle 组件中, 选择刚刚创建的 ToggleGroup 作为其 Group。
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 using UnityEngine;using UnityEngine.UI;public class ToggleExample : MonoBehaviour { public Toggle myToggle; void Start () { myToggle.onValueChanged.AddListener(ToggleValueChanged); } void ToggleValueChanged (bool isOn ) { if (isOn) { Debug.Log("Toggle is ON" ); } else { Debug.Log("Toggle is OFF" ); } } }
滑块 UI 滑块组件( Slider) 是一个常用的用户界面元素, 用于表示数值的变化, 并允许用户通过拖动滑块来改变这些数值。 滑块组件可以用来控制音量、 调节亮度、 改变速度等多种场景。
创建滑块
创建一个新的滑块: 在 Unity 编辑器的 Hierarchy 视图中, 选择 GameObject > UI > Slider 来创建一个新的滑块对象。
默认结构: 创建后, Unity 会自动为你创建一个包含滑块背景、 滑块手柄( Fill Area) 及其内部的填充部分( Fill Rect) 等组件的滑块对象。
主要属性
Direction: 滑块的方向, 可以是水平( Horizontal) 或垂直( Vertical) 。
Min Value: 滑块的最小值。
Max Value: 滑块的最大值。
Value: 当前滑块的值, 可以在 Inspector 中直接设置或通过脚本动态修改。
Whole Numbers: 如果勾选, 滑块的值将只能取整数。
Handle Slide: 如果勾选, 用户可以通过拖动手柄来改变滑块的值。
On Value Changed: 一个回调函数列表, 当滑块的值发生变化时, 这些函数会被调用。 可以在这里添加脚本中的方法来响应滑块值的变化。
Fill Area 和 Fill Rect: 滑块的 Fill Area 包含一个 Fill Rect, 用来显示滑块当前所处的位置。 Fill Rect 的大小和位置会根据滑块的当前值动态改变。
滑块的子物体
Slider/Handle Rect: 用于表示滑块的手柄, 用户可以通过拖动它来改变滑块的值。
Slider/Fill Rect: 代表滑块填充部分的矩形, 随着滑块值的变化而变化。
Slider/Thumb: 滑块的手柄图标, 可以自定义其外观。
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;using UnityEngine.UI;public class SliderExample : MonoBehaviour { public Slider mySlider; void Start () { mySlider.onValueChanged.AddListener(SliderValueChanged); } void SliderValueChanged (float value ) { Debug.Log("Slider value changed to: " + value ); } }
高级用法
动态调整值: 可以在脚本中动态地调整滑块的值。
禁用滑块: 可以禁用滑块, 使其无法通过用户交互改变值。
自定义外观: 可以通过设置不同的 Sprite 或者改变颜色来自定义滑块的外观。
多滑块同步: 可以使用脚本来同步多个滑块的状态, 使它们的值保持一致。
滚动条 UI 滚动条组件( Scrollbar) 是一个常见的用户界面元素, 用于表示和控制数值的变化范围。 滚动条通常用于模拟长文档或列表的滚动行为, 让用户能够通过拖动滚动条来改变当前显示的内容。
创建滚动条
创建一个新的滚动条: 在 Unity 编辑器的 Hierarchy 视图中, 选择 GameObject > UI > Scrollbar 来创建一个新的滚动条对象。
默认结构: 创建后, Unity 会自动为你创建一个包含滚动条背景、 滑块手柄等组件的滚动条对象。
主要属性
Direction: 滚动条的方向, 可以是水平( Horizontal) 或垂直( Vertical) 。
Value: 当前滚动条的值, 可以在 Inspector 中直接设置或通过脚本动态修改。
Size: 滚动条手柄的大小, 表示当前显示内容占总内容的比例。
OnValueChanged: 一个回调函数列表, 当滚动条的值发生变化时, 这些函数会被调用。 可以在这里添加脚本中的方法来响应滚动条值的变化。
滚动条的子物体
Scrollbar/Background: 用于表示滚动条的背景。
Scrollbar/Handle Rect: 代表滚动条手柄的矩形, 用户可以通过拖动它来改变滚动条的值。
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using UnityEngine;using UnityEngine.UI;public class ScrollbarExample : MonoBehaviour { public Scrollbar myScrollbar; void Start () { myScrollbar.onValueChanged.AddListener(ScrollbarValueChanged); } void ScrollbarValueChanged (float value ) { Debug.Log("Scrollbar value changed to: " + value ); } }
高级用法
动态调整值: 可以在脚本中动态地调整滚动条的值。
禁用滚动条: 可以禁用滚动条, 使其无法通过用户交互改变值。
自定义外观: 可以通过设置不同的 Sprite 或者改变颜色来自定义滚动条的外观。
与 ScrollRect 结合使用: 滚动条通常与 ScrollRect 组件结合使用, 以实现内容的滚动效果。
滚动视图 UI 滚动视图组件( ScrollView) 是一个重要的用户界面元素, 用于控制一个区域内的内容滚动。 通常与 Panel、 Content Size Fitter、 Layout Group、 Scrollbar 等组件结合使用, 以实现内容的平滑滚动、 自动布局等功能。
创建滚动视图
在 Unity 编辑器的 Hierarchy 视图中, 选择 GameObject > UI > Scroll View 来创建一个新的滚动视图对象。
默认结构: 创建后, Unity 会自动为你创建一个包含 Viewport( 视口) 、 Content( 内容容器) 、 Scrollbar( 滚动条) 等组件的滚动视图对象。
基本概念
Viewport( 视口) : 视口是一个矩形区域, 它决定了用户可以看到的内容部分。
Content( 内容) : 这是实际包含所有要显示的对象的游戏物体。 内容通常比视口大, 因此需要滚动才能看到所有的内容。
Scrollbar( 滚动条) : 滚动条用来控制和指示视口如何在内容上移动。 可以有垂直滚动条、 水平滚动条或两者都有。
Scroll Rect是核心组件, 它定义了如何进行滚动操作。
Scroll Rect: 选择哪个对象作为滚动区域。
Content: 内容容器, 用来放置滚动的对象。
Viewport: 可视窗口。
Scrollbar (Horizontal/Vertical): 分别用于控制水平和垂直方向上的滚动。
Movement Type: 定义了滚动的方式, 可以选择 Unrestricted, Clamped, Elastic, Snap。
Inertia: 如果开启, 则滚动会有惯性效果。
Scroll Sensitivity: 控制滚动的灵敏度。
Scroll Rect Events: 事件触发器, 当滚动发生时可以触发脚本中的方法。
水平布局组件 水平布局组( Horizontal Layout Group) 用于将子物体水平排列。 每个子物体之间的间距是均匀的, 并且可以根据设置自动调整位置。
Type: 布局类型, 这里是 Horizontal。
Child Alignment: 子物体的对齐方式, 可以选择左对齐、 居中或右对齐。
Padding: 布局的边缘填充, 可以设置上下左右四个方向的填充距离。
Spacing: 子物体之间的间距。
垂直布局组件 垂直布局组( Vertical Layout Group) 用于将子物体垂直排列。 每个子物体之间的间距是均匀的, 并且可以根据设置自动调整位置。
Type: 布局类型, 这里是 Vertical。
Child Alignment: 子物体的对齐方式, 可以选择顶对齐、 居中或底对齐。
Padding: 布局的边缘填充, 可以设置上下左右四个方向的填充距离。
Spacing: 子物体之间的间距。
网格布局组件 网格布局组( Grid Layout Group) 用于将子物体按照网格的形式排列。 每个子物体占据网格中的一个单元格, 并且可以根据设置自动调整位置。
Type: 布局类型, 这里是 Grid。
Constraint: 网格的约束类型, 可以选择固定列数( Fixed Column Count) 或固定行数( Fixed Row Count) 。
Constraint Count: 网格的列数或行数, 取决于 Constraint 属性。
Cell Size: 单元格的大小, 可以分别设置宽度和高度。
Padding: 布局的边缘填充, 可以设置上下左右四个方向的填充距离。
Start Axis: 开始轴, 可以选择从左到右( Horizontal) 或从上到下( Vertical) 。
Start Corner: 开始角, 可以选择左上角( Top Left) 、 右上角( Top Right) 、 左下角( Bottom Left) 或右下角( Bottom Right) 。
Child Control Width: 如果勾选, 表示子物体的宽度将受网格单元格宽度的控制。
Child Control Height: 如果勾选, 表示子物体的高度将受网格单元格高度的控制。
自动扩容组件 自动扩容组件( Content Size Fitter) 它可以根据其子物体的大小自动调整自身的大小。 这对于实现滚动视图的自动扩容非常有用, 尤其是在处理不确定数量的 UI 元素时。
Fit on X: 如果勾选, 表示组件将在水平方向上自动调整大小。
Fit on Y: 如果勾选, 表示组件将在垂直方向上自动调整大小。
Preferred Width: 如果 Fit on X 未勾选, 则使用这个宽度值作为组件的首选宽度。
Preferred Height: 如果 Fit on Y 未勾选, 则使用这个高度值作为组件的首选高度。
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;public class ScrollRectExample : MonoBehaviour { public ScrollRect myScrollRect; void Start () { myScrollRect.onValueChanged.AddListener(ScrollRectValueChanged); } void ScrollRectValueChanged (Vector2 value ) { Debug.Log("ScrollRect value changed to: " + value ); } }
输入框 Input Field 组件允许用户输入文本。
基本属性
Text - 这是输入框显示的文本内容。 可以在这里直接输入默认文本或通过脚本来改变其值。
Character Limit - 设置用户可以输入的最大字符数。 如果设置为0, 则没有字符限制。
Input Type - 选择输入类型:
标准 - 普通的文本输入。
数字与小数点 - 只能输入数字和小数点。
整数 - 只能输入整数。
ASCII可打印字符 - 只能输入ASCII可打印字符。
密码 - 输入时会隐藏文本( 通常用于密码) 。
多行 - 允许输入多行文本。
Line Input - 如果输入类型为多行输入, 可以选择单行还是多行输入。
Placeholder - 当输入框为空时显示的提示文本。
Read Only - 设置输入框是否只读。
高级属性
Selection Color - 文本选中时的颜色。
Cursor Color - 文本输入光标的颜色。
Cursor Toggle Rate - 光标闪烁的速度。
Submit On Enter - 是否在按下回车键时提交输入。
事件回调 On Value Submit - 用户提交输入时触发的事件。 可以通过脚本来监听这个事件, 例如点击屏幕外或按Enter键。
下拉框 下拉菜单( Dropdown) 是一个常用的UI组件, 它允许用户从多个选项中选择一个值。
基础设置
Options - 这是下拉列表中的选项列表。 可以在Inspector面板中添加或删除选项。 每个选项都是一个字符串。
Value - 当前选中的选项索引, 从0开始计数。 可以在此处设置默认选项或者通过脚本在运行时修改。
Clear On Deselect - 如果勾选了此选项, 当用户选择了一个新选项后, 将清除之前的选择。
事件回调 On Value Changed - 当选项发生改变时触发的事件。 可以添加事件监听器来响应选项的变化。 这通常用来执行某些操作, 比如更改游戏状态或更新其他UI元素。
创建步骤
创建Canvas - 在Hierarchy视图中创建一个新的Canvas作为UI容器。
添加Dropdown - 在Canvas下创建一个Dropdown对象, 可以通过菜单GameObject > UI > Dropdown来创建。
配置Dropdown - 在Inspector面板中设置Dropdown的属性, 如添加选项等。
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 using UnityEngine;using UnityEngine.UI;public class ExampleScript : MonoBehaviour { public Dropdown dropdown; void Start () { string [] options = dropdown.options; Dropdown.OptionData optionData = new Dropdown.OptionData("New Option" ); dropdown.AddOptions(new List<Dropdown.OptionData>() { optionData }); dropdown.value = 1 ; dropdown.onValueChanged.AddListener(delegate { OnValueChanged(dropdown.value ); }); } void OnValueChanged (int value ) { Debug.Log("Selected option index: " + value ); } }
事件接口 UI系统提供了多种事件处理接口, 以支持各种用户交互方式。 以下是Unity UI系统中常用的事件接口及其用途, 以及每个接口的基本使用示例代码。
IPointerEnterHandler 当鼠标光标进入UI元素时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class PointerEnterExample : MonoBehaviour , IPointerEnterHandler { public void OnPointerEnter (PointerEventData eventData ) { Debug.Log("Pointer Enter detected on " + gameObject.name); } }
IPointerExitHandler 当鼠标光标离开UI元素时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class PointerExitExample : MonoBehaviour , IPointerExitHandler { public void OnPointerExit (PointerEventData eventData ) { Debug.Log("Pointer Exit detected on " + gameObject.name); } }
IPointerDownHandler 当鼠标按钮按下或触摸开始时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class PointerDownExample : MonoBehaviour , IPointerDownHandler { public void OnPointerDown (PointerEventData eventData ) { Debug.Log("Pointer Down detected on " + gameObject.name); } }
IPointerUpHandler 当鼠标按钮释放或触摸结束时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class PointerUpExample : MonoBehaviour , IPointerUpHandler { public void OnPointerUp (PointerEventData eventData ) { Debug.Log("Pointer Up detected on " + gameObject.name); } }
IPointerClickHandler 当用户点击( 按下并释放) UI元素时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class PointerClickExample : MonoBehaviour , IPointerClickHandler { public void OnPointerClick (PointerEventData eventData ) { Debug.Log("Pointer Click detected on " + gameObject.name); } }
IDragHandler 当用户拖拽UI元素时每帧调用。
1 2 3 4 5 6 7 8 9 10 11 using UnityEngine;using UnityEngine.EventSystems;public class DragExample : MonoBehaviour , IDragHandler { public void OnDrag (PointerEventData eventData ) { Vector2 delta = eventData.delta / 100f ; transform.Translate(delta.x, delta.y, 0 ); } }
IBeginDragHandler 当用户开始拖拽UI元素时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class BeginDragExample : MonoBehaviour , IBeginDragHandler { public void OnBeginDrag (PointerEventData eventData ) { Debug.Log("Begin Drag detected on " + gameObject.name); } }
IEndDragHandler 当用户结束拖拽UI元素时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class EndDragExample : MonoBehaviour , IEndDragHandler { public void OnEndDrag (PointerEventData eventData ) { Debug.Log("End Drag detected on " + gameObject.name); } }
当用户滚动鼠标滚轮或触摸屏时调用。
1 2 3 4 5 6 7 8 9 10 11 using UnityEngine;using UnityEngine.EventSystems;public class ScrollExample : MonoBehaviour , IScrollHandler { public void OnScroll (PointerEventData eventData ) { float scrollDelta = eventData.scrollDelta.y; Debug.Log("Scroll detected: " + scrollDelta); } }
ISelectHandler 当UI元素被选中时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class SelectExample : MonoBehaviour , ISelectHandler { public void OnSelect (BaseEventData eventData ) { Debug.Log("Select detected on " + gameObject.name); } }
IDeselectHandler 当UI元素被取消选择时调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class DeselectExample : MonoBehaviour , IDeselectHandler { public void OnDeselect (BaseEventData eventData ) { Debug.Log("Deselect detected on " + gameObject.name); } }
IUpdateSelectedHandler 当UI元素处于选中状态时每帧调用。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class UpdateSelectedExample : MonoBehaviour , IUpdateSelectedHandler { public void OnUpdateSelected (BaseEventData eventData ) { Debug.Log("Update Selected detected on " + gameObject.name); } }
ISubmitHandler 当UI元素被提交时调用( 例如, 通过按下回车键或确认按钮) 。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class SubmitExample : MonoBehaviour , ISubmitHandler { public void OnSubmit (BaseEventData eventData ) { Debug.Log("Submit detected on " + gameObject.name); } }
IInitializePotentialDragHandler 当用户按下鼠标或触摸屏幕但尚未移动时调用, 用于确定是否开始拖拽。
1 2 3 4 5 6 7 8 9 10 using UnityEngine;using UnityEngine.EventSystems;public class InitializePotentialDragExample : MonoBehaviour , IInitializePotentialDragHandler { public void OnInitializePotentialDrag (PointerEventData eventData ) { Debug.Log("Initialize Potential Drag detected on " + gameObject.name); } }
可视化着色器 Shader Graph 是 Unity 编辑器中的一个工具, 它允许开发者通过可视化编程的方式创建着色器。 Shader Graph 在 Unity 2019.1 版本中引入, 并且与传统的 Shader 脚本编写相比, 提供了一种更为直观的方式来构建复杂的渲染效果。
安装和创建
在 Unity 编辑器的菜单栏中选择 Window > Package Manager, 打开 Package Manager 窗口。 在这里你可以看到所有已安装的包, 查找 Shader Graph 是否已经在列。
如果 Shader Graph 没有出现在你的 Package Manager 中, 或者显示为可安装状态, 请点击“ +” 按钮旁边的“ Browse” , 打开 Unity 包管理器的界面, 在搜索框中输入“ Shader Graph” , 找到 Shader Graph 后点击安装。
创建 Shader Graph 文件 Assets > Create > Shader Graph > Builtln > Lit Shader Graph。
导航栏介绍 Blackboard Blackboard 是 Shader Graph 中的一个重要组成部分, 它提供了当前 Shader Graph 的全局变量列表。 这些变量可以在 Shader Graph 中被引用, 并且可以在材质面板中进行编辑。
Graph Inspector Graph Inspector 提供了有关当前 Shader Graph 的详细信息, 包括但不限于 Graph 的类型、 内部结构、 输入和输出端口等。
属性 用途 描述
Material
这里指的是 Shader Graph 本身所关联的材质
在 Unity Shader Graph 中, “ Material” 通常指的是当前 Shader Graph 应用到的材质球。 当你在 Shader Graph 中进行编辑时, 所做的更改会直接影响到关联的材质。 你可以在 Unity 编辑器中选择一个材质球, 并通过右键菜单选择 “ Create > Shader > Shader Graph” 来创建一个新的 Shader Graph, 这个 Shader Graph 将会与当前选定的材质球相关联。
Allow Material Override
这个选项控制着是否允许在运行时对材质进行覆盖。
当勾选了 “ Allow Material Override” 时, 意味着在运行时可以通过脚本来动态地替换当前材质球。 这在某些特定的应用场景下非常有用, 例如在游戏开发中, 可能需要根据游戏的状态动态地改变材质属性, 或者在调试过程中使用不同的材质进行测试。
Surface Type
这个选项决定了 Shader Graph 的渲染模式。
Opaque: 不透明模式, 是最常用的模式, 适用于完全不透明的对象。 Cutout: 剪切模式, 适用于有明确边缘的半透明物体, 如树叶, 只有一部分像素会被渲染。 Fade: 渐变模式, 适用于渐隐渐现的半透明效果, 如烟雾。 Transparent: 透明模式, 适用于一般的透明物体, 如水或玻璃, 渲染顺序会影响最终结果。
Render Face
决定了着色器应用于哪些面。
Front: 仅渲染正面。 Back: 仅渲染背面。 Both: 渲染前后两面。
Depth Write
决定了着色器是否写入深度缓冲区。
如果开启, 则着色器可以更新深度缓冲区; 如果关闭, 则不会更新, 这意味着物体可能会出现穿透现象。
Depth Test
决定了着色器如何与深度缓冲区进行比较。
Always: 总是通过测试。 Equal: 当前像素与深度缓冲区中的值相等时通过测试。 Less: 当前像素小于深度缓冲区中的值时通过测试。 LessEqual: 当前像素小于等于深度缓冲区中的值时通过测试。 Greater: 当前像素大于深度缓冲区中的值时通过测试。 NotEqual: 当前像素与深度缓冲区中的值不等时通过测试。 Never: 从不通过测试。
Alpha Clipping
用于剪切( Clipping) 操作, 通常与 Cutout 模式一起使用。
Alpha Clipping 设置了一个阈值, 当像素的 Alpha 值低于这个阈值时, 该像素将被丢弃。
Fragment Normal Space
决定了法线空间
Tangent: 切线空间。 Object: 对象空间。 World: 世界空间。 Camera: 摄像机空间。
Custom Editor GUI
允许用户自定义 Shader Graph 编辑器的界面元素。
这是一个高级功能, 允许开发者编写自己的 GUI 来扩展 Shader Graph 编辑器的功能。 这通常涉及到脚本编写, 并不是所有用户都会用到。
Main Preview Main Preview 是 Shader Graph 中的一个预览窗口, 它显示了当前 Shader Graph 应用到一个标准几何体( 通常是球体) 上的效果。
节点介绍 Artistic 分类 Artistic 分类下的节点主要用于提供艺术家友好的功能, 使得非程序员也可以轻松地创造各种视觉效果。
⭐⭐ Adjustment 分类 Adjustment 分类下的节点主要用于调整颜色和图像属性, 如混合通道、 调整对比度、 调整色调、 颜色反转、 替换颜色、 调整饱和度和调整白平衡等。 这些节点可以用来增强或修改图像的颜色表现, 从而在着色器中实现更加精细的颜色控制。
Channel Mixer:
功能: 混合颜色通道。
描述: 此节点允许用户调整RGB颜色通道的贡献比例。 可以用来改变颜色的组成, 例如增加红色通道的权重, 减少绿色通道的权重等。
Contrast:
功能: 调整对比度。
描述: 此节点通过增加或减少图像中颜色的对比度来增强或减弱图像的亮度差异。 提高对比度会使暗部更暗, 亮部更亮。
Hue:
功能: 调整色调。
描述: 此节点允许用户调整颜色的色调分量。 色调是指颜色的基本颜色特性, 例如红色、 绿色、 蓝色等。 调整色调可以改变图像的整体颜色偏向。
Invert Colors:
功能: 反转颜色。
描述: 此节点反转输入颜色的每个通道。 可以用来实现类似负片的效果。
Replace Color:
功能: 替换颜色。
描述: 此节点允许用户将一个颜色替换为另一个颜色。 可以用来改变图像中的特定颜色。
Saturation:
功能: 调整饱和度。
描述: 此节点增加或减少颜色的饱和度, 即颜色的纯度。 增加饱和度可以使颜色更加鲜艳, 减少饱和度可以使颜色趋向灰色。
White Balance:
功能: 调整白平衡。
描述: 此节点用于调整图像的白平衡, 即调整红、 绿、 蓝三色的比例, 以改变图像的整体色调。 这通常用于校正光源引起的色彩偏差。
⭐⭐ Blend 分类 Blend 分类下的节点主要用于混合两种或多种颜色或纹理。 这些节点可以帮助你在着色器中实现不同的混合效果, 比如透明度混合、 颜色叠加等。 尽管“ Blend” 分类下的节点可能相对简单, 但它们在处理多层纹理、 透明对象以及其他需要混合技术的场景时非常有用。
⭐⭐ Filter 分类 Filter 分类下的节点主要用于执行图像或颜色过滤操作, 这些操作可以帮助开发者实现诸如抖动( Dithering) 、 渐变过渡( Fade Transition) 等效果。 这些效果可以用来改善图像质量, 或是实现某种视觉效果。
Dither:
功能: 抖动( Dithering) 。
描述: 此节点通过引入细微的噪声来模拟颜色渐变, 以减少因颜色量化导致的伪影。 抖动可以用来减少颜色带状现象, 尤其是在处理透明度渐变或低分辨率图像时。
Fade Transition:
功能: 渐变过渡。
描述: 此节点用于实现两个颜色或图像之间的平滑过渡。 通常用于实现渐隐渐显效果, 或者在两个不同状态之间进行平滑转换。
⭐⭐ Mask 分类 Mask 分类下的节点主要用于创建遮罩, 这些遮罩可以用来选择性地影响某些像素, 以便在渲染过程中应用特定的效果或调整。
Channel Mask:
功能: 通道遮罩。
描述: 此节点允许用户选择特定的颜色通道( R/G/B/A) 作为遮罩, 可以用来提取纹理中的单个颜色通道信息。 例如, 可以用来提取一个纹理中的红色通道信息作为遮罩。
Color Mask:
功能: 颜色遮罩。
描述: 此节点允许用户基于颜色范围来创建遮罩。 可以用来选择图像中特定颜色的区域, 然后对这些区域进行特定的操作。 例如, 可以用来创建一个遮罩来只影响图像中的红色部分。
⭐⭐ Normal 分类 Normal 分类下的节点主要用于处理法线信息, 这些信息对于实现光照、 表面细节、 凹凸效果等非常重要。
Normal Blend:
功能: 法线混合。
描述: 此节点用于混合两个法线信息, 通常用于将多个法线贴图的效果结合起来, 例如在同一个模型上同时应用两个不同细节级别的法线贴图。
Normal From Height:
功能: 从高度图生成法线。
描述: 此节点从一个高度图生成法线信息。 高度图是一种灰度图, 其中每个像素的灰度值表示该点的高度, 通过高度图可以计算出表面的凹凸感。
Normal From Texture:
功能: 从纹理生成法线。
描述: 此节点直接从一个包含法线信息的纹理中读取法线数据。 通常用于应用预先准备好的法线贴图来模拟表面细节。
Normal Reconstruct Z:
功能: 重建Z轴法线。
描述: 此节点用于从一个二维法线向量( 通常存储在法线贴图中) 中重建完整的三维法线向量。 这通常是因为法线贴图只存储了xy分量, 而z分量可以通过xy计算得出。
Normal Strength:
功能: 调整法线强度。
描述: 此节点用于调整法线信息的强度, 可以用来增强或减弱表面细节的表现力。
Normal Unpack:
功能: 解包法线。
描述: 此节点用于将压缩存储的法线信息解包成原始格式。 通常法线信息会以一种压缩的形式存储在纹理中, 这个节点负责将其还原。
⭐⭐ Utility 分类 Utility 分类下的节点主要用于提供一些辅助性的功能, 这些功能可以帮助开发者更好地处理颜色、 空间转换等问题。
Colorspace Conversion:
功能: 颜色空间转换。
描述: 此节点用于在不同的颜色空间之间转换颜色或纹理。 颜色空间是指用于描述颜色的方式, 常见的有sRGB、 Linear、 HSV等。 在处理光照、 合成等场景时, 颜色空间的转换尤为重要。
Channel 分类 Channel 分类下的节点主要用于处理颜色通道, 这些节点可以帮助你合并、 翻转、 拆分和重新排列颜色通道。
Combine:
功能: 合并颜色通道。
描述: 此节点用于将多个颜色通道的信息合并成一个颜色。 例如, 可以将一个纹理的红色通道与另一个纹理的绿色通道合并起来。
Flip:
功能: 翻转颜色通道。
描述: 此节点用于交换颜色通道。 例如, 可以将RGB颜色通道变为GBR。
Split:
功能: 拆分颜色通道。
描述: 此节点用于将一个颜色分解成其各个颜色通道。 例如, 可以从一个颜色中提取出红色、 绿色和蓝色分量。
Swizzle:
功能: 重新排列颜色通道。
描述: 此节点用于根据指定的顺序重新排列颜色通道。 例如, 可以选择一个颜色中的特定通道并按照新的顺序输出。
Custom Render Texture 分类 Custom Render Texture 分类下的节点主要用于处理自定义渲染纹理( Custom Render Texture) 。 这些节点允许你在着色器中访问并操作这些纹理。
Self:
功能: 获取当前渲染纹理。
描述: 此节点用于获取当前正在处理的渲染纹理。 它可以用来访问当前帧的像素数据, 以便进行进一步的处理。
Size:
功能: 获取渲染纹理尺寸。
描述: 此节点用于获取当前渲染纹理的宽度和高度。 可以用来确定纹理的大小, 以便在处理时进行正确的坐标映射或缩放。
Slice Index/Cubemap Face:
功能: 获取切片索引/立方体贴图面。
描述: 此节点用于获取当前渲染纹理的切片索引( 对于体积纹理) 或立方体贴图的当前面。 在处理体积纹理或立方体贴图时, 这个信息非常重要, 因为它指定了正在处理的具体切片或面。
Input 分类下的节点主要用于获取片段着色器的各种输入数据。 这些输入数据可以包括但不限于顶点颜色、 UV坐标、 时间等。
⭐⭐ 2D 分类 2D 分类下的节点主要用于处理2D图像和纹理。
Light Texture:
功能: 处理光照纹理。
描述: 此节点用于获取光照纹理( LightTexture) 的信息, 并将其应用于着色器中, 以实现光照效果。 光照纹理通常包含了光照方向、 颜色等信息, 可以用来模拟光源对物体的影响。
⭐⭐ Basic 分类 Basic 分类下的节点主要用于提供基本的数据类型和常量。
Boolean:
功能: 布尔值。
描述: 此节点用于提供布尔值( true 或 false) , 可以用来控制条件分支或开关。
Color:
功能: 颜色值。
描述: 此节点用于提供一个颜色值, 通常用于设置着色器中的颜色, 如材质的基本颜色( Base Color) 。
Constant:
功能: 常量。
描述: 此节点用于提供一个固定的数值, 可以是任何数据类型( 如浮点数、 整数、 向量等) 。
Float:
功能: 浮点数。
描述: 此节点用于提供一个浮点数值, 常用于控制光照强度、 颜色强度等。
Integer:
功能: 整数。
描述: 此节点用于提供一个整数值, 常用于索引选择或其他需要整数值的场合。
Slider:
功能: 滑块。
描述: 此节点用于提供一个可以通过滑块调节的数值, 方便在编辑器中调整参数。
Time:
功能: 时间。
描述: 此节点用于提供当前游戏时间的信息, 如时间戳、 delta time等, 常用于动画或随时间变化的效果。
Vector 2:
功能: 二维向量。
描述: 此节点用于提供一个二维向量, 常用于纹理坐标UV、 位移等。
Vector 3:
功能: 三维向量。
描述: 此节点用于提供一个三维向量, 常用于表示位置、 方向、 法线等。
Vector 4:
功能: 四维向量。
描述: 此节点用于提供一个四维向量, 常用于表示颜色RGBA、 齐次坐标等。
⭐⭐ Geometry 分类 Geometry 分类下的节点主要用于提供几何信息, 这些信息对于处理光照、 纹理映射和其他基于位置的效果非常重要。
Bitangent Vector:
功能: 双切线向量。
描述: 此节点用于获取双切线向量, 通常用于法线贴图处理, 帮助计算正确的光照效果。
Instance ID:
功能: 实例ID。
描述: 此节点用于获取网格实例的ID, 可以用来区分场景中的多个相同网格实例。
Normal Vector:
功能: 法线向量。
描述: 此节点用于获取表面法线向量, 用于光照计算和其他基于表面方向的效果。
Position:
功能: 位置。
描述: 此节点用于获取顶点的位置, 可以用于计算光照、 阴影等效果。
Screen Position:
功能: 屏幕位置。
描述: 此节点用于获取像素在屏幕上的位置, 可用于实现屏幕空间效果, 如屏幕空间反射或后处理效果。
Tangent Vector:
功能: 切线向量。
描述: 此节点用于获取切线向量, 与双切线向量一起用于法线贴图处理, 帮助正确计算光照。
UV:
功能: 纹理坐标。
描述: 此节点用于获取纹理坐标( UV坐标) , 用于将纹理映射到表面上。
Vertex Color:
功能: 顶点颜色。
描述: 此节点用于获取顶点的颜色信息, 可以用来在顶点级别应用颜色。
Vertex ID:
功能: 顶点ID。
描述: 此节点用于获取顶点的ID, 可以用来区分网格中的不同顶点。
View Direction:
功能: 视图方向。
描述: 此节点用于获取从摄像机到表面点的方向向量, 用于计算光照效果, 如高光。
View Vector:
功能: 视图向量。
描述: 此节点用于获取从摄像机到表面点的向量, 可用于计算光照和反射效果。
⭐⭐ Gradient 分类 Gradient 分类下的节点主要用于处理梯度颜色, 这些节点可以帮助开发者生成和采样颜色梯度, 用于创建平滑的颜色过渡效果。
Blackbody:
功能: 黑体辐射颜色。
描述: 此节点用于生成黑体辐射的颜色梯度, 根据温度值来决定颜色。 黑体辐射模型可以用来模拟光源的颜色变化, 如太阳光或白炽灯。
Gradient:
功能: 颜色梯度。
描述: 此节点用于定义一个颜色梯度, 可以通过设置多个颜色键来创建一个平滑的颜色过渡。 可以用来生成渐变背景、 环境光晕等效果。
Sample Gradient:
功能: 采样颜色梯度。
描述: 此节点用于从一个已经定义好的颜色梯度中采样颜色。 通过提供一个0到1之间的值, 可以获取对应位置的颜色。
⭐⭐ Lighting 分类 Lighting 分类下的节点主要用于处理光照相关的功能, 这些节点可以帮助开发者实现不同的光照效果, 如环境光、 烘焙光、 主光源方向以及反射探针效果。
Ambient:
功能: 环境光。
描述: 此节点用于获取场景中的环境光信息。 环境光是一种全局照明, 即使没有其他光源存在, 环境光也会照亮场景中的物体。
Baked GI:
功能: 烘焙光照。
描述: 此节点用于获取烘焙光照信息。 烘焙光照是在构建场景时预计算的光照信息, 可以用来提高实时渲染的性能。
Main Light Direction:
功能: 主光源方向。
描述: 此节点用于获取主光源的方向信息。 主光源通常是场景中最亮的光源, 如太阳或主要的灯光。
Reflection Probe:
功能: 反射探针。
描述: 此节点用于获取反射探针的信息。 反射探针可以在场景中捕捉环境光和反射效果, 用于实时渲染中模拟物体周围的环境光照。
⭐⭐ Matrix 分类 Matrix 分类下的节点主要用于处理矩阵运算, 这些矩阵可以用来进行坐标变换、 旋转、 缩放等各种操作。
Matrix 2x2:
功能: 2x2 矩阵。
描述: 此节点用于提供一个 2x2 的矩阵, 通常用于处理二维图形的变换, 如旋转和平移。
Matrix 3x3:
功能: 3x3 矩阵。
描述: 此节点用于提供一个 3x3 的矩阵, 通常用于处理三维图形的变换, 如旋转、 缩放和平移。
Matrix 4x4:
功能: 4x4 矩阵。
描述: 此节点用于提供一个 4x4 的矩阵, 通常用于处理三维图形的齐次坐标变换, 可以包含平移、 旋转、 缩放等操作。
Transformation Matrix:
功能: 变换矩阵。
描述: 此节点用于获取变换矩阵, 可以是世界矩阵、 视图矩阵、 投影矩阵等, 用于将坐标从一个空间变换到另一个空间。
Mesh Deformation 分类下的节点主要用于处理网格变形, 这些节点可以帮助开发者实现网格的动态变形效果, 如骨骼绑定、 权重混合等。
Compute Deformation:
功能: 计算变形。
描述: 此节点用于计算网格变形, 通常用于实现高级的网格变形效果。 它可能涉及到复杂的计算过程, 如非线性变形、 基于物理的变形等。
Linear Blend Skinning:
功能: 线性混合蒙皮。
描述: 此节点用于实现骨骼动画中的线性混合蒙皮技术, 即根据骨骼的权重混合多个骨骼的变换来实现网格的变形。
⭐⭐ PBR 分类 PBR( Physically Based Rendering 物理基渲染) 分类下的节点主要用于实现基于物理特性的材质渲染, 这些节点可以帮助开发者实现更真实的材质表现。
Dielectric Specular:
功能: 介电质高光。
描述: 此节点用于计算介电质材料( 如玻璃、 水等) 的高光效果。 介电质材料具有特定的光学特性, 其反射和折射行为不同于金属或哑光表面。 该节点通常用于实现菲涅耳效应( Fresnel effect) , 即随着视角的变化, 反射率发生变化的现象。
Metal Reflectance:
功能: 金属反射率。
描述: 此节点用于计算金属材质的反射率。 金属材质具有较高的反射率, 特别是在某些角度下会表现出强烈的镜面反射效果。 该节点通常用于实现金属材质的真实感, 通过控制金属表面的反射强度来模拟不同金属的外观。
⭐⭐ Scene 分类 Scene 分类下的节点主要用于处理场景中的信息, 这些信息可以用于实现各种特效, 如与摄像机相关的操作、 雾效、 深度信息等。
Camera:
功能: 摄像机信息。
描述: 此节点用于获取当前摄像机的信息, 如摄像机的位置、 方向等。
Eye Index:
功能: 眼睛索引。
描述: 此节点用于获取眼睛索引, 在立体渲染或多视图渲染中很有用, 用于区分左眼和右眼的渲染。
Fog:
功能: 雾效。
描述: 此节点用于获取当前场景中的雾效信息, 可以用来在着色器中实现雾化效果。
Object:
功能: 对象信息。
描述: 此节点用于获取当前对象的信息, 如对象的局部坐标、 世界坐标等。
Scene Color:
功能: 场景颜色。
描述: 此节点用于获取场景的颜色信息, 可以用来在着色器中实现与场景颜色相关的特效。
Scene Depth:
功能: 场景深度。
描述: 此节点用于获取当前像素在场景中的深度信息, 可以用来实现深度相关的特效, 如景深、 屏幕空间反射等。
Scene Depth Difference:
功能: 场景深度差。
描述: 此节点用于获取当前像素与其周围像素的深度差异信息, 可以用来实现边缘检测、 屏幕空间阴影等特效。
Screen:
功能: 屏幕信息。
描述: 此节点用于获取屏幕的信息, 如像素在屏幕上的位置等。
⭐⭐ Texture 分类 Texture 分类下的节点主要用于处理纹理采样和相关操作, 这些节点可以帮助开发者实现不同类型的纹理效果, 如2D纹理、 立方体贴图、 3D纹理、 虚拟纹理等。
Calculate Level Of Detail Texture 2D:
功能: 计算细节级别2D纹理。
描述: 此节点用于根据细节级别( LOD) 计算并返回适当的2D纹理。 适用于需要根据不同细节级别显示不同纹理的情况。
Cubemap Asset:
功能: 立方体贴图资源。
描述: 此节点用于引用一个立方体贴图资源, 可以用来实现环境光照或其他基于立方体贴图的效果。
Gather Texture 2D:
功能: 聚集2D纹理。
描述: 此节点用于从2D纹理中采集多个样本点的数据, 并将结果合并成一个值。 常用于实现屏幕空间反射或抗锯齿等效果。
Sample Cubemap:
功能: 采样立方体贴图。
描述: 此节点用于从立方体贴图中采样颜色信息。 通常用于实现环境光照、 反射等效果。
Sample Reflected Cubemap:
功能: 采样反射立方体贴图。
描述: 此节点用于从立方体贴图中采样反射颜色信息。 通常用于实现反射效果。
Sample Texture 2D:
功能: 采样2D纹理。
描述: 此节点用于从2D纹理中采样颜色信息。 是最常用的纹理采样节点之一。
Sample Texture 2D Array:
功能: 采样2D数组纹理。
描述: 此节点用于从2D数组纹理中采样颜色信息。 适用于需要存储多个2D纹理的情况。
Sample Texture 2D LOD:
功能: 根据细节级别采样2D纹理。
描述: 此节点用于根据细节级别( LOD) 从2D纹理中采样颜色信息。 适用于需要根据不同细节级别显示不同纹理的情况。
Sample Texture 3D:
功能: 采样3D纹理。
描述: 此节点用于从3D纹理中采样颜色信息。 适用于需要在三维空间内存储颜色数据的情况。
Sample Virtual Texture:
功能: 采样虚拟纹理。
描述: 此节点用于从虚拟纹理中采样颜色信息。 虚拟纹理是一种大纹理分割成多个小纹理的技术, 可以减少内存占用。
Sampler State:
功能: 采样器状态。
描述: 此节点用于设置纹理采样的状态, 如过滤模式、 地址模式等。 可以用来优化纹理采样性能。
Split Texture Transform:
功能: 拆分纹理变换。
描述: 此节点用于拆分纹理变换矩阵, 提取出平移、 缩放和旋转等信息。 可以用来单独调整纹理的变换。
Texture 2D Array Asset:
功能: 2D数组纹理资源。
描述: 此节点用于引用一个2D数组纹理资源。 适用于需要存储多个2D纹理的情况。
Texture 2D Asset:
功能: 2D纹理资源。
描述: 此节点用于引用一个2D纹理资源。 是最常用的纹理引用节点之一。
Texture 3D Asset:
功能: 3D纹理资源。
描述: 此节点用于引用一个3D纹理资源。 适用于需要在三维空间内存储颜色数据的情况。
Texture Size:
功能: 纹理尺寸。
描述: 此节点用于获取纹理的尺寸信息。 可以用来根据纹理大小调整其他参数。
⭐⭐ Universal 分类 Universal 分类下的节点主要用于处理通用的着色器功能, 这些功能通常与Unity的通用渲染管线( URP) 相关。
URP Sample Buffer:
功能: 采样URP缓冲区。
描述: 此节点用于从URP的缓冲区中采样数据。 它可以用来获取屏幕空间中的颜色、 深度等信息, 对于实现屏幕空间反射、 景深、 后处理效果等非常有用。
Math 分类 Math 分类下的节点提供了多种数学运算功能, 可以帮助你执行基本的算术运算、 矢量操作、 逻辑判断以及其他复杂的数学计算。
⭐⭐ Advanced 分类 Advanced 分类下的节点主要用于执行更复杂的数学运算, 这对于精确控制着色器中的颜色和光照计算非常重要。
Absolute (Abs):
功能: 计算绝对值。
描述: 此节点将输入值转换为其绝对值, 即如果输入是负数, 则转换为正数。
Exponential (Exp):
功能: 计算指数函数。
描述: 此节点计算e的输入次幂, 其中e是自然对数的底数( 约等于2.71828) 。
Length:
功能: 计算向量长度。
描述: 此节点计算输入向量的欧几里得长度( 即向量的模) 。
Log:
功能: 计算自然对数。
描述: 此节点计算输入值的自然对数, 即以e为底数的对数。
Modulo (Mod):
功能: 求模运算。
描述: 此节点计算输入值除以给定值后的余数, 常用于周期性操作。
Negate:
功能: 取反。
描述: 此节点将输入值乘以-1, 即反转输入值的符号。
Normalize:
功能: 归一化向量。
描述: 此节点将输入向量缩放为单位长度( 长度为1) , 同时保持方向不变。
Posterize:
功能: 减少颜色深度。
描述: 此节点减少输入颜色的位深度, 产生类似海报化的效果, 使得颜色分级更为明显。
Reciprocal:
功能: 求倒数。
描述: 此节点计算输入值的倒数( 1 / 输入值) 。
Reciprocal Square Root:
功能: 计算倒数平方根。
描述: 此节点计算输入值的倒数平方根( 1 / sqrt(输入值)) , 在某些光照模型中用于快速近似归一化。
⭐⭐ Basic 分类 Basic 分类下的节点主要用于执行基本的数学运算, 这些运算在着色器编程中非常常见。
Add:
功能: 执行加法运算。
描述: 此节点将两个输入值相加, 并返回结果。 可以用于合并颜色、 增加亮度等。
Divide:
功能: 执行除法运算。
描述: 此节点将第一个输入值除以第二个输入值, 并返回结果。 可以用于调整亮度、 颜色强度等。
Multiply:
功能: 执行乘法运算。
描述: 此节点将两个输入值相乘, 并返回结果。 可以用于调整颜色强度、 混合颜色等。
Power:
功能: 计算输入值的幂。
描述: 此节点将第一个输入值的每个分量提升到第二个输入值的指数, 并返回结果。 可以用于模拟光照的指数衰减等。
Square Root:
功能: 计算输入值的平方根。
描述: 此节点计算输入值的平方根, 并返回结果。 在光照计算中常用, 也可以用于调整颜色强度。
Subtract:
功能: 执行减法运算。
描述: 此节点将第二个输入值从第一个输入值中减去, 并返回结果。 可以用于颜色对比、 光照减淡等。
⭐⭐ Derivative 分类 Derivative 分类下的节点主要用于计算导数, 即在片段着色器中计算像素值相对于屏幕空间位置的变化率。 这些导数可以用于实现诸如法线贴图、 屏幕空间反射( SSR) 、 边缘检测等多种高级效果。
DDX:
功能: 计算水平方向的导数。
描述: 此节点计算输入值在水平方向( x轴) 上的变化率。 常用于计算法线贴图中的水平细节变化。
DDY:
功能: 计算垂直方向的导数。
描述: 此节点计算输入值在垂直方向( y轴) 上的变化率。 常用于计算法线贴图中的垂直细节变化。
DDXY:
功能: 计算水平和垂直方向的导数。
描述: 此节点同时计算输入值在水平和垂直方向上的变化率。 常用于需要同时考虑两个方向变化的情况, 如屏幕空间反射或边缘检测。
⭐⭐ Interpolation 分类 Interpolation 分类下的节点主要用于执行插值操作, 这些操作对于在不同值之间平滑过渡非常有用。 插值在许多场景中都有应用, 如动画、 渐变颜色、 光照计算等。
Inverse Lerp:
功能: 计算值在两个边界值之间的相对位置。
描述: 此节点计算一个值在两个边界值之间的相对位置。 例如, 给定最小值 a 和最大值 b, 以及一个值 value, 它会返回 value 在 [a, b] 区间内的相对位置。 如果 value 等于 a, 则返回0; 如果 value 等于 b, 则返回1。
Lerp:
功能: 线性插值。
描述: 此节点在线性范围内插值两个值。 它接收三个输入: 起始值 a、 结束值 b 以及一个 t 值( 0到1之间) , 然后返回 a 到 b 之间的线性插值结果。 当 t 为0时, 结果为 a; 当 t 为1时, 结果为 b。
Smoothstep:
功能: 平滑插值。
描述: 此节点执行平滑插值, 使得结果在 [0, 1] 区间内更加平滑。 它接收三个输入: 起始值 a、 结束值 b 以及一个 t 值( 0到1之间) , 然后返回 a 到 b 之间的平滑插值结果。 当 t 为0时, 结果为 a; 当 t 为1时, 结果为 b; 但在 [0, 1] 区间内, 结果将变得更加平滑, 避免了线性插值可能产生的突然变化。
⭐⭐ Matrix 分类 Matrix 分类下的节点主要用于处理矩阵操作, 这些操作在计算变换、 光照、 投影等方面非常有用。
Matrix Construction:
功能: 构建矩阵。
描述: 此节点允许用户通过输入矩阵的行向量来构建一个矩阵。 它可以用于创建任意大小的矩阵, 通常用于构建变换矩阵, 如旋转、 缩放和平移矩阵。
Matrix Determinant:
功能: 计算矩阵的行列式。
描述: 此节点计算输入矩阵的行列式。 行列式是一个标量值, 可以用于判断矩阵是否可逆。 只有方阵才有行列式。
Matrix Split:
功能: 分解矩阵。
描述: 此节点将输入矩阵分解成其组成的行向量。 这对于提取矩阵中的特定信息( 如旋转角度、 缩放因子等) 非常有用。
Matrix Transpose:
功能: 转置矩阵。
描述: 此节点计算输入矩阵的转置。 转置矩阵是指将原矩阵的行变成新矩阵的列, 原矩阵的列变成新矩阵的行。
⭐⭐ Range 分类 Range 分类下的节点主要用于执行范围相关的操作, 如限制值的范围、 映射值到新的范围、 随机生成值等。 这些节点在创建着色器时非常有用, 尤其是在需要确保值处于特定区间或需要生成随机数的情况下。
Clamp:
功能: 限制值的范围。
描述: 此节点将输入值限制在指定的最小值和最大值之间。 如果输入值小于最小值, 则返回最小值; 如果输入值大于最大值, 则返回最大值; 否则返回输入值本身。
Fraction:
功能: 取小数部分。
描述: 此节点返回输入值的小数部分。 例如, 输入值为3.14, 则返回0.14。
Maximum:
功能: 找到最大值。
描述: 此节点接收两个输入值, 并返回两者中的较大值。
Minimum:
功能: 找到最小值。
描述: 此节点接收两个输入值, 并返回两者中的较小值。
One Minus:
功能: 计算1减去输入值的结果。
描述: 此节点接收一个输入值, 并返回1减去该值的结果。 常用于颜色反转等操作。
Random Range:
功能: 生成指定范围内的随机数。
描述: 此节点生成一个介于指定最小值和最大值之间的随机数。 可以用于创建随机效果。
Remap:
功能: 映射值到新的范围。
描述: 此节点将输入值从一个范围映射到另一个范围。 例如, 可以将[0, 1]范围内的值映射到[0, 255]范围。
Saturate:
功能: 饱和( 限制在0到1之间) 。
描述: 此节点将输入值限制在0到1之间。 如果输入值小于0, 则返回0; 如果输入值大于1, 则返回1; 否则返回输入值本身。
⭐⭐ Round 分类 Round 分类下的节点主要用于执行数值的舍入操作, 如向上取整、 向下取整、 四舍五入等。 这些节点在处理需要精确控制数值的场景下非常有用, 特别是在需要确保数值符合特定格式或进行数值简化的情况下。
Ceiling:
功能: 向上取整。
描述: 此节点将输入值向上取整到最接近的整数。 例如, 输入值为3.1, 则返回4。
Floor:
功能: 向下取整。
描述: 此节点将输入值向下取整到最接近的整数。 例如, 输入值为3.9, 则返回3。
Round:
功能: 四舍五入。
描述: 此节点将输入值四舍五入到最接近的整数。 例如, 输入值为3.5, 则返回4。
Sign:
功能: 获取符号。
描述: 此节点返回输入值的符号。 如果输入值为正数, 则返回1; 如果输入值为零, 则返回0; 如果输入值为负数, 则返回-1。
Step:
功能: 阶跃函数。
描述: 此节点接收两个输入值, 如果第一个输入值小于等于第二个输入值, 则返回1; 否则返回0。 常用于将连续值转换为二进制信号。
Truncate:
功能: 截断。
描述: 此节点将输入值截断为整数部分, 去除小数部分。 例如, 输入值为3.7, 则返回3。
⭐⭐ Trigonometry 分类 Trigonometry 分类下的节点主要用于执行三角函数操作, 这些操作在处理与角度、 旋转相关的问题时非常有用。 三角函数可以用于多种用途, 如计算光照方向、 旋转物体、 生成波形等。
Arccosine (ACos):
功能: 计算反余弦函数。
描述: 此节点计算输入值的反余弦值, 即返回一个角度θ, 使得cos(θ) = 输入值。 结果通常在 [0, π] 范围内。
Arcsine (ASin):
功能: 计算反正弦函数。
描述: 此节点计算输入值的反正弦值, 即返回一个角度θ, 使得sin(θ) = 输入值。 结果通常在 [-π/2, π/2] 范围内。
Arctangent (ATan):
功能: 计算反正切函数。
描述: 此节点计算输入值的反正切值, 即返回一个角度θ, 使得tan(θ) = 输入值。 结果通常在 [-π/2, π/2] 范围内。
Arctangent2 (ATan2):
功能: 计算两数的反正切函数。
描述: 此节点计算两个输入值 y 和 x 的反正切值, 即返回一个角度θ, 使得tan(θ) = y/x。 结果通常在 [-π, π] 范围内, 并且能正确区分象限。
Cosine (Cos):
功能: 计算余弦函数。
描述: 此节点计算输入角度的余弦值。 输入可以是弧度或度数, 具体取决于上下文。
Degrees To Radians (DegToRad):
功能: 将角度从度转换为弧度。
描述: 此节点将输入的角度值从度转换为弧度。 通常用于将角度值转换为适合三角函数使用的弧度形式。
Hyperbolic Cosine (Cosh):
功能: 计算双曲余弦函数。
描述: 此节点计算输入值的双曲余弦值, 即cosh(x) = (exp(x) + exp(-x)) / 2。
Hyperbolic Sine (Sinh):
功能: 计算双曲正弦函数。
描述: 此节点计算输入值的双曲正弦值, 即sinh(x) = (exp(x) - exp(-x)) / 2。
Hyperbolic Tangent (Tanh):
功能: 计算双曲正切函数。
描述: 此节点计算输入值的双曲正切值, 即tanh(x) = sinh(x) / cosh(x)。
Radians To Degrees (RadToDeg):
功能: 将角度从弧度转换为度。
描述: 此节点将输入的角度值从弧度转换为度。 通常用于将三角函数的结果转换为易于理解的度数形式。
Sine (Sin):
功能: 计算正弦函数。
描述: 此节点计算输入角度的正弦值。 输入可以是弧度或度数, 具体取决于上下文。
Tangent (Tan):
功能: 计算正切函数。
描述: 此节点计算输入角度的正切值。 输入可以是弧度或度数, 具体取决于上下文。
⭐⭐ Vector 分类 Vector 分类下的节点主要用于执行向量操作, 这些操作在处理光照、 反射、 折射、 旋转等场景中非常有用。
Cross Product (Cross):
功能: 计算向量叉积。
描述: 此节点计算两个三维向量的叉积, 得到的结果是一个新的三维向量, 该向量垂直于输入的两个向量。
Distance:
功能: 计算两点之间的距离。
描述: 此节点计算两个点之间的欧几里得距离。
Dot Product (Dot):
功能: 计算向量点积。
描述: 此节点计算两个向量的点积, 结果是一个标量值, 表示两个向量的方向关系。
Fresnel Effect:
功能: 计算菲涅耳效应。
描述: 此节点计算菲涅耳效应, 用于模拟材料边缘的高光效果, 常用于水、 金属等材质。
Projection:
功能: 计算向量投影。
描述: 此节点计算一个向量在另一个向量上的投影。
Reflection:
功能: 计算反射向量。
描述: 此节点计算一个向量关于平面的反射向量, 常用于模拟光线反射。
Refract:
功能: 计算折射向量。
描述: 此节点计算一个向量经过介质界面时的折射向量, 常用于模拟透明材质的折射效果。
Rejection:
功能: 计算向量拒斥。
描述: 此节点计算一个向量在另一个向量方向上的拒斥向量, 即垂直于投影的部分。
Rotate About Axis:
功能: 绕轴旋转向量。
描述: 此节点计算一个向量绕指定轴旋转一定角度后的结果向量。
Sphere Mask:
功能: 生成球形遮罩。
描述: 此节点生成一个球形遮罩, 可以根据输入的位置和半径来确定遮罩区域。
Transform:
功能: 变换向量。
描述: 此节点用于变换向量, 支持多种变换模式, 如从世界空间到视图空间、 从局部空间到世界空间等。
⭐⭐ Wave 分类 Wave 分类下的节点主要用于生成不同类型的波形, 这些波形可以用来模拟各种自然现象, 如水波、 风声、 音频信号等。
Noise Sine Wave:
功能: 生成带有噪声的正弦波。
描述: 此节点生成一个正弦波形, 并在其基础上添加随机噪声, 使其看起来更加自然和不规则。
Sawtooth Wave:
功能: 生成锯齿波。
描述: 此节点生成一个锯齿波形, 波形的上升沿是斜线, 下降沿是直线。
Square Wave:
功能: 生成方波。
描述: 此节点生成一个方波形, 波形在两个电平之间切换, 上升沿和下降沿是垂直的。
Triangle Wave:
功能: 生成三角波。
描述: 此节点生成一个三角波形, 波形的上升沿和下降沿都是斜线, 形成一个三角形。
Procedural 分类 Procedural 分类下的节点主要用于生成基于算法的图案和效果, 而不依赖于外部纹理。 这些节点可以帮助你在着色器中创建各种程序化的图案, 从而实现复杂的视觉效果。 这些节点可以用于创建各种程序化的图案和效果, 如噪声、 条纹、 圆环等。
Checkerboard:
功能: 生成棋盘格图案。
描述: 此节点生成一个黑白相间的棋盘格图案。 可以通过调整UV坐标来改变棋盘格的大小和位置。
⭐⭐ Noise 分类 Noise 分类下的节点主要用于生成噪声图案。
Gradient Noise:
功能: 生成梯度噪声。
描述: 此节点生成一种基于梯度的噪声图案, 通常用于创建更加平滑的过渡效果。 梯度噪声在模拟自然现象( 如云朵、 地形等) 时非常有用。
Simple Noise:
功能: 生成基本的噪声图案。
描述: 此节点生成一种基本的噪声图案, 通常用于模拟粗糙表面或创建随机效果。
Voronoi:
功能: 生成Voronoi图案。
描述: 此节点生成基于Voronoi图的图案, 通常用于模拟蜂窝结构或创建具有几何美感的效果。
⭐⭐ Shape 分类 Shape 分类下的节点则用于生成各种几何形状。
Ellipse:
功能: 生成椭圆形状。
描述: 此节点生成一个椭圆形状, 可以通过调整UV坐标来改变椭圆的大小和位置。 适用于创建圆形或椭圆形的图案。
Polygon:
功能: 生成多边形形状。
描述: 此节点生成一个多边形形状, 可以通过调整UV坐标来改变多边形的大小和位置。 适用于创建各种多边形图案。
Rectangle:
功能: 生成矩形形状。
描述: 此节点生成一个矩形形状, 可以通过调整UV坐标来改变矩形的大小和位置。 适用于创建矩形图案。
Rounded Polygon:
功能: 生成带圆角的多边形形状。
描述: 此节点生成一个带圆角的多边形形状, 可以通过调整UV坐标来改变多边形的大小和位置。 适用于创建带有圆角的多边形图案。
Rounded Rectangle:
功能: 生成带圆角的矩形形状。
描述: 此节点生成一个带圆角的矩形形状, 可以通过调整UV坐标来改变矩形的大小和位置。 适用于创建带有圆角的矩形图案。
SpeedTree 分类 SpeedTree 是一款专为游戏开发、 电影制作和可视化行业设计的专业级树木建模软件。 它允许用户创建逼真的树木模型, 并提供了丰富的工具集来定制树木的每一个方面。 SpeedTree 不仅可以用来创建单个树木模型, 还可以用来生成整个森林或者复杂的植被系统。
SpeedTree8Billboard:
功能: 获取SpeedTree树叶的Billboard信息。
描述: 此节点返回SpeedTree树叶的Billboard信息, 用于在远距离观察时模拟树叶。 Billboard技术可以使树叶在远距离看起来更加密集, 减少绘制调用的数量。
SpeedTree8ColorAlpha:
功能: 获取SpeedTree树叶的颜色和Alpha信息。
描述: 此节点返回SpeedTree树叶的颜色和Alpha值, 通常用于在着色器中进行颜色混合或其他颜色处理。 Alpha值可以用来实现透明效果。
SpeedTree8InterpolatedNormals:
功能: 获取SpeedTree树叶的插值法线信息。
描述: 此节点返回SpeedTree树叶的插值法线信息, 用于模拟树叶表面的细节。 插值法线可以提高光照计算的真实感。
SpeedTree8Wind:
功能: 获取SpeedTree树叶的风效信息。
描述: 此节点返回SpeedTree树叶受风影响的状态, 用于模拟风对树叶的影响。 可以用来创建动态的树叶效果。
Utility 分类 Utility 分类下的节点主要用于提供各种实用工具, 这些工具可以帮助你进行颜色空间转换、 数据夹紧、 取模运算等操作。 这些节点通常在构建复杂着色器时起到辅助作用。
Custom Function:
功能: 允许用户编写自定义的GLSL/HLSL代码。
描述: 此节点允许用户直接在Shader Graph中编写自定义的着色器代码片段。 这可以用来实现Shader Graph中尚未提供的功能或进行更复杂的计算。
Preview:
功能: 提供Shader Graph的实时预览。
描述: 此节点用于实时预览当前Shader Graph的效果, 可以在编辑过程中即时查看着色器的变化。
⭐⭐ Logic 分类 Logic 分类下的节点主要用于执行逻辑运算和条件判断。 这些节点可以帮助你在着色器中实现复杂的条件分支逻辑, 如根据某些条件选择不同的颜色或纹理, 或者执行逻辑运算来控制着色器的行为。
All:
功能: 检查所有输入是否都为真。
描述: 此节点接收多个布尔输入, 并返回一个布尔值, 表示所有输入是否都为真。 如果所有输入都是真, 则返回真; 否则返回假。
And:
功能: 执行逻辑与运算。
描述: 此节点接收两个布尔输入, 并返回一个布尔值, 表示两个输入是否都为真。 如果两个输入都是真, 则返回真; 否则返回假。
Any:
功能: 检查是否有任一输入为真。
描述: 此节点接收多个布尔输入, 并返回一个布尔值, 表示是否有任一输入为真。 如果有任一输入为真, 则返回真; 否则返回假。
Branch:
功能: 实现条件分支。
描述: 此节点根据输入的条件选择执行不同的路径。 它通常用于根据条件选择不同的颜色或纹理。
Comparison:
功能: 执行数值比较。
描述: 此节点接收两个数值输入, 并根据选择的操作符( 如等于、 大于、 小于等) 返回一个布尔值。
Is Front Face:
功能: 检查片段是否在面向摄像机的一侧。
描述: 此节点返回一个布尔值, 表示片段是否位于面向摄像机的一侧。 这对于双面渲染或实现某些特殊效果非常有用。
Is Infinite:
功能: 检查输入值是否为无穷大。
描述: 此节点接收一个数值输入, 并返回一个布尔值, 表示输入值是否为无穷大( +∞ 或 -∞) 。
Is NaN:
功能: 检查输入值是否为NaN( 非数字) 。
描述: 此节点接收一个数值输入, 并返回一个布尔值, 表示输入值是否为NaN。
Nand:
功能: 执行逻辑非与运算。
描述: 此节点接收两个布尔输入, 并返回一个布尔值, 表示两个输入是否都不为真。 如果两个输入都是真, 则返回假; 否则返回真。
Not:
功能: 执行逻辑非运算。
描述: 此节点接收一个布尔输入, 并返回一个布尔值, 表示输入的逻辑非。 如果输入为真, 则返回假; 如果输入为假, 则返回真。
Or:
功能: 执行逻辑或运算。
描述: 此节点接收两个布尔输入, 并返回一个布尔值, 表示两个输入中至少有一个为真。 如果两个输入中至少有一个为真, 则返回真; 否则返回假。
UV 分类 UV 分类下的节点主要用于处理UV坐标, 这些坐标用于从纹理中采样颜色或其他信息。 UV坐标指的是纹理坐标, 用于定位纹理中的像素。
Flipbook:
功能: 用于创建翻页书( Flipbook) 效果。
描述: 此节点可以将UV坐标映射到一个更大的纹理区域, 使得每个片段可以采样不同的子纹理, 通常用于动画序列。
Parallax Mapping:
功能: 实现视差贴图效果。
描述: 此节点通过调整UV坐标来模拟深度, 增强表面细节的真实感。 视差贴图通常用于模拟地形或具有深度变化的表面。
Parallax Occlusion Mapping (POM):
功能: 实现视差遮挡贴图效果。
描述: 此节点不仅调整UV坐标来模拟深度, 还考虑了遮挡效果, 可以更真实地模拟凸起或凹陷的表面细节。
Polar Coordinates:
功能: 将UV坐标转换为极坐标系。
描述: 此节点将标准UV坐标转换为极坐标系, 用于创建圆形或旋转对称的纹理效果。
Radial Shear:
功能: 创建径向扭曲效果。
描述: 此节点通过调整UV坐标来创建径向拉伸或挤压的效果, 适用于创建漩涡或放射状的纹理效果。
Rotate:
功能: 旋转UV坐标。
描述: 此节点允许你旋转UV坐标, 从而改变纹理的方向。 这对于调整纹理的方向非常有用。
Spherize:
功能: 将UV坐标映射到球面上。
描述: 此节点将UV坐标映射到一个球面上, 通常用于创建球形或球面投影的纹理效果。
Tiling And Offset:
功能: 控制UV坐标的平铺和偏移。
描述: 此节点允许你调整UV坐标的平铺( 重复次数) 和偏移( 起始位置) 。 这可以用来控制纹理在物体表面上的重复次数和初始位置。
Triplanar:
功能: 实现三平面映射效果。
描述: 此节点在三维空间中使用三个平面映射来避免UV接缝问题, 适用于没有UV贴图的复杂几何体, 如岩石或不规则形状的物体。
Twirl:
功能: 创建旋涡效果。
描述: 此节点通过调整UV坐标来创建旋涡效果, 适用于创建旋涡状的纹理或动画效果。
网络通信 Socket 在网络编程中, Socket 是一种通信模型, 允许程序之间通过网络进行双向数据交换。 在 Unity 中使用 Socket 可以实现客户端与服务器之间的通信, 这对于多人在线游戏尤为重要。 Unity 可以利用 C# 的 Socket 类来进行 TCP 或 UDP 的通信。
基本概念
Socket: 在计算机网络中, Socket 是一对端点之间的通信链路两端之一, 用于在网络中进行消息传递。 Socket 可以是 TCP( 传输控制协议) 或 UDP( 用户数据报协议) 。
TCP (Transmission Control Protocol): 是一种面向连接的、 可靠的、 基于字节流的传输层通信协议。
UDP (User Datagram Protocol): 是一种无连接的协议, 它发送数据之前不需要建立连接, 因此也就不需要维护连接状态。
实现步骤
初始化客户端/服务器: 设置端口号并准备接收数据。
接收数据: 使用 BeginReceive 方法启动异步接收流程, 当数据到达时, 会调用 ReceiveCallback 方法处理数据。
处理数据: 解析接收到的数据, 并打印出来, 然后向客户端回应。
发送数据: 客户端构造要发送的数据, 并将其发送到指定的服务器地址。
关闭客户端/服务器: 在应用退出时关闭客户端或服务器, 释放资源。
TCP 示例 💗💗 TCP 服务器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 using UnityEngine;using System.Net.Sockets;using System.Net;using System.Threading;public class TCPServer : MonoBehaviour { private Socket serverSocket; private bool isListening = false ; void Start () { serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.TCP); int port = 8888 ; IPEndPoint serverEP = new IPEndPoint(IPAddress.Any, port); serverSocket.Bind(serverEP); serverSocket.Listen(5 ); Debug.Log("Server listening on port " + port); ListenForClients(); } private void ListenForClients () { if (!isListening) { isListening = true ; serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket); } } private void AcceptCallback (IAsyncResult ar ) { try { Socket clientSocket = serverSocket.EndAccept(ar); Debug.Log("Client connected." ); ReceiveData(clientSocket); ListenForClients(); } catch (Exception e) { Debug.LogError("Error accepting client connection: " + e.Message); } } private void ReceiveData (Socket clientSocket ) { byte [] buffer = new byte [1024 ]; clientSocket.BeginReceive(buffer, 0 , buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), clientSocket); } private void ReceiveCallback (IAsyncResult ar ) { try { Socket clientSocket = ar.AsyncState as Socket; int bytesRead = clientSocket.EndReceive(ar); string message = System.Text.Encoding.ASCII.GetString(buffer, 0 , bytesRead); Debug.Log("Received message: " + message); SendData(clientSocket, message); } catch (Exception e) { Debug.LogError("Error receiving data: " + e.Message); } } private void SendData (Socket clientSocket, string message ) { byte [] buffer = System.Text.Encoding.ASCII.GetBytes(message); clientSocket.BeginSend(buffer, 0 , buffer.Length, SocketFlags.None, new AsyncCallback(SendCallback), clientSocket); } private void SendCallback (IAsyncResult ar ) { try { Socket clientSocket = ar.AsyncState as Socket; int sent = clientSocket.EndSend(ar); Debug.Log("Sent " + sent + " bytes to client." ); } catch (Exception e) { Debug.LogError("Error sending data: " + e.Message); } } }
💗💗 TCP 客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 using UnityEngine;using System.Net.Sockets;using System.Net;using System.Threading;public class TCPClient : MonoBehaviour { private Socket clientSocket; void Start () { ConnectToServer(); } private void ConnectToServer () { clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.TCP); IPAddress ipAddress = IPAddress.Parse("127.0.0.1" ); int port = 8888 ; IPEndPoint serverEP = new IPEndPoint(ipAddress, port); clientSocket.BeginConnect(serverEP, new AsyncCallback(ConnectCallback), clientSocket); } private void ConnectCallback (IAsyncResult ar ) { try { clientSocket.EndConnect(ar); Debug.Log("Connected to server." ); SendMessage("Hello from client!" ); } catch (Exception e) { Debug.LogError("Error connecting to server: " + e.Message); } } private void SendMessage (string message ) { byte [] buffer = System.Text.Encoding.ASCII.GetBytes(message); clientSocket.Send(buffer); Debug.Log("Message sent to server: " + message); } }
UDP 示例 💗💗 UDP 服务器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 using UnityEngine;using System.Net.Sockets;using System.Net;using System;public class UDPServer : MonoBehaviour { private UdpClient udpServer; private IPEndPoint remoteEP; void Start () { InitializeServer(); } private void InitializeServer () { int port = 8888 ; udpServer = new UdpClient(port); remoteEP = new IPEndPoint(IPAddress.Any, 0 ); BeginReceive(); } private void BeginReceive () { udpServer.BeginReceive(new AsyncCallback(ReceiveCallback), udpServer); } private void ReceiveCallback (IAsyncResult ar ) { try { UdpClient client = ar.AsyncState as UdpClient; byte [] data = client.EndReceive(ar, ref remoteEP); string message = System.Text.Encoding.ASCII.GetString(data); Debug.Log("Received message: " + message + " from " + remoteEP.Address.ToString()); RespondToClient(message); } catch (Exception e) { Debug.LogError("Error receiving data: " + e.Message); } finally { BeginReceive(); } } private void RespondToClient (string message ) { byte [] response = System.Text.Encoding.ASCII.GetBytes("Echo: " + message); udpServer.Send(response, response.Length, remoteEP); Debug.Log("Responded to client." ); } void OnApplicationQuit () { udpServer.Close(); } }
💗💗 UDP 客户端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 using UnityEngine;using System.Net.Sockets;using System.Net;using System;public class UDPClient : MonoBehaviour { private UdpClient udpClient; private IPEndPoint serverEP; void Start () { InitializeClient(); } private void InitializeClient () { udpClient = new UdpClient(); IPAddress ipAddress = IPAddress.Parse("127.0.0.1" ); int port = 8888 ; serverEP = new IPEndPoint(ipAddress, port); SendMessage("Hello from client!" ); } private void SendMessage (string message ) { byte [] data = System.Text.Encoding.ASCII.GetBytes(message); udpClient.Send(data, data.Length, serverEP); Debug.Log("Sent message: " + message); } void OnApplicationQuit () { udpClient.Close(); } }
UnityWebRequest UnityWebRequest 是 Unity 引擎中的一个类, 用于处理所有类型的 Web 请求。 它是一个非常灵活的工具, 可以用来从互联网上下载数据, 无论是文本、 二进制文件还是其他类型的数据。 这个类是异步操作的, 因此非常适合用来处理那些可能会花费一些时间的任务, 比如从服务器下载数据。
基本用法 1 var request = new UnityWebRequest("http://example.com/api/v1/data" , "GET" );
上传数据 1 2 3 4 5 6 var handler = new UploadHandlerBuffer(System.Text.Encoding.UTF8.GetBytes("key1=value1&key2=value2" ));var request = new UnityWebRequest("http://example.com/api/v1/upload" , "POST" , handler);request.disposeUploadHandlerOnDispose = true ;
下载数据 1 2 3 4 5 6 var handler = new DownloadHandlerBuffer();var request = new UnityWebRequest("http://example.com/api/v1/data" , "GET" , handler);request.disposeDownloadHandlerOnDispose = true ;
设置请求头 1 request.SetRequestHeader("Content-Type" , "application/json" );
设置请求体 1 request.SetBody(System.Text.Encoding.UTF8.GetBytes("{ \"key\": \"value\" }" ));
请求超时时间
请求是否完成 1 while (!request.isDone) { }
HTTP 响应码 1 2 yield return request.SendWebRequest();Debug.Log(request.responseCode);
请求失败 1 2 3 4 5 6 yield return request.SendWebRequest();if (request.isNetworkError || request.isHttpError){ Debug.LogError(request.error); }
发送请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 IEnumerator Start () { var request = UnityWebRequest.Get("http://example.com/api/v1/data" ); yield return request.SendWebRequest(); if (request.isNetworkError || request.isHttpError) { Debug.LogError(request.error); } else { var result = request.downloadHandler.text; Debug.Log(result); } }
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 using UnityEngine;using System.Collections;using System.Collections.Generic;using System.Text;public class WebRequestExample : MonoBehaviour { private const string API_URL = "http://example.com/api/v1/data" ; private const string IMAGE_URL = "http://example.com/images/example.png" ; void Start () { StartCoroutine(GetDataFromAPI()); StartCoroutine(DownloadImage()); } IEnumerator GetDataFromAPI () { var request = UnityWebRequest.Get(API_URL); request.timeout = 5000 ; yield return request.SendWebRequest(); if (request.isNetworkError || request.isHttpError) { Debug.LogError(request.error); } else { var result = request.downloadHandler.text; Debug.Log("Received JSON data: " + result); } request.Dispose(); } IEnumerator PostDataToAPI () { var jsonData = "{ \"key\": \"value\" }" ; var bodyRaw = Encoding.UTF8.GetBytes(jsonData); var request = UnityWebRequest.Post(API_URL, "POST" ); request.uploadHandler = new UploadHandlerRaw(bodyRaw); request.downloadHandler = new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type" , "application/json" ); yield return request.SendWebRequest(); if (request.isNetworkError || request.isHttpError) { Debug.LogError(request.error); } else { var result = request.downloadHandler.text; Debug.Log("Received JSON data: " + result); } request.Dispose(); } IEnumerator DownloadImage () { var request = UnityWebRequestTexture.GetTexture(IMAGE_URL); request.timeout = 5000 ; yield return request.SendWebRequest(); if (request.isNetworkError || request.isHttpError) { Debug.LogError(request.error); } else { Texture2D texture = ((DownloadHandlerTexture)request.downloadHandler).texture; Debug.Log("Received image texture." ); byte [] bytes = texture.EncodeToPNG(); System.IO.File.WriteAllBytes(Application.persistentDataPath + "/image.png" , bytes); Debug.Log("Image saved to: " + Application.persistentDataPath + "/image.png" ); } request.Dispose(); } }
Unity Multiplayer Unity Multiplayer( 之前称为UNET, 即Unity Networking) 是Unity提供的一套用于开发多人游戏的工具集和技术框架。 它旨在简化多人游戏的开发流程, 使得开发者能够更容易地创建联网游戏。 Unity Multiplayer 支持多种网络模式, 包括客户端-服务器模式、 点对点模式等, 并提供了一系列工具和服务来帮助开发者构建高性能的多人游戏。
Unity Multiplayer 是一个强大的工具集, 可以帮助开发者快速搭建多人游戏的基础结构。 它不仅提供了基础的网络通信功能, 还包含了高级特性, 如客户端预测、 状态同步等, 以提高游戏性能和用户体验。 通过使用Unity Multiplayer, 开发者可以专注于游戏逻辑的实现, 而不必从头开始解决复杂的网络问题。
主要特性
网络传输层: 提供了基础的网络传输能力, 包括UDP和TCP的支持。
网络身份认证: 通过NetworkIdentity组件来标记哪些游戏对象需要在网络中同步。
同步变量( SyncVars) : 允许同步游戏对象的状态, 如位置、 旋转等。
远程过程调用( RPCs) : 允许客户端向服务器请求执行某些操作, 也可以让服务器向所有客户端广播消息。
命令( Commands/Cmds) : 客户端发送请求到服务器, 服务器验证后执行相应的命令。
事件( Events/Evts) : 服务器向所有客户端广播发生的事件。
客户端预测( Client Prediction) : 客户端提前预测动作结果, 以减少网络延迟带来的影响。
状态同步( State Synchronization) : 定期同步游戏状态, 确保客户端与服务器状态一致。
网络管理器( NetworkManager) : 管理网络会话, 如启动服务器、 连接客户端等。
主要组件
NetworkManager: 用于管理和控制网络会话。
NetworkIdentity: 标记需要进行网络同步的游戏对象。
NetworkTransform: 同步物体的位置、 旋转和缩放。
NetworkAnimator: 同步动画状态。
NetworkBehavior: 提供网络同步的基本行为。
NetworkClient: 表示客户端逻辑。
NetworkServer: 表示服务器逻辑。
API 和脚本
NetworkTransport: 用于发送和接收网络数据。
NetworkSettings: 网络配置选项。
NetworkConnection: 表示网络连接。
NetworkReader 和 NetworkWriter: 用于序列化和反序列化数据。
NetworkServer 和 NetworkClient: 提供服务端和客户端的API。
NetworkIdentity: 用于管理网络对象的身份。
RPC( Remote Procedure Calls) : 用于远程调用方法。
工具和服务 除了基本的网络组件外, Unity Multiplayer 还提供了一些工具和服务来帮助开发者构建完整的多人游戏:
Unity Relay: 一种服务, 用于帮助客户端通过NAT( 网络地址转换) 建立连接。
Unity Matchmaking: 用于管理玩家匹配的服务。
Unity Dashboard: 用于监控和管理Unity Multiplayer服务的Web界面。
开发流程
设计网络架构: 确定游戏的网络模式( 如客户端-服务器、 P2P等) 。
设置NetworkManager: 配置NetworkManager组件以管理网络会话。
添加网络组件: 为需要同步的游戏对象添加NetworkIdentity和其他相关组件。
实现网络逻辑: 使用Unity Multiplayer提供的API编写客户端和服务器端的逻辑。
测试网络功能: 使用Unity编辑器或专用工具测试网络功能的正确性和性能。
部署游戏: 使用Unity提供的工具和服务来部署和管理多人游戏。
Multiplayer Sample Framework Unity 的 Multiplayer Sample Framework( 也称为 MSF) 是一个示例项目集合, 旨在展示如何构建多人游戏的各种网络模式和技术。 它包括了多种不同的网络模式的示例代码, 如权威服务器模式( Authoritative Server) 、 客户端预测( Client Prediction) 、 状态同步( State Synchronization) 等。 这些示例旨在帮助开发者理解如何构建和优化多人游戏的网络架构。
Multiplayer Sample Framework 是一个非常有价值的资源, 对于希望深入理解 Unity 多人游戏开发的开发者来说, 它是不可或缺的学习工具。 通过研究这些示例, 开发者可以获得对网络同步、 延迟补偿、 预测以及其他多玩家游戏关键技术的深刻理解。
主要特性
权威服务器模式: 在这种模式下, 所有的游戏逻辑都在服务器上运行, 客户端只负责渲染和输入。 这种模式有助于防止作弊, 因为所有的关键决策都在服务器上做出。
客户端预测: 这是一种技术, 它允许客户端预测其命令的结果, 从而减少延迟感。 当服务器确认这些预测时, 如果有必要, 客户端将修正任何差异。
状态同步: 这是一种同步机制, 其中游戏状态周期性地从服务器发送到客户端, 以确保客户端的状态与服务器保持一致。
断开连接处理: 处理客户端断开连接的情况, 包括重新连接和断线后的游戏状态恢复。
性能优化: 提供有关如何减少网络带宽使用和提高网络效率的技术。
示例项目 要使用Multiplayer Sample Framework, 你可以从Unity的官方资源库下载相关的示例项目。 通常这些示例可以通过Unity Asset Store获得, 或者在Unity的GitHub存储库中找到。
SimpleFPS: 一个简单的第一人称射击游戏示例, 展示了基础的网络同步和输入处理。
CharacterControllerFPS: 类似于SimpleFPS, 但使用了CharacterController而不是Rigidbody。
ClientPredictionFPS: 演示客户端预测技术的应用。
StateSynchronizationFPS: 演示如何使用状态同步来同步游戏状态。
Other examples: 可能还包括其他示例, 如多人赛车游戏、 合作游戏等, 每个示例都针对特定的网络挑战提出了解决方案。
项目部署 Unity 是一个非常流行的跨平台游戏开发引擎, 支持多种平台的项目打包与部署。
部署流程 💗💗 打包前的准备
测试: 确保游戏在编辑器中运行无误, 并且所有功能都按预期工作。
优化: 检查游戏性能, 如帧率、 内存使用等, 并进行必要的优化。
资源清理: 删除不再需要的资源文件, 减少最终包体大小。
依赖检查: 确认所有外部插件和资源都已经正确导入并兼容。
权限设置: 根据目标平台的要求, 设置好应用所需的权限。
💗💗 构建设置 进入 Unity 编辑器中的 File > Build Settings 或者使用快捷键 Ctrl+Shift+B( Windows) / Cmd+Shift+B( Mac) 打开构建设置窗口。 在此处你可以选择目标平台, 并决定是否包含开发调试信息等。
💗💗 配置玩家设置 对于不同平台, 你还需要配置对应的 Player Settings。 这可以通过 Edit > Project Settings > Player 访问。 这里可以设置应用程序名称、 图标、 公司名称等基本信息, 还可以选择分辨率、 目标设备等高级选项。
💗💗 创建构建 选择好目标平台后, 点击 Build 或 Build and Run 按钮来创建一个可执行版本的项目。 如果你选择的是 Build and Run, Unity 将会直接在连接的目标设备上运行你的游戏。
💗💗 对于不同平台的具体步骤
Android:
确保安装了 Android SDK 和 JDK。
在 Build Settings 中选择 Android 平台。
可以选择生成 .apk 文件或者使用 Gradle 构建系统。
如果需要上传到 Google Play 商店, 还需要对 .apk 进行签名。
iOS:
安装 Xcode 和 iOS 开发工具。
在 Build Settings 中选择 iOS 平台。
构建完成后会生成一个 .xcworkspace 文件, 使用 Xcode 打开并编译上传至 App Store。
Windows/Mac/Linux:
直接选择对应的桌面平台。
创建 .exe、 .app 或者 .x86_64 文件。
根据需要发布到 Steam、 Itch.io 或其他分发平台。
WebGL:
WebGL 是用于网页的游戏版本。
构建后会生成一系列 HTML 和 JavaScript 文件。
可以通过托管服务( 如 GitHub Pages) 来发布。
💗💗 测试构建 构建完成后, 在正式发布前, 请务必在目标平台上对构建版本进行彻底的测试, 以确保没有问题。
💗💗 发布 最后一步就是将游戏发布到相应的商店或平台上, 比如 Steam、 App Store、 Google Play 等。
AssetBundles Unity中的AssetBundles是一个强大的功能, 它允许开发者将游戏资源( 如纹理、 模型、 动画等) 打包成独立的文件, 并在运行时按需加载。 这种方法有助于优化资源管理, 减少内存使用, 并且可以支持资源的热更新。
AB包资源打包 💗💗 编辑器打包
准备资源: 首先, 你需要准备好要打包成AssetBundles的游戏资源。
构建设置:
在Unity编辑器中, 选择菜单栏上的File > Build Settings来配置你的构建设置。
选择Asset Bundles选项卡, 然后选择要包含在构建中的资源。
构建AssetBundles: 通过脚本或者编辑器菜单( 如Assets > Build All AssetBundles) , 将选定的资源打包成AssetBundles文件。
💗💗 脚本打包
准备游戏资源
项目中新建 Editor 文件夹
把脚本放入文件夹中
在编辑器工具栏中运行 Tools/Build AssetBundles 选项1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using System.IO;using UnityEngine;using UnityEditor;using UnityEditor.Callbacks;using UnityEditor.AssetBundles;public class BuildAssetBundles { private const string OutputPath = "Assets/StreamingAssets/AssetBundles" ; [MenuItem("Tools/Build AssetBundles" ) ] public static void Build () { if (!Directory.Exists(OutputPath)) { Directory.CreateDirectory(OutputPath); } string [] assetPaths = Selection.GetFiltered(typeof (Object), SelectionType.Assets); BuildAssetBundleOptions options = BuildAssetBundleOptions.None; options |= BuildAssetBundleOptions.ChunkBasedCompression; BuildPipeline.BuildAssetBundles(OutputPath, options, EditorUserBuildSettings.activeBuildTarget); Debug.Log("AssetBundles have been built successfully." ); } }
AB包资源加载 在Unity中, AssetBundle类提供了多个方法来处理外部资源包( AssetBundles) 。 以下是一些常用方法的详细介绍以及简单的代码示例:
💗💗 LoadFromCacheOrDownload 此方法会尝试从缓存中加载AssetBundle, 如果不在缓存中则会下载。 成功后会返回AssetBundle对象。
1 2 3 4 5 6 7 8 9 public IEnumerator LoadMyAssetBundle (){ string url = "http://example.com/assetbundles/mybundle" ; var ab = AssetBundle.LoadFromCacheOrDownload(url, 0 , null ); yield return ab; GameObject myGameObject = ab.LoadAsset<GameObject>("myGameObject" ); }
💗💗 LoadFromFile 此方法用于从本地文件系统加载AssetBundle。
1 2 3 4 5 string path = Application.persistentDataPath + "/assetbundles/mybundle" ;AssetBundle ab = AssetBundle.LoadFromFile(path); GameObject myGameObject = ab.LoadAsset<GameObject>("myGameObject" );
💗💗 LoadFromMemory 此方法用于从内存中的字节数组加载AssetBundle。
1 2 3 4 5 byte [] bundleBytes = GetMyAssetBundleBytes(); AssetBundle ab = AssetBundle.LoadFromMemory(bundleBytes); GameObject myGameObject = ab.LoadAsset<GameObject>("myGameObject" );
💗💗 LoadAsset 此方法用于从已加载的AssetBundle中加载单个资源。
1 GameObject myGameObject = ab.LoadAsset<GameObject>("myGameObject" );
💗💗 AllAssets 此方法返回AssetBundle中所有资源的数组。
1 2 3 4 5 Object[] allAssets = ab.GetAllAssets(); foreach (var asset in allAssets){ Debug.Log(asset.name); }
💗💗 Unload 此方法用于卸载AssetBundle及其加载的所有对象。
AB资源包管理类 在Unity项目中, 为了更好地管理AssetBundles( 简称AB包) , 通常会创建一个专门的类来处理与AB包相关的所有操作, 比如加载、 卸载、 获取资源等。 这样做的好处是可以集中管理AB包的生命周期, 简化代码结构, 并提高代码的可维护性和复用性。
💗💗 代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 using UnityEngine;using UnityEngine.Networking;using System.Collections;using System.Collections.Generic;public static class AssetBundleManager { private static Dictionary<string , AssetBundle> _loadedBundles = new Dictionary<string , AssetBundle>(); private static Dictionary<string , List<AssetBundleLoadOperation>> _operationsInProgress = new Dictionary<string , List<AssetBundleLoadOperation>>(); public static void LoadAssetBundleAsync (string bundleName, System.Action<AssetBundle> onComplete ) { StartCoroutine(LoadAssetBundleInternalAsync(bundleName, onComplete)); } private static IEnumerator LoadAssetBundleInternalAsync (string bundleName, System.Action<AssetBundle> onComplete ) { if (_loadedBundles.ContainsKey(bundleName)) { Debug.Log($"AssetBundle '{bundleName} ' already loaded." ); onComplete?.Invoke(_loadedBundles[bundleName]); yield break ; } string url = "http://example.com/assetbundles/" + bundleName; UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(url); yield return uwr.SendWebRequest(); if (uwr.isNetworkError || uwr.isHttpError) { Debug.LogError($"Failed to download AssetBundle '{bundleName} ': {uwr.error} " ); onComplete?.Invoke(null ); } else { AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr); if (bundle != null ) { _loadedBundles[bundleName] = bundle; Debug.Log($"AssetBundle '{bundleName} ' loaded successfully." ); onComplete?.Invoke(bundle); } else { Debug.LogError($"Failed to load AssetBundle '{bundleName} '." ); onComplete?.Invoke(null ); } } } public static void LoadAsset <T >(string bundleName, string assetName, System.Action<T> onComplete ) where T : Object { StartCoroutine(LoadAssetInternalAsync<T>(bundleName, assetName, onComplete)); } private static IEnumerator LoadAssetInternalAsync <T >(string bundleName, string assetName, System.Action<T> onComplete ) where T : Object { if (_loadedBundles.TryGetValue(bundleName, out AssetBundle bundle)) { T asset = bundle.LoadAsset<T>(assetName); onComplete?.Invoke(asset); yield break ; } else { Debug.LogError($"AssetBundle '{bundleName} ' not found or not loaded." ); onComplete?.Invoke(default (T)); yield break ; } } public static void UnloadAssetBundle (string bundleName, bool unloadAllLoadedObjects ) { if (_loadedBundles.ContainsKey(bundleName)) { _loadedBundles[bundleName].Unload(unloadAllLoadedObjects); _loadedBundles.Remove(bundleName); Debug.Log($"AssetBundle '{bundleName} ' unloaded." ); } else { Debug.LogWarning($"Attempted to unload non-existent AssetBundle '{bundleName} '." ); } } }
💗💗 使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 IEnumerator Start () { yield return AssetBundleManager.LoadAssetBundleAsync("mybundle" ); GameObject myGameObject = AssetBundleManager.LoadAsset<GameObject>("mybundle" , "myGameObject" ); if (myGameObject != null ) { Instantiate(myGameObject); } } void OnDestroy (){ AssetBundleManager.UnloadAssetBundle("mybundle" , true ); }
设计模式 单例模式 单例模式( Singleton Pattern) 是一种常用的软件设计模式, 它保证一个类只有一个实例, 并提供一个全局访问点。
在游戏开发中, 我们经常需要在整个游戏中保持一些数据的一致性, 比如管理游戏的音量设置、 玩家数据、 或者共享资源等。 这时候就可以使用单例模式来确保这些数据只有一份副本。
⭐⭐ 创建一个基础的 Singleton 类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 using UnityEngine;public abstract class Singleton <T > : MonoBehaviour where T : MonoBehaviour { private static T _instance; private static object _lock = new object (); public static T Instance { get { if (_instance == null ) { lock (_lock) { if (_instance == null ) { _instance = FindObjectOfType<T>(); if (_instance == null ) { GameObject singleton = new GameObject($"[{typeof (T).Name} ] Singleton" ); _instance = singleton.AddComponent<T>(); } } } } return _instance; } } protected virtual void Awake () { DontDestroyOnLoad(this ); } }
⭐⭐ 创建具体的单例实例 1 2 3 4 5 6 7 8 public class GameSettingsManager : Singleton <GameSettingsManager >{ public int MusicVolume { get ; set ; } = 50 ; public int SFXVolume { get ; set ; } = 75 ; }
⭐⭐ 使用单例模式 1 2 3 4 5 6 void Start (){ GameSettingsManager.Instance.MusicVolume = 60 ; Debug.Log("Music Volume: " + GameSettingsManager.Instance.MusicVolume); }
工厂模式 工厂模式( Factory Pattern) 是一种创建型设计模式, 它提供了一个创建对象的最佳方式。 该模式的核心思想是通过一个工厂对象决定创建哪个类的对象, 而不需要指定具体的类名。 这有助于将对象创建与使用对象的代码分离, 提高系统的可扩展性和灵活性。
在 Unity 游戏开发中, 工厂模式可以用来创建游戏中的各种对象, 如敌人、 子弹等。
⭐⭐ 定义接口 1 2 3 4 5 6 public interface IGameObject { void Initialize () ; void UpdateState () ; }
⭐⭐ 创建具体的类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Enemy : MonoBehaviour , IGameObject { public void Initialize () { } public void UpdateState () { } } public class Bullet : MonoBehaviour , IGameObject { public void Initialize () { } public void UpdateState () { } } public enum GameObjectType{ Enemy, Bullet }
⭐⭐ 创建工厂类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class GameObjectFactory { public static IGameObject CreateGameObject (GameObjectType type ) { switch (type) { case GameObjectType.Enemy: Enemy enemy = new GameObject("Enemy" ).AddComponent<Enemy>(); return enemy; case GameObjectType.Bullet: Bullet bullet = new GameObject("Bullet" ).AddComponent<Bullet>(); return bullet; default : throw new ArgumentException("Unsupported game object type!" ); } } }
⭐⭐ 使用工厂模式 1 2 3 4 5 6 7 8 9 10 11 12 public class GameManager : MonoBehaviour { void Start () { IGameObject enemy = GameObjectFactory.CreateGameObject(GameObjectType.Enemy); enemy.Initialize(); IGameObject bullet = GameObjectFactory.CreateGameObject(GameObjectType.Bullet); bullet.Initialize(); } }
策略模式 策略模式( Strategy Pattern) 是一种行为设计模式, 它使你能在运行时改变对象的行为。 策略模式定义了一系列算法, 并将每一个算法封装起来, 使它们可以相互替换。 策略模式让算法独立于使用它的客户。
在 Unity 游戏开发中, 策略模式可以用来实现角色的不同行为模式, 比如 AI 控制的角色可以根据不同的情况选择不同的行动策略。
⭐⭐ 定义接口 1 2 3 4 public interface IAttackStrategy { void Attack () ; }
⭐⭐ 创建具体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class SwordAttack : IAttackStrategy { public void Attack () { Debug.Log("Attacking with a sword!" ); } } public class BowAttack : IAttackStrategy { public void Attack () { Debug.Log("Attacking with a bow!" ); } } public class MagicAttack : IAttackStrategy { public void Attack () { Debug.Log("Casting magic spells!" ); } }
⭐⭐ 创建上下文类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Character : MonoBehaviour { private IAttackStrategy _attackStrategy; public void SetAttackStrategy (IAttackStrategy strategy ) { _attackStrategy = strategy; } public void PerformAttack () { _attackStrategy.Attack(); } }
⭐⭐ 使用策略模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class CharacterController : MonoBehaviour { private Character _character; void Start () { _character = GetComponent<Character>(); _character.SetAttackStrategy(new SwordAttack()); ChangeAttackStrategyToBow(); } private void ChangeAttackStrategyToBow () { _character.SetAttackStrategy(new BowAttack()); _character.PerformAttack(); } private void ChangeAttackStrategyToMagic () { _character.SetAttackStrategy(new MagicAttack()); _character.PerformAttack(); } }
代理模式 代理模式( Proxy Pattern) 是一种结构型设计模式, 它允许你在不修改原始类的情况下, 增加额外的功能或控制访问。 代理模式通常用于在访问一个对象时提供间接层, 可以用来延迟初始化、 控制访问、 记录操作等。
在 Unity 游戏开发中, 代理模式可以用来解决一些性能问题, 比如延迟加载大纹理或者控制对复杂对象的访问等。
⭐⭐ 定义接口 1 2 3 4 public interface ITexture { void Display () ; }
⭐⭐ 创建具体类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class RealTexture : ITexture { private Texture2D _texture; public RealTexture (string imagePath ) { _texture = Resources.Load<Texture2D>(imagePath); } public void Display () { Debug.Log("Displaying texture." ); } }
⭐⭐ 创建代理类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ProxyTexture : ITexture { private RealTexture _realTexture; private string _imagePath; public ProxyTexture (string imagePath ) { _imagePath = imagePath; } public void Display () { if (_realTexture == null ) { _realTexture = new RealTexture(_imagePath); } _realTexture.Display(); } }
⭐⭐ 使用代理模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ExampleUsage : MonoBehaviour { private ITexture _texture; void Start () { _texture = new ProxyTexture("path/to/your/texture" ); ShowTexture(); } void ShowTexture () { _texture.Display(); } }
观察者模式 观察者模式( Observer Pattern) 是一种行为设计模式, 它定义了对象间的一种一对多依赖关系, 以便当一个对象的状态发生改变时, 所有依赖于它的对象都会得到通知并自动更新。 这种模式非常适合用于实现事件处理系统。
在 Unity 游戏开发中, 观察者模式可以用来处理游戏中的事件监听和响应机制, 比如游戏角色的生命值变化时通知 UI 界面更新, 或者玩家得分变化时通知排行榜更新等。
⭐⭐ 定义接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface IObserver { void OnNotify (object sender, EventArgs args ) ; } public class ScoreChangedEventArgs : EventArgs { public int NewScore { get ; } public ScoreChangedEventArgs (int score ) { NewScore = score; } }
⭐⭐ 创建具体观察者类 1 2 3 4 5 6 7 8 9 10 11 public class UIScoreUpdater : MonoBehaviour , IObserver { public void OnNotify (object sender, EventArgs args ) { if (args is ScoreChangedEventArgs e) { Debug.Log($"Score updated to {e.NewScore} ." ); } } }
⭐⭐ 创建被观察者类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class ScoreManager : MonoBehaviour { private List<IObserver> _observers = new List<IObserver>(); public void RegisterObserver (IObserver observer ) { _observers.Add(observer); } public void UnregisterObserver (IObserver observer ) { _observers.Remove(observer); } public void NotifyObservers (int score ) { foreach (var observer in _observers) { observer.OnNotify(this , new ScoreChangedEventArgs(score)); } } public void IncreaseScore (int amount ) { int currentScore = GetScore(); currentScore += amount; SetScore(currentScore); NotifyObservers(currentScore); } private int GetScore () { return 0 ; } private void SetScore (int score ) { } }
⭐⭐ 使用观察者模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class GameManager : MonoBehaviour { private ScoreManager _scoreManager; private UIScoreUpdater _scoreUpdater; void Start () { _scoreManager = FindObjectOfType<ScoreManager>(); _scoreUpdater = FindObjectOfType<UIScoreUpdater>(); _scoreManager.RegisterObserver(_scoreUpdater); _scoreManager.IncreaseScore(100 ); } void OnDestroy () { _scoreManager.UnregisterObserver(_scoreUpdater); } }
实用工具 DoTween 动画库 DoTween是Unity的一个流行动画库, 它允许开发者使用简单而强大的API来创建平滑的动画。 与Unity内置的动画系统相比, DoTween提供了更多的灵活性和控制选项, 并且可以用于几乎任何类型的动画, 包括但不限于位置、 旋转、 缩放等属性的变化。
安装
通过Unity Package Manager安装:
打开Unity Hub, 选择你的项目。
在Unity编辑器中, 选择“ 窗口” >“ 包管理器” 。
在Unity Package Manager窗口中, 点击左下角的”+”, 搜索”DoTween”并安装。
手动下载:
访问DoTween的GitHub页面或者官方网站下载最新版本。
将下载的文件解压后, 将Plugins文件夹内的内容导入到Unity项目的Plugins文件夹内。
文档
AB包打包工具 工具简介 Unity Asset Bundle Browser 工具是 Unity 标准功能之外的额外功能。 要访问此工具, 必须从 GitHub 下载并安装, 该过程独立于标准 Unity Editor 的下载和安装。
此工具使用户能够查看和编辑 Unity 项目的资源包的配置。 它将阻止会创建无效捆绑包的编辑, 并告知现有捆绑包的任何问题。 此外还会提供基本的构建功能。
通过使用此工具, 无需选择资源并在 Inspector 中手动设置资源包。 它可以放入 5.6 或更高版本的任何 Unity 项目中。 此工具将在 Window > AssetBundle Browser 中创建一个新菜单项。 捆绑包的配置和构建功能在新窗口中拆分为两个选项卡。
官方手册 访问地址: https://docs.unity3d.com/cn/2022.3/Manual/AssetBundles-Browser.html
手册左上角可以切换手册的版本。
XLua 解释器 XLua 是一个针对 Unity 游戏引擎的 Lua 解释器, 它主要用于将 Lua 脚本集成到 Unity 中, 从而可以利用 Lua 的灵活性和轻量级特性来开发游戏逻辑。 XLua 的设计目标是在保证安全性的前提下提供高性能的 Lua 执行环境, 并且能够方便地与 C# 代码进行互操作。
⭐⭐ Lua 脚本语言: 学习笔记
XLua 的特点
高性能: XLua 采用了 LuaJIT 的 JIT 编译技术, 可以将 Lua 代码编译成本地机器码, 从而提高执行速度。
安全性: XLua 提供了沙箱环境, 可以限制 Lua 代码的执行权限, 防止恶意代码对游戏产生不良影响。
易用性: XLua 提供了丰富的 API, 可以方便地在 Lua 代码中调用 C# 方法, 反之亦然。
调试支持: XLua 支持 Lua 调试器, 可以方便地进行代码调试。
XLua 的安装
下载地址和手册: https://github.com/Tencent/xLua
从 Releases 中下载发行版, 或直接下载本仓库代码.
打开下载下来的源码压缩包, 你会看到一个 Assets 目录, 这目录就对应 Unity 工程的 Assets 目录, 保持这目录结构, 将其内容置入 Unity 项目即可.
注意, Assets/Examples 目录下为示例代码, 你应该在生产环境下删去他们.
1 2 3 git clone https://github.com/Tencent/xLua.git
核心组件
LuaEnv: LuaEnv 是 XLua 的核心类, 用于创建 Lua 环境。 它负责管理 Lua 状态, 并提供执行 Lua 代码的方法。
LuaTable: LuaTable 类表示 Lua 中的表, 可以用于存储和操作 Lua 数据。
Global: Global 属性提供了对全局环境的访问, 可以用于注册 C# 函数到 Lua 环境中。
沙箱环境 XLua 提供了沙箱环境来限制 Lua 代码的执行权限。 可以通过创建一个独立的 Lua 状态来实现这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var env = new LuaEnv();var sandbox = env.NewTable();sandbox.Set("__index" , new Dictionary<string , Delegate> { { "print" , (Action<string >)Console.WriteLine }, { "math" , new LuaTable() { ["abs" ] = (Func<double , double >)Math.Abs } } }); env.Global = sandbox; env.DoString("print(math.abs(-10))" );
加载 Lua 脚本示例 💗💗 创建一个简单的 Lua 脚本 test.lua 1 2 3 4 5 6 7 function sayHello (name) print ("Hello, " .. name .. "!" ) end return { sayHello = sayHello }
💗💗 在 Unity 中创建一个 C# 脚本 LuaExample.cs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 using UnityEngine;using XLua;public class LuaExample : MonoBehaviour { private LuaEnv env; void Start () { env = new LuaEnv(); env.DoString("print('Hello, World!')" ); string luaCode = File.ReadAllText("Assets/test.lua" ); env.DoString(luaCode); env.Load("Assets/test.lua" ); var luaFunc = env.Global.Get<LuaFunction>("sayHello" ); luaFunc.Call("Unity" ); } void OnDestroy () { env.Dispose(); } }
Unity 与 Lua 交互 💗💗 在Unity中创建一个新的Lua文件, 比如叫做Example.lua。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 -- Example.lua ---@class Example ---@field public Name string The name of the example. ---@field public Age number The age of the example. ---@constructor function Example (name, age ) self.Name = name self.Age = age end ---@return Example function Example:new (name, age) local obj = {} setmetatable(obj, self) self.__index = self Example.__init(obj, name, age) return obj end ---@param obj Example ---@param name string ---@param age number function Example.__init(obj, name, age) obj.Name = name obj.Age = age end ---@param value number ---@return number function Example:AddAge(self, value ) self.Age = self.Age + value return self.Age end ---@param value string ---@return string function Example:Greet(value ) return "Hello " .. value .. ", I am " .. self.Name .. " and my age is " .. tostring(self.Age) end
💗💗 在Unity中写一个C#脚本来加载并使用上面定义的Lua脚本。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using UnityEngine;using XLua;public class LuaInteraction : MonoBehaviour { private LuaTable Example; void Start () { LuaEnv env = new LuaEnv(); env.DoString(@" require('Example') -- 假设Example.lua位于默认路径下 " ); Example = env.Global.Get< LuaTable >("Example" ); LuaTable exampleInstance = Example.Call< LuaTable >("new" , "John Doe" , 30 ); int newAge = exampleInstance.Get<int >("AddAge" )(5 ); Debug.Log($"New age after adding 5 years: {newAge} " ); string greeting = exampleInstance.Get<string >("Greet" )("Unity" ); Debug.Log(greeting); env.Dispose(); } }
Lua 与 Unity 交互 💗💗 在Unity中创建一个新的Lua文件, 比如叫做test.lua。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 local CS = require ('CS' )CS.UnityEngine.Debug.Log("Hello from Lua!" ) local go = CS.UnityEngine.GameObject('NewGameObject' )go.transform.position = CS.UnityEngine.Vector3(0 , 0 , 0 ) local meshFilter = go.AddComponent(CS.UnityEngine.MeshFilter)meshFilter.mesh = CS.UnityEngine.Mesh.PrimitiveMesh(CS.UnityEngine.PrimitiveType.Cube) local collider = go.AddComponent(CS.UnityEngine.BoxCollider)collider.size = CS.UnityEngine.Vector3(1 , 1 , 1 ) local renderer = go.AddComponent(CS.UnityEngine.MeshRenderer)renderer.material = CS.UnityEngine.Material.New(CS.UnityEngine.Color.red)
💗💗 在 Unity 中创建一个 C# 脚本 LuaExample.cs 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 using UnityEngine;using XLua;public class LuaExample : MonoBehaviour { private LuaEnv env; void Start () { env = new LuaEnv(); env.Load("Assets/test.lua" ); } void OnDestroy () { env.Dispose(); } }
学习资源