Lec01 概览
- 修改位置
transform.Translate();
transform.position += new Vector3(0, 0, 5* Time.deltaTime);
- 输入输出
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
- 触发器事件
public void OnTriggerEnter(Collider other){}
// 还有 OnTriggerStay, OnTriggerExit
- 移动时相机倾斜
Transform c = Camera.main.transform;
Quaternion cur = c.rotation;
Quaternion target = cur * Quaternion.Euler(0, 0, x * 0.1f);
Camera.main.transform.rotation = Quaternion.Slerp(cur, target, 0.5f);
Lec02 基本概念
1. 常用组件
| 名称 | 功能 |
|---|---|
| Transform | 提供位置、旋转、缩放、父子关系 |
| Light | 提供光源 |
| Camera | 摄像机 |
| Post Processing | 后期处理,调整画面的色彩、空间、光效、环境光遮蔽等 |
| Mesh Filter | 网格过滤器,用于指定网格 |
| Mesh Renderer | 网格渲染器, 渲染网格 |
| Skinned Mesh Renderer | 皮肤网格渲染器,用于带骨骼的模型 ,网格变形时伸缩面不会断开 |
| Collider | 各种碰撞体组件 |
| Character Controller | 内置的角色控制器组件 |
| Rigidbody | 刚体,物理系统 |
| Particle System | 粒子系统 |
| Audio Source | 音源 |
| Audio Listener | 音频侦听器 |
| Animator | 动画状态机 |
| Navmesh Agent | 导航代理 |
| Terrian | 地形 |
2. 获取组件
// 通过物体获取
collider = this.GetComponent<SphereCollider>();
collider = GetComponent<SphereCollider>();
// 通过组件获取
collider = transform.GetComponent<SphereCollider>();
物体上任一组件 可以代表物体; transform 字段直接获取 Transform组件
// 获取 多个同名组件
MyScript[] myScripts = GetComponents<MyScript>();
GetComponents 获取组件数组
3. 获取物体
- GameObject
// 通过名称获取, 未激活的找不到
GameObject player = GameObject.Find("Player");
// 通过标签获取
player = GameObject.FindGameObjectWithTag("Player"); // 查找第一个
GameObject[] players = GameObject.FindGameObjectsWithTag("Player"); // 查找所有
- transform
| 方法 | 用途 |
|---|---|
| transform.Find | 沿着给定路径查找Transform组件,如 transform.Find("../uncle/sister") |
| transform.GetChild | 根据序号查找子物体 |
| transform.GetSiblingIndex | 获得该物体在兄弟节点之间的序号 |
| transform.IsChildOf | 判断是否是子物体 |
| 属性 | 用途 |
|---|---|
| transform.parent | 获取父物体 |
| transform.root | 获取根物体 |
| transform.childCount | 获取子物体总数 |
- 直接通过公开变量 引用物体
4. 创建物体
/* 通过 预制体 创建物体 */
Instantiate(prefab, transform); //指定父物体
Instantiate(prefab, null); // null表示没有父物体,置于场景根节点
Instantiate(prefab, new Vector3(0,0,0), Quaternion.Indentity);// 指定位置朝向
/* 创建 组件 */
myGameObject.AddComponent<Rigidbody>();
/* 销毁 */
Destory(myGameObject); // 调用该方法,会在之后合适时机去销毁
DestoryImmediate(); // 立即销毁
Destory(myGameObject, 0.8f); //0.8s后销毁
/* Invoke 定时创建 */
public GameObject prefab;
public float r = 2.0f;
int c = 0;
void Start()
{
Invoke("CreatePrefab", 0.5f);
}
void CreatePrefab()
{
Vector3 pos = new Vector3(r*Mathf.Cos(2*Mathf.PI*c/12), 0.5f, r*Mathf.Sin(2*Mathf.PI*c/12));
c++;
Instantiate(prefab, pos, Quaternion.identity);
if (c < 12)
{
Invoke("CreatePrefab", 0.5f);
}
}
5. 脚本的生命周期
脚本生命周期 MonoBehaviour Lifecycle,
可以理解为脚本从创建到销毁的过程中触发的各种事件。
常用脚本事件:Awake Start FixedUpdate
OnCollisionEnter Update 渲染 OnGUI
OnDestory
/* 跟随的相机 */
public class FollowCam : MonoBehaviour
{
public Transform followTarget;
Vector3 offset;
void Start()
{
offset = transform.position - followTarget.position;
}
void LateUpdate() // 确保被跟随物体移动后,再移动相机
{
transform.position = followTarget.position + offset;
}
}
6. 协程
// 协程实现 定时创建
public GameObject prefab;
public float r = 2.0f;
void Start()
{
StartCoroutine(CreatePrefabCor());
}
IEnumerator CreatePrefabCor()
{
for (int i = 0; i < 12; i++)
{
Vector3 pos = new Vector3(r*Mathf.Cos(2*Mathf.PI*i/12),0.5f,r*Mathf.Sin(2*Mathf.PI*i/12));
Instantiate(prefab, pos, Quaternion.identity);
yield return new WaitForSeconds(0.5f);
}
}
Lec03 物理系统
1. 基本概念
- 刚体
Rigidbody组件以及Rigidbody2D组件。已经挂载该组件的物体,不宜通过脚本直接修改位置或朝向,而是通过施加力、修改速度、修改角速度来实现。运动学(Kinematic)则是挂载该组件,但运动不受物理控制。运动学刚体在需要碰撞检测时依旧被系统处理,带来一些性能开销。 - 休眠
当一个刚体“停止”一段时间,直到再次受到力的影响之前,物理引擎都不再反复计算其运动,刚体进入休眠状态。刚体的休眠和唤醒一般都是自动进行。 - 碰撞体
碰撞体定义物理外形,一个物体可以挂载多个碰撞体组件,也可以通过子物体挂载实现。- 分为 静态碰撞体,刚体碰撞体, 动力学刚体碰撞体
- 两个碰撞体发生碰撞,至少有一个刚体碰撞体。
- 不需要移动的障碍物做成静态碰撞体,需要移动的做成动力学刚体碰撞体。
- 两个障碍物之间碰撞,不受外力的做成动力学刚体,受外力的做成普通刚体。
- 触发器
碰撞体组件勾选IsTrigger属性。作为触发器的物体不再是物理上的固体,允许其他物体从中穿过。 - 物理材质
/* Physics Material 可调参数:*/
Dynamic Friction //动态摩擦系数
Static Friction //静态摩擦系数
Bounciness //弹性系数
Friction Combine //与其他物体接触时的摩擦力系数算法
Bounce Combine //... 的弹性系数算法
- 层,物理关节,射线检测,角色控制器
2. 脚本编程
- 刚体运动
// 修改刚体位置
if (Input.GetKeyDown(KeyCode.Space))
{ // 实现多段跳跃,跳跃时跳跃方向速度置零,效果更好。
rigid.velocity = new Vector3(rigid.velocity.x, 0, rigid.velocity.z);
rigid.AddForce(new Vector3(0, jumpForce, 0));
}
- 射线检测
// Physics.Raycast() 常用重载
bool Raycast(Vector3 origin, Vector3 direction, float maxDistance, int layerMask);
Ray ray = new Ray(Vector3 origin, Vector3 direction);
bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
// RaycastHit 射线碰撞信息
Vector3 point = hitInfo.point; // 碰撞点
Collider coli = hitInfo.collider; // 碰撞体组件
Transform trans = hitInfo.transform; // 获取transform组件
Vector3 normal = hitInfo.normal; // 碰撞点的法线向量
// 穿过多个物体的射线
Physics.RaycastAll();
// 区域覆盖性射线 Physics.Overlap...
Collider[] OverlapSphere(Vector3 position, float radius, int layerMask);
// 射线调试
Debug.DrawLine(Vector3 start, Vector3 end);
Debug.DrawLine(Vector3 start, Vector3 end, Color color, float duration);
Debug.DrawRay(Vector3 start, Vector3 dir);
Debug.DrawRay(Vector3 start, Vector3 dir, Color color, float duration);
- FixedUpdate
与Update不同的是,物理更新的时间间隔默认0.02秒。刚体的运动属于物理更新,因此追随刚体运动的相机应当在FixedUpdate中实现。 - 更多施加力的方式
// 施加角速度, 刚体存在angularDrag角阻尼,会慢慢停下
rigid.angularVelocity = new Vector3(0,10,0);
// 修改质心, 使用本地坐标系
rigid.centerOfMass = new Vector3(0, -10, 0);
// 在给定位置施加力
void AddForceAtPosition(Vector3 force, Vector3 position, ForceMode mode);
// 其中 力的模式,是一个枚举类型,修改让力的作用方式发生变化。
// 刚体约束, 在Inspector直接修改,或:
rigid.constraints = RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezeRotationY;
Lec04 数学基础
1. 坐标系
transform.position //世界坐标系
transform.localPosition //局部坐标系
Camera.main.ScreenToViewportPoint(Input.mousePosition); // 鼠标指针在屏幕上的位置
transform.TransformPoint(); // 局部 -> 世界
transform.InverseTransformPoint(); // 世界 -> 局部
transform.Translate(Vector3.forward); // 物体沿自身前方前行
{
Vector3 worldToLocal = transform.InverseTransformDirection(Vector3.forward);
transform.Translate(worldToLocal); // 物体沿世界前方前行 ,即z轴
}
原因:Translate方法 默认以局部坐标系 为基准,前者将Vector3.forward默认为自身前方; 后者先将世界前方转换为局部坐标系,再移动。
2. 向量
/* 方法 */
Cross() // 叉乘
Dot() // 点乘
Project() // 投影
Angle() // 角度
Distance() // 距离
/* 属性 */
x、y、z // 分量
normalized // 标准化向量
magnitude // 长度
sqrMagnitude // 长度平方
3. 四元数
- 万向节锁定问题
欧拉角的3个轴存在嵌套结构,以yxz为例,当中间的轴转动带动最内层的轴,使得内层轴和外层轴重合,从而缺失了一个方向的转动,发生万向节锁定。 - 四元数
/* 方法 */
* // 相乘表示依次旋转
Euler() // 由欧拉角得到一个四元数
Slerp() // 球面插值
Lerp() // 插值
LookRotation() // 由向量得到四元数
/* 属性 */
x、y、z、w // 分量
eulerAngles // 获得对应的欧拉角
identity // 获得无旋转的四元数
- 四元数乘法不满足交换律:
旋转 * 旋转: 按照旋转的坐标系坐标轴 依次旋转
旋转 * 朝向 or 朝向 * 旋转: 得到新的朝向
旋转 * 向量: 得到新的向量 - Slerp球面插值
static Quaternion Slerp(Quaternion a, Quaternion b, float t);
- 朝向
/* 物体朝向鼠标拖拽的方向 */
if (Input.GetKey(KeyCode.Mouse0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
Vector3 target = hitInfo.point - transform.position;
target.y = transform.position.y; // 实现 平视
transform.forward = target; // 赋值时 自动标准化
}
}
- FPS角色控制
// 隐藏鼠标指针
Cursor.visible = false;
// 锁定鼠标到屏幕中央
Cursor.lockState = CursorLockMode.Locked;
__________________________________
// 鼠标控制转向
float mx = Input.GetAxis("Mouse X");
float my = - Input.GetAxis("Mouse Y"); // 左手坐标系
Quaternion qx = Quaternion.Euler(0, mx, 0);
Quaternion qy = Quaternion.Euler(my, 0, 0);
transform.rotation = qx * transform.rotation; // 绕y 世界坐标系
transform.rotation = transform.rotation * qy; // 绕x 局部坐标系
Lec05 UI系统
1. Rect Transform 矩阵变换组件
Anchor Presets : 调整控件的对齐方式,选择Stretch拉伸模式,偏移为零时将铺满整个父控件。
2. Image 图片组件
Soure Image : 图片源
Color : 修改图片叠加颜色
Material : 修改图片材质,一般为空
Raycast Target : 射线检测目标
Image Type : 图片类型,Simple、Sliced、Tiled、Filled
Set Native Size : 重置整个图片为原始像素大小
Preserve Aspect : 保留长宽比,图片类型为简单和填充时,勾选该选项在拉伸图片时长宽比例不变
3. Text 文本组件
Horizontal Overflow : 横向超出,分Wrap折行、Overflow超出
Vertical Overflow : 纵向超出,分Truncate丢弃、Overflow超出
4. Button 按钮组件
Interactable : 是否可交互
Transition : 外观状态切换方式
Navigation : 导航顺序
OnClick() 事件
5. Toggle 单选框组件
Is On : 勾选
Group : 单选框组,同一组的单选框只有1个可勾选
6. Slider 滑动条组件
Interactable : 是否可交互
Fill Rect : 填充区域
Handle Rect : 手柄区域
Direction : 滑动条方向
Whole Numbers : 勾选后数值都取整
Value : 滑动条数值
7. Input Field 输入框组件
Charater Limit : 字符数量限制,限制用户输入的最大字符数量
Content Type : 输入格式,Standard、Password、Integer Number、Email Adderss
Line Type : 指定单行或多行
Place Holder : 占位符,提示用的字符
光标选项: Caret Blink Rate闪烁频率、Caret Width、Custom Caret Color
Selection Color : 选中颜色
8. Scroll Rect 组件
Horizontal : 是否可以横向滚动
Vertiacl : 是否可以纵向滚动
Movement Type : 移动方式,有Elastic、Clamped、Unrestricted
Elasticity : 弹性
Inertia : 惯性,开启后指定 Decelaration Rate 减速率
Scroll Sensitivity : 滚动灵敏度
指定滚动条的Visibility : Permanet 始终显示、Auto Hide、Auto Hide And Expand Vierport
9. Canvas 画布组件
Render Mode : 渲染模式
- Screen Space -Overlay : 画布与场景无关,直接渲染在游戏的最上层。
- Screen Space -Camera : 整个画布会像普通物体一样被摄像机渲染,而且正好和摄像机视野一样大,贴合画面且具有一定的z轴深度。
- World Spcae : 画布彻底变成一层普通物体,UI画布整体可以旋转、缩放、移动,适合UI于游戏场景交互的互动式游戏。
10. Canvas Scaler 画布缩放器组件
Scale Match Mode : 屏幕适配模式
- Match Width or Height : 自行选择优先匹配宽度或高度
- Expand : 将内容适当放大到满足画布的长或宽的任意一边。
- Shrink : 将内容一直放大到同时满足长和宽。
9. Event System
17种输入事件。事件的参数有BaseEventData、PointerEventData、AxisEventData,前者是后两者的基类。
通过Event Trigger事件触发器触发输入事件,参数是BaseEventData,可以将其转为派生类:
PointerEventData pevt = bevt as PointerEventData;
为按钮组件添加响应函数:
myBtn = GetComponent<Button>();
myBtn.onClick.AddListener(() => { Debug.Log("click!"); });
| 接口名称 | 说明 |
|---|---|
| IPointerEnterHandler | 鼠标进入 |
| IPointerExitHandler | 鼠标离开 |
| IPointerDownHandler | 鼠标按下 |
| IPointerUpHandler | 鼠标抬起 |
| IPointerClickHandler | 鼠标点击一次 |
| IInitializePotentialDragHandler | 发现可拖拽物体 |
| IBeginDragHandler | 开始拖拽 |
| IDragHandler | 拖拽中 |
| IEndDragHandler | 停止拖拽 |
| IDropHandler | 拖拽释放 |
| IScrollHandler | 鼠标滚轮 |
| IUpdateSelectedHandler | 选中物体时反复触发 |
| ISelectHandler | 物体被选择 |
| IDeselectHandler | 物体被取消选择 |
| IMoveHandler | 物体移动 |
| ISubmitHandler | 提交按钮按下 |
| ICancelHandler | 提交按钮取消 |