2026年3月5日 · Mikhail Vasilyev

《构宙》开发日志:引擎原型

Watch on YouTube

一个半月前,我在网站上发布了工作室的计划——关于《构宙》引擎:它是什么,我们会在上面做哪些项目,一直到策略游戏和埃及系列的续作。那里还有一份路线图。引擎很复杂,为了降低风险,我想一步步把它搭起来。但玩家在评论里说得很直接:这种东西根本搭不出来。所以我决定先从一个原型做起——证明这样的引擎终究是能搭出来的。我要展示的就是它。

原型菜单:引擎让你从四个模拟里选一个——Stone Age《石器时代》、Slay the Spire《杀戮尖塔》、恒星系统生成器,以及 Oregon Trail《俄勒冈之旅》

这就是引擎现在的样子。表面上看,它是个相当简陋的控制台程序。但它很好地说明了最重要的一点——不同的机制都跑在同一个通用引擎上。

现在上面跑着四个模拟。第一个是 Stone Age《石器时代》,工作室最早的一款游戏,2013 年的。另外三个是照着别人的项目做的。我没打算抄袭它们,也不会发布,它们摆在这里只是为了说明:完全不同的游戏机制可以跑在同一个引擎上。

Stone Age《石器时代》

《石器时代》在引擎上被完整复刻了出来。一样的属性、年份和回合、人口、土地。你把工人派进森林,他们采集食物,人口增长,科技出现——你研究它们,解锁建筑和进化树,从南方古猿到能人,再往后。事件、结局——原作里的一切都在。

原型控制台:Stone Age《石器时代》——部落属性、土地、科技与进化菜单

Slay the Spire《杀戮尖塔》

接下来是 Slay the Spire《杀戮尖塔》,一款很出色的卡牌肉鸽游戏,应该有人玩过。引擎上只做了战斗这部分:玩家有手牌、能量和生命,敌人有自己的意图。Strike(打击)造成伤害,Defend(防御)提供格挡。你消耗能量,结束回合,就这样轮流来,直到分出胜负。

同一个控制台运行 Slay the Spire《杀戮尖塔》——生命、能量、敌人的意图,以及手牌

GURPS

第三个模拟是 GURPS,一套桌面游戏系统,相当复杂。我只从中取了一个模块,恒星系统生成器。有意思的是,这个模块本身根本不是游戏,而是一个复杂的生成器。它生成了一个系统:一颗恒星,外加一大堆属性,十条轨道,上面是各不相同的世界。第一颗又小又是岩质的,像水星——有自己的质量、大气压等等。整个模拟里一共有六千多条事实。这是一次很好的压力测试:能看出引擎能扛住多少数据。

GURPS 模块里生成的一个恒星系统——恒星、各条轨道,以及第一个世界的属性

Oregon Trail《俄勒冈之旅》

第四个是 Oregon Trail《俄勒冈之旅》,1971 年的经典,也是最早的电脑游戏之一。讲的是拓荒者驾着篷车横穿美洲:上路前先采购物资——牛、食物、弹药、衣物——然后一路打猎、分配口粮、应对各种事件。我们这就遭到了袭击。就这样一直走到旅程的终点。

同一个控制台里的 Oregon Trail《俄勒冈之旅》:物资——食物、弹药、衣物、金钱——以及遇到骑手时的行动选择

四款游戏都跑在同一个引擎上,而且没有一个需要写代码。

运行时改

但引擎不只是把这些游戏跑起来——你还能在运行时直接改它们,不碰代码。拿 Slay the Spire《杀戮尖塔》来说。

引擎上 Slay the Spire《杀戮尖塔》的起始回合:生命、能量、敌人,以及手里的五张牌——Strike(打击)的伤害还是 6

我把 Strike(打击)牌的伤害改成 100:

/set Strike.CalcDamage Value 100

这两张牌的属性一下子都变了,因为它们是同一个类。

手里有两张 Strike(打击)牌,现在都是 100 点伤害——这个属性一下子改到了该类所有牌上

也可以加一张全新的牌 Fireball(火球):

/add Fireball Is DirectDamage
/set Fireball.CostEnergy Value 2
/add Fireball Has CalcDamage
/set Fireball.CalcDamage Value 20
/add Fireball Has ApplyDamage
/add Fireball.ExecutionEffects Has CostEnergy
/add Fireball.ExecutionEffects Has CalcDamage
/add Fireball.ExecutionEffects Has ApplyDamage

它本来不存在,现在进了游戏——躺在手里,能打出,造成 20 点伤害,然后像普通牌一样进弃牌堆:

改完之后:两张 Strike(打击)牌都是 100 点伤害,手里还多出一张 20 点伤害的新牌 Fireball(火球)

连规则本身也能改,一条命令就行。我把“打出的牌进弃牌堆”这条规则去掉。

/remove PlayCard Has MovePlayedCard

现在它们留在手里了。打出 Defend(防御):格挡挂上了,能量也花了,可牌还在。

改了规则之后:Defend(防御)打出——能量 0/3,格挡 5——但所有打出的牌都留在手里,标着 [X]

在一款用编程语言写的普通游戏里,要做到这一点,得钻进代码、重新编译整个项目。在这里不用。

同样的方式,还能往游戏里加进原本压根没有的东西。比如金币——我把它建起来,并描述它是怎么花的:

/set Player.Gold Value 100
/add CostGold Output Owner.Gold
/add CostGold Math.Subtract.Apply true

出现了一项刚才还没有的属性——金币,而且一上来就是整整一百。

状态栏里出现了金币——一下子就是一百,这是游戏刚才还没有的一项属性

有了这些金币,还能做一个新动作 Bribe(贿赂)。它花的不是能量,而是金币:

/add Bribe Is DirectDamage
/set Bribe.CostEnergy Value 0
/set Bribe.CostGold Value 30
/add Bribe Has CalcDamage
/set Bribe.CalcDamage Value 15
/add Bribe Has ApplyDamage
/add Bribe Has CostGold
/add Bribe.ExecutionEffects Has CostGold
/add Bribe.ExecutionEffects Has CalcDamage
/add Bribe.ExecutionEffects Has ApplyDamage
/create Bribe Player.Hand

Bribe(贿赂)要花三十金币,造成十五点伤害——而且立刻就能用。

手里出现了一个新动作 Bribe(贿赂):零能量、三十金币、十五点伤害

你可能会觉得这是作弊,觉得敲这些命令很别扭。但这不是作弊。这是在改整个游戏赖以成立的逻辑事实和数据——它的对象、属性和机制。本质上,这就是这款游戏所用的语言。

这门语言不学也行。你可以让 AI 把一句普通的话翻译成《构宙》能懂的命令。比如:

give 999 gold

翻译过来不过就是“加 999 金币”。

用大白话向 AI 发出请求——“give 999 gold”。引擎会自己找到对应的命令并执行

AI 想了想,找到对应的命令并执行,于是我们就有了 999 金币。

换种说法也行,“金币 100”一样管用。“让我变成神”——AI 会给你无敌。结束回合、攻击、回血——这些都能用话说出来,引擎都懂。而且这里没有一处是脚本写死的,全都是真的在跑。

计划

命令我想再简化一下。现在要做出同样这张 Fireball(火球),得用大约八条命令,我想把它压到三四条。下一个视频里,我会尽量展示一些更直观的东西——2D 渲染。

关于引擎和后续计划的更多内容,见《构宙》专区。

声明:Stone Age《石器时代》是工作室自己的游戏。Slay the Spire《杀戮尖塔》、GURPS 和 Oregon Trail《俄勒冈之旅》归各自的权利人所有,这里只作为引擎演示展示——这些版本不在任何地方发布。