关于lua:关于AI逻辑写在Lua中的问题

4次阅读

共计 3365 个字符,预计需要花费 9 分钟才能阅读完成。

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(原群已满员)

正文完
 0