1)Text Mesh Pro图文混排如何对任何图片都能实现
2)PlayerSettings.WebGL.emscriptenArgs设置无效的问题
3)Prefab对DLL中脚本的引用丢失
4)如何在第三人称蓝图模板中获得当前相机SpringArm的Target Arm Length
这是第386篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助力大家更全面地掌握和学习。
UI
Q:目前Text Mesh Pro图文混排需要把图片打入图集并放入TMP的Resources文件夹中。项目中想在任务UI面板展示很多装备或物品的icon,这些icon都是打好了的图集,很多别的系统也要用,不可能都放入TMP的这个资源文件夹里,但这样就无法进行图文混排,请问有什么解决办法吗?
A1:把TMP里面所有的Resources.Load接口,都替换成项目自身的Bundle加载接口,应该就可以解决了。
感谢王灿光@UWA问答社区提供了回答
A2:可以注册以下回调:TextMeshProUGUI.OnFontAssetRequest,这样就可以自定义一个加载方法。
如果加载成功了,TMP就不会Resources.Load。
感谢程一峰@UWA问答社区提供了回答
WebGL
Q:游戏里用了C++的第三方库集成到xLua里面,端版是用CMake构建,可以配置宏、Include路径等,很方便。
我现在用Unity 2021.3发布的WebGL版本,xLua是把所有Lua代码放在了"工程目录/WebGLPlugins"下面,在引擎里去#include这里的C代码,也没问题。
但是自己的C/C++代码比较多,也不能全部扔在同一个目录下,如果加了目录,就有跨目录Include的问题(主要是lua.h,lauxlib.h)。从实际表现来看,include .c或.cpp时,用到的.h文件如果是在同目录就没问题,如果跨目录了就会找不到。
我用PlayerSettings.WebGL.emscriptenArgs = "-Imy_file_folder_path";这样设置搜索路径,但是没用;然后定义宏-Dxx也没用,不知道为什么。(参数中没有自己定义的路径和宏,都是Unity自己的,虽然ProjectSettings.asset已经生效了。)
请问有解决方案吗?
A:在Unity 2021.2之后更新Emscripten,emscriptenArgs属性失效了,可以把Lua代码和C/C++代码都放到一个层级,然后改引用。
还有一个方式:找到你Unity安装目录\PlaybackEngines\WebGLSupport\BuildTools\Emscripten\emscripten\emcc2.py,如果没有emcc2.py就找emcc.py,在里面找到get_clang_command方法,这个方法就是拼接执行编译C/C++代码语句的,在[src_file]后面增加+ ['-IAssets/XXX/XXX'],注意-I和Assets之间没空格,大概这样子:
`def get_clang_command(src_file): return get_compiler(use_cxx(src_file)) + get_cflags(options, state.orig_args) + compile_args + [src_file] + ['-IAssets/XXX/XXX'] `
注意py文件缩进问题,多个文件夹就添加多个"-I",我猜因为它自己有"-I."参数,所以可以使用相对目录(对clang++编译不太熟,我在Windows的Unity 2021.3.38f1上使用可行。)
compile_args变量是记录传进来的参数的,有精力也可以找找调用emcc2.py的地方传进来更合适,我这边没找到。
其它需要改C/C++编译参数的地方我也在这里改了,如果有其它更简便有效的方法,欢迎分享。
感谢高松@UWA问答社区提供了回答
Script
Q:开发时,不希望策划看到源码,于是将源码替换成DLL,但是这样挂在Prefab上的脚本引用会丢失,请问怎么解决?
A1:是原有的预制挂了CS,后面想打成DLL重新挂?如果是这样,遍历预制,去批量修改GUID和FileID。可参考文章《Unity将C#脚本转换为DLL,Prefab等文件不丢失引用的方法(转)》,文章里面用了DLLSwitcher插件,也可以自己理解Prefab GUID fileID和DLL,CS文件对应的关系就行了。
感谢c8K2SVRRcz1P@UWA问答社区提供了回答
A2:代码要分成底层和逻辑层。底层用DLL+Obfuscator,逻辑层就不能了,因为如果也加密,开发验收查bug都会费劲。
如果要防止策划带走代码,按照我说的底层DLL就行,即使他带出去,只有逻辑层的开发,后面也会一大堆问题,除非自己写底层,就要调试,时间还不如自己重新写,这样的博弈论一旦开始,这个代码库重要性就不高了。
同时也要防止策划带走服务端代码,做到服务端拿不到客户端,客户端拿不到服务端,这样即使有一方代码,也是无用代码。
感谢夏霖锐@UWA问答社区提供了回答
Rendering
Q:使用SpringArm组件会让相机在发生碰撞时拉近,但是为什么获得到的Target Arm Length值却一直不变?
A:在代码中,Target Arm Length永远是不变的,但是它下面有RelativeSocket,在蓝图中可以使用GetSocketTransform来获取,并且使用RTS_Component参数,取Location然后用VectorLength来计算:
`FTransform USpringArmComponent::GetSocketTransform(FName InSocketName, ERelativeTransformSpace TransformSpace) const { FTransform RelativeTransform(RelativeSocketRotation, RelativeSocketLocation); switch(TransformSpace) { case RTS_World: { return RelativeTransform * ComponentToWorld; break; } case RTS_Actor: { if( const AActor* Actor = GetOwner() ) { FTransform SocketTransform = RelativeTransform * ComponentToWorld; return SocketTransform.GetRelativeTransform(Actor->GetTransform()); } break; } case RTS_Component: { return RelativeTransform; } } return RelativeTransform; } `
还可以用SpringArm与Camera的位置相减来计算,分别GetWorldLocation再Sub和VectorLength:
可以发现两种方式得到的数据似乎有些小区别,这是因为该案例中还有一个相机跟随鼠标位置移动的功能,它会对Camera进行SetRelativeLocation,偏移其Y和Z值。方式一是从SpringArm中取,与Camera无关,所以不受偏移量影响;方式二用到了Camera的RelativeLocation,因此将偏移量也算了进去。
另外还有一种方式,无法计算距离,而是直接检测相机是否与世界发生了碰撞,发生碰撞时就会进行缩放。
欢迎有经验的朋友转至社区交流:
UWA问答 | 游戏开发者互动问答社区 | 侑虎科技
封面图来源于网络
今天的分享就到这里。生有涯而知无涯,在漫漫的开发周期中,我们遇到的问题只是冰山一角,UWA社区愿伴你同行,一起探索分享。欢迎更多的开发者加入UWA社区。
UWA官网:www.uwa4d.com
UWA社区:community.uwa4d.com