Unity 杂记

1.协程

协程并不会在Unity中开辟新的线程来执行,其执行仍然发生在主线程中。当我们有较为耗时的操作时,可以将该操作分散到几帧或者几秒内完成,而不用在一帧内等这个操作完成后再执行其他操作。 
如我们需要执行一个循环:

IEnumerator CaculateResult()
{
    for (int i = 0; i < 10000; i++)
    {
        //内部循环计算
        //在这里的yield会让改内部循环计算每帧执行一次,而不会等待10000次循环结束后再跳出
        //yield return null;
    }
    //如果取消内部的yield操作,仅在for循环外边写yield操作,则会执行完10000次循环后再结束,相当于直接调用了一个函数,而非协程。
    //yield return null;
}

协成里的for是把值类型引用化。迭代器局部变量保存再堆上

【注意】

1> 使用WaitForFiexdUpdate类暂停的时间取决于Unity编辑器中的TimeManager的FixedTimestep.TimeScale也是取决于FixedTimestep。

2>WaitForEndOfFrame  用来处理等待帧结束,再恢复执行的代码。作用是等所有的Camera和GUI渲染完成后,再恢复携程的执行。eg:截屏

协程背后的秘密:迭代器

执行:

1>迭代器调用MoveNext()  ==>  遇到yield return语句。此时迭代器获取当前的值  ”start“,并且返回true以告诉还有数据。

2>Main使用当前枚举器中的Current属性获取数据并且打印。

3> Main再次调用MoveNext()方法。

4>迭代器再次从上次暂停的yield return的地方开始执行。。。

5>知道MoveNext(0方法返回false.告知没有数据

IEnumerator枚举器详说:【反编译后】

   1》创建state【用来标识迭代器状态】和current【标识当前的值】字段。

   2》构造函数中初始化标识迭代器的状态state=0。

   3》MoveNext(),内部是状态机+goto跳转

 IEnumerable<T>

                

10.12 关于unity Camera.main.ScreenToWorldPoint( Input.mousePosition); 

正确:   Vector3 _current2= Camera.main.ScreenToWorldPoint(( new Vector3( Input.mousePosition.x, Input.mousePosition.y, 10.0f)));    //当z=0时,2D的点转换后的还是一个2D的点【透视】   正交模式下是可以的【正交是2D面转3D面】

   添加RectTransform组件。

        RectTransform currentBoardRect = cube.GetComponent<RectTransform>();
        Vector3 vecWord = Vector3.zero;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(currentBoardRect, Input.mousePosition, Camera.main, out vecWord);
        cube.transform.position = vecWord;

11.unity3D场景加载的时候优化

https://www.cnblogs.com/llguanli/p/6824304.html

  (1)自己写个场景管理来加载xml或者json ,合并海员场景预制体

https://www.cnblogs.com/alongu3d/p/3192499.html

  (2)分割加载,场景中公共的资源或对象放在一个关卡中,把属于某一个独一无二的对象放在某一个关卡中

http://luminesca.blogspot.com/2013/05/sublevels.html

(3)移动式加载,背景移动,

12. 材质贴图缩放和偏移量之间的关系,贴图受缩放影响时,则 tiling+offset=0.5f

//Tiling   显示框的缩放量 offset 是纹理的偏移

offset  是显示框的偏移量

1)拿flappy bird素材来说,起始状态是这样的↓, 


注意显示框(黄色),它包括的范围是这样的↓ 


2)当offset_x设置为0.5的时候,显示框(黄色)包括的范围应该是这样的↓ 


offset_x设置为0.5的结果状态是这样的↓ 


3)当offset_x设置为0.8的时候,显示框(黄色)包括的范围是这样的↓ 


offset_x设置为0.8的结果状态是这样的↓ 


所以说,offset是显示框的偏移量

Tiling是显示框的缩放量

1)为做对比,再看一次原始的时候↓ 


2)tiling_x=0.5的时候,显示框(黄色)包括的范围应该是这样的↓ 


实际显示效果↓(图片也被横向的拉伸了) 


3)tiling_x=0.3的时候,显示框(黄色)包括的范围是这样的↓ 


实际显示效果↓ 


(对比下tiling_x=0.5, offset=0.5和tiling_x=1, offset=0.5时的区别,前者要“胖”些,这是因为显示框的大小不同导致的)
 

1.找出5个点中,找出任意两点距离大于1的算法

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TestNearPoint : MonoBehaviour {

    private    List<Vector3> _listStar = new List<Vector3>();
    private int _rangle=1;
    void Start ()
    {
        _listStar.Add(new Vector3(0,0));
        _listStar.Add(new Vector3(0, 1));
        _listStar.Add(new Vector3(2, 2));
        _listStar.Add(new Vector3(0, 3));
        _listStar.Add(new Vector3(1, 0));
        _listStar.Add(new Vector3(2, 0));
        _listStar.Add(new Vector3(4, 1));
        _listStar.Add(new Vector3(6, 6));
        _listStar.Add(new Vector3(4, 9));

        List<Vector3> _listDif = new List<Vector3>();
        for (int row = 0; row < _listStar.Count; row++)
        {
            for (int cow = 0; cow < _listStar.Count; cow++)
            {
                if (Vector3.Distance(_listStar[row], _listStar[cow]) > _rangle)
                {

                }
                else
                {
                    _listStar[cow] = _listStar[row];
                    if (_listDif.Contains(_listStar[cow]) == false)
                    {
                        _listDif.Add(_listStar[cow]);
                    }
                }
            }
        }
        for (int row = 0; row < _listDif.Count; row++)
        {
            Debug.LogError(_listDif[row]);
        }
    }
	
}

Animator 倒播

    /// <summary>
    /// 倒播
    /// </summary>
    public void SetBackPlay_CurrentAnimator(AnimatorInfo _AniInfo)
    {
        if (GetCurrentPlayingAnimationClip(currentAnimator) !=null)
        {
            _currentFram -= Time.deltaTime * 0.5f;
            currentAnimator.Play(GetCurrentPlayingAnimationClip(currentAnimator), 0, _currentFram);
        }
    }


   /// <summary>
   /// 获取当前的动画
   /// </summary>
    public  string GetCurrentPlayingAnimationClip(Animator _currentAnimator)
    {
        if (_currentAnimator == null)
        {
            return string.Empty;
        }
        for (int row = 0; row < _currentAnimator.runtimeAnimatorController.animationClips.Length; row++)
        {
            if (_currentAnimator.GetCurrentAnimatorStateInfo(0).IsName(_currentAnimator.runtimeAnimatorController.animationClips[row].name))
            {
                return _currentAnimator.runtimeAnimatorController.animationClips[row].name;
            }
        }
        return string.Empty;
    }
}

       

/洗牌算法 

随机一个Index,把该index对应的值和当前遍历到的i对应的值进行互换。

        Vector3 temp = new Vector3();
        int index0;
        for (int i = 1; i < _listPositionInfo.Count; i++)   //洗牌算法
        {
            index0 = Random.Range(0, (_listPositionInfo.Count - 1));
            temp = _listPositionInfo[index0];
            _listPositionInfo[index0] = _listPositionInfo[i];
            _listPositionInfo[i] = temp;
        } 

Physics.Raycast 理解
方法原型与参数说明

其实这个函数有个很藏的很深的地方就是这个layermask, 一般情况我们获取layer的值都会是layermask.nametolayer 这个函数去取得对应的层级,然后把这个int形的参数给到函数使用。但是如果是使用了Physics.Raycast去获取碰撞物的时候,你怎么都获取不到被碰撞的物体。(即使你划线来表示你的射线,也会觉得好像没有任何问题)

最后在unity的官方上找到了说明

Casting Rays Selectively
Using layers you can cast rays and ignore colliders in specific layers. For example you might want to cast a ray only against the player layer and ignore all other colliders.

The Physics.Raycast function takes a bitmask, where each bit determines if a layer will be ignored or not. If all bits in the layerMask are on, we will collide against all colliders. If the layerMask = 0, we will never find any collisions with the ray.

上面说明了一个问题就是,这个值如果是使用物理来进行碰撞的时候是使用的位移操作来进行的,也就是这里的layermask获得的值还要进行位移

第一种情况:表示在第8层上检查碰撞信息

int layerMask = 1 << 8;       

(Physics.Raycast(transform.position, Vector3.forward, Mathf.Infinity, layerMask))    Debug.Log("The ray hit the player");
第二种情况:除了第几层其他接受碰撞射线的检查则可以使用下面的方法

 int layerMask = 1 << 8;           

 layerMask = ~layerMask;

Unity 纹理,动画,网格加载分析及优化技巧

https://blog.csdn.net/zphshiwo/article/details/80742976

一个向量旋转angle角度:

 Vector2 newVec = Quaternion.AngleAxis(angle, Vector3.back) **Vector2.right;

angle:旋转度数           axis:围绕哪个轴旋转          oriVec:初始向量
 

1.热跟新无法在ios平台实现的原因?

  热跟新无法在ios热更的原因并不是ios禁止了JIT编译这种方式。而是苹果处于安全考虑,在ios中封存了内存(或者堆)的可执行权限(PROT_EXEC)。相当于变相的封锁了JIT编译方式。

2.如果对带有相同EdgeColider不产生碰撞,则给其中一个添加SufaceEffector2D,并且使用Colider Mask来屏蔽不想交互的层

3.协程深入研究

    (1)开始时迭代器调用MoveNext(),当遇到一个yield reture语句。此时迭代器会获取当前的值,MoveNext的返回值是true(告知还有数据)

    (2)使用Current属性获取数据。

    (3)再次调用MoveNext()【从上次暂停的(yield reture)的地方开始】,直到返回时false(告知没有数据)

    (4)上面代码中i是值类型,但是值其实在保存在堆上的,这样才能保存每次调用MoveNext()时i的值时可用的(而不是又从1开始),说明了迭代器中的局部变量会分配在堆上的原因。

委托深入理解:其实就是一个包装器

  协变性: 描述的是返回值类型,简单来说就是绑定在委托上的函数的  返回类型  可以是培生自 委托的返回类型。

  逆变性:描述的是委托的参数类型,简单来说就是绑定在委托上的函数的  参数类型  可以是委托的 参数类型的基类

  备注:值类型和void以上都不适用

所有的委托类型都继承自:System,MulticastDelegate  MulticastDelegate继承Delegate.

  protected MulticastDelegate(object target, string method);  //委托实例化的对象 , 和要调用的方法

委托是反编译后是一个完整的类,在可以定义类的地方就可以定义委托。委托对象实际上都是一个包装了方法和调用该方法时要操作的对象的包装器    target【当前类的实例】  method【当前操作的函数】   invocationList【调用列表】

内部结构:

(2)调用多个方法

   

后边发展了+

事件:

无论申明事件成员时使用的访问修饰符是什么,编辑器最终将该字段申明未private,和委托链一样

匿名方法:

  编辑器为源码中的每一个方法创建了一个对应的方法,采用了和创建委托实例时同样的操作

unity中计算正切:

            double val = Math.Atan2(_JumpInfo._DisDown, _JumpInfo._DisLeft); // 在坐标轴第一象限中,则 y=对边【参数1】   x=邻边 【参数2】
            val = val * 180 / Math.PI;【将val弧度转成角度】

Multiple plugins with the same name 'avprovideo' (found at 'Assets/CoreLibrary/Plugins/WSA/PhoneSDK81/x86/AVProVideo.dll' and 'Assets/CoreLibrary/Plugins/x86_64/AVProVideo.dll'). That means one or more plugins are set to be compatible with Editor. Only one plugin at the time can be used by Editor.

查找:是unity 中DLL重复引用,不能兼容,根据自己的unity版本,如果是64为,则保存x86_x64的DLL,其他的删除掉,可解决

2018.5.11

今天windows跟新后,一直开不了机,重设系统后,导致c盘有的dll丢失了,应用程序打不开,缺少msvcr100.dll,网上查资料,下载了后,放到了指定位置,但是任然有问题,最简单的方法是使用DirectX修复工具来全部检查,修复。此链接https://pan.baidu.com/s/1nvIYAvB,无脑安装,修复即可

2018.2.14

在序列化结构体时,结构体中如果有数组,则报异常:类型GoPosion不能被编组为一个非托管结构

ArgumentException: Type GoPosion cannot be marshaled as an unmanaged structure.

Parameter name: t

System.Runtime.Inter

争论异常:类型GoPosion不能被编组为一个非托管结构。

解决方案:给数组加属性:    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)],参考链接http://www.codes51.com/itwd/4119330_2.html

2018.5.6

转一个常见unity问题 解决链接:http://www.xuebuyuan.com/zh-hant/2105551.html

2.18.6.11

解决办法:

      在开始调用UDPClient的Receive方法之前对UDPClient.Available属性进行判断,当Available属性大于0时才开始从缓冲区读取网络数据:

            public void UDPReciveMore()
    {
        try
        {
            while (IsClose)
            {
                if (clientRec.Available <= 0) { continue; }
                byte[] buf = clientRec.Receive(ref endpointRec);
                ReceiveCallBackUDPMore(buf.Length, ref buf);//ReceiveCallBackUDPMore
            }
        }
        catch (Exception e)
        {
            Debug.LogError("异常: " + e);
        }
    }

原因:MSDN对Available的解释是:

      “Available 属性用于确定在网络缓冲区中排队等待读取的数据的量。 如果数据可用,可调用 Read 获取数据。 如果无数据可用,则 Available 属性返回 0。

    如果远程主机处于关机状态或关闭了连接,则 Available 属性将引发SocketException。如果远程主机处于关机状态或关闭了连接,则 Available 属性将引发SocketException”。

           也就是说,错误的原因在于,但调用Close后,线程恰好继续向网络缓冲区中读取数据,所以引发SocketException。

错误文档: 点击打开链接

2018.6.11

git clone操作出现fatal:index-pack failed错误解决方案

该错误是因为当前clone文件夹的属性为“只读”,无法写入。

解决方案:将文件夹属性“只读”取消。

unity 使用Grid Layout Group时,打包除去不显示内部的text,则把自己适应选上

2017.7.17

unity 调用c++ Dll

问题:  打包出去后找不到对应的Dll了,

解决: 包打包是64位,则修改unity的打包设置为86*64 ,再打包。

2019.3.26 Unity中脚本A引用不了脚本B的命名空间的情况?

     解决: 如果导入的是Dll,则放在Plugins下,如果是自己写的脚本,则放在要引用的脚本下边。

http://imweirui.com/blog/2017/12/13/%E9%85%8D%E7%BD%AEunity2017%E5%92%8Cvs2015%E4%BD%BF%E7%94%A8c-6-0/

2019.3.29

      end = transform.TransformPoint(end);是子物体和父物体之间的转换。

      vecWorld=    transform.TransformPoint(vecModle);  //模型坐标到世界坐标

      byte[] by = data.Skip(12).Take(8).ToArray(); //data数组从12位开始取8个给by

2019.4.24 

Unity Rigidbody2D 添加一个力后,又完全清除掉力,且只是去掉了添加的力度的影响,也可以避免力的叠加问题?

GetComponent<Rigidbody2D>().AddForce()  //添加力

GetComponent<Rigidbody2D>().velocity=GetComponent<Rigidbody2D>().velocity.normalized*4;  //清除力,即设置为原本的速度

FairyGUI - 超强UI编辑器,跨平台开源UI解决方案   

简介: http://www.fairygui.com/guide/

案例   http://www.sikiedu.com/course/139/tasks(UI编辑器入门) 

 http://www.sikiedu.com/course/170/tasks(狼人杀)

Unity事件系统

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
{
    public delegate void EventTriggerDelegate(GameObject go);
    public EventTriggerDelegate onClick;
    public EventTriggerDelegate onDown;
    public EventTriggerDelegate onEnter;
    public EventTriggerDelegate onExit;
    public EventTriggerDelegate onUp;

    /// <summary>
    /// 获取事件监听者
    /// </summary>
    public static EventTriggerListener Get(GameObject go)
    {
        EventTriggerListener listener = go.GetComponent<EventTriggerListener>();
        if (listener == null)
        {
            listener = go.AddComponent<EventTriggerListener>();
        }
        return listener;
    }

    public override void OnPointerClick(PointerEventData eventData)
    {
        if (onClick != null)
        {
            onClick(gameObject);
        }
     }

    public override void OnPointerDown(PointerEventData eventData)
    {
        if (onDown != null)
        {
            onDown(gameObject);
        }
    }

    public override void OnPointerEnter(PointerEventData eventData)
    {
        if (onEnter != null)
        {
            onEnter(gameObject);
        }
    }

    public override void OnPointerExit(PointerEventData eventData)
    {
        if (onExit != null)
        {
            onExit(gameObject);
        }
    }

    public override void OnPointerUp(PointerEventData eventData)
    {
        if (onUp != null)
        {
            onUp(gameObject);
        }
    }
}
using Robots.Const.String;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;


/// <summary>
/// 大厅主页事件回调
/// </summary>
public class MainSenceEventHandle : MonoBehaviour {

    public Button btn_LeaveGame;
    public Button btn_Fight;
    public Button btn_Cooperation;
    public Button btn_Ralaxation;
    public Button btn_Explain;
    public Button btn_ExplainLeave;
    /// <summary>
    /// 过度画面
    /// </summary>
    public Transform img_CutScene;

   
    private AsyncOperation async;
    private float progressValue;
    public Slider slider;
    public Text text;
   
    private void Start()
    {
        EventTriggerListener.Get(btn_LeaveGame.gameObject).onClick = OnClick_Home_Leave;
        EventTriggerListener.Get(btn_Fight.gameObject).onClick = OnClick_Home_Fight;
        EventTriggerListener.Get(btn_Cooperation.gameObject).onClick = OnClick_Home_Cooperation;
        EventTriggerListener.Get(btn_Ralaxation.gameObject).onClick = OnClick_Home_Ralaxation;
        EventTriggerListener.Get(btn_Explain.gameObject).onClick = OnClick_Home_Explain;
        EventTriggerListener.Get(btn_ExplainLeave.gameObject).onClick = OnClick_Home_ExplainLeave;
    }

    private void OnClick_Home_Leave(GameObject go)
    {
        Debug.LogError("点击   离开游戏   " + go.name);
        Application.Quit();
    }
    private void OnClick_Home_Fight(GameObject go)
    {
        Debug.LogError("点击    进行对战  " + go.name);


        Set_CutSenceRobots(enGameStyle.Fight);
        AgainGameInit();
    }
    private void OnClick_Home_Cooperation(GameObject go)
    {
        Debug.LogError("点击    进入合作   " + go.name);


        Set_CutSenceRobots(enGameStyle.Cooperration);
        AgainGameInit();
    }
    private void OnClick_Home_Ralaxation(GameObject go)
    {
        Debug.LogError("点击     进入休闲  " + go.name);


        Set_CutSenceRobots(enGameStyle.Ralaxation);
        AgainGameInit();
    }
    private void OnClick_Home_Explain(GameObject go)
    {
        Debug.LogError("点击     进入说明  " + go.name);
        btn_Explain.transform.GetChild(0).localScale = Vector2.one;
    }
    private void OnClick_Home_ExplainLeave(GameObject go)
    {
        Debug.LogError("点击     离开游戏说明  " + go.name);
        btn_Explain.transform.GetChild(0).localScale = Vector2.zero;
    }


    /// <summary>
    /// 
    /// </summary>
    /// <param name="enGOStyle"></param>
    private void Set_CutSenceRobots(enGameStyle enGOStyle)
    {

        img_CutScene.localScale = Vector2.one;
        //展示机器人
        //设置GameSence中的配置数据  UI布局
        GameGloble.current.EnCurrentGoStyle = enGOStyle;
        GameGloble.current.CurrentNum = Random.Range(1, 6);

        if (GameGloble.current.CurrentNum == 1)
        {
            SetGameRobots(Tags.PlayerTag_Jar, Tags.PlayerTag_Octopus);
        }
        else   if (GameGloble.current.CurrentNum == 2)
        {
            SetGameRobots(Tags.PlayerTag_Jar, Tags.PlayerTag_OilDrum);
        }
        else if (GameGloble.current.CurrentNum == 3)
        {
            SetGameRobots(Tags.PlayerTag_Radio, Tags.PlayerTag_Octopus);
        }
        else if (GameGloble.current.CurrentNum == 4)
        {
            SetGameRobots(Tags.PlayerTag_Radio, Tags.PlayerTag_OilDrum);
        }
        else if (GameGloble.current.CurrentNum == 5)
        {
            SetGameRobots(Tags.PlayerTag_Radio, Tags.PlayerTag_OilDrum);
        }

        StartCoroutine(LodeSence());
    }

    /// <summary>
    /// 设置上场的机器人
    /// </summary>
    /// <param name="tag1"></param>
    /// <param name="tag2"></param>
    private void SetGameRobots(string tag1,string tag2)
    {
        for (int row = 0; row < img_CutScene.GetChildCount(); row++)
        {
            if (img_CutScene.GetChild(row).CompareTag(tag1))
            {
                img_CutScene.GetChild(row).gameObject.SetActive(true);
                img_CutScene.GetChild(row).localPosition = new Vector3(360, 0);
            }
            if (img_CutScene.GetChild(row).CompareTag(tag2))
            {
                img_CutScene.GetChild(row).gameObject.SetActive(true);
                img_CutScene.GetChild(row).localPosition = new Vector3(-360, 0);
            }
        }
    }
    private IEnumerator LodeSence()
    {
        yield return new WaitForSeconds(1);
        async = SceneManager.LoadSceneAsync("GameSence");
        async.allowSceneActivation = false;
        while (!async.isDone)
        {
            if (async.progress < 0.9f)
            { progressValue = async.progress; }
            else { progressValue = 1; }
            slider.value = progressValue;
            progressValue = (int)(slider.value * 100);
            text.text = progressValue + " %";
            if (progressValue >= 0.9f)
            {
                progressValue += Time.deltaTime;
            }
            if (progressValue >= 1)
            {
                async.allowSceneActivation = true;
            }
            yield return null;
        }
    }

    /// <summary>
    /// 再一次开始游戏初始化
    /// </summary>
    public  void AgainGameInit()
    {
        GameDataInfo.isGameEnd = false;
        GameDataInfo.isGameTimeEnd = false;
        GameDataInfo.isRotateFactory = false;
        UnitAllData_Control.InitClearDic();
        GameGloble.current.CurrentPlayerFactoryA = null;
        GameGloble.current.CurrentPlayerFactoryB = null;
        GameDataInfo.Count_A = 0;
        GameDataInfo.Count_B = 0;
       
    }
}

UGUI: 通过鼠标控制UI在屏幕中的位置

在ScreenSpace-Camera模式和ScreenSpace-Overlay  模式下都可以使用。而直接使用GameObject.Find("Image").transform.position = Input.mousePosition;方式,则会由深度数值不正确而引发的问题。

对于在canvas下的物件,相机模式是透视的,则要以这种方式来转换的:

        Vector3 vecWord = Vector3.zero;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(GameObject.Find("Image").GetComponent<RectTransform>(), Input.mousePosition, Camera.main, out vecWord);
        GameObject.Find("Image").transform.position = vecWord;

anchoredPosition 和 Position的区别: 

已知 e.Position 是触摸或点击事件提供的屏幕坐标(Vector2),Canvas 设置为 Screen Space - Overlay。

如果屏幕是 iPhone7 的大小 667x375,那么点在最右下角的时候,e.Position 的值就是(667, 375)。

如果把按钮的 RectTransform.position 赋值为 e.Position,就能把这个按钮放在屏幕右下角 (667, 375)位置。

如果把按钮的 RectTransform.anchoredPosition 赋值为 e.Position,那么按钮会在哪里取决于 anchor 的位置(参见下图):

如果 anchor 在左上角(0, 0),那么相对 anchor 设置坐标为 (0, 0) + (667, 375) = (667, 375)
如果anchor在右下角(667, 375),那么相对 anchor 设置坐标为 (667, 375) + (667, 375) = (1334, 750),设置到屏幕外了。
其他情况类推。
position 的原点是 Canvas 屏幕空间的原点, anchoredPosition 的原点是元素本身的 anchor。

localposition和position以及模型自身的坐标  区别:

   局部坐标,有父物体时时相对于父物体的坐标,没有父物体则和position一样。

孙子层级物体相对爷爷层级物体的坐标;  

        //其实=孙子层级(x,y,z)+爷爷层级(x,y,z)
        Vector3 vec = 爷爷层级.transform.InverseTransformPoint(孙子层级.transform.position);

模型自身的坐标: transform.up  获取的是模型自身的坐标  此时代表是模型本地坐标。

unity_左手坐标系: 

大拇指永远指向是x轴。

Unity不要使用缩放

统一缩放的物体不会和非统一缩放的物体一起批处理

Unity中最好不要使用Linq: 

unity3d 爆屏警告Tiled GPU perf. warning: RenderTexture color surface () was not。。的解决办法

 Edit -> Graphics Emulation

调为 no Emulation

Mathf.Acos(-1) return NaN?

https://answers.unity.com/questions/778626/mathfacos-1-return-nan.html

ACos仅为-1和1之间的输入值范围定义。我怀疑结果是由Vector3.Dot返回的。点有时会稍微超出这个范围(即使您的输入向量是标准化的),因为计算不精确-当四舍五入为“-1”时,它仍然可能被打印出来。

Unity常见问题总结:

https://answers.unity.com/index.html

使用叉乘计算角度,使得小车永远在自己画的线内部行走:

                Vector3 vec = current - (Vector3)listVecTest[count];

                    //取屏幕的原点的Y向量作为参照向量,计算画的线的前后两帧连线和参照向量的夹角。
                    Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector2(0,0));
                    worldPos = new Vector3(worldPos.x, worldPos.y,0);
                    Vector3 vecStart = new Vector3(worldPos.x, worldPos.y, 0)- new Vector3( worldPos.x,  worldPos.y+5, 0);

                    Debug.DrawLine(current, (Vector3)listVecTest[count], Color.green, 5);
                    Debug.DrawLine(new Vector3(worldPos.x, worldPos.y, 0), new Vector3(worldPos.x, worldPos.y + 5, 0), Color.red, 5);

                    Vector3  crossVec= Vector3.Cross(vec, vecStart);
                    float angle  =   Vector3.Angle(vec, vecStart);
                    if (crossVec.z > 0)//右手法则,z>0,顺时针旋转
                    {  
                        Debug.Log("Clockwise Angle  " + angle);
                        playerTest.transform.eulerAngles = new Vector3(0, 0, 90 - angle);
                    }
                    else if (crossVec.z == 0)
                    {
                        Debug.Log("  Angle "+ angle);//+90   或者  -90
                        if (angle == 90)
                        {
                            playerTest.transform.eulerAngles = new Vector3(0, 0, 90);
                        }
                        else if (angle == 180)
                        {
                            playerTest.transform.eulerAngles = new Vector3(0, 0, -90);
                        }
                    }
                    else if (crossVec.z < 0)
                    {
                        Debug.Log("Antclockwise  Angle   " + angle);   //   angle+ 90
                        playerTest.transform.eulerAngles = new Vector3(0, 0, angle + 90);
                    }

unity绘制线:

Debug.DrawLine(startPoint, endPoint, Color.red);  //绘制两个点之间的线

Debug.DrawRay(startPoint, direct, Color.yellow);   //知道一个点和方向绘制线

unity 实例化prefab 报错 Step Offset must be less or equal to


Step Offset must be less or equal to + * 2 
今天实例化一个prefab时,各种报上面这个错。开始以为是实例化prefab传参的问题。 
后来发现是因为prefab上挂的Character controller组件导致的,组件上的默认参数,不符合上面报错的要求,修改下就好了。 
主要是类似问题网上没有提供解决方法的,写篇博客记录下吧。希望能帮到其他人。

发现父物体的缩放是0.

Unity  AssetStore 上下载的插件保存位置路径:

C:\Users\WangYanJie\AppData\Roaming\Unity\Asset Store

Unity Character Controller 之间不发生碰撞的 方法

点开
Edit / Project Setting / Physics

如下图所示,

给 该Character Controller 所在的对象设置 Layer, 同时取消勾选 
    Layer 与 Layer 在矩阵 中的 钩, 即可 设置 该 Character Controller 之间不发生不想碰撞
 

【Unity&2.5D&Shader】2D2.5D精灵实时阴影怎么使用

drawPlanePar.GetComponent<SpriteRenderer>().GetComponent<Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;

猜你喜欢

转载自blog.csdn.net/qq_35433081/article/details/80929005
今日推荐