1)对于AI逻辑写在Lua中的问题
2)Shader中宏的作用
3)Update中的new Struct对象
4)通过在编辑的预制体中获取资源门路


这是第266篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)

Lua

Q:当初战斗的外围逻辑都在xLua外面,蕴含了AI的逻辑,这部分计算量极大,会造成画面卡死。

尝试过用Thread把xLua虚拟机包一层,后果还是会报Main Thread的谬误。也尝试用闭包的形式,从Lua回传到CSharp,用System.Action接住,而后丢线程外面跑,然而会卡断主线程。

当初想尝试用两个Lua虚拟机,一个放Thread外面只跑战斗,其余的放在主Lua虚拟机中。那么整个游戏运行起来,会有3个虚拟机:Mono、xLua和xLuaInThread。

策动心愿AI做得聪慧一些,对应的思考维度和运算量都会大幅提高。不晓得是否有其余举荐的计划?

A1:我感觉不是虚拟机方向的问题:

  1. Lua和Unity交互的细节没有把控好,比方重复在lua.transform.position等等相似的。
  2. 不论是Tolua还是xLua,并不是说齐全就不必C#了。应该是基于几个准则:扩展性、热更性和性能,比方MMORPG的头顶UI必定不是全副是Lua开发的,业务在Lua然而挪动那些必定是C#(一旦做完了,接下来简直不会再动到C#代码了)。
  3. Lua和C#交叉的细节须要把控。
  4. Lua自身的应用细节也须要把控好。

感激沈杰@UWA问答社区提供了答复

A2:不须要多个虚拟机。能够浏览《游戏编程精粹》里的这两篇文章(年代有点久了不记得是哪一本,也不记得具体讲了那些内容,只是取得了思路后,本人实现过):

  1. 用于游戏对象AI的微线程
  2. 应用微线程治理AI

我在已经的我的项目中实现基于协程的工作管理器,大抵有这些特点:

  1. 每个游戏对象运行的脚本在独立创立的协程上。
  2. 每个协程入口对立采纳相似C语言的入口办法标准,如:

    • 入口函数Main。
    • 随眠函数Sleep,Yield,Waitframe,Waittime(这些办法能够准确管制AI的计算频率与精度)。
    • 退出相干办法Exit,Atexit。
  3. 对立在宿主程序中,对游戏中多个协程进行按需调度,比方期待指定工夫,帧数后调用Resume唤醒协程。

感激lujian@UWA问答社区提供了答复

Shader

Q:Particle Additive Shader中应用了该宏:UNITY\_DECLARE\_DEPTH\_TEXTURE(\_CameraDepthTexture);,查了一下没找到相干阐明。字面了解是申明了一个深度图。

在默认管线(向前渲染)中,依照惯例了解深度图须要通过设置Camera的depthTextureMode来指定。还请各位指教。

A:Shader中很多宏确实是没有官网阐明的,咱们须要去CGInclude文件夹中寻找其确切定义。

UNITY_DECLARE_DEPTH_TEXTURE在HLSLSupport.cginc里:

确实是为了申明一张图,回到Particle Add.shader中发现是为了申明深度图:

这是为了在片元着色器中的深度采样做筹备:

该SAMPLE_DEPTH_TEXTURE_PROJ办法同样在HLSLSupport.cginc中:

而后持续在该文件中找tex2Dproj:

由此可见这些操作就是在相机保留的深度图中,通过tex2D获取了深度,为LinearEyeDepth筹备参数从而失去场景深度。该Shader通常在开了软粒子之后被用到。

感激翟孟飞@UWA问答社区提供了答复

Script

Q:Struct中蕴含String字段,如果在Update中new,会不会有GC问题?思考是否须要用缓存池来解决,目前我测试了一下将Struct改成Class是必定有,如果是Struct类型,就没找到。

A1:对Class进行new是会调配堆内存,然而这个堆内存不肯定是String字段造成的。Class的实例自身就会占用堆内存,而它的字段会不会造成堆内存调配,取决于new的时候会不会对类型进行实例化。实例化的时候给String赋值,如果是间接确定的字符串内容,编译器会主动进行缓存优化,只会在第一帧创立字符串分配内存。

至于Struct,构造体作为值类型自身不会占用堆内存。对Struct进行new会不会调配堆内存,取决于new的时候,它的字段会不会实例化,会不会占用堆内存。如果Struct没有写构造函数,即便外面有援用类型,在new Struct的时候也不会实例化,不会调配堆内存。如果写了构造函数,就要看构造函数外面是否调配堆内存了。String的状况与上文提到的统一。

感激Prin@UWA问答社区提供了答复

A2:C#语法中除了构造函数造成的堆内存调配,还有构造体对外传递造成栈上逃逸问题。具体表现是结构的构造体作用域不仅局限在Update函数内。

在Unity的Playable模块里能够见到大量的ref Struct签名,是C# 7里专门解决栈逃逸的语法,依葫芦画瓢即可。

感激陈xx@UWA问答社区提供了答复

Script

Q:我想调用AssetDatabase.GetAssetPath 获取资源门路,但我点击图1物体,应用AssetDatabase.GetAssetPath(gameObject),却获取不到。想请问:如何通过图1获取到图2对应的物体门路?

A1:PrefabUtility.GetNearestPrefabInstanceRoot用来获取最近的预制体实例;Root PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot用来获取预制体门路。

        [MenuItem("Tools/GetPrefabInstancePath")]        public static void GetPrefabInstancePath()        {            if (null != Selection.activeGameObject)            {                if (PrefabUtility.IsPartOfPrefabInstance(Selection.activeGameObject))                {                    var path = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(Selection.activeGameObject);                    Debug.Log("Prefab Path:" + path);                }            }        }

感激马三小伙儿@UWA问答社区提供了答复

A2:同意楼上的答复,此处我再稍作补充:

PrefabUtility.GetNearestPrefabInstanceRoot和AssetDatabase.GetAssetPath,前者针对的是曾经实例进去的对象(官网:返回指定对象所属的最近预制件实例根的资源门路),后者针对的是资源(官网:返回绝对于我的项目文件夹的资源门路名称)。题主的问题属于是前者,如果间接点击资源并用AssetDatabase.GetAssetPath,就能够获取到资源门路。

感激翟孟飞@UWA问答社区提供了答复

20210906
更多精彩问题等你答复~

1.Vulkan API的性能及兼容性
2.Unity TMP字体计划如何抉择
3.如何实现AAB包的增量更新

封面图来源于:Daydream Renderer for Unity
Daydream Renderer是一组脚本和着色器,旨在容许在Daydream平台上以60fps的帧率实现高质量实时渲染。


明天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题兴许都只是冰山一角,咱们早已在UWA问答网站上筹备了更多的技术话题等你一起来摸索和分享。欢送酷爱提高的你退出,兴许你的办法恰能解他人的当务之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官网技术博客:blog.uwa4d.com
官网问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官网技术QQ群:793972859(原群已满员)