响应式数据结构
所谓响应式数据结构是指一类针对数据的封装方法,将数据项与改变回调放在一起,能相对简单地实现数据自动绑定以及其它和数据更新相关的功能。
一个典型的响应式数据结构大概如下
public class ReactiveData<T> { protected T dataContent; public event Action<T> dataCallback; public ReactiveData() { dataContent = default(T); } public ReactiveData(T data) { dataContent = data; } public void SetData(T data) { dataContent = data; dataCallback?.Invoke(dataContent); } public T GetData() { return dataContent; } }
非常简单的代理方法封装,通过为自动绑定数据添加代理方法,并且使用SetData方法修改数据内容即可实现数据变化时的响应。
这类封装方法比较典型的应用场景包括玩家的各项动态数值,比如生命值和魔法值,使用响应式数据结构能避免在UI控制代码中频繁更新或者需要设置额外的机制通知界面更新。
此外还有一些特殊的数据关联场景也可以使用这种封装机制。
标签化数据设置
对于数值类的数据,展示到界面上时只要直接转为字符串显示即可,但这种可以直接展示的数字往往并不会很多,很多情况下它们不会是最主要的界面展示元素。
尽管它们也许十分重要。
游戏界面上更多时候展示的是图片以及说明性的文字,还有剧情的补充说明以及各种按钮文字等等元素,它们不光用于提升玩家的游玩体验,也是游戏内容的重要组成部分。
在简单的游戏开发中,文字和图片的展示往往会内嵌到代码中,也就是俗称的“硬编码”方式,比如用配置类里写好的路径读取图标,或者直接在UI组件里写好按钮上显示的文字等等。
随着游戏内容的丰富和复杂性的提升,这样的方法很快便会从简单易用变成麻烦制造者,硬编码的配置文件会在内容急剧膨胀的过程中变得越来越不可读,数千行的配置代码或许对计算机而言不算什么,但对开发者来说却是噩梦。
这时候比较常见的解决方案就是将配置挪到文件中,让游戏在启动时读取出来,而为了顺利索引到需要的配置项,为每个配置项预先设定标签就显得十分重要了。
以一个图片路径配置为例
public class ImageConfiguration { public Dictionary<int,string> uriSet; }
字典内使用数字去索引了所有图片的URI,在使用时只要能获取到图片数字ID即可取出对应的路径,方便进行动态加载。
使用这种方案的话,图片配置就可以使用Excel之类的文本编辑工具编写,然后读取并转化为这个配置类的内容,在游戏中使用。
文本内容同样可以使用这种方式进行外部配置,将文本标签化之后便能让游戏通过读取配置文件来得到应该显示的文字。
而文本内容的标签化,正是多语言系统的基础。
文本标签化与多语言
所谓的多语言系统,本质上来说就是让游戏根据当前的语言环境自动去读取对应的文本内容并予以展示,在文本标签化的前提下,这个功能很容易实现。
但多语言和简单的文本标签化也有一些区别,普通的标签化文本其标签和内容是一一对应的,这样才能准确找到应该显示的内容。
然而多语言的需求中,标签和内容的映射是一对多的,同一个标签下会有不同语言的内容,因此需要多加一个维度来进行标签构建方可达到要求。
增加维度的方法有几种,最简单的是按照语言的不同分成不同的配置文件,游戏启动时按照环境读取对应的文件即可。
此外也可以将所有语言的文本内容都打包到一个配置文件中,新增一个语言属性来区分每条不同的内容。
一种可能的实现如下
// 多语言配置 public class LocalizeConfiguration { public Dictionary<string, TextDataSet> localizeData; public string currentLoc; } // 单个语言的标签化文本 public class TextDataSet { public string languageTag; public Dictionary<string, string> textSet; } // 使用方法 localizeConfig.localizeData["LANG_TAG"].textSet["TEXT_TAG"];
多语言中的自动绑定
有了标签化的多语言文本内容之后,在展示方面就需要借助自动绑定的思想了,即将具体进行文字展示的组件与标签绑定起来,刷新的时候根据语言环境和所绑定好的标签搜索应该显示的内容。
一种可能的方案如下
public class LocalizeText : MonoBehavior { private Text contentText; private LocalizeConfiguration configs; private string contentTag; private string contentStr; private void Awake() { contentText = GetComponent<Text>(); } public void SetupTag(string tag) { contentTag = tag; } public void NotifyUpdate() { contentStr = configs.localizeData[configs.currentLoc].textSet[contentTag]; contentText.text = contentStr; } }
在这个脚本的基础上,将场景内所有挂载了它的对象统一管理起来,遇到需要刷新语言环境的时候只要依次调用NotifyUpdate方法即可。
小结
响应式数据,标签化文本等做法都是一些看上去多此一举或者十分繁琐的行为,但在某些特定场景需求之下,它们又能发挥出一定的功效。
至于多语言工具,有大量成熟的第三方插件或者框架可以使用,在实际开发中并不一定需要从头开始自己编写一套。
PS:最近跑去参加了一下TapTap举办的线上游戏开发比赛,感受了一下竞赛的氛围~
PPS:寻路算法的研究差不多告一段落了,相关功能也已经添加到了游戏中,抽空就写日志分享吧~
暂无关于此日志的评论。