Unity 面试题整理2020

一.Unity部分

  1. Mask和RectMask2D 区别
     区别点1:
      mask:可以处理不规则图形遮罩 依赖Image组件 剪裁范围是Image大大小
      rectMask2D:只能处理矩形遮罩效果,不依赖Image组件,剪裁范围是他RectTransform的rect大小

     区别点2:
      mask:会在首尾(首=mask节点 尾=maks节点的子节点遍历完毕) –产生2个drawcall
      rectMask2D:rectMask2D 不产生drawcall

     区别点3:
      mask:多个maks之间如何符合合批的条件 就可以合批 (mask1的首和mask2的首 合批 mask1的尾和mask2的尾合批 首尾不能合批–需要同渲染层级depth 同材质,同图集)
      rectMask2D:多个rectMask2D之间不能合批

     相同点4:
      rectMask2D:mask和rectMask2D的内部和外部不能合批

  2. 手指/鼠标如何判断向左向右向上向下
    在平面组成的2D坐标系上,分为四个象限,再分为8块,
    例如:当一个方向为东北或者西北上面时,记为“向上滑”
    方向

            if (m_Dir.y < m_Dir.x && m_Dir.y > -m_Dir.x)//向右
                dir = FingerDragDir.right;
            else if (m_Dir.y > m_Dir.x && m_Dir.y < -m_Dir.x)//向左
                dir = FingerDragDir.left;
            else if (m_Dir.y > m_Dir.x && m_Dir.y > -m_Dir.x)//向上
                dir = FingerDragDir.up;
            else if (m_Dir.y < m_Dir.x && m_Dir.y < -m_Dir.x)//向下
                dir = FingerDragDir.down;
    

    在1部分 m_Dir.y < m_Dir.x–>向右–》
    x=斜边cos(度数) y=斜边sin(度数)
    度数在[0,45]之间 cos(度) < sin(度)–》y<x

  3. 向量的点乘和叉乘
    点乘:
     点积的计算结果是个标量,只有大小 没有方向,也称为标量积
     公式:UV=UxVx+UyVy+UzVz==》|U|*|v|*cos(θ)==》U·V=V·U
     几何意义:
      U * V=0–》U和V相互垂直
      U * V>0–》U和V夹角小于90度,V在U的前方
      U * V<0–》U和V夹角大于90度, V在U的后方
     用途:
      ①计算2个向量之间的夹角

    //如果u、v都是单位向量,u.v=cos(a)==>a:
    private void TestDot(Vector3 a, Vector3 b)  
    {
          
            
        // 计算 a、b 单位向量的点积,得到夹角余弦值,|a.normalized|*|b.normalized|=1;  
        result = Vector3.Dot(a.normalized, b.normalized);  
        // 通过反余弦函数获取 向量 a、b 夹角(默认为 弧度)  
        float radians = Mathf.Acos(result);  
        // 将弧度转换为 角度  
        angle = radians * Mathf.Rad2Deg;  
    } 
    // 通过向量直接获取两个向量的夹角(默认为 角度), 此方法范围 [0 - 180]  
    float angle = Vector3.Angle(a, b); 
    

      ②判断敌人在自己的前方还是后方
       Vector3.Dot(transform.forward, target.position-transform.position)
       返回值为正(0<夹角<90)时,目标在自己的前方,反之(90<180)在自己的后方

    叉乘:
     叉乘结果是向量,其模是两个向量为边的平行四边形面积,叉积只能用于3D向量,2D向量没有叉积
     公式:UV=(UxVy-UyVx)+(UxVz-UzVx)+(UyVz-UzVy)》|U|*|v|*sin(θ)**》U·V=-V·U
     计算方式:
      对2个3D向量 u、v 计算叉积 结果w 向量 同时垂直于 u和v
      左手拇指法则:提起左手,将拇指之前的 4个手指指向第一个向量u,然后朝着v的方向 沿角度 0<a<π 弯曲手指,此时拇指所指方向 就是w的方向
     用途:
      ①计算2个向量之间的夹角
      ②计算平面法线 【法线:垂直一个平面的向量】
      ③求转向【顺时针还是逆时针】

    判断顺、逆时针,是在 2D 平面内的,所以需指定一个平面,下面以X、Z轴组成的平面为例,--》判断Y轴上的正负,即为“叉乘的正负值”,判断 b 在 a 的顺时针或者逆时针方向。
    Vector3 c = B.position - A.position;
    CrossTest(A.forward, c.normalized);
    private void CrossTest(Vector3 tmpA, Vector3 tmpB)
    {
          
          
        Vector3 result = Vector3.Cross(tmpA, tmpB);
        if(result.y> 0)
            Debug.Log("tmpB在 tmpA的顺时针方向");
        if (result.y == 0)
            Debug.Log("tmpB在tmpA同向");
        if (result.y < 0)
            Debug.Log("tmpB在tmpA的逆时针方向");
    }
    
    Vector3.Cross(transform.forward, target.position-transform.position).y
    返回值为正时,目标在自己的右方,反之在自己的左方
    

      ④计算出两向量组成的平行四边形面积

    根据平行四边形公式  S=a*h,h为高,a为底。a = |p1|
    又因为h = |p2|*sinθ,则 a* h = |p1|*|p2|*sinθ 即 |p1Xp2| = S
    float s = Vector3.Magnitude(resultCross); 
    
  4. Unity的协程作用及用途
     ①协程是:主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行,协程不是多线程。Unity的协程是在每帧结束之后去检测yield的条件是否满足
     ②主要用于:延时、WWW、等待异步加载、等待某个条件是否满足
     ③协程和多线程的区别:
      多线程是独立于主线程的,同一时间可以有多个多线程运行。协程只能存在于主线程,同一时间最多执行一个协程。
     ④协程和子程序(方法)区别:
      如加载文件,子程序会卡主主线程,直到加载完毕,才执行下面程序。协程类似异步,主线程执行加载文件,只加载0.1s然后挂起执行其他程序,主线程下次再来,恢复协程,以此往复,不卡主线。

  5. 防止UI穿透

    /// <summary>
    /// 检测是否点击3d对象【自己实现的 UI防穿透、移动端有效】
    /// </summary>
    public static bool CheckIsClick3DObj_Self()
    {
          
          //EventSystem.current.IsPointerOverGameObject Unity自带的 移动端无效
        EventSystem eventSystem = EventSystem.current;
        PointerEventData eventData = new PointerEventData(eventSystem);
        if (Application.isMobilePlatform)//移动端
        {
          
          
            if (Input.touchCount > 0)
            {
          
          
                eventData.pressPosition = Input.GetTouch(0).position;
                eventData.position = Input.GetTouch(0).position;
            }
        }
        else//Unity_Editor 下或者电脑上能运行
        {
          
          
            eventData.pressPosition = Input.mousePosition;
            eventData.position = Input.mousePosition;
        }
        List<RaycastResult> list = new List<RaycastResult>();
        eventSystem.RaycastAll(eventData, list);
        //graphicRayCaster.Raycast(eventData, list);
        return list.Count > 0;
    }
    
  6. transform.forward和Vector3.forword的区别:

    7.2D和3D混合界面 的渲染顺序

二.C#部分

  1. 排序算法–[原理]

    常见的冒泡、选择、插入、希尔、归并、快速排序
    详细讲解

  2. 值类型与引用类型作用、区别

    值类型:
     数字类型:整形(u)byte (u)short (u)int (u)long 浮点类型double float decimal
     布尔类型:bool
     复合类型:enum struct
    引用类型:
     数组:Array、字符串:string、类:class、接口:interface、委托:delegate、object

    区别:
     1.值类型的变量和值在栈中分配,引用类型变量在栈中分配,引用实例在堆中分配
      譬如:Object A=new A(); 变量A存放在栈区,栈区A的值存放的是引用对象的地址,引用对象的内容是存放在堆
     2.值类型数据读取速度快,引用类型数据读取速度满
     3.栈中的内存自动回收,堆中的内存由.net的GC自动释放
     4.值类型继承System.TypeValue,引用类型继承System.Object
     5.值类型变量在赋值或传递参数时,是重新开辟空间,将值拷贝给新的变量
     6.引用类型变量的数据一修改,所有指向同一地址的变量的数据都会修改

  3. 抽象类与接口区别:

     抽象类和接口都不能实例化,继承都必须实现所有抽象方法
     抽象类不是完全抽象可以有抽象和未抽象的方法,接口是完全抽象
     抽象类可以定义属性、构造函数,接口不能定义
     接口是多继承的,类是单继承的
     接口是不能用访问修饰符修饰,抽象类必须用public修饰

  4. 类与结构体区别:

     类是引用类型,存储在堆中,内存GC回收,结构体是值类型,存储在栈中,内存自动回收。
     定义成员类可以初始化,结构体只有static\cost的可以,数据成员不行
     类的变量可以设置null,结构体不行
     类定义无参构造和私有无参构造,结构体只能定义有参构造,且必须为所有成员赋初始值
     类有析构函数,结构体没有
     类可以被继承,结构体不能被继承。
     结构体适用于数据量小,层级简单。类适用于数据量大或层级复杂比如多继承。

三.Lua部分

四.优化部分

  1.UI优化:

    1.将同一画面图片放到同一图集中

    2.图片和文字尽量不要交叉,会产生多余drawcall(相同材质和纹理的UI元素是可以合并的)

    3.UI层级尽量不要重叠太多

    4.取消勾选不必要的射线检测RaycastTarget

    5.将动态的UI元素和静态的UI元素放在不同的Canvas中,减少canvas网格重构频率

猜你喜欢

转载自blog.csdn.net/baidu_39447417/article/details/108074248