Loading
0101 / 09粒子生命的第一个版本,以两种不同的方式死去了。
当两种颜色互相吸引时,它们不断向内加速,直到几乎占据同一个点。一千个粒子变成少数几个耀眼的奇点:视觉上强烈,物理上却毫无用处。当矩阵要求它们互相排斥时,粒子又会扩散成均匀的尘埃。没有膜,没有链条,没有旋转的臂,也没有任何能够持续足够久、从而变得有趣的结构。
每一种矩阵,都只是坍缩与扩散之间的不同版本。
这不是调参问题。减小力、增大摩擦、减少粒子数量,或者选择更温和的数值,只会改变同一种失败到来的速度。真正错误的是力的形状。我要求吸引力同时制造靠近与分离,但吸引只懂得前者。
当粒子学会保持距离时,这个项目才真正开始运转。
决定性的想法: 稳定结构需要两条相反的指令:距离足够远时靠近,距离过近时分开。
这里使用引擎中的原始方程与调参范围。f 为归一化值;单个邻居在摩擦前贡献 Δv = f × 80 × 1/60。
粒子生命从一些简单到不配称作“智能体”的对象开始。
每个粒子只有位置、速度和五种颜色类型之一。它没有记忆、目标、传感器、新陈代谢,也没有世界模型。每一步物理计算中,它只观察附近的粒子并提出两个问题:对方是什么类型?距离有多远?
第一个答案从 5×5 交互矩阵中选择一个值。第二个答案进入一条力曲线。两者共同决定这个粒子是向邻居加速,还是远离邻居。
这就是全部的行为词汇:二十五种有方向的关系,一条距离规律,在数千次局部相遇中重复,每个模拟秒执行六十次。
我的目标不是把某种“像生命”的东西做成动画。动画会允许我直接画出想要的结果。我的目标是规定局部物理,然后失去对全局结果的控制——创造结构自行出现的条件,而不是把结构写进代码。
我在《涌现与复杂性》中讨论过更一般的区别。粒子生命是一次具体实验:如果规则真的简单,你就应该能够触碰它、改变它,并观察后果如何传播。
最初的力,在本应最谨慎的地方反而最强。
设想两个互相吸引的粒子。如果吸引一直延伸到零距离,那么每一步都会让它们更近。它们获得更多向内的速度,最终逼近“两个粒子位于同一点”的数值奇点。摩擦可以减慢坍缩,却无法创造一个让它们停下的距离。
把矩阵值反过来。互相排斥的粒子会不断分离,直到超出作用半径。此后力变成零,它们保持分开。把这两种情况扩大到两千个粒子,结果不可避免:
| 关系 | 局部结果 | 全局结果 |
|---|---|---|
| 一直吸引到零距离 | 粒子对坍缩 | 稠密的奇点团块 |
| 半径内持续排斥 | 粒子对分离 | 均匀扩散的尘埃 |
缺失的是平衡点:一个指令会改变符号的距离。
最终引擎把粒子间距归一化为 t = d / R。其中 d 是两个粒子的距离,R 是最大作用半径。随后,它把半径分成两个有效区域。
0 ≤ t < β 通用排斥
β ≤ t < 1 由矩阵决定吸引或排斥
t ≥ 1 力为零近距离区域忽略颜色与矩阵,每一对粒子都互相排斥。中间区域由 5×5 矩阵接管。超过 R 后,两者不再相互作用。
矩阵值只控制中间区域。近距离排斥对所有粒子都成立,因此吸引能够稳定下来,而不是坍缩。
引擎中的标量力是下面这段分段函数:
const t = distance / interactionRadius;
const force = t < beta
? t / beta - 1
: matrix[myType][theirType] *
(1 - Math.abs(2 * t - 1 - beta) / (1 - beta));第一段从零距离时的 -1 上升到 β 处的 0,始终代表排斥。第二段是一个三角形的力阱:两端为零,中间最强,正负号由矩阵决定。
默认参数是 R = 100 px、β = 0.3。边界因此位于:
β × R = 0.3 × 100 px = 30 px对于互相吸引的粒子,中间区域把它们向内拉,内部区域把它们向外推。符号在 30 像素处改变,因此它们会稳定在这里。测试并不只验证公式;它会模拟一对真实粒子,测量最终间距。在调优后的参数下,结果在测试容差内为 30.00 像素。
互相排斥的粒子则不同。两个区域都把它们向外推,直到接近 R;超过 100 像素后,它们不再感受到力。同一条曲线因此同时支持稳定靠近与清晰分离,而不需要为两种关系编写特殊逻辑。
两个稳定保持距离的粒子不是生命,甚至很难称为结构。但它们引入了第一个版本永远无法产生的东西:能够持续存在的空白空间。
这个空间很重要。成员无法占据同一点的团簇拥有内部形状;链条拥有链节长度;膜能够抵抗压缩;多种颜色可以形成相邻区域,而不是坍缩到同一个坐标。系统一旦能够保存距离,矩阵就能组织这些距离。
全局形态并不是隐藏模板:
Galaxy 类负责画旋臂;每个粒子只会求和局部的粒子对作用力、更新速度,并在世界边界处环绕。“Galaxy”“Cells”和“Soup”是事后为矩阵行为起的名字,不是动画程序。
此时,“涌现”才获得了准确含义。规则中存在一个粒子对的偏好距离,却不存在一个五色旋转追逐环。只有当大量有方向的关系同时穿过空间与时间时,那个环才会出现。
很容易把 forceScale、摩擦、R 与 β 看成四个凭感觉调节的旋钮。引擎让我明白事实并非如此。
摩擦会在每个固定步骤中应用。原始的力强度使终端速度始终低于验收范围,无论矩阵的吸引值有多大。矩阵数值无法修复一个在物理上不可达到的力预算。我必须测量系统、搜索允许的参数网格,并把整条曲线作为一个整体调优。
最终默认值不是自然界的神圣常数。它们只是针对当前画布尺度、粒子数量、时间步和视觉语言测得的工作点。改变时间步或摩擦模型,相同数字就不再代表相同的行为。
粒子生命会产生看起来有生命的运动,但这并不证明粒子是活的。
它们不会繁殖、消耗能量、适应环境,也不会跨代保存信息。把一个旋转团簇称作生物,只会用一个轻松的比喻取代真正有趣的问题。
模拟展示的是一个更窄、也更有用的事实:我们本能地使用生物语言描述的行为,可以从完全不具备生物属性的粒子中出现。没有欲望,也可以出现追逐;没有忠诚,也可以出现凝聚;没有建造者,也可以出现边界。
已知、已测、未知: 力的规律是已知的;粒子间距和系统指标是测得的;视觉上的“生命感”是否对应更深的科学事实,仍然未知。
打开粒子生命模拟器,选择 Galaxy。
前十五秒什么都不要改。先观察粒子如何建立间距,再看大尺度旋臂逐渐变得清晰。然后暂停,把矩阵中恰好一个正值向零移动。继续运行十五秒。
不要只问它是否仍然漂亮。问得更具体:某一种颜色是否不再加入旋转结构?团簇数量是否改变?运动是否趋于稳定?变化影响了整个世界,还是只影响一种关系?
在第二篇中,二十五个滑块将从一堵墙变成一种可读语言——一种可以让某种颜色追逐、同时让另一种颜色逃离的语言。