50万玩家等着和“鬼”交朋友!这个游戏里的 NPC,可不好糊弄了丨Created with Cocos...

NPC 是模拟经营游戏中不可或缺的组成部分,但现如今绝大多数 NPC 依然是“工具人”式的存在,脸谱化严重。那么,如果一个游戏里的 NPC,有各自的作息习惯,会衡量生活的“幸福指数”,经历生老病死、死后甚至可能变成“鬼怪”,将会带来怎样一种游戏体验?

即将在年前正式上线的古风模拟经营手游《解忧小村落》(以下简称《解忧》)做出了自己的尝试。游戏由古德工作室基于 Cocos Creator 研发,过去一年先后进行了三轮测试,目前在 TapTap 上已有超50万玩家预约。

fc16fe6f8958847b2e697630cb19b782.png

《解忧小村落》TapTap 预约开启:

https://www.taptap.cn/app/214345

《解忧》描绘了一个“人鬼共存”的世界。这里有历法、时辰、天气、昼夜,玩家将在这个拟真的自然世界里,作为村落的村长,同此地的居民和鬼怪一起,经历春耕夏耘、秋收冬藏,跟随四季和天气的变化合理开展种田、畜牧、建造工作,逐步打造一个心仪的世外桃源。

b37c5120b1e756f5d46c4033b32a3a95.png

《解忧》依然保留了模拟经营的经典玩法——种植收获、采集建造、生产售卖等,而游戏最具差异的,莫过于其对 NPC(居民和鬼怪)的描绘。

每一位居民都有自己的职业,玩家可以“招募”这些居民,根据职业将他们派遣到合适的岗位上工作。游戏加入了“作息管理”,居民们会在不同时辰休息、工作、吃饭、散步、出游,玩家可以调整每一位居民的作息,甚至让他们“996”打工——但是,这些安排会影响居民的“健康值”和“幸福感”,若健康值过低,居民会生病乃至死亡,若幸福感过低,则可能导致居民搬离村落。

在这个游戏里,每位居民都是独立的个体,有各自的生活与经历,随时可能触发不同的事件。反之,也会有访客来到此地引起各种波澜,比如流窜的小偷盗窃居民财富、游历四方的郎中到访等……玩家将和居民一起去经历这些事件,并用自己的方式,应对某些棘手的局面。

a9ee7f6888d8df85685a91ded2de1fb2.png

鬼怪图鉴

鬼怪则是《解忧》中一个重要且特别的存在。他们看上去一点也不恐怖,甚至还萌萌的,虽然喜欢游走在村子里四处捣蛋,但又有各自独特且可爱的性格。鬼怪和居民一样,都是村落里的一份子,玩家可以“收服”和“招募”自己喜欢的鬼怪一同建设村落。

可以说,《解忧》始终围绕“佛系建设人鬼共存的和谐村落”展开,无论是删繁就简的游戏内容、清新可爱的画风,或是大批有血有肉的 NPC,游戏都在努力营造一种闲适、自由、真实的体验。

这样一款游戏是怎样被创作出来的?其中又蕴藏着哪些巧思与独特之处?C 姐和《解忧小村落》技术总监万骁聊了聊——

1

鬼怪:

“路见有鬼,但不必绕道”

《解忧》立项的契机是什么?

《解忧》的研发团队一共24人,成员们主要来自阿里游戏、百田等,平时都喜欢玩模拟经营游戏。有一次聊天聊到模拟经营的“模拟性”上,感慨现在这类游戏中的 NPC 还是工具人居多。所以我们就想,有没有可能让 NPC 更“动态”或者更“真实”呢?比如,他们是否能有更加复杂的情绪表达、变化的身体状况,会生老病死,甚至在死后成为“鬼怪”(一些中国特色)。

由此衍生了《代号:百鬼》的立项——也就是今天的《解忧》。当时我们计划用1年左右的时间做出这个模拟经营+鬼怪的游戏,现在看来,团队离目标越来越近了。

游戏的“鬼怪系统”在玩法上有哪些亮点?

2ae7e06a924c287ce459f632b07a76b3.jpeg

目前的版本中共有53只鬼怪,之后还会陆续增加。在我们的设定中,鬼怪是人类在生前遭遇不幸后,因执念太深而化身为鬼。每只鬼怪都有自己的故事,科场鬼生前是个落榜多次的书生,墓鬼是个喜欢玩躲猫猫的小女孩……这些前尘往事,将随着“鬼怪传记”的逐步解锁徐徐呈现。

鬼怪们各有各的调皮,会给村落里的建筑、居民等造成影响,比如墓鬼无聊时会把居民抓来墓场同自己玩耍、碰上野鬼会让居民迷路,水鬼会影响渔夫钓鱼等。玩家可以“收服”自己喜欢的鬼怪,通过喂养鬼怪、给鬼怪送礼等方式来提升鬼怪的等级与好感度。等级越高,鬼怪的妖力值越高,工作产生的收益也越高;提升好感度,则可以解锁该鬼怪的传记故事、前生人物等。

c4b39ae06b2b51626fa783be0e40fddf.jpeg

07a0f4b98e96494645e5e2eb92d26c2e.jpeg

在达成一定条件后,玩家可以“招募”鬼怪入住村落,并根据他们生前的职业与技能,派遣他们到不同建筑里工作。由于鬼怪的“特殊身份”,和居民不同,鬼怪不会疲惫劳累,可以不停地干活 (不是。

鬼怪形象都很 Q 萌,和大家分享一下美术设计思路吧。

6e96cdc7a29e17652475605eae679af4.png

游戏中所有的鬼怪都是能在古籍里找到原型的。我们查阅了大量的资料,夸张和放大鬼怪的特点,让鬼怪的形象更富记忆点。以“疫鬼”的设计为例,因为是和疾病有关的鬼怪,因此底色是苍白的;手持灯笼,象征其夜行性;符咒束缚和红衣,则是借鉴民间对瘟疫恶鬼的压制手段,代表疫鬼被人们惩戒和封印。

2

风格:

“真佛系,不上班”

除了鬼怪,《解忧》中还有大量的居民,这方面又是如何设计的?

《解忧》整体美术风格为古风 Q 版,我们想在此基础上,结合游戏基调,做出和市场上其他同类型游戏有所区别的美术风格。

923d955d64aba7e80796566fc2d337d5.png

居民的设计围绕着“模拟”这个关键词展开,力求真实感。游戏中,不同居民有各自的职业身份,基于此我们又在年龄、性别、体型三个维度做了区别如上图,一个农夫职业有12个模型,为的就是让玩家感受到《解忧》世界里居民的多样与真实性。

《解忧》中有大量的建筑,怎么避免因建筑种类过多而显杂乱?

结合游戏内容,我们将建筑分为士、农、工、商、民宅、装饰建筑等大类,以中国古代建筑结构为基底,设计其共同的设计语言,包括墙体结构、屋顶造型与颜色、环境植物搭配等。这样既能保证建筑种类丰富,也能让玩家一眼看出建筑所属类型,方便游戏布局。

54ac864e742102abf9d58f6f704dba63.gif

相对于大场景以绿色为主的主色调,建筑上我们有丰富的颜色类型,这样玩家在发展自己小村落的过程中,能慢慢感受到场景色彩的变化,由乡间林野变成繁华村落,从而获得成就感。

从美术风格到游戏内容,《解忧》给人的感觉都非常轻松治愈。

是的。当下很多模拟经营类游戏都会选择布局长线运营,但实际体验后发现,大多数长线游戏都让人“肝疼”。我们希望《解忧》能让玩家体验到更加纯粹的种田快乐,而不是在游戏里“赛博上班”。

87ff5a13758628b198a45866a833b416.png

《解忧》始终围绕着“佛系”这一体验去做设计,删繁就简。游戏中没有重复的每日任务,就是想减少玩家“在游戏里打工”的感觉,取而代之的是用“订单”模式,让玩家通过自主决策发展村落。玩家只需思考这个季节种什么或发展什么产业能增大收益,派遣居民和鬼怪去各个生产建筑劳作,在关键元素一步步铺设好后,就可以进入“看海”模式,去和居民、鬼怪交个朋友,看看他们的人生轨迹,探索村庄的发展变迁,或者是享受布置造景的成就感。

目前《解忧》中商业化内容非常少,团队这方面有什么规划吗?

因为是朝着“纯粹”这个基调去的,所以我们对商业上的内容一直很谨慎。目前游戏内已经开始有考虑商业化的内容了,不出意外主要有两个方向:其一是传统基建,前期侧重资源内购,后期再逐渐推出各种风格的建筑让玩家收集;其二是如果能做到的话,我们希望鬼怪本身的形象、情感、故事是可以立起来的,并与玩家产生更深层次的情感共鸣,玩家可以在这个基础上,为自己喜爱的鬼怪花钱进行培养。

3

技术:“优化不停”

能否分享一下游戏的客户端设计方案?

场景多纹理

场景的所有单位均为 Spine,游戏内场景有 2w+ 格子的地图大小,因此我们希望能让所有场景单位都能合批,减少开销。

我们制作了8、16的不同贴图 shader 来进行不同机型适配,再根据 MAX_TEXTURE_IMAGE_UNITS,来确定使用哪一套材质。

601a00ea0ac33bd72a78b71e6c700ad7.png

重写 MultiSpineAssemble。下面是 web 端的修改,因为要多传一个贴图索引,所以在 vbuf 也要相应的传入数据。

77113ffa835f9d37f432f488a5b675ed.png

05a40b664f0e885834e28cf6205d8b3e.png

281eea5568342dbc78f246e711897e2d.png

因为原生平台 fillBuffers 重写了,所以原生平台改动就非常多。

86d7c36c4c7eef11c8ac9f27728cece4.png

4afe3c8731915fe7b9c025703ace19cf.png

原生平台有双 color 、单 color 之分,所以需要在顶点宏这里多一套宏定义。

d6e1f72e2d5d54c18e49eb7d1bd65667.png

相应顶点结构体也要在增加贴图索引进去。

最重要的来了。MeshBuffer 需要在接口处区分是多纹理还是常规。

7b093e93e2e6d474786ebcd8dbb2c6bc.png

98fbeca4d274d464c320eebdae37c799.png

在 Types.h 里定义我们要使用的 shader 常量 ATTRIB_NAME_TEXTURE_IDX。

98053f6f5d2af2405950d3ae85420006.png

在 VertexFormat 内加上对应的多纹理顶点定义。

26aea6a8c5a63a60cffc3b58ecc22090.png

最后,在这几个类做好多纹理跟非多纹理判断和使用。

3a4a309c8a41261f1be6622301982af6.png

Label char 模式优化

这部分我们参考了论坛里“乐府-堂主”的实现方法:

https://forum.cocos.org/t/label-1-bitmap/97573

https://forum.cocos.org/t/label-2-char/97766

帖子提供了核心代码,但我们对其中一处进行了必要的修改。

替换旧字体时,一定要记得把 xAdvance 赋值。因为在做横向排版的时候是 xAdvance 进行排版,若按照帖子里的逻辑,旧字体始终要比新替换的字体大,不赋值的话会有间隔。

8aad100fca8b30e3445a4281e9fa6bca.png

UI 动态合批

虽然 FairyGUI 是个非常不错的 UI 编辑器,但是在 Cocos 运行时效率确实不太好,同时动态生成的节点有些冗余,我们在做完场景优化完后才意识到 UI 优化一定要重视起来。

所以我们重写了 sprite、label 相关Assembler,目的还是动态合批(多纹理)。

e5292e60572f82c1c133ba6cbe670bf1.png

13c9c90935e2abf552f00181214980b5.png

我们准备了4组材质(8、16共享材质和8、16备选材质)。若参与 UI 合批的 sprite 的贴图超过了能合批的最大数量,就要使用备选材质不参与合批。

我们 UI 的 label 都是使用 char 模式,所以只要给共享材质默认设置到第0位置即可。

9cc2310fa16bd308398b4650b6d70b57.png

Sprite 的判断相对复杂点,需要先判断材质中1~8/16中,是否有设置过且不一样(设置完就只能用备选材质了)。

e3a0c21c514674421049972be7e7cbd6.png

我们写一个 MultiUIBatch 的组件挂在 UI 的根节点上,用于创建共享材质、子节点动态添加、渲染监听刷新子渲染组件的贴图索引。

bc61e592fb4d504b529373aeee009bf0.png

每个渲染组件(sprite、label)在 onload 都会挂在一个用于检测是否要刷新贴图索引的脚本。

e8e8d39aba992ec6d324ee5b178aa977.png

该脚本会发送一个全局实践,用于给 MultiUIBatch 判断是不是自己的子渲染组件。

a36363410c1daa901f86bc976c26f241.png

流程示意:

dff446b14fb5c8375006daf16403f638.png

因为做好了超出共享材质贴图上限的处理,所以理论上应该没什么 bug 吧。

最后就是将 FairyGUI 里使用 Label 和 Sprite 的地方,换成重写的 MultiLabel 和 MultiSprite 即可。注意在 UI 销毁的时候做好材质回收。

理论上,如果 UI 都是图集并且图集复用率高的话,1个 UI 只有1个 DC。

游戏兼顾了高品质的渲染表现和流畅的运行体验,性能优化方面,有什么经验与心得吗?

ECS 模式

大场景多单位的游戏,如 RTS、SLG 等,一定要使用 ECS 模式。

《解忧》有 2w+ 格子,除开建筑是占位格子以外,NPC 是性能压力最大的一部分。我们使用了非严格意义上的 ECS 模式,System 与 ComponentBase(继承于 cc.Component)都有子组件(ChildCompBase),子组件负责的内容各不相同,我们在实现子组件的时候,都是基于通用扩展的目的去实现的,理论上只要给某个 System 添加寻路的 ChildCompBase,它就具备寻路行为;给 ComponentBase 添加 Spine 组件,就具备显示 Spine 的播放动作行为。

Node 的时候我们采用单帧动态,根据 FPS 改变创建数量,让 Node 从对象池添加到场景时更加平滑些。

b2abbbf4634486b4024af44f223ddcd2.png

《解忧》场景驱动逻辑

上图为游戏的场景驱动逻辑,其中黄色部分是性能优化集中的地方,因为使用 ECS 模式,所以会有部分 ChildCompBase 存在 update 的频繁调用情况,我们在处理方面会根据 fps 减少调用次数,判断 sys 是否在相机内并创建。

合理使用对象池

《解忧》自己实现了一套对象池,对象池内实现了对 Node、其他 Class 对象、RenderTexture 回收:

  • Node 回收:针对场景物件。

  • 其他 Class 回收:针对System、ChildCompBase、行为树。

  • RenderTexture 回收:针对 RenderTexture 对象。

混合模式

游戏场景的单位都是 Spine。但在美术同学的设计中,夜晚部分建筑会在 Spine 加灯光效果(Add 混合模式),这样就会打断合批。好在白天的时长比晚上要长,美术同学在白天把叠加模式的 alpha 设置为0,所以我们在 spine 取插槽 Slot 的时候,判断 color.a = 0 就用 normal。

de27762c0c3c25b3c217638cd0dc7677.png

上图是我们使用 Spine 时的测试结果。场景建筑没有什么动画,所以使用 RealTime 即可满足需求(主要内存少),而 NPC 有大量的移动、表演及其他动作,如果采用 RealTIme 模式,性能确实堪忧。

如何处理大量的 NPC 行为逻辑?

6f5b9104826dd1a175a4f9dde0c1c620.png

《解忧》中 NPC 数量比较多,且有很多不同的行为,比如在主场景中 NPC 有派遣、散步等常规行为,而在酒馆、客栈中,行为就更多更复杂了。为此我们自己搭建了一个可视化的 behavior3web 编辑器,方便策划大佬们理顺一个行为是否合理。

游戏后续将重点优化哪些方面?

一个是针对逻辑耗时进行重点优化。目前渲染方面的优化效果还不错,但是因为场景太多单位要运算,所以逻辑耗时比渲染耗时要长,这是目前头疼的事情。

二是同屏单位控制问题,主要需要控制同屏 NPC 数量,或者采用 RenderTexture 把相同 NPC 的画面通过 FBO“复制”到 RenderTexture,并通过特定相机去渲染。

游戏内容方面,由于团队人力比较吃紧,我们在首发版本砍掉了鬼怪小游戏玩法,还有很多特别事件玩法想要增加,这些内容我们都将在后续版本中陆续提供给玩家。

52e01f58f272585dee28ae570fed4316.jpeg

点击文末【阅读原文】即可前往 TapTap 预约/体验《解忧小村落》。Cocos 将持续打磨技术,完善引擎功能特性,推进生态建设,助力更多开发者高效实现创意想法!

往期精彩

60038cfa1cb5b03f255987d4f6567847.png

3b843cfc920162203a5801d884c0d236.png

c79856ae68eccf886efbecf05f8bdc9f.pngd79f7c2b4df7eed601520b1489006e95.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值