unity学习笔记

1、monobehavior中的重要内容

延时函数:

a、延迟函数

延迟函数的使用:Invoke,参数1:函数名,字符串;参数2:延迟时间,秒为单位。

eg:Invoke(“函数名” ,秒);调用的函数一定要存在,如果调用的函数名不存在,那么因为调用不到会进行警告。

传入的第一个参数是函数的字符串,而且传入的函数没法传入参数,只能包裹一层。虽然直接传入带参函数不行,但是可以将它封装一下,然后在用延时函数是可以的。

b、延时重复函数

使用:invokeRepeating

参数1:函数名字符串;参数2:第一次执行的延时函数;参数3:之后每次执行的间隔;时间以秒为单位。

c、取消延时函数

CancelInvoke();取消所有演示函数。

CancelInvoke(“函数名”);取消指定的函数的延时函数。

IsInvoking()/   IsInvoking(“函数”);判断是否有延时函数/是否有指定的函数。

在unity中,脚本依附的对象失活或脚本失活,延时函数可以继续进行。但是脚本依附的对象销毁或脚本移除,延时函数就无法执行了。

协同程序:

unity中允许多线程,只是新开的线程无法访问unity中相关的内容。unity中的多线程要记得关闭。

命名空间:using System.Threading

方法:Thread

a、协同程序是什么

协程不是多线程,主要作用就是将代码分段分时执行,不卡主线程。主要运用于异步加载文件、场景、异步下载文件、批量创建等场合。

b、协程的使用

继承mono类的可以开协程;先申明一个协程的关键:返回值为IEnumerator类型及其子类。函数通过yield return进行返回。协程可见本质是个迭代器。 

unity中引入了StartCoroutine()方法来开启协程,在()中传入协程函数就行了。

也引入了StopAllCoroutine()方法来关闭所有协程,而关闭指定的协程,也是传入指定的协程。

c、关于yieldreturn后不同内容的含义

1、下一帧执行:yield return+数字/null ;在update和lateupdate之间执行。

2、等待指定秒后执行:yield return + new  waitForSeconds(数字);在update和lateupdate之间执行。

3、等待下一个物理帧更新时候执行:yield return + new waitForFixedUpdate() ;在fixedupdate和碰撞检测相关函数后执行。

4、等待相机和GUI渲染后执行:yield return + new waitForEndOfFrame ;在lateupdate之后渲染处理完毕后执行。

5、一些特殊类型的对象,如异步加载相关函数返回的对象;在update和lateupdate之间执行。

6、跳出协程。yield break

协程开启后组件和物体销毁,协程不执行,物体失活协程不执行,相关组件失活协程执行。

2、resource资源动态加载

特殊文件夹

Application.dataPath  工程路径获取,该方式 获取到的路径 一般情况下 只在 编辑模式下使用。

Resources 资源文件夹

路径获取:
        一般不获取
        只能使用Resources相关API进行加载:Application.dataPath + "/Resources"

        需要我们自己将创建

作用:
        资源文件夹
        1.需要通过Resources相关API动态加载的资源需要放在其中
        2.该文件夹下所有文件都会被打包出去
        3.打包时Unity会对其压缩加密
        4.该文件夹打包后只读 只能通过Resources相关API加载

 StreamingAssets 流动资源文件夹

路径获取:Application.streamingAssetsPath       

        需要我们自己将创建

作用:
        流文件夹
        1.打包出去不会被压缩加密,可以任由我们摆布
        2.移动平台只读,PC平台可读可写
        3.可以放入一些需要自定义动态加载的初始资源

persistentDataPath 持久数据文件夹

路径获取:Application.persistentDataPath

        不需要我们自己将创建

作用:
        固定数据文件夹
        1.所有平台都可读可写
        2.一般用于放置动态下载或者动态创建的文件,游戏中创建或者获取的文件都放在其中

Plugins 插件文件夹

路径获取:
        一般不获取

        需要我们自己将创建

作用:
        插件文件夹
        不同平台的插件相关文件放在其中,比如IOS和Android平台

Editor 编辑器文件夹

路径获取:
        一般不获取:Application.dataPath + "/Editor"

        需要我们自己将创建

作用:
       编辑器文件夹
       1.开发Unity编辑器时,编辑器相关脚本放在该文件夹中
       2.该文件夹中内容不会被打包出去

Standard Assets 默认资源文件夹

路径获取:
        一般不获取
        需要我们自己将创建

作用:
        默认资源文件夹
        一般Unity自带资源都放在这个文件夹下
        代码和资源优先被编译

resource资源同步加载

作用:1.通过代码动态加载Resources文件夹下指定路径资源
           2.避免繁琐的拖曳操作

常用资源类型:

        1.预设体对象——GameObject
        2.音效文件——AudioClip
        3.文本文件——TextAsset
        4.图片文件——Texture
        5.其它类型——需要什么用什么类型

        注意:
        预设体对象加载需要实例化
        其它资源加载一般直接用

资源同步加载 普通方法:

1.预设体对象 :

         第一步:要去加载预设体的资源文件(本质上 就是加载 配置数据 在内存中)
        eg:Object obj = Resources.Load("Cube");
        第二步:如果想要在场景上 创建预设体 一定是加载配置文件过后 然后实例化
        eg:Instantiate(obj);

2.音效资源

        第一步:就是加载数据
        eg:Object obj= Resources.Load("Music/BKMusic");
        第二步:使用数据 我们不需要实例化 音效切片 我们只需要把数据 赋值到正确的脚本上即可
        eg: public AudioSource audioS;

        audioS.clip = obj as AudioClip;
        audioS.Play();

3.文本资源

        文本资源支持的格式:.txt  / .xml / .bytes / .json / .html  / .csv

        eg:TextAsset ta = Resources.Load("Txt/Test") as TextAsset;

对于资源同名,resource可以使用其他的API进行加载

eg:TextAsset ta = Resources.Load("Tex/TestJPG", typeof(TextAsset)) as TextAsset; 

资源同步加载 泛型方法       

用as太麻烦,所以常用这个方法。

eg:TextAsset ta2 = Resources.Load<TextAsset>("Tex/TestJPG");

resource资源异步加载

加载过大的资源可能会造成程序卡顿 ,Resources异步加载 就是内部新开一个线程进行资源加载 不会造成主线程卡顿。

Resources异步加载方法:       

异步加载 不能马上得到加载的资源 至少要等一帧
 

eg: private Texture tex; 
    void Start()
    {
        ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/TestJPG");

        rq.completed += LoadOver;

    }
    private void LoadOver( AsyncOperation rq)
    {
        print("加载结束");
        //asset 是资源对象 加载完毕过后 就能够得到它
        tex = (rq as ResourceRequest).asset as Texture;
        print(Time.frameCount);
    }

这里通过异步加载中的完成事件监听 使用加载的资源,也是第一种方法。

注意:一定要等加载结束过后 才能使用

另一种就是采用协程异步加载

    IEnumerator Load()
    {
        //迭代器函数 当遇到yield return时  就会 停止执行之后的代码
        //然后 协程协调器 通过得到 返回的值 去判断 下一次执行后面的步骤 将会是何时
        ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/TestJPG");
        
        //第一部分
        //Unity 自己知道 该返回值 意味着你在异步加载资源 
        //yield return rq;
        //Unity 会自己判断 该资源是否加载完毕了 加载完毕过后 才会继续执行后面的代码
      
        
        //判断资源是否加载结束
        while(!rq.isDone)
        {
            //打印当前的 加载进度 
            //该进度 不会特别准确 过渡也不是特别明显
            print(rq.progress);
            yield return null;
        }
        tex = rq.asset as Texture;

        //yield return null;
        第二部分
        //yield return new WaitForSeconds(2f);
        第三部分
    }

两者异同:

        1.完成事件监听异步加载
        好处:写法简单
        坏处:只能在资源加载结束后 进行处理
        “线性加载”

        2.协程异步加载
        好处:可以在协程中处理复杂逻辑,比如同时加载多个资源,比如进度条更新
        坏处:写法稍麻烦
        “并行加载“

resource资源卸载

Resources重复加载资源会浪费内存吗?

答:Resources加载一次资源过后,该资源就一直存放在内存中作为缓存,第二次加载时发现缓存中存在该资源会直接取出来进行使用,但是 会浪费性能(每次加载都会去查找取出,始终伴随一些性能消耗)

如何手动释放掉缓存中的资源?

答:1.卸载指定资源:可以用Resources.UnloadAsset() 方法 ,但最好不要用在GameObject对象上,会作用于实例化的对象,一般用于不需要实例化的内容。

2、卸载未使用的资源:可以用Resources.UnloadUnusedAssets()方法,一般用于过场景和GC时使用

3、场景异步切换

场景同步加载: SceneManager.LoadScene()方法。

同步场景加载缺陷:

在切换场景时,Unity会删除当前场景上所有对象,并且去加载下一个场景的相关信息,如果当前场景对象过多或者下一个场景对象过多,这个过程会非常的耗时, 会让玩家感受到卡顿,所以异步切换就是来解决该问题的。

场景异步加载方法

1、通过事件回调函数,异步加载。

例如:

void start()
{
    AsyncOperation ao = SceneManager.LoadSceneAsync("Test");
    //当场景异步加载结束后 就会自动调用该事件函数 
    //我们如果希望在加载结束后 做一些事情 那么就可以在该函数中写处理逻辑
    ao.completed += (a) =>
    {
       print("加载结束");
    };

    ao.completed += LoadOver;
}

private void LoadOver(AsyncOperation ao)
{
    print("LoadOver");
}

2、通过协程 ,异步加载。

这个方法需要注意的是,加载场景会把当前场景上,没有特别处理的对象都删除了,从而导致在协程中的部分逻辑无法执行,因为找不到了。。为了解决这个问题,让处理场景加载的脚本依附的对象,在过场景时不被删除即可。

void start()
{
    DontDestroyOnLoad(this.gameObject);

    StartCoroutine(LoadScene("Test"));
}
IEnumerator LoadScene(string name)
{
    AsyncOperation ao = SceneManager.LoadSceneAsync(name);

    //协程的好处 是异步加载场景时 可以在加载的同时 做一些别的逻辑
    print("异步加载过程中 打印的信息");

    yield return ao;

    print("异步加载结束后 打印的信息");

}

4、lineRenderer相关

LineRenderer是Unity提供的一个用于画线的组件,使用它我们可以在场景中绘制线段,一般可以用于: 1绘制攻击范围 2武器红外线3辅助功能 4其它画线功能。

LineRender参数相关

LineRender代码相关:

        GameObject line = new GameObject();
        line.name = "Line";
        LineRenderer lineRenderer = line.AddComponent<LineRenderer>();

        //首尾相连
        lineRenderer.loop = true;

        //开始结束宽
        lineRenderer.startWidth = 0.02f;
        lineRenderer.endWidth = 0.02f;

        //开始结束颜色
        lineRenderer.startColor = Color.white;
        lineRenderer.endColor = Color.red;

        //设置材质
        m = Resources.Load<Material>("M");
        lineRenderer.material = m;

        //设置点
        //一定注意 设置点 要 先设置点的个数
        lineRenderer.positionCount = 4;
        //接着就设置 对应每个点的位置
        lineRenderer.SetPositions(new Vector3[] { new Vector3(0,0,0),
                                                  new Vector3(0,0,5),
                                                  new Vector3(5,0,5)});
        lineRenderer.SetPosition(3, new Vector3(5, 0, 0));

        //是否使用世界坐标系
        //决定了 是否随对象移动而移动
        lineRenderer.useWorldSpace = false;

        //让线段受光影响 会接受光数据 进行着色器计算
        lineRenderer.generateLightingData = true;

物理系统之范围检测

物理系统之碰撞检测

碰撞产生的必要条件:
        1.至少一个物体有刚体
        2.两个物体都必须有碰撞器

碰撞和触发:
        碰撞会产生实际的物理效果
        触发看起来不会产生碰撞但是可以通过函数监听触发

        碰撞检测主要用于实体物体之间产生物理效果时使用

什么是范围检测?

在指定位置进行范围判断,从而得到处于指定范围内的对象

如何进行范围检测?

必备条件:想要被范围检测到的对象 ,必须具备碰撞器

注意点:

1.范围检测相关API 只有当执行该句代码时 进行一次范围检测 它是瞬时的
2.范围检测相关API 并不会真正产生一个碰撞器 只是碰撞判断计算而已

范围检测API:
1.盒状范围检测Physics.OverlapBox()
        参数一:立方体中心点
        参数二:立方体三边大小
        参数三:立方体角度
        参数四:检测指定层级(不填检测所有层)
        参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide-检测触发器 Ignore-忽略触发器 不填使用UseGlobal
        返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)

这里需要注意,参数四里的指定层级不是指的是某一层的数,也不是直接使用LayerMask.NameToLayer("UI")作为参数进行传入,而是需要对其进行二进制转换的,也就是需要通过编号左移构建二进制数,这样每一个编号的层级 都是 对应位为1的2进制数,我们通过位运算 可以选择想要检测层级。

另一个API是Physics.OverlapBoxNonAlloc(),用法和上面类似,只是多要传入一个数组进行储存。

2、球形范围检测Physics.OverlapSphere()
        参数一:中心点
        参数二:球半径
        参数三:检测指定层级(不填检测所有层)
        参数四:是否忽略触发器 UseGlobal-使用全局设置 Collide-检测触发器 Ignore-忽略触发器 不填使用UseGlobal
        返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)

另一个API是Physics.OverlapSphereNonAlloc(),用法和上面类似,只是多要传入一个数组进行储存。

3.胶囊范围检测Physics.OverlapCapsule
        参数一:半圆一中心点
        参数二:半圆二中心点
        参数三:半圆半径
        参数四:检测指定层级(不填检测所有层)
        参数五:是否忽略触发器 UseGlobal-使用全局设置 Collide-检测触发器 Ignore-忽略触发器 不填使用UseGlobal
        返回值:在该范围内的触发器(得到了对象触发器就可以得到对象的所有信息)

另一个API是Physics.OverlapCapsuleNonAlloc(),用法和上面类似,只是多要传入一个数组进行储存。

                

        

  • 54
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值