Unity1 - Gamer羽飞
前言
- 一定要多练习
- 扩展发散
- 学完后尝试建立自己的游戏框架
内容
快捷键
场景区
- 中键: 同Q
- 右键+wasd: 作为player移动
- Alt+左键: 转动视角
- E: 旋转Rotate
- R: 缩放Scale
- T: 矩形缩放Rect,只管一个平面矩形的缩放,一般用于2D平面,如UI
- Y: 全都有
Game Object
- Sphere平面和Quad矩形的区别
- Sphere三角面更多, 可以支撑更精确复杂的计算; Quad三角面只有两个
- Sphere一般没有y, Quad一般没有z
- 不同GO的本质区别在于不同GO的Mesh Filter组件中Mesh属性的取值不同
坐标系
- 在C#中通过Transform实例化的对象来访问对象本身的Position,Rotation变量是世界坐标系下的值。
transform.position; transform.rotation;
- 若想获取与组件上的本地坐标则应访问
transform.localPosition
和transform.localRotation
- 从世界坐标转成相对父对象的局部坐标:
1
2
3
4transform.TransformPoint(transform.localPosition);
//局部坐标转世界坐标
transform.parent.InverseTransformPoint(transform.position);
//世界坐标转局部坐标
游戏资源管理
- 导入导出包UnityPackageFile: unity自身的一个压缩包
- fbx: 3D模型文件
- 默认Material材质不可更改, 更改需要新建一个Material并应用到对应的GO上. 通过GO的MeshRenderer组件中Material组件可以添加各自的Material, 不同的Material通过选定的Shader着色器(默认Standard)渲染到GO上.
- Window->Package Manager管理在Assets Store下载的资源包
Terrain地形
- 添加相邻地形
- FillHeightmapUsing: 连接地形的方法
- clamp: 相邻瓦片交叉混合
- mirror: 镜像
- 绘制地形
Opacity: 不透明度
- Paint Holes: 镂空画洞
- Set Height: 设置高度
- Flatten Tile: 展平当前terrain
- Flatten All: 展平所有terrain
- Smooth Height: 平滑高度
- Blur Direction: 仅向下舍去-1,双向0,仅向上进入1
- Stamp Terrain: 只能点一下, 不能滑动绘制
- Paint Texture: 绘制纹理
- 在Terrain Layer中选择Texture资源
Tips: 一般不用绘制, 只需要了解
- 在Terrain Layer中选择Texture资源
- 画树
- Mass Place Tree: 大量放置树
- 绘制细节
- Add Grass Texture: 给地面添加草
- 最终强度: 草的密集程度
- 地形设置
脚本的生命周期
![Unity官方图解](D:\Program Files\Typora\assets\unity1\f366aa7d27e1514bb579b495f09942bf.png)
Awake:初始化时调用,通常使用为需要提前初始化的逻辑。比如单例赋值
private void Awake(){Instance = this;}
OnEnable:在对象启用时调用,处理每次显示时都需要进行初始化的逻辑,通常和OnDisable配合使用。
比如: 游戏逻辑使用并修改了变量Number
,而下次显示时使用是又需要Number = 1
,此时就可以写private void Awake(){Number = 1;}
Start:仅当启用脚本实例时,才会在第一帧调用。通常使用为一些变量初始化逻辑。比如:获取指定物体:
private void Start(){child1 = transform.GetChild(0);}
Fixed Update:固定时间调用,所有物理计算和更新都在Fixed Update中处理,不受帧率影响。比如:一些物理属性的更新操作Force,Collider,Rigidbody等。
Update:每帧调用一次,根据帧率的快慢影响执行速度。通常的游戏逻辑都写在这里,比如:和玩家交换,当用户按下空格时进行执行什么操作。
LateUpdate:在Update完成后,每帧调用一次。常见用处是相机跟随主角,比如:主角在Update中移动,则可以在LateUpdate执行相机的移动,这将可以保证摄像机跟着的时候之前的逻辑一起完全执行完成。
OnMouseXXX: 通过鼠标的射线检测来判断鼠标当前位置是否碰到了挂载脚本游戏对象的碰撞体。
前提:
- 只能检测当前脚本挂载的游戏对象。
- 当前游戏对象需要有碰撞体。
- 不能有其他物体(UI)遮挡到此游戏对象。
函数:
- OnMouseEnter: 鼠标进入时调用一次
- OnMouseOver: 鼠标停留(经过)时一直调用
- OnMouseExit: 鼠标退出时调用一次
- OnMouseDown: 鼠标按下时调用一次
- OnMouseDrag: 鼠标拖拽(按住)时一直调用
- OnMouseUp: 鼠标抬起时调用一次
应用(一般成对使用):
- OnMouseEnter,OnMouseOver,OnMouseExit 一组。比如模拟选中状态:鼠标进入时物体变色,鼠标退出时再变回来。
- OnMouseDown,OnMouseDrag,OnMouseUp 一组。比如射击游戏:鼠标按下拖拽时调整方向,抬起时发射子弹。
- 当鼠标按下并停留在当前游戏对象上时,OnMouseOver,OnMouseDrag会同时触发。
OnTriggerXX:
函数
- OnCollisionEnter: 进入碰撞时触发一次。
- OnCollisionStay: 在碰撞体中停留时每帧触发一次。
- OnCollisionExit: 离开碰撞体时触发一次。
- OnTriggerEnter: 进入碰撞体时触发一次。
- OnTriggerStay: 在碰撞体中停留时每帧触发一次。
- OnTriggerExit: 离开碰撞体是触发一次。
还有对应2D碰撞体的六个方法(如:
OnCollisionEnter2D
) 函数后面添加2D接口,触发条件和使用方式和3D一致。 使用时注意碰撞体和检测函数同步接口,即用2D碰撞体必须用2D函数。前提同上
OnApplicationXX:
- 函数:
- OnApplicationPause: 检测到暂停的帧结束 –> 切换到后台和回来时调用。游戏停止保存数据/游戏继续数据初始化。
- OnApplicationFocus: 当屏幕 获得/失去 焦点时调用。失去焦点关闭背景音乐/获得焦点继续播放音乐。
- OnApplicationQuit: 当程序退出时调用。在移动端大退时也会对调用,但不会触发上面两个方法。
- 函数:
禁用与销毁
OnDisable
: 当对象被禁用时调用此函数(其父物体被禁用也会触发)。通常和OnEnable配合使用。比如:在OnEnable添加监听,在OnDisable移除监听OnDestroy
: 在对象存在的最后一帧的所有帧更新之后调用此函数。当物体销毁或者场景关闭时触发。比如:子弹打到墙壁时,需要销毁子弹并触发一个打击音效。
脚本执行顺序
先执行所有的
Awake()
, 再执行所有的Start()
Execution Order中设置cs脚本执行顺序, 数值越小越先执行
标签和图层
- 给GO分组的工具
- 图层可以在Camera组件Culling Mask属性中选择遮罩图层, 实现显隐不同图层的功能
Prefab预制体与变体
以.prefab文件存储的GO, 可以通过GO快速创建别人打包好的GO
在Scene中的GO组件发生改变, 可以通过右键组件应用到Prefab文件的修改
通过预制体创建的GO发生大改变, 将GO独立为新的prefab时, 选择
原始预制体
将保留对原始预制体的引用, 选择预制体变体
将不再保留对原始预制体的引用通过代码来创建GO就可以考虑使用预制体
1
2
3public GameObject sphere; //首先public一个GO变量, 然后在unity面板中拖入特定的预制体
Instantiate(sphere,transform); //使用Instantiate初始化这个变量, 并将其设置为当前GO的子GO.该函数返回值为go对象
Destroy(Instantiate(sphere,transform)); //创建并销毁go
Vector3
常用常量
Vector3.zero
: (0,0,0)Vector3.one
: (1,1,1)
函数
Vector3.Angle(new Vector3(0,0,0),new Vector3(1,1,1))
: 两个向量之间的夹角Vector3.Distance(new Vector3(0,0,0),new Vector3(1,1,1))
: 两个坐标之间的距离Vector3.Dot(new Vector3(0,0,0),new Vector3(1,1,1))
: 两个向量的乘积(返回==标量==)1
2
3
4
5//Dot源码
public static float Dot(Vector3 lhs, Vector3 rhs)
{
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
}a⋅b=(x
1,y1,z1)⋅(x2,y2,z2)=x1×x2+y1×y2+z1×z2=|a|×|b|×cosθ通过取值正负可以判断两向量方向是否相同; 通过取值是否为0可以判断是否垂直
Vector3.Cross(new Vector3(0,0,0),new Vector3(1,1,1))
: 两个向量的叉乘(返回==Vector3对象==)//Cross源码
1
2
3
4public static Vector3 Cross(Vector3 lhs, Vector3 rhs)
{
return new Vector3(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
}a×b=(a1,a2,a3)×(b1,b2,b3)=(a2×b3−a3×b3,a3×b1−a1×b3,a1×b2−a2×b1))
|a×b|=|a|×|b|×sinβ
叉乘的几何意义表示为求得以a和b为平面的法线向量c, c⊥a与b组成的平面, c的模|c|=|a|×|b|×sinβ, 或以a和b组成的平行四边形的面积
若两者叉乘之模为0, 则a与b相互平行; 若两者叉乘之模等于两者各自的模的乘积, 则a与b相互垂直
Vector3.Lerp(new Vector3(0,0,0),new Vector3(1,1,1),0.5f)
: 两个Vector3之间插值
对象常量(
Vector3 v = new Vector3(1,1,1);
)v.magnitude
: Vector3的模
Euler欧拉角与Quaternion四元数
Euler的实例化: 同Vector3
Vector3 rotate = new Vector3(0,30,0);
Quaternion的实例化:
- 常量(0,0,0,0):
Quaternion.identity
- 欧拉角to四元数:
Quaternion quaternion = Quaternion.Euler(new Vector3(0,30,0));
- 四元数to欧拉角:
Vector3 vector3 = quaternion.eulerAngles;
- 常量(0,0,0,0):
Debug
- 输出文本Text:
- 调试输出:
Debug.log("Text");
- 调试输出警告:
Debug.logWarning("Text");
- 调试输出错误:
Debug.logError("Text");
- 调试输出:
- 画线
- 画直线:
Debug.DrawLine(Vector3.zero,Vector3.one,[Color.Green]); //两个必需参数为两个点坐标
- 画射线:
Debug.DrawRay(Vector3.zero,Vector3.one,[Color.Green]); //第一个参数是起始点坐标, 第二个参数为射线向量
- 画直线:
组件属性的修改
获取GO和transform:
获取本GO:
GameObject go = this.gameObject;
也可直接使用gameObject
代替this.gameObject
GO的父子关系控制在
transform
组件中, 上面的this
表示的是本GO
的transform
, 所以上面的this.gameObject
也可以写为transform.gameObject
获取其他无关GO:
public GameObject go;
然后通过unity面板选择GameObject.Find("name")
; 使用GameObject
类方法根据name寻找GameObject.FindWithTag("tag")
; 使用GameObject
类方法根据tag寻找
获取父物体GO:
1
2
3Transform parent = transform.parent; // 获取物体的直接父物体
Transform root = transform.root; // 获取物体的根物体
int hierarchy = transform.GetSiblingIndex(); // 获取物体在父物体中的层级索引.根物体的层级索引为0,其直接子物体的层级索引依次递增获取子物体GO:
- 获取所有层级所有子物体, 包括本物体:
GetComponentsInChildren()
1
2Transform[] myTransforms = GetComponentsInChildren<Transform>();
foreach (var child in myTransforms){Debug.Log(child.name);}通过name获取一级子物体:
transform.Find("Child0")
获取二级子物体需要全路径:
transform.Find("Child0/Child00")
==注意: 对象
gameObject
没有此方法,transform
有此方法,transform
对象的方法只能寻找本身及子物体,GameObject
类方法是从所有层级所有物体中寻找==通过index获取一级子物体:
transform.GetChild(1)
获取二级子物体需要连续两次调用:
transform.GetChild(1).GetChild(0)
- 获取所有层级所有子物体, 包括本物体:
GameObject
类的实例化需要到unity面板中选择, 在代码中的gameObject
是transform
对象的一个属性, 获得的所有父子GO物体均为相应的transform
对象
GO/transform的属性和函数:
1
2
3
4
5
6
7
8go.name
go.tag
go.layer
go.activeInHierarchy //是否激活状态在层级中
go.activeSelf //本身是否激活状态
//两个同时为真才是激活状态, 只要有一个为假就不是激活状态
go.AddComponent<BoxCollider>(); //添加组件
go.SetActive(true); //设置是否激活, 这是go的函数, transform无法管控GO是否激活获取其他组件:
BoxCollider bc = GetComponent<BoxCollider>();
或直接使用匿名函数接想用的属性GetComponent<BoxCollider>().xxx
获取父物体的特定组件:
GetComponentInParent<BoxCollider>()
获取子物体的特定组件:
BoxCollider[] bc = GetComponentInChidren<BoxCollider>()
, 会遍历包含本身在内的所有层级所有子物体
Time类
Time类属性
总时间 Time.time
帧时间 Time.unscaledTime
不受Scale约束的帧时间 Time.fixedTime
频率时间/不受帧约束的时间 Time.unscaledFixedTime
不受Scale约束的频率时间 Time.realtimeSinceStartup
不受Scale影响的实际时间 Time.timeSinceLevelLoad
自最后一个非添加场景(non-additive scene)完成加载以来的Scaled时间 增量时间 Time.deltaTime
帧间隔时间/Δ帧时间 Time.unscaledDeltaTime
不受Scale约束的帧间隔时间 Time.fixedDeltaTime
频率间隔时间/不受帧约束的时间间隔 Time.fixedUnscaledDeltaTime
不受Scale约束的频率间隔时间 其他 Time.frameCount
总帧数 Time.timeScale
时间缩放尺度, 默认为1, 为0停止, 为2二倍速 Time.maximumDeltaTime
最大帧增量时间 Time.maximumParticleDeltaTime
粒子更新的最大帧增量时间 - 过于卡顿时,
Time.deltaTime
会增大, 但不会无限增大, 受Time.maximumDeltaTime
限制, 而Time.unscaledDeltaTime
不受此限制, 因此Time.time
会比Time.unscaledTime
慢一些.
- 过于卡顿时,
Application类
静态变量 | |
---|---|
Application.persistentDataPath |
不同平台持久化的Assets文件夹(读写) |
Application.streamingAssetsPath |
游戏安装目录Assets目录中streamingAssets 文件夹, 无加密(只读) |
Application.temporaryCachePath |
临时文件夹 |
Application.runInBackground |
是否在后台运行 |
Application.platform |
返回游戏运行平台(只读) |
Application.systemLanguage |
返回系统语言(只读) |
Application.unityVersion |
返回unity版本 |
静态函数 | |
Application.OpenURL("http") |
打开URL |
Application.Quit |
退出游戏 |
Scene
类与SceneManagement
类
1 |
|
1 |
|
Transform类
实例变量 | |
---|---|
transform.position |
世界位置 |
transform.localPosition |
相对位置 |
transform.rotation |
世界旋转四元数 |
transform.localRotation |
相对旋转四元数 |
transform.eulerAngles |
世界旋转欧拉角 |
transform.localEulerAngles |
相对旋转欧拉角 |
transform.localScale |
缩放 |
transform.forward |
GO的前后左右上下 |
实例函数 | |
transform.LookAt(Vector3.zero) |
一直看向某一个点(点坐标) |
transform.Rotate(Vector3.up) |
旋转(方向向量) |
transform.Translate(Vector3.forward * 50 * Time.deltaTime) |
向(0,0,1)移动(方向向量) |
Input类
按键Key
静态属性 Input.anyKey
如果用户按下任何键(包含任意设备任意输入),在按住不放的过程中一直返回true(只读) Input.anyKeyDown
按下任何键(包含任意设备任意输入),按下的那一帧返回true(只读),之后的帧即使仍然被按住也返回false Input.inputString
按下的键的值(配合 anyKey
实现自定义按键)静态方法 Input.GetKey(KeyCode)
检测是否按下了任何指定键,一直按住则一直返回 true Input.GetKeyDown(KeyCode)
检测是否按下了任何指定键,只有那一帧时true Input.GetKeyUp(KeyCode)
释放的那一帧返回true 按钮Button
静态方法 Input.GetButton(string buttonName)
检测是否按下了任何按钮,一直按住则一直返回 true Input.GetButtonDown()
检测是否按下了任何button,只有那一帧时true Input.GetButtonUp()
释放的那一帧返回true 鼠标
静态属性 Input.mousePresent
是否有mouse设备连接(只读) Input.mousePosition
当前鼠标位置(只读), z=0, 左下角是(0,0,0), 右上角是分辨率 Input.mouseScrollDelta
鼠标滚轮滚动量(只读), 返回 Vector2
, y逆时针(0,1), 顺时针(0,-1)静态方法 Input.GetMouseButton(int button)
检测是否按下了按钮,一直按住则一直返回 true, 0左键 1右键 2中键 Input.GetMouseButtonDown()
检测是否按下,只有那一帧时true Input.GetMouseButtonUp()
释放的那一帧返回true 虚拟轴
- 设置内容在
编辑-ProjectSettings
中
1
2
3float h = Input.GetAxis("Horizontal"); //获取水平轴(-1,1)
float v = Input.GetAxis("Vertical");
float x = Input.GetAxis("Mouse X"); //获取鼠标横向从移动, 左-1Input.GetAxisRaw
只返回-1,0,1三个值,没有过渡态, 一般用于2D游戏中- 设置内容在
触摸
静态属性 Input.touchCount
返回整数,代表在当前帧所有触摸点数量(只读) Input.touches
返回一个 Touch[] 数组(只读),包含了当前帧所有触摸点 静态方法 Input.GetTouch(int index)
返回特定Touch 对象属性 touch.position
touch.phase
包含Began, Moved, Stationary, Ended, Canceled五个阶段的属性, 用switch判断 陀螺仪/重力感应
- 前提:
Input.gyro.enabled = true;
默认成员属性 Input.gyro.gravity
重力加速度向量 Input.gyro.rotateRate
旋转速度 Input.gyro.attitude
当前的旋转方向的四元数 - 前提:
设备按钮
Input.backButtonLeavesApp
: 这个值为true
时,按下返回按钮会导致应用程序退出,否则,操作系统将处理返回按钮(Android、Windows Phone或Windows平板电脑)
Light组件: 光照
- Directional定向光: 图穷远光源, 平行光线
- Intensity强度: 光照亮度
- Shadow Type: 无阴影, 有锯齿阴影, 模糊边缘阴影
- Realtime Shadows: 实时阴影
- Strength: 阴影强度
- Resolution: 阴影质量
- Draw Halo: 在GO处显示光晕
- Flare: 炫光
- Culling Mask: 光照遮罩, 剔除不需要灯光的GO(如UI)
- Spot聚光: 手电筒
- Point点光源: 灯泡球体光
- Area面光源(性能消耗过高, 仅支持烘焙模式)
Camera
Projection投影:
- Perspective透视: 近大远小
- Orthographic正交: 完全平面, 一般用于2D
Depth: 相机显示顺序, 数值大的优先显示
Clear Flags清除标志:
SkyBox天空盒: 可以添加SkyBox组件更改天空
Solid Color
Don’t Clear
Depth Only: 仅显示有深度GO, 拍不到的空间不显示
如果有多个相机, 将深度高的相机设置为DepthOnly, 可以显示高深相机的内容和低深相机的内容&背景
FOV Axis: 用于设置Field of View视野的大小
Clipping Planes剪裁平面: 只有在近面和远面之间的空间才能被捕捉到
Viewpoint Rect显示矩形: 拍摄到的内容在屏幕中的位置(x,y)和宽高(w,h), 位置默认左下角(0,0), 宽高是百分比小数
音频: AudioSource组件
- 前提: 有且只有一个GO添加了AudioListener组件用以监听
- 需要播放声音的GO中添加AudioSource组件
- 音频文件一般分为两类: 音乐和音效
- AudioSource组件:
- AudioClip: 引入音频资源文件
- Mute: 静音
- Pitch: 音调
- 3D Sound Settings - Volume Rolloff: 音量衰减
- 对象属性和函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15AudioSource a = GetComponent<AudioSource>();
//属性:
Debug.log(a.isPlaying);
a.loop = true;
a.volume = 0.5f;
//音乐函数:
a.Play();
a.Pause();
a.UnPause();
a.stop();
//音效函数:
a.PlayOneShot(AudioClip audioclip); //一个AudioSource只能播放一个音乐,但可以播放多个音效
视频: VideoPlayer组件
- 使用VideoClip作为资源文件变量
- VideoPlayer组件:
- Renderer Mode渲染模式: 选择挂载体
- 属性和函数参考
AudioSource
角色控制: CharacterController
组件
SimpleMove
: 自带重力效果, y轴速度为0, 角色接触地面返回trueMove
: 绝对控制, 没有重力效果, 影响位移的只有xyz的速度和**Rigidbody
的碰撞**, 返回CollisionFlags
对象
重力: Rigidbody
组件
automatic tensor
: 自动张量, 计算张量旋转行为automatic center of mass
: 自动重心计算interpolate
: 物体运动插帧, 一般在物理帧率低于app帧率时使用, 默认关闭Interpolate:使用前两次物理更新计算当前帧, 会稍滞后于它应该在的位置, 适用于刚体速度变化较大的情况或有其他影响刚体运动的物理元素
Extrapolate:使用上一次物理更新并预测下一次物理更新以计算当前帧, 会稍超前于它应该在的位置。外推通常不太准确,并且可能在可见的范围内超出碰撞边界(然后在下一帧中进行修正)。外推通常只适用于精度不重要的情况,例如刚体以恒定速度移动,并且没有其他影响刚体运动的物理元素启用时Unity会忽略任何不是来自物理系统的变换更改, 对
transform
进行任何直接(非物理)更改后使用Physics.SyncTransforms调用Collision Detection
: 碰撞检测频率Discrete
: 离散检测(默认,多数情况够用)Continues
: 连续Continues Dynamic
: 连续动态检测, 性能消耗最高Continues Speculative
: 处于Continues和Discrete之间
Constraints
: 冻结某一方面的transform
碰撞: Collider
组件
- 碰撞的条件: 两者都有
Collider
组件 & 至少一个GO有Rigidbody
组件 - 碰撞方法:
1
2
3
4
5
6
7
8
9
10
11
12private void OnCollisionEnter(Collision collision){
//collision.colider: 与之碰撞的物体的collider
//collision.gameObject: 与之碰撞的GO对象
}
private void OnCollisionStay(Collision collision){}
private void OnCollisionExit(Collision collision){}
private void OnTriggerEnter(Collider other){
//other就是触发的collider
}
private void OnTriggerStay(Collider other){}
private void OnTriggerExit(Collider other){} Material
: 使用Physical Material
文件, 创建Friction
摩擦力Bounciness
: 弹力, 1没有能量损失Xx Combine
: 两个摩擦GO时如何计算
铰链关节,弹簧关节和固定关节: Hinge Joint
,Spring Jonit
和Fixed Joint
组件
Anchor
: 轴原点Axis
: 轴向量
射线检测
1 |
|
粒子系统: Partical System
组件
Prewarm
: 从stop开始时, 是否从0逐渐展开Start Lifetime
: 粒子在空中的存在时间3D Start Size/Rotation
: 开启后转换为3D粒子;默认为面向Camera的平面粒子Flip Rotation
: 水平翻转旋转Gravity Modifier
: 粒子重力效果Constant
: 固定值,[-1上重力,1下重力]Curve
: 受力曲线
Simulation Space
: 生成的粒子是否随GO移动而移动;Local随,World不随,Custom绑定其他GO
线段和拖尾: LineRenderer
和TrailRenderer
组件
旧动画: Animation
组件
Culling Typ
: 是否一直播放动画- 动画窗体: ctrl+6
- 使用类似AudioSource: Play(),animation clip
新动画: Animator
组件
Controller
: 由AnimatorController.controller
资源文件控制Culling Mode
:Cull Update Transforms
表示不在镜头时暂停渲染,Cull Completely
表示不在镜头时完全停止- 在Window-Animation中创建不同的动画资源
.anim
文件, 在Window-Animator中作为不同的动画状态State
进行管理 .controller
文件包含了三方面内容:- 对
.anim
文件的引用 - 对
.anim
文件的设置 .anim
文件之间的相互连接关系
- 对
动画的构成: anim
文件
Rig
-Animation Type
: 动画类型- 无: 不包含动画
Legacy
旧版: 只能用Animation
旧版动画组件Generic
泛型: 新版动画, 各种非人动画Humanoid
人型: 新版动画, 用于人
Rig
-Avatar
骨骼: 从模型或从其他地方Animation
: 对动画Clip进行细操Loop Match
: 首位帧是否相似Bake Into Pose
: 烘焙特定方向的位移, 避免在动画过程中发生位移Curves
曲线: 随动画播放时间的函数曲线, 其值同步在animator
的同名parameters
中Events
事件: 在动画的某一帧调用函数(如脚步踏地时发出脚步声)
Blend Tree
in AnimatorWindowContext: 混合动画(如走和跑的混合)Blend Type
混合模式: 由几个变量控制混合动画的计算, 变量在animator
的同名parameters
中Motion
: 选择混合的动画Automate Thresholds
: 是否默认各个Motion
的取值范围
Sub-State Machine
in AnimatorWindowContext子状态机: 不同的动画状态的分组归类- 如拿枪到一个子状态中, 换刀到另一个子状态中
Base Layer
: 动画状态图层Weight
:权重;Mask
: Avatar骨骼遮罩;IK
: 反向动力学效果;- 不使用
Mask
可以通过控制Weight
获得同Blend Tree
一样的效果, 使用Mask
可以精确实现不同部位动画的混合
导航系统(需要在PackageManagement中安装AI Navigation
组件)
1.静态障碍物
- 首先将道路GO勾选为
Navigation Static
, 然后在选择Window - AI - Navigation设置烘焙; 接着将PlayerGO添加NavMeshAgent
组件 Bake
: 烘焙Agent的半径, 高度, 可上最大坡度Slope, 台阶每一阶步高, 可掉落的高度, 可跳跃的距离. (可以添加多个Agent, 作为高矮胖瘦不同的人)掉落高度
和跳跃距离
是通过生成OffMeshLinks
实现, 需要勾选需要生成links的障碍物GO的Object
-Generate OffMeshLinks
Area
: 不同区域的成本消耗设置, 在Object
-Navigation Area
中更改Nav Mesh Agent
组件:Steering
: 位移相关Acceleration
: 加速度
Obstacle Avoidance
-Priority
: 一个路口多个Agent待通过时的优先级Area Mask
区域遮罩: 特定区域永远不可通过, 用于针对不同Agent设定不同的禁止区域
- 代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13//前面获取代理组件
using UnityEngine.AI;
NavMeshAgent agent = GetComponent<NavMeshAgent>();
//在Update方法中逐帧更新:
if(GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit)) //从屏幕点击到3D位置坐标
{
agent.SetDestination(new Vector3(hit.point)); //将坐标设为destination
}
}
2.动态障碍物
- 将特定的某些GO取消勾选
Navigation Static
, 并添加NavMeshObstacle
组件Carve
切割: 勾选后会根据该GO的位移重新烘焙原有的静态障碍道路Move Threshold
移动阈值: 最小移动多远时开始rebakeTime to Stationary
静止时间: 移动阈值后经过多少秒开始rebakeCarve Only Stationary
仅在静止时切割: 取消后会随着位移即时rebake, 性能消耗较大
3.点对点定点传送: Off Mesh Link
组件
Auto Update Position
: 当GO位置改变时, 即时更新Link
; 如果位置不会改变就取消,以降低能耗
UI
UI
由Canvas
和EventSystem
两个GO组成,Canvas
为所有UI控件GO的父物体Canvas
组件:Render Mode
:OverLay
: 永远在最上层Camera
: 可被其他GO覆盖World Space
: 在3D世界中的一层平面, 可旋转
Sort Order
: 多个Canvas
时的渲染优先级
Image
组件:Raycast Target
: 是否接收射线投射Anchors
: 缩放参照锚点Pivot
: 图片的轴心, 图片的旋转缩放坐标都是由轴心控制- 字体: 新版更清晰, 富文本更多
Color Gradient
: 颜色渐变