回到首页

会自己运转的世界

一组靠局部规则自己变化的模拟实验,从 2017 年断断续续做到现在。留下来的有生命游戏和沙漠水热反应的代码,还有一份没写完的温度草稿。

TYPE
局部规则驱动的模拟实验
STATUS
有规则和原型,还没有一个算做完
WHEN
2017 至今
BUILT WITH
Unity 和 Bevy,用 C# 与 Rust 写
WHO
我一个人做的

这是什么

这组实验是让局部规则推动变化,有格子的生灭,也有温度和物质在邻格之间的传递。开发日志最早一条写在 2017 年 12 月,那时我已经在想用元胞自动机(格子和邻居)搭游戏世界。

引擎换过好几轮,2017 年是 Laya,2018 年换成 Phaser,2021 年起用 Unity 和 Bevy,2024 年 5 月我比较过几个引擎,2026 年 4 月用 Bevy 做了沙漠实验。最早两个阶段的原工程找不到了,后面几个阶段还留着提交记录或文件。

换过的引擎2017Laya开始想用格子和邻居写世界2018Phaser换了引擎接着做2021Unity、Bevy三维格子上的温度2022Unity二维生灭规则2024Bevy同一条生灭规则,比了几个引擎2026Bevy沙漠里的水、热和化学反应找得到提交记录或文件只在开发日志里有记录,原件没找到

FIG. 1 · 换过的引擎

年份和引擎按开发日志整理。实线框是留有提交记录或文件的阶段,虚线框只在日志里有记录。

格子只看身边

Unity 那版默认是 100 × 100 个格子,每格随机有 50% 的机会存活。每格只数身边八格,左边接右边,上边接下边,边缘格也有八个邻居。

活格有两个或三个活邻居就留下,死格恰好有三个活邻居才出生,其他情况都变成死格。全部格子先读这一轮的数组,把结果写进下一轮,算完才交换,这样结果不取决于先算哪个格子。代码每帧推进一轮,没有单独的计时器。

八邻居生灭规则八邻居生灭规则只数周边八格本格中心不计入下一轮状态(按活邻居数)活邻居数当前活当前死0死死1死死2活死3活活4死死5死死6死死7死死8死死活格:2 或 3 个活邻居时保留其余为死死格:3 个活邻居时出生其余仍死整轮读取旧格、写入新格,算完才交换。格子仅作示意,不是历史运行结果。

FIG. 2 · 一轮格子更新

按代码里的规则画的示意图,不是运行截图。

地表会改变水和反应

沙漠原型用连续数组存水、矿物、溶解物、有机前体和热值,默认 512 × 512 格,一格不对应一个独立实体。每帧默认推进三次,可以调到 1–24 次,也能暂停,七种视图和鼠标探针用来看整体和单格。

每一步先处理降雨,再算水流、热扩散和溶解物扩散,应用变化之后做反应。沙、岩石、黏土和反光平地各有一组参数,保水参数决定水留下多久,流动参数管水流和扩散,催化参数管矿物风化和合成。

这里的水量和热值是实验里的数,没有做现实单位校准,热值不能读成摄氏度。推进次数跟着帧走,同一组规则跑多快会受帧率影响。

四种地表的基础参数四种地表的基础参数保水 retention01流动 permeability01催化 catalysis01沙地0.140.820.07岩石0.050.130.18黏土0.760.20.46反光平地0.080.340.03基础预设值,每格还会加入扰动并限制范围。归一化参数,未校准物理单位。

FIG. 3 · 四种地表的基础参数

数值是代码里的地表基础参数,用 0–1 的数表示,没有校准物理单位。实际每格还会加扰动,表里的数不是每格的最终值。

有机物还不是生命

雨水让矿物溶解,水、热值和地表参数一起影响有机前体的合成,之后有机物还会衰减,一部分回到溶解物里。这里说的“有机物”只是一个数值场,现在没有复制规则,生命量也没有更新。

画面里的反应适宜度只是一项显示和统计分数,越过阈值不等于生命出生。物质守恒还没建立,溶解物只按浓度差扩散,没有跟着水流搬运。

做到哪了