大家好,我是AL。欢迎来到Mortumus的第一次幕后探秘。

\n

Fin正埋在服务器的矿井里,跟数据库、订阅系统以及所有那些让世界运转的可怕分布式系统魔法搏斗。而我在另一端,确保每一次挥剑、每一个脚步声、每一簇火把的摇曳、每一件盔甲在你的屏幕上看起来对、感觉也对。

\n

暗黑奇幻MMO不是那种能从资源商店拖拽几下就拼出来的东西。我们追求的那种粗粝的、老派的感觉——战斗的分量、盔甲的嘎吱声、看到地平线上出现另一个玩家时的恐惧——只有底下的工具是专门为此打造的,才会出现。所以今天我要拉开帷幕,展示一些我们在客户端这边拼凑出来的自定义Unity系统:没人会看到它们,但每个人都会感受到它们。

\n

开始吧。

\n

视觉、掉落物和PvP隐私

\n

如果说MMO玩家有一条铁律,那就是:我们热爱装备。而在Mortumus这样的全掉落PvP游戏里,装备不只是多巴胺点滴——它是情报。一个人穿什么,告诉你他能对你做什么。

\n

保守秘密,确保安全——Equipment Visualizer

\n

很早的时候我们就意识到一个很多MMO悄悄忽略的问题:如果客户端知道视野内每个玩家每件装备的精确物品ID,有决心的作弊者就能从内存里扒出来,在决定偷袭你之前就掌握你的精确属性。

\n

所以,我们的Equipment Visualizer做了一件稍微偏执的事。对于你自己的角色,它从完整的装备服务读取——你能看到自己装备的一切。但对于其他每个玩家,它只读取服务器发布的精简\"外观\"数据。你看得见剑,看不见属性面板。陌生人的物品ID压根不会离开Fin的服务器。

\n

一件小事。但它也让内存扫描类作弊变得没什么用了。划算的交易。

\n

动画栈

\n

技巧型战斗的生死取决于动画。如果前摇读不出来,你就无法反应。如果命中没有落地感,战斗就像在打空气。如果死亡看起来就像模型……直接关掉了,一半的氛围都没了。

\n

Player Animation Coordinator

\n

我们一开始跟大多数人一样:一个巨大的动画控制器类试图管理所有东西。移动、法术、死亡、受击、idle——全在一个文件里。大约两周之后就成了一团乱麻。

\n

于是我们把它拆开了。现在Player Animation Coordinator是一个微小的入口点,启动一组小型专用模块:移动、旋转、攻击、法术、受击反应、死亡、idle。每个模块只管一件事。每个模块单独都能读懂。追踪bug从几小时变成了几分钟。

\n

对我来说是更干净的代码。对你来说是更紧凑的战斗。

\n

战斗响应性——Attack Animator & Spell Animator

\n

这是经典的MMO难题:服务器权威战斗是阻止作弊的唯一方式,但等服务器确认每次施法,感觉就像在糖浆里游泳。

\n

我们的Spell Animator耍了点小聪明——但是光明正大的。当你按下技能键,施法动画立刻播放——本地预测,所以感觉是瞬间的。然后Fin的服务器验证这次施法是否真的合法(cooldown是否结束、mana是否充足、目标是否有效等等)。如果确认了,什么都不变。如果拒绝了,我们干净地退出。

\n

Attack Animator在近战上做同样的事,而且还会根据服务器指定的武器攻速来缩放挥击速度。你的眼睛看到的是响应灵敏的战斗。服务器看到的是一个无法被欺骗的世界。

\n

\"手感好\"和\"玩得公平\"之间的甜蜜点——整个游戏都活在这里。

\n

王国之声

\n

音频占氛围的50%,而人们总是低估它需要多少工作量。

\n

营造氛围——Audio Manager & Music Region System

\n

传统游戏倾向于在你越过一条隐形线时硬切换音乐。很突兀。我们用3D多边形区域来做。Music Region System让我们在世界中绘制任意形状的区域——一片闹鬼的树林、一座被诅咒的教堂、通往boss的路——当你走进走出时,Audio Manager平滑地交叉淡入淡出配乐。没有硬切。同一首曲子不会因为你脚尖踩过边界就重新开始。

\n

而且因为这一切都通过带有混音器组路由的池化音频源运行,帧预算上的开销基本为零。

\n

Character Audio Manager

\n

Mortumus里的每一步都与角色的动画和脚下的地表挂钩——石头听起来像石头,泥巴听起来像泥巴。法术音效绑定技能,武器挥击音效绑定武器。Character Audio Manager位于动画事件和Audio Manager之间,这样我们可以按种族和职业替换SFX包,而不用碰任何gameplay代码。

\n

小事情。很多很多。它们会累积。

\n

水边

\n

每个暗黑奇幻世界都有水。沼泽、河流、被淹没的废墟、诅咒之岬尽头的大海。而水是最容易看起来假的东西之一——尤其是在它与陆地交汇的地方。mesh与地形相交处那条丑陋的多边形水际线,是游戏看起来廉价的标志。

\n

我们的水体基础

\n

我们没有从零开始构建水体。Unity实际上附带了一个叫Boat Attack的出色演示项目,包含了最好的URP水体系统之一:真实反射、折射、浮力,应有尽有。所以我们以Boat Attack的水体作为基础,因为重新发明这个轮子会白白花费我们好几个月。

\n

但Boat Attack是为……嗯,船造的。干净整洁的海岸线。在沙滩上效果很棒的海岸行为,放到Mortumus里我们真正想要的那些泥泞的、长满芦苇的、不规则的水道旁边就惨不忍睹了。所以,我们得动外科手术。

\n

自定义shader——Water Shoreline

\n

我们没有直接编辑Unity包(那样每次更新都会炸),而是写了一个薄薄的自定义shader \"WaterShoreline\",只替换pipeline中负责海岸的那一部分。其他一切——反射、流动图、焦散——直接来自Boat Attack。我们只覆盖需要的部分。

\n

两个大改动:

\n

2米泡沫硬截断没了。Boat Attack默认的泡沫带有一个固定的深度截断,会在每个海岸周围产生均匀的\"白色圆环\"。我们用更柔和的衰减加上滚动的噪声场替换了它,这样泡沫现在逐渐淡出,碎裂成有机的舌状和指状,而不是一条完美的丝带。

\n

柔和的海岸线透明度。那个多边形水际线撞地形的问题?我们在最后半米深度内将水本身淡化为透明。水际线完全消失了。地形只是在深入水下时变暗,就像真实的湿润海岸线一样。

\n\"Mortumus\n

我们的河流系统

\n

Boat Attack的水体有个问题:开箱即用地处理海洋很美,但它并不真正知道什么是河流。水可以原地泛起涟漪,但不能像真正的河流那样向下游流动、绕过弯道。当你暗黑奇幻世界的一半都应该是沼泽密布、河流纵横、湿漉漉的时候,这就是个问题。

\n

于是,我们在它上面构建了一个河流系统。

\n

Mortumus中的河流被创建为一条流动路径——一条简单的折线,由点组成,描绘出河流从源头到入海口的脊线。设计师在他们想让水流过的地方放置点,shader负责其余工作:对于水面的每一个像素,它找到最近的流动路径段,并以该段的方向作为局部水流方向。结果:直线段附近的水直流,弯道内侧的水随弯道弯曲,两者之间平滑过渡。

\n

纹理、法线和泡沫都沿着那个流动方向滚动,而不是漫无目的地漂移。你真的能看出河流往哪个方向流。

\n\"Mortumus\n\"Unity\n

所有这些都可以通过ShoreFoamTuner实时调整,这是一个小型inspector组件,放到任何有水的场景上就行。有泡沫柔度、噪声缩放、噪声强度、漂移速度、alpha衰减的滑块。不碰材质就能改变整个湖泊的氛围。

\n

社区与垃圾话:聊天 & 社交

\n

老派MMO既是关于人的,也是关于游戏的。如果社交工具体验差,世界就会感觉空荡荡的。

\n

Overhead Chat System

\n

文字锚定在角色头顶正上方,跟随他们移动,随距离淡出——这是这个类型的绝对经典,也是我们誓死捍卫的东西。

\n

它把队伍变成真正的对话。它让你能在战斗中间嘴炮对手。它让一个垂死玩家的遗言可以是一句蠢话和笑话,而不是系统日志的一行。Overhead Chat System处理对象池、距离裁剪和锚点追踪,所以即使二十个人在狭窄的地下城里互相吼叫也能扛住。

\n

穿出范儿

\n

说实话——你会在角色界面花掉多到尴尬的时间。我们都会。这是游戏里最好的镜子。

\n

角色预览系统

\n

我们的纸娃娃不是烘焙好的2D渲染——它是一个实时3D场景,渲染进UI的render texture。完整光照、真实几何体、你身上的每件装备都实时显示。旋转它,缩放它,盯着它看。这种功能完全不影响gameplay,但绝对改变拥有这个游戏的感觉。

\n\"Mortumus\n

装满背包:Icon Studio

\n

这是MMO开发的一个不太光彩的小秘密:图标。你需要几百个。每把剑、每瓶药水、每件从箱子里翻出来的垃圾掉落物都需要自己的一个小小的64x64方块,在拥挤的背包里也能看得清清楚楚。而且它们必须看起来像属于同一款游戏。

\n

你不能光截个3D模型的图就完事了。光照必须统一。相机角度必须统一。还有——这是大家最容易低估的部分——构图必须匹配物品在背包中占据的网格大小。一把1x1的匕首和一把2x3的巨剑需要截然不同的构图,否则两者看起来都不对。

\n

我们的方案:Icon Studio

\n

Icon Studio是一个自定义Unity编辑器窗口,我们造它是为了让一个人(通常是我,一边嘟囔着)能在不发疯的情况下批量产出一百个风格统一的图标。

\n

工作流程:丢进一组物品prefab列表。告诉工具每个物品在背包里占多大网格——1x1、2x2、2x3、1x4,随便什么。把相机对好一次。把构图存为预设。按下生成。

\n

妙就妙在网格大小不是装饰——它驱动实际渲染。一个2x3的物品会按2倍宽度和3倍高度(基于512px)渲染,所以放在背包里时比例是正确的,不会被拉伸。一把长剑真的能斜着填满一个1x4的格子。一瓶药水真的刚好放进1x1。背包给人的感觉就像在整理真实的物品。

\n

此外,这个工具还支持:每个物品的透明或自定义背景、骨骼姿态捕获(让基于骨骼的物品可以快照其展示姿态而不干扰gameplay rig)、以及整个物品类别的预设——所有斧头用同一个相机渲染,所有药水用另一个。免费获得一致性。

\n

最终结果是游戏中的每一个图标——那些在密集背包网格中32像素大小也能看清的——都是从实际的游戏内模型渲染的,按照物品在你背包中实际占据的形状。没有外包的2D美术。没有不一致的光照。没有匕首在UI里莫名其妙看起来比巨剑还大。

\n

这是没人会看到的那种工具。也是背包不会看起来像一袋杂乱的素材图的原因。

\n

下次再见

\n

这些系统没有一个是Mortumus的头条功能。没人会因为脚步声好听或者骷髅爆成物理碎块而买这个游戏。但这些就是一切之下的骨骼——那些看不见的工作,让大东西落在它们上面时感觉是对的。

\n

有了这个基础,Fin和我就能去构建那个我们在笔记本上涂画了两年的黑暗、残酷、全掉落的世界了——以一种不会让我们想把电脑扔进河里的节奏。

\n

— AL