Unity2019 从零到精通视频学习笔记
Unity2019 从零到精通视频学习笔记
该文对Unity2019 做简单的自学了解,并做相应的笔记
文章目录
- Unity2019 从零到精通视频学习笔记
- 一、C#基础回顾
- 基本数据结构
- 面向对象数据结构
- 异常处理
- 事件
- 异步编程
- 数据库和文件操作
- 二、引擎基本介绍
- 三、场景管理
- 四、物体管理
- 五、组件管理
- 六、UGUI图形系统
- 七、用户输入管理
- 八、自然环境设计
- 九、光照系统
- 十、3D模型管理
- 十一、物理系统
- 十二、动画系统
- 十三、寻路系统
- 十四、音效系统
- 十五、特效系统
- 十六、视频播放管理
一、C#基础回顾
基本数据结构
简单的控制台程序
namespace ConsoleApp1 {class Program{static void Main(string[] args){System.Console.WriteLine("Hello World");}} }
类型转换
//int->stringint a = 10;string strA = a.ToString();//string->intString b = "10";int iB = int.Parse(b);//使用Convert转换iB = Convert.ToInt32(b);
数组
//一维数组int[] a = { 1, 2, 3, 4, 5 };int[] b = new int[5];//注意,只声明数组长度Array.Copy(a, b, 5);//b的元素必须提前声明好foreach(int i in b){System.Console.WriteLine(i);}System.Console.WriteLine("{0}, 找到1首次出现的位置:{1}", b[0], Array.IndexOf(b, 1));//多维数组int[,] c = { { 1, 2, 3 }, { 4, 5, 6 } };System.Console.WriteLine(c[0, 1]);//string和stringbuilderString name = "wang", name2 = "li";StringBuilder names = new StringBuilder();names.Append(name);names.Append(name2);System.Console.WriteLine(names);
面向对象数据结构
基本使用
class Test{private String strTitle;public string GetMessage(){return "Message";}public string title{get{return strTitle;}set{strTitle = value;}}}
ref和param
class Program{/// <summary>/// 测试使用REF,传递引用类型/// </summary>/// <param name="a"></param>/// <param name="b"></param>static void TestRef(ref int a, ref int b){int tmp = a;a = b;b = tmp;}/// <summary>/// 测试使用params,传递无限制参数列表/// </summary>/// <param name="names"></param>static void TestParam(params String[] names){foreach(string name in names){System.Console.WriteLine(name);}}static void Main(string[] args){int a = 10, b = 15;TestRef(ref a, ref b);System.Console.WriteLine("{0}, {1}", a, b);TestParam("zhang", "li", "wang");}}
继承和多态
- abstract适合写非纯虚函数,interface适合写纯虚函数
- C#没有public、protect、private继承
- C#不存在多继承,只能继承一个类和多个接口
interface Study{void Read();void Listen();void Say();void Write();}abstract public class People{private string name;private int age;public People(string name, int age){this.name = name;this.age = age;}abstract public void Hello();}sealed public class Student: People, Study{Student(string name, int age): base(name, age){}public override void Hello(){System.Console.WriteLine("Hello");}public void Listen(){}public void Read(){}public void Say(){}public void Write(){}}
集合索引和泛型
//使用arraylist,注意这种类型可以插入任何类型,但需要拆包//如果不希望拆包,可以使用Array<int>ArrayList arrayList = new ArrayList(5);arrayList.Add(1);int b = (int)arrayList[0];//使用StackStack objStack = new Stack();Stack<int> iStack = new Stack<int>();//使用QueueQueue queue = new Queue();//使用List(必须要指定类型)List<int> iList = new List<int>();//使用Dictonary(必须要指定类型)Dictionary<int, string> keyValuePairs = new Dictionary<int, string>();
泛型
//这里使用where是一种约束,也就是T必须继承自Interface1class TempClass<T> where T: Interface1{void TestSay(T obj){obj.Say();}}
反射
- 一般不建议使用反射,反射破坏程序的封装性
- 反射可以遍历程序的名称,函数名等,也可以直接根据程序名创建对象和调用函数
public class Test{private string name;public Test(String name){this.name = name;}public void Print(){System.Console.WriteLine(this.name);}}static void Main(string[] args){//创建程序集名Test t = new Test("t");Type type = t.GetType();System.Console.WriteLine(type);//根据程序集名创建对象Type type2 = Type.GetType("ConsoleApp1.Program+Test");object[] constStructParams = new object[] { "t2" };Object t2 = Activator.CreateInstance(type2, constStructParams);((Test)t2).Print();//指定函数名调用MethodInfo info = type2.GetMethod("Print");object[] constStructParams2 = new object[] { };info.Invoke(t2, constStructParams2);}
异常处理
调试和异常处理
public static void Test(int a){if(a == 0){throw new Exception("参数不能为0");}}static void Main(string[] args){try{Test(0);}catch (Exception e){Console.WriteLine(e);}finally{Console.WriteLine("Finially");}}
事件
事件和委托
- delegate相当于函数指针,可以指向多个函数,可以在内部或外部调用。
- event只能在内部调用。
class Program{class EventTest{public delegate void GetMessage(string msg);public GetMessage GetMessageDelegate;public event GetMessage GetMessageEvent;public void RaiseEvent(){GetMessageEvent("Hello");}}static void Main(string[] args){EventTest test = new EventTest();test.GetMessageDelegate += OnGetMessage;test.GetMessageDelegate("Delegate");test.GetMessageEvent += OnGetMessage;test.RaiseEvent();}static void OnGetMessage(string msg){System.Console.WriteLine("OnGetMessage: {0}", msg);}}
异步编程
线程
- 线程
class Program{static void Main(string[] args){{Thread t = new Thread(new ThreadStart(Run));t.Start();}{Thread t = new Thread(new ThreadStart(new ThreadTest().MyThread));t.Start();}{Thread t = new Thread(new ThreadStart(delegate() {Console.WriteLine("匿名委托");}));t.Start();}{Thread t = new Thread(()=>Console.WriteLine("箭头函数"));t.Start();}{Thread t = new Thread(new ParameterizedThreadStart(RunPara));t.IsBackground = true;//后台线程,程序可以直接退出而不等线程结束t.Start("向线程中传递参数,参数必须是Object类型");t.Join();}}static void Run(){Console.WriteLine("静态函数");}static void RunPara(object str){Console.WriteLine(str);}}class ThreadTest{public void MyThread(){Console.WriteLine("成员函数");}}
匿名委托,lambda表达式,Action和Func
- 匿名委托和lambda表达同价
- Action和Func可以直接定义函数传入参数的类型,Func要求必须有返回结果,Action要求没有返回结果。
- Delegate和Action、Func相比,多出了一次声明函数类型的过程。
- 定义event可以使用Action或Func代替delegate
public delegate void FuncDelegate(int c);static void Main(string[] args){Func<int, int> func = delegate (int c) { return c; };Action<int> action = (int a) => { Console.WriteLine(a); }; FuncDelegate funcDelegate = delegate (int a) { Console.WriteLine(a); };}
async/await
- aysnc和await和Task配合使用。
- await必须在async的函数中使用。
- 一般不会使用Task去获取Result,这样会造成线程卡死。
class Program{static void Main(string[] args){{//直接使用Task,获取异步返回结果Task<int> task1 = new Task<int>(() => {return 1;});task1.Start();Console.WriteLine(task1.Result);}{Console.WriteLine(GetResultAsync().Result);}}static public async Task<int> GetResultAsync(){//Task<int> task = new Task<int>(()=> { return 1; });Task<int> task = Task.Run<int>(() => { return 1; });return await task;}}
协程
- 目前C#本身并没有有关协程的定义,在Unity3D库中有定义。
数据库和文件操作
- ADO和LINQ
- ADO主要突出了对数据库的操作。LINQ将SQL语句和C#语句融合在了一起,简化了操作的处理。
- 文件操作
- 文件操作使用StreamReader和StreamWriter操作。
- ADO和LINQ
二、引擎基本介绍
本次学习使用引擎是Unity 2019.2.12f1版本。
建议使用Unity Hub来管理Unity版本和授权。
Unity官网是unity.cn
Unity在场景的操作方式和UE4基本一致
在[Unity - Manual: Order of Execution for Event Functions](file:///D:/Program Files/Unity/2019.2.12f1/Editor/Data/Documentation/en/Manual/ExecutionOrder.html)可以找到事件函数的执行顺序
Awake:不管脚本是否激活,都会被执行
Start:游戏开始
Update:游戏刷新的时候
FixedUpdate:固定刷新,0.02s调用一次
LateUpdate:在Update之后被调用
素材管理
导入导出图片
- 导入新资源
- 向场景中插入UI.Button
- 将图片类型设置成UI/Sprit
- 将图片应用于按钮
视频和音频
导入音频
向Canvas中添加组件 音频源,设置导入的音频
向Canvas中添加音频监听器
导入视频
创建原始图像
创建渲染器纹理
将将渲染器纹理拖拽到原始图像.纹理的选项上
在原始图像创建组件 视频播放器,将渲染器纹理和视频剪辑分辨拖拽到视频播放器中
字体和粒子特效
- 一般导入比较简单,或者是美工已经做好打包的结果
模型和场景
- 一般注意如果是自己导入FBX和贴图,先导入贴图,然后导入FBX,才能实现绑定材质。
脚本
- 可以使用Debug.Log打印日志查看问题。
- 可以选择出错后终止,查看问题。
- 可以选择附加到Unity,在任何地方断点调试。
三、场景管理
同步加载场景
异步加载场景
加载场景时保留物体
首先在文件-build settings,将两个场景拖入到Build中的场景
SceneManager.LoadScene("SampleScene", LoadSceneMode.Additive);
- 第二个选项设置是同步加载还是异步加载。
- 第一个选项可以设置场景的下标,但一般不建议使用下标。
GameObject Cube = GameObject.Find("Sphere");DontDestroyOnLoad(Cube);
设置某个场景的物体不会被消除
使用协程进行异步加载
void Start(){StartCoroutine(Load());}private IEnumerator Load(){AsyncOperation asyncOperation = SceneManager.LoadSceneAsync("Scenes/SampleScene");asyncOperation.allowSceneActivation = false;while(asyncOperation.progress < 0.9f){Debug.Log(asyncOperation.progress);yield return null;}asyncOperation.allowSceneActivation = true;if(asyncOperation.isDone){Debug.Log("加载跳转完毕");}else{Debug.Log("加载没有跳转完毕");}}
- 可以认为协程是每一帧时会执行的语句,当yield return null;程序会临时返回一个结果,并等待下一帧时继续执行。
四、物体管理
- 标签和图层
标签和层级主要用于编程中搜索物体和过滤物体
预制件
创建
可以将场景中内容拖拽到资源中,保存成预制件,预制件一般只能保存一份。
预制件默认放在Resources文件夹下,可以通过API索引到预制件
//创建GameObject go = Resources.Load<GameObject>("Object/Sphere");GameObject.Instantiate(go);
如果没有放在Resources文件夹下,可通过public 变量传入预制件。
使用脚本对物体交互
//创建//GameObject go = Resources.Load<GameObject>("Object/Sphere");//GameObject.Instantiate(go);查找,如果要查找子物体,可以使用/寻找到子物体。//GameObject go1 = GameObject.Find("Sphere");//go1.SetActive(false);//查找(按照标签查找)GameObject go2 = GameObject.FindGameObjectWithTag("Hero");//go2.SetActive(false);go2.name = "Cube02";//go2.transform.position = Vector3.zero;go2.transform.position = new Vector3(0, 0, 0);//go2.transform.rotation = Quaternion.Euler(0, 90, 90);go2.transform.eulerAngles = new Vector3(0, 90, 90);//销毁Destroy(go2);
五、组件管理
查找组件
- GetComponent(s)<>:查找当前组件
- GetComponent(s)InChildren<>:查找组件自己和子元素
- GetComponent(s)InParent<>:查找组件自己和父元素
GameObject go = GameObject.Find("Text");go.GetComponentInChildren<Text>().text = "查找到组件";
禁用组件
- 组件中包含enable属性,可以用来关闭组件
- 使用Destory可以删除组件
六、UGUI图形系统
画布与事件系统
- 画布的渲染空间
- 屏幕空间-覆盖:看不到其他物体
- 屏幕空间-摄像机:可以看到在Canvas前面的3D物体
- 世界空间:Canvas本身可以移动到相机视线之外
- UI缩放模式
- 恒定像素大小
- 屏幕大小缩放:一般选择此模式,分为宽度匹配和高度匹配
- 恒定物理大小
- EventSystem
- 必须存在
- 在运行的时候可以看到事件系统的基本信息
- 画布的渲染空间
文本
- 最佳适应:能够根据文本框自己调节字体的大小
输入框
- 内容类型:文本、密码
- 输入框自己包含两个子物体:占位符和真实文本
首先先自己尝试按照流程创建用户界面
并实现三个需求:
- 点击登录,在控制台输出账号和密码
- 替换背景图片
- 点击官网,跳转到指定URL
InputField userInput;InputField pwdInput;Button loginBtn;public Sprite bg;// Start is called before the first frame updatevoid Start(){userInput = transform.Find("EditAccount").GetComponent<InputField>();pwdInput = transform.Find("EditPassword").GetComponent<InputField>();loginBtn = transform.Find("Login").GetComponent<Button>();loginBtn.onClick.AddListener(LoginBtnOnClick);//替换背景图片transform.Find("BG").GetComponent<Image>().sprite = bg;//打开网页transform.Find("website").GetComponent<Button>().onClick.AddListener(WebSiteOnClick);}void LoginBtnOnClick(){string account = userInput.text;string pwd = userInput.text;Debug.Log("Account:" + account);Debug.Log("Password:" + pwd);}void WebSiteOnClick(){Application.OpenURL("http://www.baidu.com");}
在编程的时候,注意:
- Find找到的控件只能包含孩子结点,不能包含孙子结点。
- 所有本身的对象为Transform,可以用transform获取到自身的对象。
- 不同组件拥有不同的能力,主要原因在于添加了不同的组件,需要找到合适的组件,才能修改其名字。
- 组件添加事件使用的是.OnXXX.AddXXXListener()
- 跳转到指定URL使用的函数是Application.OpenURL
Toggle
- 包含选择框和文本两个子控件,可以自由调节
- 包含IsOn属性,判断是否打钩
- 如果需要使用开关组,需要在“开关组”的选项中选择一个包含了开关组(ToggleGroup)的组件
滑动条
- 获取滑动条的值从属性value中获取
- 获取滑动条发生改变的事件是 onValueChanged
滚动视图
在UI中选择滚动视图,滚动视图中包含content是用来包含其他元素的容器,content的大小就是页面的大小。
可以选择水平Layout、垂直Layout、Grid Layout来对内容进行自动化的排序。
可以使用内容尺寸适配器(Content Size Fitter),内容尺寸适配器在垂直方向或水平方向可以根据内容自动跳转父元素的大小,设置Preferred Size,有时候对于文本也可以对根据内容做自适应。
滚动视图中包含一个Viewport,是使用遮罩的方法将其它的元素不显示,对于创建圆形头像等可以使用遮罩的方法。
GameObject用于预制件,Transform用于场景中任何物体的使用。
public GameObject Hero; public Transform Content; void Start() { }// Update is called once per frame void Update() {if(Input.GetKeyDown(KeyCode.A)){GameObject _hero = GameObject.Instantiate(Hero);_hero.transform.SetParent(Content);} }
可以自定义类似于滑动条的组件
创建父子两个Image
给子Image添加任意一个原图像(实际测试发现对于半透明图像不可用)
设置好父子物体的颜色,选择图像类型为“已填充”,填充方法为水平。
通过代码修改填充总数,可以实现将子控件填充到对应百分比的位置。
其他常用组件
- Outline:增加边框
- Shadow:添加阴影
七、用户输入管理
虚拟轴
通过Input.GetAxis获取轴的值。
float h = Input.GetAxis("Horizontal");float v = Input.GetAxis("Vertical");if(h != 0){//transform.position = new Vector3(// h + transform.position.x,// transform.position.y,// transform.position.z// );transform.eulerAngles = new Vector3(h + transform.eulerAngles.x,transform.eulerAngles.y,transform.eulerAngles.z);}if(v != 0){//transform.position = new Vector3(// transform.position.x,// transform.position.y,// v + transform.position.z//);}
获取键盘事件
- 通过GetKey、GetKeyDown、GetKeyUp来获取键盘的按下状态。
- GetKey是每一帧都能获取按下状态,GetKeyDown和GetKeyUp只获取一次。
获取鼠标事件
- 通过Input.GetMousrButton、GetMouseButtonDown、GetMouseButtonUp来获取。
- 传入的值0表示鼠标左键,1为鼠标右键。
移动设备输入
- Input.touchCount获取有多少手指碰到了。
- Input.touches获取每一根手指的状态,finggerid是手指id、position为位置,deltaPosition是和上次相比移动的距离。
八、自然环境设计
- 天空盒的创建
- 一般使用6张图片创建天空盒或Cubemap创建天空盒。
- 首先创建一个材质,选择天空盒,将6张图片设置好,就可以将天空盒拖拽到场景中了。
- Cubemap全景图的后缀是hdr,导入后需要将纹理形状改成立方体,同样可以设置天空盒。
- 山脉和地表贴图的创建
- 可以在Unity Assert Store下载Terrain Tools XXX资源包去尝试使用。
- 在实际项目中,一般是公司的地模制作,该部分不做重点学习。
- 树和草的创建
- 水和雾
九、光照系统
灯光组件
灯光按照类型可以分为:方向光、点光、聚光、区域光。
一般区域光需要进行烘焙才能显示,且只能烘焙静态物体,烘焙在窗口-渲染-照明生成,选择混合照明中烘焙全局照明,然后可以选择自动生成,就会看到烘焙后的照明效果。
可以设置阴影的强度和硬度。
照明设置
可以在照明设置环境光以及天空盒
可以选择混合模式,是否开启烘焙照明
可以选择光照贴图是CPU还是GPU
可以设置雾,当雾的密度调大时,会有浓雾的效果。
可以设置光晕:需要在光源处选择绘制光晕
可以设置炫光
- 首先创建炫光,设置纹理和纹理布局(一般是一维)
- 将创建的炫光赋值到指定的光源
自发光
- 自发光使用自发光材质实现,创建新的材质,选择发射。
- 可以选择一个发光贴图,以及选择发光颜色,强度。最终赋值给自发光物体即可。
- 自发光需要物体必须是静态的,也只能烘焙静态的物体。
光照探测器
- 光照探测器相当于记录了不同点的光照信息,从而可以实时动态的获取一些需要烘焙的光源的光照。
- 光照探测器用于渲染非静态物体。
- 建议多创建一些光照探测器。
反射探测器
- 反射探测器主要用于非常镜面的物体,例如光滑的地板
- 必须要求反射的物体具有镜面反射效果,相互配合才能看到反射探测器的效果。
十、3D模型管理
蒙皮网格与普通网格的对比
- 蒙皮网格主要是用于人物,放在人物在动画中材质被不正常拉伸。
材质的使用
- 导入项目资源包
- 能够从材质图片创建材质球
换肤功能的实现
能够使用代码替换人物衣服的材质
public SkinnedMeshRenderer body;public Material m1;public Material m2;// Update is called once per framevoid Update(){if(Input.GetKeyDown(KeyCode.A)){//换成第一件衣服body.material = m1;}else if(Input.GetKeyDown(KeyCode.S)){//换成第二件衣服body.material = m2;}}
十一、物理系统
3D物理系统
刚体:提供重力系统的物体
碰撞体:提供碰撞检测的物体,一般直接创建的物体都有碰撞体,碰撞体分为盒装、胶囊、平面等。
常用属性:
- 质量
- 阻力
- 角阻力
- 使用重力(Use Gravity)
- 是否符合运动学(Is Kinematic):不收到物理引擎驱动,物体静止不动,但有质量
- 碰撞检测:
- 约束条件:冻结某个轴,不受到物理引擎影响
恒力组件
绝对力:Force、相对力:RelativeForce:区别是是和世界坐标保持一致还是和自身坐标保持一致
绝对扭矩力:Torque、相对扭矩力:RelativeTorque
API和属性
- 刚体速度
- 添加力
- 添加爆炸力
rig = transform.GetComponent<Rigidbody>();//设定初始速度rig.velocity = new Vector3(10, 0, 0);添加力rig.AddForce(new Vector3(10, 0, 0));//使用爆炸力rig.AddExplosionForce(300, transform.position, 10);
- 在指定位置添加力:AddForceAtPosition
刚体休眠和唤醒
- 强制刚体休眠:Sleep
- 唤醒休眠中的刚体:WakeUp
碰撞器和触发器
常用属性
- 是触发器
- 物理材质:用于设置摩擦力和弹性
- Center中心
常用API
- OnCollisionEnter/OnTriggerEnter
- OnCollisionExit/OnTriggerExit
- OnCollisionStay/OnTriggerStay
触发器的使用
private void OnCollisionStay(Collision collision){Debug.Log("OnCollisionStay:" + collision.gameObject.name);}private void OnCollisionExit(Collision collision){Debug.Log("OnCollisionExit:" + collision.gameObject.name);}private void OnCollisionEnter(Collision collision){Debug.Log("OnCollisionEnter:" + collision.gameObject.name);}
物理材质
- 动态摩擦力、静态摩擦力
- 弹力
- 弹力、摩擦力结合模式:平均、最小、乘积、最大
关节组件
- 给指定的刚体添加弹簧关节,将另一个物体拖入连接的物体
- 类型
- 弹簧关节
- 直接连接两个刚体组件
- 铰链关节
- 创建铰链组件,连接
- 修改Anchor和轴的方向,时期和真实轴的方向相同
- Use Motor:使用马达
- Use Limits:使用角度限制
- 固定关节
- 两个物体相对位置固定
- 角色关节
- 模仿人物骨头的关节
- 可配置关节
- 连接的刚体
- 断开力:默认是无穷大,使用OnJointBreak(float Force) 处理断开的事件
射线
绘制射线
Debug.DrawLine/Debug.DrawRay:绘制线段(射线)
Debug.DrawLine(transform.position, transform.position + transform.forward, Color.red, 10, false);
Camera.ScreenPointToRay=>Physics.Raycast
void Update(){if(Input.GetMouseButtonDown(0)){Ray ray = camera.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if(Physics.Raycast(ray, out hit, 100f)){Debug.Log("命中了碰撞: " + hit.point + ",name: " + hit.collider.gameObject.name);}else{Debug.Log("没有命中碰撞");}}}
Physics.Raycast:检测碰撞
Physics.RaycastAll:返回所有碰撞数组
Physics.OverlapSphere:球形射线,返回碰撞数组
2D物理系统
2D刚体和碰撞器
- 一般在Canvas中创建Image或RawImage(区别:Image要比RawImage更加强大,Image主要处理图片类型,RawImage主要用于纹理类型的)
- 在创建碰撞器的时候,需要指定大小,一般需要手动指定大小和2D物体大小一致。
2D表面效果器
- 用于设置2D物体在表面的初始速度、力
- 必须在碰撞器上勾选:由效果器使用
2D区域效果器
- 在区域内施加的力
- 需要勾选:是触发器、由效果器使用
2D浮力效果器
- 在区域内收到浮力影响
2D点效果器
- 在区域内受到引力或斥力
十二、动画系统
动画启动播放控制
使用按键控制动画播放
创建动画器控制器
将一些动画拖入到动画器控制器中
在动画器选项卡中添加参数id,类型为int
设置动画器控制器的进入不同状态的条件
在模型上添加动画器,设置好动画器控制器和Avatar
编写脚本,控制动画器的值
Animator am;void Start(){am = transform.GetComponent<Animator>();}void Update(){if(Input.GetKeyDown(KeyCode.Alpha0)){am.SetInteger("id", 0);}else if(Input.GetKeyDown(KeyCode.Alpha1)){am.SetInteger("id", 1);}else if (Input.GetKeyDown(KeyCode.Alpha2)){am.SetInteger("id", 2);}else if (Input.GetKeyDown(KeyCode.Alpha3)){am.SetInteger("id", 3);}else if (Input.GetKeyDown(KeyCode.Alpha4)){am.SetInteger("id", 4);}}
选择跳转条件,取消对“可以过度到自己”的勾选。
如果希望动画可以循环,选择动画,勾选循环时间。
如果希望无延迟的切换到其它的动画,可以取消“有退出时间”
人形动画
- 尝试使用其它人物角色的动画(实际操作)
- 在检查器中可以看到人形动画的骨骼(实际操作)
动画遮罩
- 了解对于非人物角色和人物角色动画遮罩的过程。(实际操作)
- 对于非人物遮罩,使用的是转换,指定具体的Avator,取消勾选一些不需要遮罩的骨骼。
- 在层总指定具体的遮罩。
- 可以创建不同的层,然后使用不同的动画遮罩,实现动作的混合。
- 了解对于非人物角色和人物角色动画遮罩的过程。(实际操作)
动画事件
- 动画事件是在界面中添加的,播放指定的动画,在指定的帧处添加事件的响应函数。(实际操作)
十三、寻路系统
制作一个点击自动寻路程序
先搭建一个场景
将场景中的物体设置为导航静态(在检查器-静态下拉菜单中设置)
打开烘焙窗口:窗口-ai-烘焙
切换到烘焙选项卡,进行烘焙,如果模型非常的小,需要设置好半径等参数才能看到烘焙的结果。
向人物增加组件——导航网格代理
添加脚本
NavMeshAgent agent;void Start(){agent = GetComponent<NavMeshAgent>();}void Update(){if(Input.GetMouseButtonDown(0)){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;bool isCollider = Physics.Raycast(ray, out hit);if(isCollider){agent.SetDestination(hit.point);}}}
重要属性
- 代理半径、代理高度等
- 区域和成本:在区域内有一个设置成本的按钮,一般导航选择成本最低的路线。可以在对象中选择某一段路导航区域的类型,然后重新进行烘焙。
- 生成分离网格连接可以设置从高处跳跃的最大高度和最远距离。
- 必须在对象选项卡中勾选 生成网格连接(Generate OffMeshLinks),才能生成连接
动态障碍物
- 可以使用导航网格障碍禁止两个地方的导航连接
- 实际测试导航障碍不会改变导航路径的计算结果,只会阻碍物体的前进,如果代理半径过小,可能会造成导航物钻死胡同的现象。
分离网格跳跃线
- 首先在模型上创建分离网格连接组件,添加两个Transform,拖入到场景中。
- 修改导航设置,在对象选项卡中勾选 生成网格连接(Generate OffMeshLinks)
- 最后重新烘焙,就可以实现分离网格的连接。
运行时动态烘焙网格
使用官方扩展工具 NavMeshComponents工具(https://github.com/Unity-Technologies/NavMeshComponents)将NavMeshComponents/Assets/NavMeshComponents复制到项目中使用。
在需要导航的物体上创建 Nav Mesh Surface组件 并进行烘焙。
实现在点击的位置创建立方体
public GameObject buildPrefab;NavMeshSurface surface;void Start(){surface = GetComponent<NavMeshSurface>();}void Update(){if(Input.GetMouseButtonDown(0)){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;bool isCollider = Physics.Raycast(ray, out hit);if(isCollider){GameObject go = Instantiate(buildPrefab, hit.point, Quaternion.identity);go.transform.SetParent(this.transform);surface.BuildNavMesh();}}}
十四、音效系统
音频源组件和音频监听器组件
- 一个场景中只能有一个监听器,一般相机上默认有一个音频监听器
- 常用属性:静音、循环、音量
音频源组件常用函数
AudioSource audio;void Start(){audio = transform.GetComponent<AudioSource>();audio.clip = Resources.Load<AudioClip>("bj4");}void Update(){if(Input.GetKeyDown(KeyCode.A)){audio.Play();//audio.Pause();//audio.Stop();}}
音频过滤器和音频混响区(不常用,了解)
- 常用的过滤器
- 音频低通过滤器
- 音频高通过滤器
- 音频合成过滤器
- 音频失真过滤器
- 音频回声过滤器
- 音频混响过滤器
- 常用参数
- 最小距离
- 最大距离
- 音频管理器
- 全局音量
- 音频衰减因子
- DSP缓存区,缓存大小
- 常用的过滤器
十五、特效系统
粒子系统
使用资源包中的粒子(实践)
使用代码编辑粒子系统
GameObject partivalGo;ParticleSystem particleSystem;void Start(){partivalGo = GameObject.Instantiate(Resources.Load<GameObject>("22_RFX_Fire_Campfire1"));partivalGo.transform.position = transform.position;particleSystem = partivalGo.GetComponent<ParticleSystem>();//修改属性ParticleSystem.MainModule mainModule = particleSystem.main;mainModule.loop = true;//播放,暂停,停止particleSystem.Play();//particleSystem.Stop();//particleSystem.Pause();}
粒子触发回调
- 在粒子系统上选择触发器,可以设置进入、退出等是忽略、杀掉还是回调。
- 必须指定触发的检测对象。
ParticleSystem particle;void Start(){particle = transform.GetComponent<ParticleSystem>();}private void OnParticleTrigger(){List<ParticleSystem.Particle> particles = new List<ParticleSystem.Particle>();//这个地方并没有获取到任何的粒子?int num = particle.GetTriggerParticles(ParticleSystemTriggerEventType.Enter,particles);for (int i=0;i< num;i++){ParticleSystem.Particle par = particles[i];par.startColor = Color.red;particles[i] = par;}}
- 通过OnParticleTrigger了解到碰撞的粒子,以及GetTriggerParticles获取碰撞的粒子对象。
拖尾
- 将拖尾的粒子对象一般设置到人物或道具在子物体上,当物体发生移动时,会产生拖尾
- 拖尾使用的拖尾渲染器来实现
- 所有的可见物体都是通过渲染器来实现。
- Unity3D底层使用的是C++开发,通过提供一个个插件实现物体的渲染。
- 参考Low-level native plugin,使用OpenGL或DirectX开发渲染插件。
- 拖尾使用emit属性发射拖尾或停止拖尾。
粒子立场
- 在场景中添加粒子立场。
- 粒子系统需要勾选外力。
- 修改粒子立场的外力大小。
十六、视频播放管理
- 视频播放器组件
- 往相机和Canvas上添加视频播放器组件
- 视频组件常用函数
- VideoPlayer.Play()/Pause()/Stop()/isPlaying()/url/clip
Unity2019 从零到精通视频学习笔记相关推荐
- B站python教程“清华大佬终于把Python讲的如此清新脱俗!保姆级教程从入门到精通”视频学习笔记p1-p85
1.python脚本的格式:hello.py 其中hello为脚本名,py为脚本格式,在终端可以用python hello.py进行脚本的执行 2.什么是头注释:不是为代码而服务,更多是被系统或解释器 ...
- 【PM学习笔记】酸梅干超人 - 零基础学Figma学习笔记
原视频链接: B站视频 零基础学Figma学习笔记 心得体会 第1课 - 苹果商店页设计 第2课 - 线性图标设计 第3课 - 面性图标设计 第4课 玻璃拟态页设计 第5课 样式组件功能入门 第6课 ...
- 影像组学视频学习笔记(43)-标准差、标准误及95%置信区间CI、Li‘s have a solution and plan.
作者:北欧森林 链接:https://www.jianshu.com/p/f09d0f97592f 来源:简书,已获授权转载 本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(43)主要 ...
- 影像组学视频学习笔记(42)-影像组学特征提取问题解决过程复现、Li‘s have a solution and plan.
作者:北欧森林 链接:https://www.jianshu.com/p/c3e6de2f79b3 来源:简书,已获转载授权 本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(42)主要 ...
- 影像组学视频学习笔记(41)-如何使用软件提取组学特征、Li‘s have a solution and plan.
作者:北欧森林 链接:https://www.jianshu.com/p/72186eb3e395 来源:简书,已获授权转载 本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(41)主要 ...
- 影像组学视频学习笔记(37)-机器学习模型判断脑卒中发病时间(文献报告)、Li‘s have a solution and plan.
作者:北欧森林 链接:https://www.jianshu.com/p/3e7a2c84288e 来源:简书,已获授权转载 RadiomicsWorld.com "影像组学世界" ...
- 影像组学视频学习笔记(23)-主成分析PCA、降维和特征筛选的区别、Li‘s have a solution and plan.
本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(23)主要讲解: 主成分析PCA,影像组学降维和特征筛选的区别 0. PCA(Principal component analysis) ...
- 影像组学视频学习笔记(34)-使用3D Slicer软件提取影像组学特征、Li‘s have a solution and plan.
作者:北欧森林 链接:https://www.jianshu.com/p/afcd06221ea4 来源:简书,已获授权转载 RadiomicsWorld.com "影像组学世界" ...
- 影像组学视频学习笔记[44(End)]-带95%置信区间的折线图、Li‘s have a solution and plan.
作者:北欧森林 链接:https://www.jianshu.com/p/971eeaa03ec9 来源:简书,已获授权转载 本笔记来源于B站Up主: 有Li 的影像组学系列教学视频 本节(44)主要 ...
最新文章
- 电商系统如何做搜索引擎?
- CTFshow php特性 web134
- 数据库原理与应用(SQL Server)教程 主键、外键以及联合主键、复合主键和设置种子数目和增量
- 经典java NIO框架
- 机器人被抢走ntr_(科普)当被NTR剧情虐到的时候怎么办
- FFMPEG结构体分析:AVFormatContext
- SQL数据库学习之路(八)
- mean shift
- vs C4996的错误解决方法
- redmi airdots左右耳不串联怎么办_小米Redmi AirDots蓝牙耳机只能单边连接不能串联的解决办法...
- 《Java并发编程实战》读书笔记一:基础知识
- 在制作Windows虚拟机模板时的常用技巧
- java计算机毕业设计飞机航班信息查询系统演示视频2021MyBatis+系统+LW文档+源码+调试部署
- 产品部和业务部门是什么关系
- vue单页面怎么做SEO优化
- 硬盘位置不可用因格式变RAW而打不开:文件或目录损坏且无法读取/此卷不包含可识别的文件系统等无法访问错误-CHKDSK被中止
- Windows下HdWiki安装步骤
- 代码实现微信8.0特效
- 用户可以更方便高效的使用计算机,有了操作系统,用户可以更方便高效的使用计算机。...
- vue+海康威视视频插件坑点记录
热门文章
- sql 查数据库中时间最新的一条记录
- 如何查看某个端口是否可以访问
- matlab中axes显示,如何将figure图片显示在matlab GUI的axes中
- Opencv之颜色识别
- 算法(Java)——动态规划
- html做到QQ登录保存数据,QQ授权登录.html
- css 按钮固定在右上交_如何在iPad上交换左右鼠标按钮
- html元素拖动互换位置原理,【详】JS实现拖拽元素互换位置
- 【题目】27个小运动员在参加完比赛后,口渴难耐,去小店买饮料,饮料店搞促销,凭三个空瓶可以再换一瓶,他们最少买多少瓶饮料才能保证一人一瓶?
- thinkphp验证器