Unity2019 从零到精通视频学习笔记_unity2019如何导入粒子特效标准资源-程序员宅基地

技术标签: c#  游戏开发  

Unity2019 从零到精通视频学习笔记

该文对Unity2019 做简单的自学了解,并做相应的笔记

一、C#基础回顾

  1. 基本数据结构

    • 简单的控制台程序

      namespace ConsoleApp1
      {
          class Program
          {
              static void Main(string[] args)
              {
                  System.Console.WriteLine("Hello World");
              }
          }
      }
      
      
    • 类型转换

                  //int->string
                  int a = 10;
                  string strA = a.ToString();
                  //string->int
                  String 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和stringbuilder
                  String name = "wang", name2 = "li";
                  StringBuilder names = new StringBuilder();
                  names.Append(name);
                  names.Append(name2);
                  System.Console.WriteLine(names);
      
  2. 面向对象数据结构

    • 基本使用

      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");
              }
          }
      
    • 继承和多态

      1. abstract适合写非纯虚函数,interface适合写纯虚函数
      2. C#没有public、protect、private继承
      3. 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];
                  //使用Stack
                  Stack objStack = new Stack();
                  Stack<int> iStack = new Stack<int>();
                  //使用Queue
                  Queue queue = new Queue();
                  //使用List(必须要指定类型)
                  List<int> iList = new List<int>();
                  //使用Dictonary(必须要指定类型)
                  Dictionary<int, string> keyValuePairs = new Dictionary<int, string>();
      
    • 泛型

                   //这里使用where是一种约束,也就是T必须继承自Interface1
          class TempClass<T>  where T: Interface1
          {
              void TestSay(T obj)
              {
                  obj.Say();
              }
          }  
      
    • 反射

      1. 一般不建议使用反射,反射破坏程序的封装性
      2. 反射可以遍历程序的名称,函数名等,也可以直接根据程序名创建对象和调用函数
              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);
              }
      
  3. 异常处理

    • 调试和异常处理

              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");
                  }
              }
      
  4. 事件

    • 事件和委托

      1. delegate相当于函数指针,可以指向多个函数,可以在内部或外部调用。
      2. 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);
              }
          }
      
  5. 异步编程

    • 线程

      1. 线程
          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("成员函数");
              }
          }
      
      1. 匿名委托,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

      1. aysnc和await和Task配合使用。
      2. await必须在async的函数中使用。
      3. 一般不会使用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;
              }
          }
      
    • 协程

      1. 目前C#本身并没有有关协程的定义,在Unity3D库中有定义。
  6. 数据库和文件操作

    • ADO和LINQ
      1. ADO主要突出了对数据库的操作。LINQ将SQL语句和C#语句融合在了一起,简化了操作的处理。
    • 文件操作
      1. 文件操作使用StreamReader和StreamWriter操作。

二、引擎基本介绍

  1. 本次学习使用引擎是Unity 2019.2.12f1版本。

  2. 建议使用Unity Hub来管理Unity版本和授权。

  3. Unity官网是unity.cn

  4. Unity在场景的操作方式和UE4基本一致

  5. 在[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之后被调用

  1. 素材管理

    1. 导入导出图片

      • 导入新资源
      • 向场景中插入UI.Button
      • 将图片类型设置成UI/Sprit
      • 将图片应用于按钮
    2. 视频和音频

      • 导入音频

      • 向Canvas中添加组件 音频源,设置导入的音频

      • 向Canvas中添加音频监听器

      • 导入视频

      • 创建原始图像

      • 创建渲染器纹理

      • 将将渲染器纹理拖拽到原始图像.纹理的选项上

      • 在原始图像创建组件 视频播放器,将渲染器纹理和视频剪辑分辨拖拽到视频播放器中

在这里插入图片描述

  1. 字体和粒子特效

    • 一般导入比较简单,或者是美工已经做好打包的结果
  2. 模型和场景

    • 一般注意如果是自己导入FBX和贴图,先导入贴图,然后导入FBX,才能实现绑定材质。
  3. 脚本

    • 可以使用Debug.Log打印日志查看问题。
    • 可以选择出错后终止,查看问题。
    • 可以选择附加到Unity,在任何地方断点调试。

三、场景管理

  1. 同步加载场景

  2. 异步加载场景

  3. 加载场景时保留物体

    • 首先在文件-build settings,将两个场景拖入到Build中的场景

      SceneManager.LoadScene("SampleScene", LoadSceneMode.Additive);
      
      1. 第二个选项设置是同步加载还是异步加载。
      2. 第一个选项可以设置场景的下标,但一般不建议使用下标。
              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("加载没有跳转完毕");
              }
          }
      
      1. 可以认为协程是每一帧时会执行的语句,当yield return null;程序会临时返回一个结果,并等待下一帧时继续执行。

四、物体管理

  1. 标签和图层

在这里插入图片描述

标签和层级主要用于编程中搜索物体和过滤物体

  1. 预制件

    • 创建

      1. 可以将场景中内容拖拽到资源中,保存成预制件,预制件一般只能保存一份。

      2. 预制件默认放在Resources文件夹下,可以通过API索引到预制件

                //创建
                GameObject go = Resources.Load<GameObject>("Object/Sphere");
                GameObject.Instantiate(go);
        
      3. 如果没有放在Resources文件夹下,可通过public 变量传入预制件。

  2. 使用脚本对物体交互

            //创建
            //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);
    

五、组件管理

  1. 查找组件

    • GetComponent(s)<>:查找当前组件
    • GetComponent(s)InChildren<>:查找组件自己和子元素
    • GetComponent(s)InParent<>:查找组件自己和父元素
            GameObject go = GameObject.Find("Text");
            go.GetComponentInChildren<Text>().text = "查找到组件";
    
  2. 禁用组件

    • 组件中包含enable属性,可以用来关闭组件
    • 使用Destory可以删除组件

六、UGUI图形系统

  1. 画布与事件系统

    • 画布的渲染空间
      1. 屏幕空间-覆盖:看不到其他物体
      2. 屏幕空间-摄像机:可以看到在Canvas前面的3D物体
      3. 世界空间:Canvas本身可以移动到相机视线之外
    • UI缩放模式
      1. 恒定像素大小
      2. 屏幕大小缩放:一般选择此模式,分为宽度匹配和高度匹配
      3. 恒定物理大小
    • EventSystem
      1. 必须存在
      2. 在运行的时候可以看到事件系统的基本信息
  2. 文本

    • 最佳适应:能够根据文本框自己调节字体的大小
  3. 输入框

    • 内容类型:文本、密码
    • 输入框自己包含两个子物体:占位符和真实文本
  4. 首先先自己尝试按照流程创建用户界面

在这里插入图片描述

并实现三个需求:

  • 点击登录,在控制台输出账号和密码
  • 替换背景图片
  • 点击官网,跳转到指定URL
    InputField userInput;
    InputField pwdInput;
    Button loginBtn;
    public Sprite bg;
    // Start is called before the first frame update
    void 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
  1. Toggle

    • 包含选择框和文本两个子控件,可以自由调节
    • 包含IsOn属性,判断是否打钩
    • 如果需要使用开关组,需要在“开关组”的选项中选择一个包含了开关组(ToggleGroup)的组件
  2. 滑动条

    • 获取滑动条的值从属性value中获取
    • 获取滑动条发生改变的事件是 onValueChanged
  3. 滚动视图

    • 在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);
          }
      }
      
    • 可以自定义类似于滑动条的组件

      1. 创建父子两个Image

      2. 给子Image添加任意一个原图像(实际测试发现对于半透明图像不可用)

      3. 设置好父子物体的颜色,选择图像类型为“已填充”,填充方法为水平。

      4. 通过代码修改填充总数,可以实现将子控件填充到对应百分比的位置。

在这里插入图片描述

  1. 其他常用组件

    1. Outline:增加边框
    2. Shadow:添加阴影

七、用户输入管理

  1. 虚拟轴

    通过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
                //);
            }
    
  2. 获取键盘事件

    • 通过GetKey、GetKeyDown、GetKeyUp来获取键盘的按下状态。
    • GetKey是每一帧都能获取按下状态,GetKeyDown和GetKeyUp只获取一次。
  3. 获取鼠标事件

    • 通过Input.GetMousrButton、GetMouseButtonDown、GetMouseButtonUp来获取。
    • 传入的值0表示鼠标左键,1为鼠标右键。
  4. 移动设备输入

    • Input.touchCount获取有多少手指碰到了。
    • Input.touches获取每一根手指的状态,finggerid是手指id、position为位置,deltaPosition是和上次相比移动的距离。

八、自然环境设计

  1. 天空盒的创建
    • 一般使用6张图片创建天空盒或Cubemap创建天空盒。
    • 首先创建一个材质,选择天空盒,将6张图片设置好,就可以将天空盒拖拽到场景中了。
    • Cubemap全景图的后缀是hdr,导入后需要将纹理形状改成立方体,同样可以设置天空盒。
  2. 山脉和地表贴图的创建
    • 可以在Unity Assert Store下载Terrain Tools XXX资源包去尝试使用。
    • 在实际项目中,一般是公司的地模制作,该部分不做重点学习。
  3. 树和草的创建
  4. 水和雾

九、光照系统

  1. 灯光组件

    • 灯光按照类型可以分为:方向光、点光、聚光、区域光。

    • 一般区域光需要进行烘焙才能显示,且只能烘焙静态物体,烘焙在窗口-渲染-照明生成,选择混合照明中烘焙全局照明,然后可以选择自动生成,就会看到烘焙后的照明效果。

    • 可以设置阴影的强度和硬度。

在这里插入图片描述

  1. 照明设置

    • 可以在照明设置环境光以及天空盒

    • 可以选择混合模式,是否开启烘焙照明

    • 可以选择光照贴图是CPU还是GPU

    • 可以设置雾,当雾的密度调大时,会有浓雾的效果。

    • 可以设置光晕:需要在光源处选择绘制光晕

在这里插入图片描述

  • 可以设置炫光

    1. 首先创建炫光,设置纹理和纹理布局(一般是一维)
    2. 将创建的炫光赋值到指定的光源
  1. 自发光

    1. 自发光使用自发光材质实现,创建新的材质,选择发射。
    2. 可以选择一个发光贴图,以及选择发光颜色,强度。最终赋值给自发光物体即可。
    3. 自发光需要物体必须是静态的,也只能烘焙静态的物体。
  2. 光照探测器

    1. 光照探测器相当于记录了不同点的光照信息,从而可以实时动态的获取一些需要烘焙的光源的光照。
    2. 光照探测器用于渲染非静态物体。
    3. 建议多创建一些光照探测器。
  3. 反射探测器

    1. 反射探测器主要用于非常镜面的物体,例如光滑的地板
    2. 必须要求反射的物体具有镜面反射效果,相互配合才能看到反射探测器的效果。

十、3D模型管理

  1. 蒙皮网格与普通网格的对比

    • 蒙皮网格主要是用于人物,放在人物在动画中材质被不正常拉伸。
  2. 材质的使用

    • 导入项目资源包
    • 能够从材质图片创建材质球
  3. 换肤功能的实现

    • 能够使用代码替换人物衣服的材质

          public SkinnedMeshRenderer body;
          public Material m1;
          public Material m2;
      
          // Update is called once per frame
          void Update()
          {
              if(Input.GetKeyDown(KeyCode.A))
              {
                  //换成第一件衣服
                  body.material = m1;
              }
              else if(Input.GetKeyDown(KeyCode.S))
              {
                  //换成第二件衣服
                  body.material = m2;
              }
          }
      

十一、物理系统

  1. 3D物理系统

    • 刚体:提供重力系统的物体

    • 碰撞体:提供碰撞检测的物体,一般直接创建的物体都有碰撞体,碰撞体分为盒装、胶囊、平面等。

    • 常用属性:

      1. 质量
      2. 阻力
      3. 角阻力
      4. 使用重力(Use Gravity)
      5. 是否符合运动学(Is Kinematic):不收到物理引擎驱动,物体静止不动,但有质量
      6. 碰撞检测:
      7. 约束条件:冻结某个轴,不受到物理引擎影响
    • 恒力组件

      1. 绝对力:Force、相对力:RelativeForce:区别是是和世界坐标保持一致还是和自身坐标保持一致

      2. 绝对扭矩力:Torque、相对扭矩力:RelativeTorque

      3. API和属性

        1. 刚体速度
        2. 添加力
        3. 添加爆炸力
                rig = transform.GetComponent<Rigidbody>();
                //设定初始速度
                rig.velocity = new Vector3(10, 0, 0);
                添加力
                rig.AddForce(new Vector3(10, 0, 0));
                //使用爆炸力
                rig.AddExplosionForce(300, transform.position, 10);
        
        1. 在指定位置添加力:AddForceAtPosition
      4. 刚体休眠和唤醒

        1. 强制刚体休眠:Sleep
        2. 唤醒休眠中的刚体:WakeUp
    • 碰撞器和触发器

      1. 常用属性

        • 是触发器
        • 物理材质:用于设置摩擦力和弹性
        • Center中心
      2. 常用API

        • OnCollisionEnter/OnTriggerEnter
        • OnCollisionExit/OnTriggerExit
        • OnCollisionStay/OnTriggerStay
      3. 触发器的使用

            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);
            }
        
    • 物理材质

      1. 动态摩擦力、静态摩擦力
      2. 弹力
      3. 弹力、摩擦力结合模式:平均、最小、乘积、最大
    • 关节组件

      1. 给指定的刚体添加弹簧关节,将另一个物体拖入连接的物体
      2. 类型
      • 弹簧关节
        1. 直接连接两个刚体组件
      • 铰链关节
        1. 创建铰链组件,连接
        2. 修改Anchor和轴的方向,时期和真实轴的方向相同
        3. Use Motor:使用马达
        4. Use Limits:使用角度限制
      • 固定关节
        1. 两个物体相对位置固定
      • 角色关节
        1. 模仿人物骨头的关节
      • 可配置关节
      1. 连接的刚体
      2. 断开力:默认是无穷大,使用OnJointBreak(float Force) 处理断开的事件
    • 射线

      1. 绘制射线

        • 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:球形射线,返回碰撞数组

  2. 2D物理系统

    • 2D刚体和碰撞器

      1. 一般在Canvas中创建Image或RawImage(区别:Image要比RawImage更加强大,Image主要处理图片类型,RawImage主要用于纹理类型的)
      2. 在创建碰撞器的时候,需要指定大小,一般需要手动指定大小和2D物体大小一致。
    • 2D表面效果器

      1. 用于设置2D物体在表面的初始速度、力
      2. 必须在碰撞器上勾选:由效果器使用
    • 2D区域效果器

      1. 在区域内施加的力
      2. 需要勾选:是触发器、由效果器使用
    • 2D浮力效果器

      1. 在区域内收到浮力影响
    • 2D点效果器

      1. 在区域内受到引力或斥力

十二、动画系统

  1. 动画启动播放控制

    • 使用按键控制动画播放

      1. 创建动画器控制器

      2. 将一些动画拖入到动画器控制器中

      3. 在动画器选项卡中添加参数id,类型为int

      4. 设置动画器控制器的进入不同状态的条件

      5. 在模型上添加动画器,设置好动画器控制器和Avatar

      6. 编写脚本,控制动画器的值

         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);
                }
            }
        
      7. 选择跳转条件,取消对“可以过度到自己”的勾选。

      8. 如果希望动画可以循环,选择动画,勾选循环时间。

      9. 如果希望无延迟的切换到其它的动画,可以取消“有退出时间”

  2. 人形动画

    • 尝试使用其它人物角色的动画(实际操作)
    • 在检查器中可以看到人形动画的骨骼(实际操作)
  3. 动画遮罩

    • 了解对于非人物角色和人物角色动画遮罩的过程。(实际操作)
      1. 对于非人物遮罩,使用的是转换,指定具体的Avator,取消勾选一些不需要遮罩的骨骼。
      2. 在层总指定具体的遮罩。
      3. 可以创建不同的层,然后使用不同的动画遮罩,实现动作的混合。
  4. 动画事件

    • 动画事件是在界面中添加的,播放指定的动画,在指定的帧处添加事件的响应函数。(实际操作)

十三、寻路系统

  1. 制作一个点击自动寻路程序

    1. 先搭建一个场景

    2. 将场景中的物体设置为导航静态(在检查器-静态下拉菜单中设置)

    3. 打开烘焙窗口:窗口-ai-烘焙

    4. 切换到烘焙选项卡,进行烘焙,如果模型非常的小,需要设置好半径等参数才能看到烘焙的结果。

    5. 向人物增加组件——导航网格代理

    6. 添加脚本

          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);
                  }
              }
          }
      
  2. 重要属性

    • 代理半径、代理高度等
    • 区域和成本:在区域内有一个设置成本的按钮,一般导航选择成本最低的路线。可以在对象中选择某一段路导航区域的类型,然后重新进行烘焙。
    • 生成分离网格连接可以设置从高处跳跃的最大高度和最远距离。
    • 必须在对象选项卡中勾选 生成网格连接(Generate OffMeshLinks),才能生成连接
  3. 动态障碍物

    • 可以使用导航网格障碍禁止两个地方的导航连接
    • 实际测试导航障碍不会改变导航路径的计算结果,只会阻碍物体的前进,如果代理半径过小,可能会造成导航物钻死胡同的现象。
  4. 分离网格跳跃线

    • 首先在模型上创建分离网格连接组件,添加两个Transform,拖入到场景中。
    • 修改导航设置,在对象选项卡中勾选 生成网格连接(Generate OffMeshLinks)
    • 最后重新烘焙,就可以实现分离网格的连接。
  5. 运行时动态烘焙网格

    • 使用官方扩展工具 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();
                  }
              }
          }
      

十四、音效系统

  1. 音频源组件和音频监听器组件

    • 一个场景中只能有一个监听器,一般相机上默认有一个音频监听器
    • 常用属性:静音、循环、音量
  2. 音频源组件常用函数

        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();
            }
        }
    
  3. 音频过滤器和音频混响区(不常用,了解)

    • 常用的过滤器
      1. 音频低通过滤器
      2. 音频高通过滤器
      3. 音频合成过滤器
      4. 音频失真过滤器
      5. 音频回声过滤器
      6. 音频混响过滤器
    • 常用参数
      1. 最小距离
      2. 最大距离
    • 音频管理器
      1. 全局音量
      2. 音频衰减因子
      3. DSP缓存区,缓存大小

十五、特效系统

  1. 粒子系统

    • 使用资源包中的粒子(实践)

    • 使用代码编辑粒子系统

          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();
          }
      
    • 粒子触发回调

      1. 在粒子系统上选择触发器,可以设置进入、退出等是忽略、杀掉还是回调。
      2. 必须指定触发的检测对象。
          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;
              }
          }
      
      1. 通过OnParticleTrigger了解到碰撞的粒子,以及GetTriggerParticles获取碰撞的粒子对象。
  2. 拖尾

    • 将拖尾的粒子对象一般设置到人物或道具在子物体上,当物体发生移动时,会产生拖尾
    • 拖尾使用的拖尾渲染器来实现
      1. 所有的可见物体都是通过渲染器来实现。
      2. Unity3D底层使用的是C++开发,通过提供一个个插件实现物体的渲染。
      3. 参考Low-level native plugin,使用OpenGL或DirectX开发渲染插件。
    • 拖尾使用emit属性发射拖尾或停止拖尾。
  3. 粒子立场

    • 在场景中添加粒子立场。
    • 粒子系统需要勾选外力。
    • 修改粒子立场的外力大小。

十六、视频播放管理

  1. 视频播放器组件
    • 往相机和Canvas上添加视频播放器组件
  2. 视频组件常用函数
    • VideoPlayer.Play()/Pause()/Stop()/isPlaying()/url/clip
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zYongheng/article/details/119943724

智能推荐

Altium designer 原理图转换为pcb时出现的 unknown pin 和 failed to add class member_ad转pcb提示未知引脚-程序员宅基地

文章浏览阅读4.3k次,点赞14次,收藏31次。网上有很多方法,大部分都是让直接新建一个pcb文件,这显然太不现实了。 上述错误可以看出,unknown pin 的错误是在add pin to net的时候发生的 failed to add class member 的错误实在add to component class member发生的 要想根本解决这个问题,要了解net和class的作用。 首先net的作用是..._ad转pcb提示未知引脚

pycharm-python文件注释头-程序员宅基地

文章浏览阅读272次。#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : ${DATE} ${TIME} # @Author : Aries # @Site : ${SITE} # @File : ${NAME}.py # @Software: ${PRODUCT_NAME}--------------------- 作者:Leo-Woo 来源:CSDN 原文..._python标准的头注释 pycharm

ora hash oracle官网,oracle计算hash值-程序员宅基地

文章浏览阅读503次,点赞2次,收藏2次。oracle计算hash值1、dbms_utility.get_hash_value(name VARCHAR2,base NUMBER,hash_size NUMBER)函数说明name:输入值base:返回hash value的起始值(hash bucket最小值)hash_size:返回hash表的期望大小(hash bucket最大值)这个函数用于计算并返回落在给定范围内的hash值2、o..._oracle中ora_hash用法

【源码分析】Lottie 实现炫酷动画背后的原理_lottie.setanimation原理-程序员宅基地

文章浏览阅读272次。0. 前言自我在内网发布了一篇关于 Lottie 的原理分析的文章之后,就不断有同事来找我询问关于 Lottie 的各种东西,最近又有同事来问,就想着可能对大家也会有所帮助,就稍作处理后分享出来。需要注意的是,这文章写于两年前,基本版本 2.0.0-beta3,虽然我看过最新版本,主要的类没有什么差别,不过可能还是会存在一些差异。可以感受一下我两年前的实力。_lottie.setanimation原理

2023最新版本Activiti7系列-流程中的任务_activiti7流程和任务的关系-程序员宅基地

文章浏览阅读777次。Activiti7中各种任务的详解_activiti7流程和任务的关系

随便推点

Android开发之ADB命令使用技巧_adb iockbrowsor-程序员宅基地

文章浏览阅读2.1k次。学习Android的小伙伴们一定都听过ADB吧,如果没有听过也没有关系,下面我将介绍ADB及一些ADB命令的使用技巧.ADB的全称是Android Debug Bridge,直接翻译过来就是Android调试桥,它就像一个纽带,可以让我们在电脑上操作手机,我们可以在电脑上对其发送一些指令来调试它._adb iockbrowsor

ACL 2022 | 基于Prompt的自动去偏:有效减轻预训练语言模型中的偏见-程序员宅基地

文章浏览阅读1.3k次。Background去除偏见问题一直在真实对话系统中一直收到广泛的关注,在大型人类产生的语料库上训练的预训练语言模型,很多模型继承了类似人类的偏见和不想要的社会定型,例如,在 mask filling 任务中,BERT 将句子“The man/woman had a job as [MASK]”中的 [MASK] 分别替换为“经理/接待员”,反映了职业的性别偏见。我们认为..._auto-debias

UML静态视图——类图、对象图、包图_uml中属于静态视图的是-程序员宅基地

文章浏览阅读3.6k次,点赞2次,收藏2次。画类图最重要的就是抽象出类,先来回忆类的基本内容。一、类1、类的概念:类是面向对象程序设计的中的一个基本概念,类是具有相同属性、方法、语义和关系的一组对象的集合。2、类的分类: 实体类:保存要放进永久存储的信息 边界类:位于系统与外界的交界处。包括所有的窗体、报表、打印机等硬件接口以及与其他系统的接口。 控制类:负责协调其他类的工作。一般每个用例都有一个控制_uml中属于静态视图的是

前端js生成并导出Excel文件_js生成excel文件-程序员宅基地

文章浏览阅读6k次。不用调接口,全由js就可完成Excel文件的生成和导出,示例如下:_js生成excel文件

基于Java,SpringBoot,Vue,UniAPP的微信商城小程序_基于springboot的微信小程序商城-程序员宅基地

文章浏览阅读507次,点赞3次,收藏8次。本课题旨在探讨和实现一个基于SpringBoot后端框架和UniApp前端框架的微信商城小程序。SpringBoot作为一种简化的、用于快速开发企业级应用的开源框架,提供了一套全面的基础架构支持,包括自动配置、依赖管理以及安全性等特性,使得开发者能够以最少的配置快速启动和运行项目。结合UniApp,一种使用Vue.js开发所有前端应用的框架,它允许开发者编写一次代码,然后发布到iOS、Android、Web(包括微信小程序及其他小程序平台)等多个平台。_基于springboot的微信小程序商城

哈工大计算机组成原理第四章下——>缓存Cache(更新中。。)_主存的效率是什么-程序员宅基地

文章浏览阅读266次。哈工大计算机组成原理第四章下——>缓存Cache(更新中。。)_主存的效率是什么

推荐文章

热门文章

相关标签