本地化第一需要考虑的元素自然就是语言,转换到游戏内容的话就是文本处理。绝大多数的多语言相关内容都只需要客户端关心,然而为了日后的更新便利,在一定程度上服务端和运营也参与了多语言文本的处理,这主要包括以下几个方面:策划配置表,服务器错误码提示,UI拼接时候的预置标题文本,敏感屏蔽词,以及相关的语言推送等。

1 配置表

配置表作为客户端最常用的数据展示,是需要第一个进行改造的。而大部分时候,这些文本会分散在各个表格之中,比如副本表的关卡标题,关卡描述。道具表的道具标题,道具描述。英雄表的英雄背景介绍,技能表的技能说明等等。太过于分散的语言表无疑会让策划或者运营翻译时变的更加复杂,同时还会产生遗漏,再者如果委托第三方进行翻译的话,还可能导致数据泄露的风险。

所以大部分做多语言的时候,都会将策划表格所使用的文本描述类的文字提取到一个单独的language表格中,用key来区分,同时在其他表格需要用到文本的时候配置成为语言表当众的key值。
比如上一章我们介绍提供游戏内语言支持的表格中,关键行配置的就是key值(红框内的是策划描述,配置为4的时候导表工具不会导出该列,只是策划自己用来做提示用的)。
同样,我们会在language表中配置该key所对应的多国语言。

策划这边表格约定好了之后,接着就是程序处理。其实流程很简单,只是程序在获取显示的时候一定要记得,凡是涉及到文本描述的字段一定要调用共用接口去配置表读取即可。

这里稍微插入讲一下程序方面针对多语言的设计。

一般来说这里有两种设计,一种是以语言为主体,所有的同语言的文本使用一张单独的表,这样每次在加载语言的时候就只需要加载一张表格,减少内存大家的同时也可以增加游戏的启动速度。坏处就是策划在维护表格的时候每个语言表文件都需要去修改,会产生遗漏。

第二种就是我们现在的方式,所有的语言都在一张大表格中,每一个key都配置了多个支持的语言,好处就是策划维护方便,当然坏处就是加载时候会产生额外的内存开销。

之所以我们使用第二种方式,是因为还有一个影响因素,我们的多语言是可以通过服务器下发配置进行增改的,也就是给线上纠错留下一个可操作空间。由于服务器不可能针对客户端做定制化的数据下推,所以服务器推送的数据也是以key为基础,推送所有跟该key相关的多语言文本给客户端进行处理。

那可能会有同学会问,服务器推送下来的数据,客户端肯定是知道自己需要哪种语言的,只保留处理自己目前用到的不就好了吗?

这里又要引入另外一个游戏特性,就是我们的语言是支持动态切换的,即在游戏内通过多语言的界面选择之后,不用退出游戏,立刻就会改变所有的文本显示。也就是说服务器下发的这些增补数据客户端必须都要缓存下来以应对该种情况。同时,服务器下发的增补数据也是策划使用工具导出维护的,所以从各个角度来说,我们都需要一份统一的数据格式方便策划维护,也方便程序处理。

所以客户端这边的语言获取代码就可以这样去表示:
设计语言的存储结构。

语言表的字典结构,其中key就是LanguageItem中的key

获取文本的时候根据当前偏好的语言,返回对应的文本(注:这里的枚举还没有重构为国际化标准):

插曲讲完之后再继续说说策划的表结构,因为语言表也不是同一个策划去维护的,所以在大表中有分为很多个页签。

因为客户端存储是以字段方式进行的,所以页签再多,只要key不重复,都可以随时将它们组合在运行时的存储结构中。

不过这里还有一个需要注意的地方就是base_text这张表。这里涉及的是一个更新问题。因为表格都属于资源也就是都可以在热更或者补丁中进行更新,但一个悖论就是,热更新模块怎么更新它自己呢?

在执行热更新的界面本身也是需要显示文本的,所以这个表的作用就是定义了这些相对固定,启动就需要使用的文本情况。

但也不是说这张表不能更新,只是更新了之后只有下次启动的时候才能看到更新后的文本效果了。

2 服务器下发

客户端更新和服务器更新比较大的区别就是客户端更新需要倒腾玩家。而玩家应该越少折腾越好。从更新流程而言,繁琐程度都差不多,都需要进行一整套的补丁流程,但从产品而言如果能不麻烦玩家或者用户的就尽量不要叨扰。

从设计上说,服务器拥有对客户的更大的控制权也是好事,毕竟如果100万用户你想达到100%的更新覆盖率要很久,但是如果是由服务器发布的,客户端只要连接上来就能体现最新的内容,并且几乎是无感知的。

关于服务器的详细下发技术我们会在下个小节讨论。在日常的操作过程中,我们会在策划的表格目录下放置一个hotfix的目录。策划可以将需要由服务器下发更新的数据表放置在该目录下,然后导表工具会识别该目录内容,将数据导入到服务器指定的hotfix目录下。

服务器启动的时候会读取该目录下的数据缓存,每次客户端登陆成功会通过指定协议下发增改数据,客户端收到增改数据进行缓存处理,客户端能在运行时不重启就修复显示内容。

同时服务器也提供了工具给运营后台,可以手动控制服务器进行Horfix全局下发,也就是说服务器不必是客户端新链接上才可以下发,它同样支持针对所有在线用户,在任何时候进行不停机修复内容。

当然这么好用的功能可不能仅用在语言文本更新上,实际上它是支持任意策划表格的修复。比如我们再版署过审时候就用来更新屏蔽词库。

3 UI预置

文本另外一个常用的地方就是UI界面了。大部分时候在编辑UI的时候都需要将文本直接直接放在在界面上以查看UI效果。或者有一些静态的Label等描述控件都是需要持久显示在界面上的。所以这里我们既要能够让UI编辑人员能够直观的编辑和处理Prefab,又要确保游戏在运行过程当中不要产生遗漏,都能正常替换为指定语言的文本。

前面其实我们有提过,在字体和插件这块我们使用的是TextMeshPro。虽然在实现方式上有差异,但和UGUI的Text组件相比较而言,接口差异并不是特别大。UI层面使用的Component是TextMeshProUGUI,它也是简单的赋值text字段即可。

要实现这个也很简单。多语言的管理和数据都是在游戏初始化的时候进行的,也就是说它会先于所有的UI逻辑完成。等到游戏内开始加载界面的时候,所有的组件和数据都已经可用。所以只需要在Text的相关组件上绑一个自定义的多语言组件,先填好语言文本的Key值,并在Awake的时候进行文本查找和赋值即可。

代码层面也非常简单:
仅此而已。

另外我们前面有提到,游戏是支持运行时动态切换语言的,这也得益于该脚本。当在语言选择界面切换了某个语言之后,会触发一个SwitchLanguage的函数。
而它只是找出当前所有的组件进行一次重新赋值即可。

4 屏蔽词

屏蔽词是国内做游戏,永远逃不开的、必须处理的一个功能点。随着时间推移,词库的词条数量只增不减的情况下已经变得越来越庞大,甚至在我们申请版号的过程中还在不停的增加。我们现在用的字库已经有大约55万条之多。这些屏蔽词不仅仅是占据了大量的内存空间,也为业务开发带来了不同程度的阻碍。比如聊天,比如邮件私信,比如联盟公告、社交留言等等,但凡玩家能够自由输入的地方都需要判定屏蔽词。

关于屏蔽词的实现可以查看我的另外两篇文章:

1、版署送审,一共要踩多少坑?实名、防沉迷和屏蔽词的完善方案

https://zhuanlan.zhihu.com/p/142116058

2、Unity手游实战:从0开始SLG——独立功能扩展(二)使用DFA处理屏蔽字
https://zhuanlan.zhihu.com/p/84685657

除了上述所描述的内存和业务处理之外,还有一个特别为版署审核定制的任务:增量下发屏蔽词库。关于Trie树的相关介绍直接看上面的文章即可。

在游戏内我们的屏蔽词库甚至达到了55多万条内容。这庞大的字库会严重拖慢游戏初始化的时间,并且在处理的过程中产生大量的GC,拉高Mono的峰值。

这里有两个应对措施,第一将屏蔽词的格式进行离线处理,处理为可以直接进行序列化的格式,以减少运行时的解析时长和mono内存。第二由服务器下发的屏蔽词也事先处理为对应格式,服务器下发解析之后扩充trie树,以完成屏蔽词库的扩充。

但不管怎么优化,庞大的基数还是会对游戏启动和内存峰值造成了较大的影响,并且似乎难以避免。下面是开发过程中缩减后的词库数量(防止每次启动耗费大量时间)。

5 推送

最后一个相关的内容是移动平台上的通知推送。为了让运营后台能够针对不同地区或者语言系统进行对应语言的消息推送,需要能够识别出对应玩家所使用的语言标签。

这个相对来说可能和多语言关系不大。我们接入的是TPNS系统。系统的后台有一个特性可以给指定标签的用户推送消息,我们的想法就是给不同语言系统的玩家在初始化的时候做个标签,然后运营针对不同语言系统的标签组使用对应的语言进行推送。

所以这里大概也就是拓展了一下TPNS的SDK功能,在玩家登陆后上报一个标签而已。

以上便是本次本地化元素相关的一些内容,下一章节讲一下服务器下发的具体流程。

最后,恭喜TLOU2拿下今年7个奖项,心中最美的画面永远停留在这里了

unity 加载关卡_Unity手游实战:从0开始SLG——本地化篇(四)提取本地化元素相关推荐

  1. unity 加载关卡_unity中加载新关卡函数简单用法

    Application.LoadLevel 加载关卡 static function LoadLevel (index : int) : void Description描述 Loads the le ...

  2. unity 加载关卡_Unity5.0_Application.isLoadingLevel 正在加载关卡_软件教程_资源库

    摘要:Unity5.0_Application.isLoadingLevel 正在加载关卡_软件教程_资源库 Application.isLoadingLevel 正在加载关卡? static var ...

  3. unity asset store下载不了_Unity手游实战:从0开始SLG——资源管理系统-基础篇(三)AssetBundle原理...

    先用一句话介绍一下AssetBundle吧. AssetBundle系统提供了一种压缩文件的格式,可以把1到多个文件进行索引和序列化. Unity项目在交付安装之后,会通过AssetBundle对不包 ...

  4. 刺激战场服务器未响应加载失败,刺激战场辅助提示驱动加载失败 怎么办 | 手游网游页游攻略大全...

    发布时间:2016-06-07 恶灵附身bink2w64.dll加载失败怎么办?有恶灵附身玩家跟小编说他在玩到第7章石门保存时突然弹出了"bink2w64.dll加载失败"的错误提 ...

  5. Unity手游实战:ECS设计思想和Entitas插件

    Unity手游实战:ECS设计思想和Entitas插件 一.ECS设计思想 ECS设计理念并不是一个新兴的事物,早在90年代就存在了.但是走入大众视野则要归功于<守望先锋>这款游戏.201 ...

  6. Unreal Engine 4 —— 异步加载关卡的实现方法及思考

    这篇文章介绍了在ue4中实现异步加载关卡的方法,以及我对应的思考. 背景 在很多游戏中都有用到关卡的异步加载,关卡的异步加载指的是在游戏的某个阶段,使用多线程的方法进行新关卡对应的内容加载.从而能够免 ...

  7. Unity加载进度条

    转载自:http://www.58player.com/blog-2537-89690.html 背景           通常游戏的主场景包含的资源较多,这会导致加载场景的时间较长.为了避免这个问题 ...

  8. Unity加载倾斜摄影模型/激光点云,开源

    [重大更新]现已支持WebGL 业余时间尝试了下用Unity加载倾斜摄影模型/激光点云,目前支持Bentley ContextCapture生成的3MX格式 源码见 https://github.co ...

  9. 用爬虫抓取动态加载数据丨Python爬虫实战系列(6)

    提示:最新Python爬虫资料/代码练习>>戳我直达 前言 抓取动态加载数据 话不多说,开练! 爬虫抓取动态加载数据 确定网站类型 首先要明确网站的类型,即是动态还是静态.检查方法:右键查 ...

  10. UE5热更新(通过Pak包加载关卡资源,并添加到流关卡)

    请先阅读我上一篇文章)UE5热更新(Pak包的Cook,打包,加载,踩过的一些坑 ** 老规矩,还是先说踩过的坑.** 加载关卡和加载其他蓝图资源有一些不同.加载其他蓝图资源,我们要先创建一个新的FP ...

最新文章

  1. linux下配置apache多站点访问-小案例
  2. cmake (3)多个源文件aux_source_directory
  3. 为什么不读顶级会议论文?
  4. 滴滴李先刚:语音识别在复杂场景的性能将显著提升
  5. mysql建表的规则_MYSQL建表规则 - Love彼岸花开的个人空间 - OSCHINA - 中文开源技术交流社区...
  6. 如何在水晶报表显示上下标
  7. 一个前端的10年前端职业路
  8. 粉尘防爆设备-尘密性设备
  9. 使用Win2D在UWP程序中2D绘图(二)
  10. Arduino-定义串口
  11. 开源软件清除了“开源”和“商业”之间的障碍——商业软件、开源软件和自由软件的区别
  12. java 复制文本到剪贴板,使用Java将文本复制到剪贴板
  13. 有些微信小程序助你提高生活效率!
  14. pandas 取某一列数据的几种形式比较
  15. 史上最全常见前端大厂面试知识点汇总【已过字节, 腾讯teg,华为,网易】
  16. 多恩布什《宏观经济学》第十三版笔记和课后答案
  17. Anaconda创建虚拟环境时报错 InvalidArchiveError Error with archive D:\\(anaconda的路径)\\pkgs\\vs2015_runtime
  18. git 多人在同一分支上迭代开发时,如何保证分支提交历史保持线性
  19. Eclipse+Java+Swing实现宠物商店管理系统
  20. CEOI 2020, Day 2 A,B题解 CF1403A CF1403B

热门文章

  1. OGRE: OgreOverlaySystem.h: No such file or directory
  2. ***_ha_高可用_链路备份
  3. Locality-sensitive hashing
  4. Santander Customer Transaction Prediction(2)
  5. 从零开始的Unity萌导书#1:Hello,Unity!
  6. Jenkins可持续集成
  7. Javascript的函数直接量定义
  8. 高通“扶”大唐 狙击低端芯片玩家
  9. SQL Server - 深入探讨SQL Server 2016新特性之 --- Temporal Table(历史表)
  10. 如何将秘钥分发到多台机器