6

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

 3 years ago
source link: https://blog.uwa4d.com/archives/TechSharing_266.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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


这是第266篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

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

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。
  1. 统一在宿主程序中,对游戏中多个协程进行按需调度,比如等待指定时间,帧数后调用Resume唤醒协程。

感谢lujian@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6128bfac8f8c834241858fd5


Shader

Q:Particle Additive Shader中使用了该宏:UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);,查了一下没找到相关说明。字面理解是声明了一个深度图。

在默认管线(向前渲染)中,按照常规理解深度图需要通过设置Camera的depthTextureMode来指定。还请各位指教。

A:Shader中很多宏的确是没有官方说明的,我们需要去CGInclude文件夹中寻找其确切定义。

UNITY_DECLARE_DEPTH_TEXTURE在HLSLSupport.cginc里:

1.png

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

2.png

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

3.png

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

4.png

然后继续在该文件中找tex2Dproj:

5.png

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

感谢翟孟飞@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/612db43b8f8c8342418c5c0f


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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6130343f8f8c8342418ff792


Script

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

6.png

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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/613033058f8c8342418ff5bf

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK