分类
未分类

游戏开发中的多语言文本管理2

前一阵子在做新项目的时候想了一下目前的项目在本地化文本管理方面遇到的诸多问题,正好又碰到了一个新朋友来问这个问题,翻出了7年前我写的一篇博客,现在回头看的话感觉当时写的太简陋了,因此决定重新分享我的个人经验,在多语言文本管理中遇到的问题,以及我建议的解决方法。

中心化管理:看起来很美

市面上最常见的多语言文本管理的手段是中心化的管理手段,即多语言文本完全脱离其所被使用的场合,作为一个单独的表单或文件存在,任何需要显示文本的地方,都以key为唯一的索引从这个文本中来获取对应的本地化语言的文本。

在举一个具体的例子之前,我们要明确一个观点:一个项目中的文本主要分两种:UI文本和数据文本。UI文本指的是界面上各种控件显示的文本,数据文本则是需要策划管理的游戏数据的文本。除此之外还有第三种文本:服务器文本,这个属于比较特殊的情况,不在下面的例子中讨论,文章结尾的地方会专门说明。

假如我们在做一款RPG游戏,有英雄和技能两个表,最终导出了三个文件,那么一个典型的中心化管理的多语言文本可能是这样设计的文件结构:

  • hero.json
  • skill.json
  • text.json

我们只看hero.json和text.json来说明问题。

假设一个英雄非常简单,只有两个属性:名字、技能,那么英雄的数据可能长这样:

  • hero_id = 1
  • hero_name = “text_hero_name_001”
  • hero_skill = [1,2,3]

本文重点关注的即是hero_name的部分,这是需要多语言管理的部分。显然“text_hero_name_001”是一个key,其指向的真实文本储存于text.json中。

那么text.json长什么样?如果我们用同一个text.json来存储全部多语言的文本,那么可能长得类似这样(Dictionary/Object风格):

  • text_hero_name_001 =
    • {
      • “zh_CN” : “王老王”,
      • “en_US” : “King Old King”,
    • }

也可能是这样(CSV风格):

  • key,”zh_CN”,”en_US”,
  • text_hero_name_001,”王老王”,”King Old King”,

也可能是每个语言对应一个text.json文件,这种就不再举例赘述,但不管哪种,本质都是一样的:文本脱离于其所被使用的环境,进行中心化管理,并且在被使用的地方通过Key来索引。

这看起来没有任何问题,也是业界的主流做法,但在我这些年游戏开发的经验中却觉得这样做的问题非常大,甚至可以说这都是程序思维的产物,能实现需求但却基本没考虑策划和UI的维护成本,下面就开始详细的阐述这种方式的弊端。

问题一:脱离使用环境

假设你是一个UI同学,现在做了一个简单的弹出层,有标题、正文和确定按钮,你需要三个文本来描述这个界面:

  • 标题:确认充值?
  • 正文:做游戏不赚钱,就是交个朋友。确认充值648钻?
  • 按钮:确认

那么按照上述的管理方式,界面上可能是这样的:

  • 标题:text_dialogue_title_iap_001
  • 正文:text_dialogue_content_iap_001
  • 按钮:text_dialogue_button_iap_001

一个UI同学在UI编辑器或游戏引擎中长久的面对这种不可读、不可排版的文本,长此以往对心灵会产生什么样的打击不言而喻——当然,这跟程序没关系,程序也不在乎。

假如UI抱怨的非常凶,要求程序在编辑环境中也要默认把这堆看不懂的key给显示成简体中文,而程序勉为其难的也给做了,那么至少解决了UI同学的问题,但前文提过,UI文本只是一个项目中的一部分,还有另外一个大头:数据文本

还是刚才的hero.json的例子,假如我们这个RPG项目有100个英雄,那么我们在hero.json中能看到的是什么呢?是任何一个英雄你都不知道他的名字是什么,只能看到从text_hero_name_001到text_hero_name_100这种意义不明的东西。

作为一个策划,你不太可能记得住一个英雄的ID,反而记住他的名字要容易得多。那么现在你要去找一个英雄的数据,你要怎么办?你可能要去text.json中找到这个英雄的名字,再看对应的key来识别他的ID,再去hero.json中找到这个英雄的数据。

这时候假如有个策划不那么讲究,没按照规范去好好的给hero_name对应的文本建key,并且当时他偷摸就提交了,谁也不知道,本来应该叫做”text_hero_name_100″,但这个策划给起成了”text_hero_name_wanglaowang”,那你找起来就会想杀人了。

这时候还有更大的问题,如果一个策划想要知道一个英雄有什么技能,那怎么办?因为技能表里也是不带名字的,他就只能先想办法找到英雄的ID,然后再找到技能的ID,然后再去看技能的名字

这种套娃操作每多一层,策划的心理都会多一层崩溃。

除此之外,脱离使用环境还使得你的项目需要翻译外包的时候看似容易,只要把text.json丢过去就行了,但因为翻译的人员不知道这个文本是用在哪里的,因此很容易出现翻译完了结合上下文意义错误或UI的显示出现异常的情况。这部分的沟通成本也是相当巨大的。

问题二:单一职能原则

假设我们还是上面那个做充值对话框的UI同学。这个项目肯定不止这样一个对话框,所以我们还会做很多很多其他的对话框,比如购买各种东西的确认对话框、各种危险操作的确认对话框、需要选择个数或者填写内容再提交的对话框等等。

做多了之后我们就会发现,这些对话框都有一个确定按钮,而且按钮的文本内容可能都一样,都是“确定”,但却每次都要起一个新的text的key。当这个UI同学打开了text.json后,发现有几十上百个不同key的文本都叫“确定”的时候,他一定会怀疑这种做法是不是有问题。

最后UI们商量了一下,决定所有的确定按钮都用一个key,比如这个key叫做“text_dialogue_button_confirm”。大家觉得工作简单多了,所有的确定按钮都用这一个文本,不用再弄大量臃肿的文本了。

直到再过了一段时间,策划提了一个需求,充值界面的确认按钮不能只写“确认”,要写“确认,我家有矿”。策划认为简单的改文本就行,于是就把“text_dialogue_button_confirm”的内容给直接改了。

改完了之后发现项目出了大问题,所有的对话框的确认按钮的文本都变成了“确认,我家有矿”。然后QA爸爸就提着刀过来了。

QA爸爸把这个问题捅到了项目主管那里,等到项目主管发现这个问题之后,决定检查一下所有的text.json里面的文本,要确认下到底有哪条key是不止被用了一次的,但却发现很难做到这样,因为项目进展到这个阶段,text.json里面可能已经有上万条数据了,你既没法简单的知道里面有没有完全没被引用实际上已经冗余了的条目(比如删了一个技能,但技能的名字没删),也没法确认里面的某一个条目有没有被多次引用(类似上面的确认的问题,策划和美术都会有这个情况),从而导致改动的时候引发意料之外的问题。

当然,你可以硬性的规定,凡是要复用的text都放到同一个文件里(比如它叫general_text.json),凡是应该被用且应该只被引用一次的text都放在text.json里,但毕竟只要key是人为的手写的,就无法完全避免这个问题,很快两个文件里面可能又会出现混乱——text.json里面出现了被引用多次的key,而general_text.json里面出现了冗余的key。

假设这时候有一个程序同学觉得可以从工具上来入手解决这个问题,于是他写了一个工具,从此text.json的key都是自动管理的了,策划同学可以方便的在各个数据表中添加、修改、删除文本,key的关联都是自动完成的,或者说text.json的key完全都由这个工具自动管理了,key甚至对策划来说是不可见的,从而从根本上避免了策划手误的问题。

这听起来很美好是吧?但其实并不是的,因为这个方案依然有问题。

从原则上来说我个人是非常不建议项目在常规的开发工作流中加入一些自己开发的工具的,除非是在这方面有相当丰富经验的开发团队,或者这个工具本身足够简单、不进入工作流(比如用了一次就不用了的“日抛型”工具)。原因有三点。

首先是这个工具的可维护性问题。这些工具在开发之时只是为了尽快的解决某些小问题,并没有严格的当做一款可以交付使用的产品来对待,因此缺乏文档,并且开发的也相对随意(用户是内部开发人员而不是游戏玩家)。这个工具本身需要测试但缺乏测试,它的完整性和可靠性需要支付相当大的成本,而这部分成本本来是可以去开发玩家可以体验到的功能的。这还只是短期的问题,如果我们从长计议的话,短期少做点功能,把工具做好,也没什么问题,但长期问题实际上更大。当这个工具被用了几个月甚至几年之后,不出bug的概率几乎等于0,而当初写这个工具的人可能早已不在这个项目组甚至离职了,而由于缺乏文档且开发随意,接手维护这个工具的人可能完全无法上手,这种情况下项目就陷入了一个两难的境地。还有很多情况下,随着工作流的调整或人员的变化,慢慢的这个工具也会被不断的迭代,但其迭代的速度往往是滞后于团队的变化的,甚至最终成为拖后腿的卡点——你不得不用它,而你又明知道它已经不好用了。

其次是这个工具的可靠性问题。这些工具所依赖的开发环境过于复杂,公司的一次停电、游戏引擎的一次升级、一个脏数据的写入、一个策划不小心的误操作(比如把ID填重复了),都有可能产生大量的问题,这些问题是最早做工具的同学所意料不到的(大家都知道,程序员是乐观的),而为了解决这些问题所有的策划都不得不停工,并且问题解决的代价和效果也不得而知(比如可能导致json中的所有排序都变了,虽然实际上没变化因为json里面排序不重要,但QA爸爸能看到的就是一个上万行的json文件的每一行都变了,而导致QA爸爸提着刀过来)。

最后一旦你开始依赖这种小工具后,往往会接二连三的做一大堆工具,前面的两个问题很快会变成多个问题,很快就会陷入按下葫芦起了瓢的状态,甚至当出了问题之后你都不知道究竟是哪个小工具的锅,开发工具的人抱怨使用工具的人提的问题模糊而不确定(甚至怀疑是使用者自己的问题),使用工具的人抱怨开发工具的人做的破玩意不靠谱,最终所有人都难受。

因此,如果你必须要把某个工具加入工作流中,那么如果有外部的、成熟的、有长期维护的解决方案,尽量不要自己造轮子,宁可花点钱买解决方案,也比自己花精力去做这些事情要强,否则当你过了几个月甚至几年后,一定会为当初自己的决定后悔——假如你还在这个项目组的话。

要相信你的问题别人都早就遇到过了,用别人造好的轮子总是比自己造轮子强,人类社会就是这么进步的。

问题三:依赖性问题

假如你是一个策划,已经设计好了一个新的英雄,以及他的技能,现在要开始配表了。

既然要加英雄,那么理所当然的你打开了hero.json,但是当你加到一半的时候发现加不下去了,因为hero_name需要一个key,你必须先去text.json里面配置好这个文本,再填回到hero.json中来才能完成配置。提交的时候你必须同时提交这两个文件,否则英雄的名字就会显示错误,显然这是会被QA爸爸暴揍的。

等你搞完了之后又发现这个英雄要加技能,那必须又先去配技能表。而配技能表的时候又发现了必须要去先去text.json里面写好技能的名字。

而现实情况中这个套娃的情况往往更严重,以我目前的项目为例,我需要新加一个宝箱,这个宝箱有【名字】有【描述】,这个宝箱有一个对应的道具ID,道具有【名字】有【描述】,这个宝箱里面是一件新时装,这个时装有【名字】有【描述】,这个新时装有对应的道具ID, 道具有【名字】有【描述】,这个新时装有对应的时装碎片,这个碎片有【名字】有【描述】,这个碎片有对应的道具 ID , 道具有【名字】有【描述】。等这一套折腾完,你会发现最耗费精力的不是宝箱->时装->碎片的套娃,而是不管你干啥都需要去text.json里面加名字,而这对于策划来说也是非常痛苦的。

当然,在删除配置的时候策划也会面对同样的噩梦,要删一个东西就要删大量对应的text,而这种删除操作的危险性在上面的一个问题中已经提到过了,因此最终往往会演变成“冗余就冗余,只加不减就好了, 这样至少不会出错”的情况。这会导致外包成本急剧增加,因为你也不知道哪些文本有用,哪些文本没用的。

更严重的是这会让你的项目很屎,而这屎不是喂给玩家的,是喂给策划的。大家都知道这里面充满了屎,但谁也没法认出来究竟哪些是屎。一个敢喂自己屎的策划,对玩家能做出多么丧心病狂的决策都是有可能的。

当一个东西变得反直觉的时候,大概率有更好的方案可以去替代它。

问题四:冲突问题

极端的情况下,不管你改客户端的什么表,都需要同时的去改text.json。而text.json只有一个,所有策划共用,因此冲突的几率极高,同时类似SVN的版本管理工具对json文件的比对支持的也不是特别好(你可能需要专门的json语意比对工具),于是策划的作业变成了一场噩梦,你只是想把自己改的东西提交上去而已,但却发现这竟然如此困难。

而更大的问题是,你不只是提交就完事了,你还需要合并呢,合并的时候更是一场噩梦。

虽然靠培训每个人都要学会提交、合并、解决冲突可以来克服这个困难,但毕竟这个困难实际上……有可能压根就不存在,而只是因为一开始设计的偷懒导致的没必要的困难。你让程序把所有代码都写在一个文件里他们自然不干,那为什么策划和UI的所有文本都在一个文件里他们就干了呢?——因为不用他们维护,这是个屁股决定脑袋的问题。

问题五:唯一性问题

由于大量的文本都堆在一个文件里,为了保持key的可读性和唯一性,命名就成了一大难题,其困难程度甚至比美术同学考虑美术资源的命名还困难,因为美术资源可以分文件夹,但key都堆在一起。

想找到一套完美的可以描述所有东西的key的方法不是不行,但这种结果大概率会让key变得非常冗长。比如美术可能考虑把界面的名字或者prefab的名字加进去,策划则要把是哪个表的哪个id的哪个字段用到的加进去。很快你的项目就会出现一个神奇的现象:大部分的字符串的key甚至比其本身的内容还要长的多的多,整个text.json文件奇大无比,但“三斤鸭子两斤嘴”,肉没多少。这种情况的体验就像是大家上班的时候互相不叫昵称也不叫姓名,而是互相喊身份证号的完整号码来互相沟通一样,显得非常蠢。

那怎么办?

解决方法我觉得很简单,去中心化,直接对症下药,需要完成以下几个需求:

  • 文本不再中心化全放在一起,而是分散开来,根据各个模块分散到各个文件中,并且把程序设计成只能访问自己相关模块的文本。这样即能解决一个大文件策划互相冲突的问题,也能解决滥用key的引用导致无法追踪每个key都被哪里用到了问题。一言以蔽之,把text从全局的改成本地的。
  • 文本尽量贴近其所被使用的场合,甚至可以完全免掉key是最好的。这样既不用费劲去给key取名字,也不用去琢磨key的冗余或被多次引用的问题了,也不用去开发劳什子自动关联key的工具了。

于是hero.json会变成什么样子?大概会变成这样:

  • hero_id = 1
  • hero_name =
    • {
      • “zh_CN” : “王老王”
      • “en_US” : “King Old King”
    • }
  • hero_skill = [1,2,3]

回头一看,这其实就是我七年前贴的文章中《炉石传说》的做法。暴雪在《星际争霸2》中采用的还是中心化的管理办法,而《炉石传说》他们选择了另外的做法,我猜是他们吃屎吃够了。

如果策划用Excel来管理多语言的话,需要写插件,否则一个格子里面写Dictonary/Object风格的东西会很蛋疼;或者策划可以在多列中配置语言,但最终把多列导出成Dictionary/Object风格的内容。但是毕竟长痛不如短痛,总比搞好几个表来回贴key要舒服得多。

有人可能说了,这样策划要每次都去写”zh_CN”和”en_US”这种文本,不很容易错吗?但你想想,是写这样固定的文本容易错,还是每次都要依照一个规则去想一个新的key更容易错呢?

还有人可能会说,这样客户端不管当前语言是什么,都会加载全部的语言文本,有点浪费资源。但根据我个人的理解,占内存大头的永远不会是文本文本,而是二进制文件,因此这方面的性能问题也可以忽略不计。反而这可能成为一个好处,即切换语言不需要重启客户端更容易实现了,但毕竟我不是专业的程序,这里可能还涉及到加载字体等问题,这里要视项目最初的需求是否需要不重启客户端就能切换语言了。

好了,策划的同学解决完了,那么UI同学怎么办?

比较简单的做法是扩展一个支持多语言的控件,比如原本系统的文本控件只能输入一套文本,让程序扩展一下可以写多套文本即可,同时默认显示中文。比如一个确定按钮,本来UI拉上来一个button后直接在text里面写“确定”就行了,现在的话会有多行的text,其中第一行是”zh_CN”的,UI同学要在这里写”确定”,然后在第二行”en_US”里面写”Confirm”。同时还可以支持切换预览多语言效果。实际上很多多语言插件都是用类似的思路去做的,比如Unity的I2 Language(这里不是打广告,我没用过,但看demo感觉挺好用的,还支持图片和音频的多语言,而且这也是Unity Asset Store中最受欢迎的本地化插件)。

UI文本本地化之后的一个问题就是外包的时候我们还是需要导出文本,因此在一开始设计结构的时候需要尽量设计一个不依赖于Key同时还可以方便导出导入的结构,单独把每个界面prefab的文本导出,翻译完成后再导回来即可。上面提过的I2 Language貌似还支持谷歌翻译以及导入导出功能(这插件本质上还是中心化管理文本的,只是界面上隐藏了),感兴趣的同学可以自己试试。

但是以上毕竟只是脑洞,我决定在新项目中试一下用这种方式来管理文本的实际效果如何。因为都是我一个人做的,所以UI的多语言文本我决定不写在控件上,而写在代码里,一个prefab的代码把需要用到的文本统一在一个地方以Dictonary/Object的风格来声明好,方便后面调用。而策划配表的部分,我决定在Excel中每个文本一列,再导出的时候把同一个key的文本合并成Dictonary/Object风格的变量。

这里实际也引申出了另外两个关于UI实现问题。

第一个问题是Prefab这个东西往往是客户端程序和UI同学都要打交道的,这里非常容易出现问题,比如UI同学一不小心把某个节点隐藏了,QA同学提了BUG,程序同学绞尽脑汁的去调查问题最终发现居然不是自己的锅。解决方案业内也有一些,有的比较笨的办法是由程序同学来拼界面,这样避免UI同学染指Prefab,但拼完了难免坐标不对,UI同学要再调整一下;有的方法则是参考策划的工作流,把UI的编辑过程独立于游戏引擎之外,把界面当做是资源文件导入到项目中,从而实现了UI同学和程序同学作业对象的分离。也有其他的做法,比如对UI设计师和UI程序员的要求更高,双方必须紧密的结对作业,而不是各自分属不同的部门。还有的做法是UI在PhotoShop里面做完了工作后策划来拼界面,把和程序对接的工作交给了策划,从而UI不用考虑上传SVN的问题。还有的做法是逼着UI同学去学写代码,比如至少会用个蓝图啥的,从而避免程序同学染指Prefab。反正各种奇奇怪怪的做法都有,哪种是最好的不好说,要视团队和项目的具体情况而定。以上的种种方法中我个人最倾向的是哪种?如果是UI表现十分重要的游戏,那么提高对UI和程序人才素质的要求,强制其结对作业共同对UI的结果负责,是比较好的解决手段,能够实现质量和性能都比较出色的UI界面,但这样对人才的要求很高(相当于半个TA),大部分的团队不一定能做到,这种情况下另外一个选择是退而求其次,将UI的设计工作交给策划,只保证功能性但不保证美观度,在人力捉襟见肘的小公司/独立团队或功能无限庞杂的大项目中这也是个不错的方法。不管哪种,其本质都是要适应UI工作的特殊性,这不是一个可以简单的“美术vs程序”二元割裂的工作,而是必须有机的结合在一起才能完成的综合性工作,一切想着切割UI和程序的工作流的方案都注定不是最优的。

第二个问题是界面的很多状态和内容应该是以资源驱动为主导还是以代码驱动为主导?比如一个界面默认状态是应该隐藏的,那么是UI同学把隐藏给勾上比较好,还是程序同学在代码里初始化的部分写上强制隐藏好?按照我的倾向性的话,如果不影响性能的前提下,我倾向于用代码来控制。UI资源本身毕竟是静态的,因此凡是动态的东西都应该由代码来控制,这也是为什么多语言文本我觉得写在代码中比挂在界面上要好的原因,因为涉及到多语言,本身就已经不是静态的文本了。

祝我好运吧emmmm,前途未卜,不知道还会踩到多少坑,但总比现在的情况舒服。

(另外别问我为什么我不用I2 Language,因为Godot天下第一)

写在最后:关于服务器文本

所谓的服务器文本,即并列于UI文本和数据文本之外的第三类文本,这种文本常见的是停服公告、发给玩家的邮件、紧急维护通知跑马灯等种种由于具体写什么文本完全无法预估而只能在服务器端设置文本,客户端收到什么就显示什么的文本。这类文本大部分属于运营工具的范畴。

那么这类文本如何实现本地化?

这首先要看游戏服务器的结构,是各个语言的用户都混在一个服务器里面玩?还是每个语言的用户自己有自己的服务器?如果是后者的话那么很简单,每个语言的服务器发对应语言的公告就好了(甚至可能是完全不同的运营商),如果是前者那么这涉及到另外一个问题:客户端能否切换多语言?如果能的话,比如我用英文客户端登录之后,系统发给我的邮件可能是英语写的,这时候我切换成中文客户端重登后,看到的这封邮件是英文的还是中文的呢?确定了这个需求之后,才能设计服务器端文本的多语言是应该如何处理的。

只要提前考虑好,程序做起来都是很容易的。难的都是已经在线上跑了一阵子了又不得不改,这才是最难受的。

分类
未分类

堕落与背叛:暴雪曾经辉煌的叙事主题

首先一个开门见山的问题:

最能代表暴雪IP的是哪几张脸?

我觉得是上面这三张脸,分别代表了《魔兽争霸》《暗黑破坏神》和《星际争霸》三个系列。

那么这几张脸有什么共同点?

我觉得就是他们的故事主题都是堕落与背叛

阿尔萨斯的故事,是一个内心深处有着弱点的年轻王子被巫妖王利用,不断做出亲者痛仇者快的事情,最终彻底堕落,完全背叛了自己所本应坚持的道路与职责,并成为真正的巫妖王的故事。

因此阿尔萨斯堕落的原因有一半是其固有人格缺陷的内因,另外一半则是被诅咒教派拿来当枪使,沦落为其摆脱燃烧军团的道具,一半是外因。

暗黑破坏神的故事则更为黑暗,整个李奥瑞克一家全都不得善终。一条线是李奥瑞克王如何堕落为骷髅王,背叛了自己的王后与人民的故事,整个故事给人一种结合了《指环王》中刚铎摄政王迪耐瑟的疯狂与洛汗国王希优顿被奸臣支配的堕落,并且下场比两个人更惨。另外一条线是李奥瑞克王的儿子,年轻的王子艾丹铲除了暗黑破坏神后,将其灵魂石封印在自己的额头中与其在精神上对抗,但最终不敌,堕落为黑暗流浪者,直至完全变为下一代暗黑破坏神的故事。

在《暗黑破坏神》的语境中,李奥瑞克王和艾丹都是好人,但由于外在的污染所堕落,因此暗黑破坏神的故事更为黑暗,如果说阿尔萨斯还是自作自受罪有应得的话,暗黑破坏神的调性则基本是好人没好报

刀锋女王的故事与前两个有所不同,其之所以成为刀锋女王是由于被自己人背叛,沦为了牺牲品后又崛起成为刀锋女王的故事。在阵营转换之后,她也和阿尔萨斯类似,对原本所在的阵营或者说种族再没什么怜悯之心了,狡诈狠辣,击败种种强敌,最终称霸了科普卢星区。

刀锋女王为人类带来的威胁犹如魔兽中的诅咒神教或暗黑中的几大恶魔,但在星际争霸中,这一恶果是由人类所自己培养出来的,因此其结果颇有讽刺意味——在星际争霸中负责“伟大光荣正确”的种族是星灵,而魔兽争霸中负责“伟大光荣正确”的种族是人类。

因此我们可以概括出来暴雪塑造大BOSS的成功配方了,就是由于各种原因让他们堕落,背叛原本的阵营,并最终成为原本阵营的心头大患的故事。听起来好像没什么技术含量,但暴雪正是在这里下的功夫足够扎实,以其中最为出彩的阿尔萨斯堕落史为例:

  • 阿尔萨斯不听师父乌瑟尔的命令,屠杀了黑石兽人
  • 阿尔萨斯发现吃了被污染的谷物会感染瘟疫,并最终感染者会变成亡灵
  • 阿尔萨斯杀掉了污染谷物的来源,死灵法师克尔苏加德,但克尔苏加德说上面还有大佬,恐惧魔王玛尔甘尼斯
  • 阿尔萨斯遇到了麦迪文的预言,但拒绝前往卡里姆多
  • 阿尔萨斯发现被污染的谷物已经发给斯坦索姆的百姓吃掉了,因此进行了屠城,与玛尔甘尼斯展开屠杀竞赛。师父乌瑟尔拒绝服从,被阿尔萨斯剥夺了骑士资格,两人决裂
  • 阿尔萨斯击败了玛尔甘尼斯,并追随他来到了诺森德,吉安娜劝他不要去当他不听,两人决裂
  • 阿尔萨斯遇到了穆拉丁·铜须,为了让手下听命于自己,偷偷烧了返航用的船,并把罪名嫁祸给雇佣兵身上
  • 阿尔萨斯为了击败玛尔甘尼斯,去寻找霜之哀伤,并且不顾穆拉丁·铜须的劝阻获得了霜之哀伤,代价则是穆拉丁的死亡
  • 阿尔萨斯击败了玛尔甘尼斯,丢下了自己的部队任凭他们自生自灭
  • 一段时间之后,阿尔萨斯回到了洛丹伦,亲手杀了自己的父亲,继承了王位
  • 阿尔萨斯杀了自己的师父乌瑟尔,并从其手中夺取了父亲的骨灰盒,用来复活克尔苏加德成为巫妖

我们会发现阿尔萨斯的堕落史中存在这三个友方角色乌瑟尔、穆拉丁和吉安娜,以及两个敌方角色克尔苏加德和玛尔甘尼斯。乌瑟尔是老师,穆拉丁是亦师亦友,吉安娜则是爱人。阿尔萨斯最终背叛了所有的友方角色,直接害死了乌瑟尔和穆拉丁(后面还有吉安娜的师父大法师安东尼达斯、希尔瓦娜斯风行者等等),杀了被巫妖王当枪使的玛尔甘尼斯,并且最终把克尔苏加德从当年你的敌人变成了自己的随从。通过这一系列故事,我们可以清晰的看到阿尔萨斯是如何不断做出亲者恨仇者快的事情,最终完全倒戈,以及后面继续的一系列暴行的。

在《魔兽争霸1》和《魔兽争霸2》中,故事都是简单的善恶二元对抗,人类就是好的,兽人就是坏的。而《魔兽争霸3》通过刚才说的阿尔萨斯所代表的人物故事,把整个系列的叙事水平提高到了一个前所未有的高度。

类似的,李奥瑞克一家的堕落史与刀锋女王的遭遇背叛也都是非常详实的,情节跌宕起伏而令人信服。暴雪通过这些高超的故事,奠定了这几个角色成为各自系列中的C位角色。

很多非C位的角色,也有着类似的叙事主题,如魔兽的麦迪文与古尔丹、伊利丹、玛维·影歌、迦罗娜、凯尔萨斯,暗黑的衣卒尔、爱德莉亚,星际的萨米尔·杜兰等等。因此可以说很大程度上这种故事构成了暴雪的叙事特色。

然而,暴雪已经很多年没有再讲述类似主题的故事了,甚至可以说是完全背叛了原本的叙事基调,这无疑是令人失望的,甚至让很多老粉丝感到遭到背叛的,比如我,这是我成为暴黑的很大一个原因。

不得不说,暴雪目前自己对于老粉丝所做的事情,也是堕落和背叛。

在细数暴雪的罪名之前,要先提一下,暴雪除了堕落与背叛之外另外一个擅长的主题——牺牲与荣耀。

三个系列的作品中也都有很多类似的角色,《魔兽争霸》中的格罗姆·地狱咆哮,提里奥·弗丁,安度因·洛萨,《星际争霸》中的塔萨达,泽拉图,以及《暗黑破坏神》中的塔·拉夏,刚刚提过的艾丹王子,亚瑞特圣山的三蛮子等等。

在《暗黑破坏神》的黑暗幻想语境中,牺牲与荣耀是没意义的,最终无罪之人依然会堕落,这是是整个暗黑破坏神的一贯基调。在《星际争霸》与《魔兽争霸》中则没有那么黑暗,牺牲与荣耀成为了塑造悲情英雄的主要手段。塔萨达与迪里奥·弗丁都是面对族人的错误做法勇于进行挑战的典范,格罗姆·地狱咆哮更是通过牺牲完成了自我救赎,这些故事都非常感人,与前面说的堕落与背叛一同构成了《星际争霸1》与《魔兽争霸3》的主要故事,这也是这两部作品之所以伟大的原因:英雄的堕落令人惋惜,英雄的牺牲令人感动

回头看看《魔兽世界》、《暗黑破坏神3》以及《星际争霸2》的剧情,失望之处比比皆是了。

《暗黑破坏神3》完全没有了堕落,也完全没有了牺牲。死亡天使马瑟尔的动机苍白而又无力,智力水平和灭霸差不多,完全没有深刻的剖析他为什么要与泰瑞尔对着干。莉亚的死亡和迪卡·凯恩的死亡都是单纯的黑恶势力的牺牲者,而不是堕落者。反而是铁匠海德格老婆变成了僵尸不得不杀掉,以及寇马克发现自己整个人生都是谎言的故事更加丰满,但这些角色完全都不在主线中,有没有他们都不耽误。爱德莉亚的背叛倒是有些应该有的味道,无奈她本人也并不是什么关键角色。泰瑞尔的下凡也非常的无聊,离开天使议会的原因非常的小孩子气,并且从头到尾没什么关键作为,令人觉得这连牺牲都算不上。玩家作为涅法雷姆很快就明白了所有的恶魔都不是自己的对手,自己的主角光环如此之强,完全背叛了当年艾丹王子好人没好报的叙事基调。

《星际争霸2》也基本是一样的水平。曾经大量描写刀锋女王是多么凶恶狡诈的篇幅,都被2代苍白无力的洗白剧情所抛弃,给你一种棺材板都压不住了的感觉。刀锋女王从原本的荼毒生灵的大反派摇身一变成为宇宙的拯救者,就好像你跟我说一个十恶不赦的罪犯也可以被原谅,并且你必须原谅一样强奸民意。星灵的战役同样是主角光环感十足,你知道你最终能争取到并团结所有人,显得塔萨达当年的牺牲是如此没有必要。萨米尔·杜兰当年的种种阴谋诡计背后所透露出的可怕真相沦为不断刷怪为玩家送经验的手段而已,玩家都心疼艾蒙了。

《魔兽世界》就更扯淡了,现在各个角色充满了莫名其妙的背叛,由于动机是如此苍白,你甚至会以为他们疯掉了——脑残吼可不是浪得虚名的,希尔瓦娜斯烧树的动机更是莫名其妙,玛里苟斯更是脑子有病,诺兹多姆也是脑子有病,你会发现这些角色偏执的程度跟吉安娜她爸海军上将普罗摩尔有一拼。那些被强行写死的角色也是变着花样的作死,给人的感觉不是牺牲而是愚蠢——比如瓦里安·乌瑞恩,另一个时间线的先知维纶,大法师罗宁,等等。原本好好荡气回肠的史诗,变成了被疯子和傻子所充斥的无聊世界观。

不过暴雪的用户群体现在分化的也十分严重了,就在《暗黑破坏神:不朽》在youtube上遭遇差评风波的时候,《守望先锋》的动画空前好评冲上了youtube的时下流行榜。 这说明新游戏的群体基本不吃老三样那一套了,所以也许暴雪很清楚自己在干什么吧。

分类
未分类

如何证明VR的最终交互方案是坐着轮椅打手电?

首先我自己基本没咋接触过VR设备,所以这篇文章完全是痴人说梦纸上谈兵的……类似思维实验一类的东西也罢,大家如果有懂行的就随便看看罢了,觉得我说的有可取之处的可以交流一下,在下面留言就好。

今天在群里讨论了一个话题:VR如果能普及,那么它的最终交互方案是什么样的呢?我们作为VR设备的用户,扣上了头盔后,是基于什么核心逻辑与VR世界进行交互的呢?

为了回答这个问题,我觉得第一步应该做的是看看,现在成熟的交互方案都是什么,无外乎三种东西:

  • 键盘+鼠标
  • 摇杆,或者说手柄
  • 触摸屏

以上三个东西有什么共性?

  • 可以将用户的动作在赛博空间中放大,即用户不用费力操作,就可以在虚拟空间中实现复杂、大幅度的位移,这一点尤其对VR非常关键
  • 所见即所得,反馈机制简单清晰,可以自解释——挪鼠标指针就会在屏幕上动,敲键盘屏幕上就会出字
  • 用户除了手之外几乎都不用动弹,就可以完成99%的交互动作
  • 可以同时执行多种操作,键盘、手柄都有组合键,触摸屏也有multi-touch

顺便一提,罗永浩的tnt就是第三点扯了,那么大个屏你要我触屏,我关几个窗口胳膊就酸了。

那么,最适合于在VR世界中参考的是哪一种成熟交互方案呢?

我认为答案是——手柄

为啥呢?因为VR说白了就是玩家在赛博世界中操作第一人称的化身罢了,而操作化身是家用机手柄的主流操作方式,比键鼠和触屏都要方便得多,因此我们最优先应该试验的是能不能把手柄的操作逻辑映射到VR世界中。

那么手柄操作化身在赛博空间中主要是咋搞的呢?我认为分为两部分:

  • 第一部分是双摇杆
  • 第二部分是其他按键

先来研究双摇杆,双摇杆就是左摇杆控制人物在二维平面上前后左右移动,右摇杆控制摄像机镜头转动,就跟用键鼠WSAD前后左右平移,鼠标转视角一样。

这种交互方式本质上是在模拟在三维空间中,以在二维平面上移动为主的摄像机控制解决方案。这种移动方式非常接近于生活在陆地上的人类的客观体验,即虽然世界是3D的,但我们的移动基本都是在地面这个二维平面上的,除非我们攀爬或者跳跃,否则基本不会突然离开这个二维平面。

如果用户是一只鸟,或者是一只鱼,他们如果天生就是在三维空间中随意移动而不只是在二维平面上移动的,刚说的那种双摇杆用起来就会感觉像吃了屎一样难受。你不妨想想《魔兽世界》或者《激战2》这种MMO,水下玩起来都是非常难受的,一方面是人类离开了地面难以判断距离,另一方面就是双摇杆天生就不适合在3D空间中移动。

而当你需要攀爬或者跳跃的时候,就要用到其他按键了,这些按键是与世界交互的方式,而双摇杆是移动和旋转摄像机的方式。

我们不妨和2D游戏对比,比如格斗游戏,左摇杆只有左右是移动,上变成了跳,下变成了蹲,这明显和刚说的在3D世界中的左摇杆用处是不一样的。

那么双摇杆的逻辑套用到VR空间中是否成立呢?答案是——成立!

左摇杆我们可以靠各种手段来代替,比如用歪脖子来代替WSAD,或者专门有个摇杆来代替WSAD;而右摇杆我们直接转脖子就行了,这个类比自然到不能再自然。

那么这样一来我们在VR世界中的移动和旋转摄像机的体验会变成什么样呢?

答案是——电动轮椅。

你看,右扶手上有个摇杆,这就是左摇杆,至于右摇杆,就是你自己的脖子了

好,现在我们解决了双摇杆所负担的在赛博空间中移动和旋转摄像机的问题,那么我们到底要怎么和赛博空间中的各种实体交互呢?

按我有限的理解,现在的VR交互方案都是基于“想象会从玩家身体发射出去一条射线,这个射线射到了什么实体我就能和什么实体交互”这样一种逻辑的,但我觉得这一点都不靠谱。为啥呢?因为虽然这条虚拟射线符合人类中心视觉的生物特性,但是由于人类在第一人称的情况下总是用双手去与世界交互的,而双手的特性就是……能同时干好几件事情。

也就是说,刚说的基于射线的交互逻辑,由于没法同时进行多项操作,在便利性上完全比不上传统键鼠、手柄、触屏。

所以伟大的玩家大人现在已经有了电动轮椅了,那怎么和世界交互更好呢?

模仿玩家在现实中与周边物体交互的逻辑无疑是愚蠢的,因为我们在我们所创造的世界中是要当上帝的,如果我们一块钱掉到地上了都要弯腰、伸手才能去捡起来,那我们还玩啥VR啊?

所以如果你是上帝,怎么和一个世界交互?

或者说……如果你是个魔法师呢?

是不是只要拿个魔棒指一指,念念口诀(甚至更简单的,按按按钮)就行了?

听起来就像……屎大棒?

与世界交互,全靠枪口发出来的激光,上帝说要有激光,于是就有了激光

或者是……重力枪?

哪里不爽点哪里
高登博士保佑你

于是我们其实还是采用了“射线”的方式,只不过把这个射线从躯干上转移到了手中,并且如果愿意的话让玩家同时拿两个魔法棒似乎也没啥不妥呢。

这么一比较的话,在现实中最类似于魔法棒的东西,无疑是手电筒了,假设手电筒有A和B两个按钮,我们把光束指向一栋大楼,按住A键就能给它拎起来或者摧毁,那不是很带劲。

当然,我们要考虑到,在赛博空间中想要精准的想照哪里照哪里确实有难度,那么不妨我们可以让一个魔法棒( 体感手柄 )移动负责移动屏幕上的准星,另外一个魔法棒(体感手柄)负责实际发射射线或者与物体交互似乎也可以呢。或者更简单的,不按住A键就是大幅移动,按住A键就是微幅移动,也没毛病。

或者一个魔法棒负责发射射线,另外一个负责微调射线,这样你就可以搞出来一条弯曲的射线,然后两个魔法棒的按键都可以负责交互,这样你又能做到组合键,怕不也是美滋滋?

这是一条赛贝尔曲线,假设你可以用你的两只手搓出这样一道BEAM,用来毁天灭地,怕不是爽歪歪?

甚至你干脆可以每个手指头发射一条射线,用照射在物体上的射线数量来靠手势完成各种风骚的操作?

别说了,我觉得我已经构思好一款次时代VR武侠大作了——《六脉神剑》

所以,不管用哪种,下图就是最合理的终极VR交互解决方案。

你可以试试双持激光笔,然后坐着轮椅出门,大概就是玩VR游戏的最佳感觉了,不接受反驳

当然,我们还可以辅助一些语音交互方案,比如你喊“芝麻开门”,游戏里的城门就开了。甚至可以自定义一些宏,或者搞一些人工智障什么的,比如“小爱同学,今晚10点把我传送到主城,我要排副本”。

太阳底下没有新鲜事,所有的东西都能找到源头,VR交互最终解决方案,也无非是轮椅、手电、外加阿里巴巴与四十大盗而已。