下载 App
《万象纪》开发日志 #2|想法与神力:把“涌现”交到玩家手里
修改于10/0899 浏览综合
写在前面
第一篇日志结束时,我们有了一座“活的”岛:猿群在觅食、迁徙,树会被风吹动,路是被走出来的,营地会长成村子。但玩家什么也做不了,界面也还只是一张视觉稿。
阶段 2 要解决两件事:
- 让“想法”真的在个体之间发现、传播、失传。这是整个游戏的心脏,文明形态要从这里长出来。
- 让玩家能出手,而且出手有手感。降一道雷,要立刻看到闪电、起火、人群惊慌,听到雷声,史书上多一行字;很多年以后,还能在史书里读到这道雷的回响。
这个阶段的闸门是“出手有手感”。接力顺序是:想法引擎 → 神力与信仰 → 导演 → 界面(重做后接上模拟)→ 特效、镜头与音效 → 编年史与命名 → 复审 → 返工。下面按这个顺序讲。


一、想法引擎:让“发现”真的会发生
1. 19 个想法,一套条件词汇
阶段 2 录入了原始和部落两个时代的全部 19 个想法:
- 原始时代:采集、群居(开局就有)、石器、语言、用火、狩猎、熟食、衣物、万物有灵、丧葬;
- 部落时代:农耕、定居、驯化、陶器、编织、部落、图腾崇拜、草药、交换。
每个想法都有前置和环境条件,条件用一套小词汇写成,例如:
| 想法 | 条件 | 意思 |
|---|---|---|
| 石器 | near:flint 6 | 6 格内有燧石 |
| 语言 | companions ≥ 5 | 4 格内至少有 5 个同伴 |
| 用火 | witnessed:fire | 亲眼见过火 |
| 万物有灵 | witnessed:lightning / disaster / death | 见过雷电、灾难或死亡 |
| 农耕 | biome:grass 或 river 且 food_pressure | 住在草原或河边,而且正在挨饿 |
| 部落 | pop ≥ 20 | 聚落人口够多 |
这些条件就是玩家能“撬动”历史的地方:神力不会直接给文明加科技,它改变的是条件。一道落在林子里的雷,会让附近的猿人“见过火”;接下来会不会有人学会用火,交给他们自己。
2. 四件事,每个 tick 都在发生
- 发现:个体掌握前置、满足条件后,按“难度 × 好奇心 × 人口密度 × 时代加成”掷骰。第一个发现的人会成为有名字的人物,记进编年史。
- 传播:个体会挑 3 格内的一个邻居,教他一个对方还不会的想法;自己正在用的想法更容易教出去。没有语言的时候传播很慢,有了语言快 4 倍。
- 践行与竞争:每 50 个 tick,每个人在同一“生态位”里重新挑一个最好用的想法来用;保守的人会更倾向于继续用老办法。
- 继承与失传:孩子会继承父母的想法,但会丢掉一些;会某个想法的人全死了,这个想法就失传了。之后它可能被重新想出来,也可能再也回不来。
为了性能,引擎每个 tick 只轮转处理十分之一的个体,概率相应乘 10。前沿想法用位集缓存,只在一个人学会新东西时才重算。最后的结果是:300 个个体、七种神力连续施放,模拟仍然只要约 0.5 ms/tick。
不干预的情况下,我们用 5 个不同种子的世界各跑 6000 tick:每个世界都自己发现了语言和石器,并且传到了 97% 以上的人。
3. 让玩家“看见”传播
数据里的传播玩家是看不见的,所以表现层要把它画出来:
- 发现:一圈星芒,头顶弹出“灵感”,名字和想法挂 2 秒;
- 传播:一个光点从老师飞向学生,颜色代表这个想法所在的生态位,弧线会跟着两个人移动,落地时学生头顶冒出灵感。

这里还修过一个很好笑的 bug:模拟层写的是“语义表情”(1 = 灵感,6 = 感恩),表现层一开始直接拿它当气泡图标的编号用,于是有人想出新点子时头上冒出来的是“!”,向神感恩的人头上冒出来的是一个骷髅。


二、神力与信仰
1. 一个入口
玩家的任何操作都是一条命令,只能通过 sim.apply(command) 进入模拟,在下一个 tick 开始时执行并记入日志。好处是:种子 + 命令日志 = 一局完整的历史,可以逐位重放。复审里任何“刚才那一下为什么会这样”,都能原样复现出来。
2. 七种常规神力
| 神力 | 消耗 | 冷却 | 作用 |
|---|---|---|---|
| 雷霆 | 8 | 3 秒 | 点燃树木或草地;附近的人“见过火”“见过雷”并感到恐惧。击中人时 60% 会死,40% 活下来成为“天选者” |
| 降雨 | 12 | 8 秒 | 20 秒内湿度上升、作物变好,能浇灭火 |
| 干旱 | 12 | 8 秒 | 40 秒内湿度和食物下降,容易起火,人会想迁走 |
| 丰饶 | 15 | 10 秒 | 肥力上升,食物 +50%,60 秒内衰减 |
| 瘟疫 | 20 | 30 秒 | 一个聚落的死亡率 ×4,持续 30 秒;没有文字时,想法可能随人一起失传 |
| 地动 | 30 | 45 秒 | 拖出一条线(≤ 12 格),抬成山脊或陷成河道 |
| 托梦 | 25 | 15 秒 | 给一个人植入一个他此刻“伸手可及”的想法(见下文) |
火是一个独立的系统:燃烧有阶段,按湿度向四周蔓延,降雨能浇灭,烧过的地方留下焦土,植被会变成焦树。范围内的人会在同一个 tick 做出反应:抬头、下跪、逃跑、欢呼,头顶冒出对应的表情。
3. 信仰与祈愿
神力消耗信仰。开局有 40 点信仰,上限是 100 + 人口 × 0.5;每秒的被动收入是 0.5 + 1.5 × 虔诚度 × √(人口 / 50)。虔诚度取决于文明怎么解释世界:什么都不信时系数只有 0.2,有了“万物有灵”是 0.6,立起图腾是 0.8。
聚落会祈愿:求火、求雨、求丰收、驱兽、求医,每个祈愿只等 20 秒。回应了,立刻得到 10~25 点信仰,聚落也会更虔诚一阵;没回应,虔诚度下降,编年史里会写一句“向天求火,天没有回应”。
用常规神力回应祈愿,在世人眼里只是“雨就是下了”,不算神迹。这是有意的设计:常规干预不会把文明推向神权。


4. 托梦:第一把火必须从天上来
托梦是最有叙事感的神力:点一个人,在他梦里放一个想法。
一开始,托梦可以无视想法的环境条件。复审时发现了问题:托梦能直接给“用火”,而“用火”恰好是价值最高、排在候选第一位的想法。于是新手关精心设计的“雷击 → 起火 → 有人看见 → 学会用火”整条因果链,可以被一次托梦跳过。我们用脚本模拟玩家来跑首局,第一把火平均第 1 秒就出现了,就是这么来的。
我们改了规则:托梦只能给前置和全部环境条件此刻都已满足的想法,和自然发现用同一套条件检查,没有任何豁免。面板上另外列出最多 3 个“还不能领悟”的想法,并写明原因,比如:
用火 · 他们还没见过火
托梦能加速领悟,但不能替代亲身经历。这条提示同时也在告诉玩家下一步该做什么:先让他们见到火。


三、界面:从“史书”到“上帝桌边的法器”
1. 推翻第一版
第一篇日志里的界面是“一部摊在沙盘边上的史书”:半透明墨色玻璃、细线框、宋体标题。真正接上游戏之前,我们又看了一遍,结论是太像网页前端了:好看,但不像一个让人想伸手去点的游戏界面。
新的方向是“上帝桌边的法器”:界面是一组有材质、有重量的物件。

- 星盘(左上):时代、纪年、人口;换时代时星盘会转一圈;
- 香火灯 + 沙漏(右上):灯腹里的光液就是信仰,有 15 档,收入的光点会沿着弧线飞进灯里;沙漏管暂停和加速;
- 神龛石碑(左侧):12 颗宝珠,7 颗常规神力,5 颗非常神力被锁链锁着;冷却时宝珠熄灭,再一行一行重新点亮;
- 挂轴编年史(右侧):毛笔一笔一笔写出来,回响会盖一枚朱印;
- 人物卡:朱漆底、铜拱头像框、缎带名牌;
- 还有羊皮纸便签、纸做的祈愿泡,以及会变成“握着”“托着神力”的神之手光标。


这些法器全部是文本像素画加程序化光照做出来的,材质是 21 张九宫格(黑漆铜边牌、朱漆牌、羊皮纸、纸签、墨石、铜键……)。毛玻璃、细线框、胶囊这些网页组件全部删掉;高清效果只保留物件投影、自发光辉光和漆面的光泽。
2. 手感都在细节里
- 宝珠悬停会上浮发光,按下会被压扁再弹回来;
- 信仰不够时宝珠和香火灯一起变暗、抖动,灯上的数字变红;
- 选中的宝珠会被“拔出”悬浮起来,非常神力的锁链会抖动;
- 数字滚动而不是直接跳变,香火灯的灯焰在收到信仰时会亮一下;
- 系统设置了“减少动态效果”时,这些动效会自动降级。
3. 接上模拟:一次施放的完整流程
- 点宝珠(或按 1~9)拿起神力,光标变成托着神力的手;
- 地面上出现范围预览符文:会贴合地形,跨断崖时干净地断开,落在林子里会铺在树冠上;金色表示可以施放,红色表示信仰不够,灰色表示还在冷却;
- 左键施放:手边立刻有波纹,宝珠弹一下,香火灯闪出“-8”,冷却开始;
- 世界里:雷落下、起火、人群反应、飘字、编年史写下一行;
- 右键或 Esc 一级一级取消。地动可以点两个点或直接拖一条线。



界面占多少画面也有硬指标:全部法器同时打开时,世界画面仍有 70% 以上可见(1280×720 下实测 72.6%);平时大约 88%。
四、特效与声音:每次出手都要“响”
1. 特效系统
- 粒子池:3000 个粒子加每帧的火舌,实例合计不超过 4000;按每格 32 像素生成像素块,火花有拖尾,余烬会慢慢暗下去;
- 闪电:中点位移加分叉,硬边剖面,一次落雷有三次回击;
- 地面痕迹:湿痕、龟裂、焦痕、丰饶的嫩绿,所有地形材质共用一张痕迹纹理;地动时地块按波浪逐阶抬升或下陷;
- 投影式贴花:范围预览按场景深度投影,所以能“披”在断崖和树冠上;
- 火:林地里的火舌更高,树冠会着火;每 4×4 格汇成一股烟柱;火光是闪烁的点光源,但只取最近的 4 盏,因为实测点光源是林火开销的大头。
地动还带出一个性能问题:改地形会重建地形网格,施放那一帧会卡住约 1.4 秒。改成按区块增量重建、提前预热之后,降到 25 ms 左右;我们还专门写了测试,保证增量重建的结果和全量重建完全一致。

2. 声音
所有音效都是用 WebAudio 实时合成的,没有一个采样文件:七种神力、火、发现、传播、祈愿出现与回应、18 个界面事件,还有演出用的音效。音频引擎有音效、音乐、环境三条总线和一个压缩器,同时最多 24 个声音,页面切到后台自动静音;子弹时间里音效会被低通滤波,听起来像隔了一层水。
3. 复审之后的返工:降雨和干旱“没感觉”
复审时,七种神力里降雨和干旱被评为“没感觉”:降雨看起来像营地上空的一团灰烟,更像失火;干旱只有两个红字有存在感;两者的起手音都只有 -34 dB 左右,几乎听不见。
返工以后:
- 降雨:先聚起一团积云,雨幕落下,第一秒是满柱的大雨;湿痕从中心向外蔓延,地上的积水会倒映天空;镜头附近的全局光照变成“阴天”;
- 干旱:龟裂从落点向外裂开,刮起小旋风,光照变成“烈日”;
- 声音:起手音提到 -22 / -20 dB;雨声里 4 kHz 以上的嘶声占比从 48% 降到 2%。


4. 降噪:不是每次“灵感”都值得一声叮
另一个问题是灵感刷屏。每个人各自“重新想出”一个别人早已会的想法,都会放全套的星芒、名牌和“叮”。在一个部落村子里,4 倍速下 23 秒能响 127 次发现音、130 次传播音,头顶一片白色的灵感气泡。
我们给灵感特效分了三档:
- 全套:只给本局第一次有人想出这个想法——星芒、名牌、气泡、飘字和一声“叮”;
- 中档:这个想法第一次出现在某个聚落、而且是自己想出来的——小星芒、短气泡、轻轻一声钟,没有名牌;
- 静默:其余所有再发明——一颗小星,不出声,没有气泡。
另外,一个全套或中档时刻之后 1.5 秒内、4 格以内的发现一律降为静默:一群人同时开窍,只响一次。传播音也只在一个想法第一次传进某个聚落时响。改完后,同样的 23 秒里发现音是 0 次,传播音 2 次。

五、导演:把历史“拍”出来
第一篇日志里我们说过,设计支柱之一是“历史被看见”:玩家不看编年史,也能说出这一局发生了什么。导演系统负责这件事。
- 挑什么来拍
每个事件都有一个兴趣分:基础分(发现比传播重要)、新奇度(第一次比第十次重要)、可见度(在不在画面附近)、和玩家的关系(是不是你的神力引起的)。事件进入一个优先队列,过期就丢掉。导演有三种模式:
协作(默认):只有大事才自动接管镜头,两次接管至少隔 20 秒,每次最多 8 秒;其他值得看的事件,在编年史那一行上留一个“观看”按钮;玩家 20 秒不操作时,镜头会像拍纪录片一样在有趣的地方之间慢慢漫游;
导演:观影模式,镜头完全交给导演,玩家仍然可以施放神力;
自由:从不接管镜头。
无论哪种模式,玩家的任何输入都会让导演在同一帧交还镜头。
- 怎么拍
镜头库目前有:
DESCENT:每次施放后 0.11 秒的猛推加一点后坐,0.6 秒后回到神视,给出手一个“落点”;
PUSH_IN:推到发现者身上;
HERO:低机位,按方位搜索一个最好看的角度;
TRACK / TRACE:跟拍、沿路追踪;
ESTABLISH / ORBIT / EMERGE / ROAM:交代环境、环绕、先升后拉、闲置漫游。
机位会用高度场和建筑包围盒做射线检测,避免被山和房子挡住;挡住主角的树冠会被溶解掉;构图上尽量把主角放在三分线上,保留背景和运动方向的余地。
一个参数上的取舍:规格里写的推近距离是 2~3 格,但那么近时,一个精灵像素会放大到 20 多个屏幕像素,画面变成一堆粗大的色块。我们把 PUSH_IN 定在约 6.6 个单位、HERO 约 6 个单位:既是特写,又保留像素画的质感。
- 导演要让位于玩家
复审发现,玩家闲置 20 秒后导演开始漫游,这时玩家拿起神力,却得对着一个还在移动的遮幅镜头瞄准;读编年史时,界面又被淡化到只剩 20%。我们加了一条“玩家意图”规则:拿起神力或打开人物卡,镜头立刻交还;玩家拿着神力、开着卡片、在读卷轴,或者指针停在界面上时,只有招牌演出可以自动开拍;输入后的宽限时间从 1 秒延长到 3 秒。
- 字幕
导演推到一个人身上,玩家却不知道为什么。所以现在每个带事件的自动镜头,都会在下方的遮幅里用像素字体逐字打出对应的那行编年史。点编年史里任意一行的“观看”,镜头会飞过去,同样打出这一行。

六、第一把火
1. 为什么是它
第一篇日志里我们定过一条规则:火要学会才有。聚落学会用火之前,篝火圈是冷的,夜里一片漆黑;而用火只有“亲眼见过火”的人才学得会。
所以第一把火是每一局的第一个转折:玩家降下一道雷,林子烧起来,有猿人看见了;过一阵子,营地里第一次亮起火光。这一刻不是脚本触发的,是文明自己走到的。我们为它做了一段专门的演出 FIRST_FIRE:由“这一局第一次有人学会用火”这个真实事件触发,并且无视导演的 20 秒冷却。
2. 第一版:交付了,但不震撼
第一版 8 秒:俯冲 → 摇臂降到地面 → 低机位仰拍,火在主角身后、火光照在脸上 → 0.25 倍的子弹时间(暗角、色差,声音被低通)→ 标题卡「第 N 年 / 火」逐字盖章,配上鼓和钟 → 镜头升起,看火种传开、篝火一处处点亮。任意输入都能跳过。
复审的结论是:
- 3 分钟内交付了:照着猿群劈雷的话,24~40 秒就会有人学会用火;完全不干预,自然雷暴也会在 2.85 分钟时带来第一把火;
- 遮幅、子弹时间、标题卡、声音、可跳过全都在,但不震撼,6/10。最关键的两三秒里:机位离精灵太近,大像素块加上景深糊成了一片;摇臂下降时还穿过了一只鹿,一个巨大的像素鹿头占了半个画面;火在画面里是一面橙色的墙,而不是“一堆火”;界面只淡到 20%,压在电影黑边上,黑边看起来像界面的底板,玩家根本意识不到这是遮幅。

3. 重拍:推、绕、入夜、屏息、落点
第二版重新设计了节奏:
- 推:从神视推向主角;
- 绕:沿主角头部连续地画一道弧线,主角始终钉在三分点上;
- 入夜:画面暗下来,火光成为唯一的光源;
- 屏息:子弹时间,余烬在空中飘,主角手里的火把在他脸上“呼吸”;
- 落点(第 2.9 秒):主角举起火把,一个 12 倍大的「火」字重重盖下,冲击环扩散,一声低沉的重击,震屏、辉光、闪白;
- 呼气:镜头升起,天亮了,下方遮幅打出编年史里的这一行。
机位不再凭感觉摆,而是从 270 个候选机位里打分挑选:不能悬空,要看得见头和身子,主角不能站在火里,中间不能隔着树干,最好逆光;离得远时就换长焦。演出期间界面完全隐去。火把是表现层临时塞到主角手里的,好让火始终在画面里、离脸足够近。


我们给第二版的自评是 8/10。还没解决的问题也写在这里:在大片林火里,“一堆火”有时仍然会变成“一面火墙”,只能靠选机位避开;绕镜的弧线偶尔会擦过崖边(视频里能看到约 0.4 秒)。


七、编年史:一部会自己写的史书
1. 写什么,怎么写
编年史把模拟事件写成句子:发现、托梦、传播、普及、失传、重新发现、时代、聚落的建立、分出、迁徙和毁灭、每一种神力、天选者、祈愿的回应与落空、名人之死……每一类有 2~6 种句式,挑句用一条独立的随机数流,所以写作不会影响模拟,同一局永远写出同一本书。
原始和部落时代用口述的语气(“枫桥营的老人后来常讲……”);后面的时代会换成史书体和报纸体,等时代系统登场时再展示。
人名和地名也由生成器给出:早期的人用自然名(雷芽、虹眉、鸢羽、潮花……),聚落名由地貌词根加后缀组成,后缀会随规模演化(枫桥营 → 枫桥村)。在正式的命名器接上之前,编年史里写的是“12 的 337 发现了……”。
下面是几局实录里的原句(未修改):
text第 0 年 金羽领着族人在河边歇脚,此地后称枫桥营。 六只猿人聚在河边,这里后来叫作清溪营。 第 1325 年 雷芽敲出了锋利的「石器」,枫桥营的人都围过来看。 第 2050 年 枫桥营的虹眉拿起石矛,学会了「狩猎」。 第 2850 年 雷霆击中了泉根,泉根却站了起来。族人说,这是天选的人。 第 4925 年 没有人教过鸢羽。那天,鸢羽把小羊留在身边,学会了「驯化」。 第 5050 年 枫桥营的老人后来常讲:虹果第一个学会了「用火」。 第 5125 年 两道雷接连劈在枫桥营附近。 第 5250 年 枫桥营和清溪营向天求平安,天没有回应。
text第 7250 年 没有人教过烟羽。那天,烟羽对着雷声跪下,悟出「万物有灵」。 第 7850 年 潮花从梦中醒来,记住了「语言」。
text第 12000 年 最后一个会「丧葬」的人——泉鳞,也走了。 第 13350 年 鸢羽老死了。人们还记得鸢羽带来的「驯化」和「语言」。 第 14125 年 雁爪重新摸索出了失传已久的「丧葬」。 第 16450 年 枫桥营求火得火,从此更加虔诚。 第 17750 年 清溪营向天求火,天没有回应。 第 18050 年 熊爪第一个学会了「用火」,枫桥营的人都围过来看。
最后一段是视频里那次“回应求火”的局:玩家回应了枫桥营的祈愿,枫桥营先学会了用火;而没有得到回应的清溪营,只能等火种自己传过来。
2. 把它当一本书来读
编年史最大的难点不是句子,而是刷屏。我们的做法是:每轮把整整 25 分钟的编年史导出成一份全文,从头到尾当一本书读,记下“读不下去”的地方,改句子或改写作规则,再导出重读。前后读了四轮,改掉的问题包括:
- 句式重复:“……的人都围过来看”在一份口述里出现了七八次。包装句扩到每种语气 5~6 句。
- 回响刷屏:用脚本代打的一局里,1201 行有 815 行是孤零零的“……这一切,始于 N 年前那道雷霆”。改成回响只跟在真正写出来的那一行后面,每个事件最多一条;句子里已经写明起因的,不再追加回响。这一局最后收到 249 行,回响 13 条。
- 神力刷屏:连续施放同一种神力合并成一行(“两道雷接连劈在枫桥营附近”);回应祈愿的那次施放,直接被回应行替换。
- 人名和事迹粘连:人名以“掌”“足”“尾”“花”结尾时,“雾掌握着石矛”会被读成“掌握”。改了 6 条事迹的开头字(握着 → 拿起,以 → 用……)。
- 病句:“始于 0 年前那托梦”“世界步入部落”“向天求驱散野兽”,都改掉了。
- 排版:卷轴里“「石 / 器」”被折成两行,现在朱笔关键词连同书名号整体不折行。


八、复审:闸门“出手有手感”
1. 测时延
复审用脚本驱动无头浏览器,用真实的鼠标和键盘走完每种神力的施放流程,从松开鼠标那一刻开始计时,在页面里逐帧打点(1 倍速,1280×720,单位毫秒):
| 神力 | 手边波纹 | 世界特效首帧 | 人群反应 | 飘字 | 编年史新行 |
|---|---|---|---|---|---|
| 雷霆 | 4 | 152 → 3~30 | 同 tick | 145 | 146 |
| 降雨 | 2 | 89 | 同 tick(12 人欢呼) | 84 | 84 |
| 干旱 | 3 | 35 | 同 tick(16 人) | 29 | 30 |
| 丰饶 | 2 | 112 | 同 tick(8 人) | 104 | 106 |
| 瘟疫 | 1 | 76 | 同 tick(30 人) | 66 | 67 |
| 地动 | 2 | 91 | 同 tick(33 人) | 87 | 87 |
| 托梦 | 1~2 | 26~75 | 同 tick | 14~67 | 16~68 |
| 目标 | ≤ 100 | ≤ 100 | ≤ 500 | ≤ 1000 | ≤ 1000 |
世界特效首帧超过 100 ms 的有雷霆(152 ms)和丰饶(112 ms),原因是施放要等下一个模拟 tick 才真正执行。手边的波纹和宝珠是即时的,所以手感上几乎察觉不到;但雷霆是最常用的神力,返工时我们让施放被接受的那一帧就先把闪电“预演”出来,模拟事件再按命令编号去重,雷霆首帧降到了 3~30 ms。
2. 结论和返工清单
两道闸门都是有条件通过:
- 活的世界:小人有状态、有群体戏(觅食、劳作、交谈、被狼追着四散、迁徙),10 分钟观察零错误。条件:默认缩放下猿人只有一两个像素,开局第一屏看不到生命;灵感刷屏。
- 出手有手感:七种神力的反馈链全部在时限内。条件:降雨和干旱没感觉;导演会在玩家拿着神力时抢镜头;第一把火的构图不成立。
这些条件就是上面各节提到的返工:第一把火重拍、演出时界面完全隐去、自动镜头加字幕、降雨干旱重做、灵感降噪、导演让位于玩家、托梦新规则、雷霆首帧预演,以及开局第一眼:现在开局 3.4 秒内,镜头会从高处落到最密的一群猿人身上并跟着他们走。
还留着的问题:EMERGE 起镜偶尔穿模;天选者的自动 HERO 镜头会抢第一把火的戏;音乐和环境音还没有做(只有音效)。


九、下一步
阶段 3 是时代:文明要从部落走向更远的时代,建筑、服饰、夜景都要跟着变,时代更替也要有自己的演出。
下一篇日志见。如果你玩过类似的游戏,或者对“第一把火”这段演出有想法,欢迎留言告诉我们。










