银河快报

动手做一个银河系游戏,从一行代码到旋转的星尘

说来好笑,我最初想做一个银河系游戏,只是因为晚饭吃撑了,窝在椅子上刷手机,看到一个天文望远镜拍下的仙女座照片,忽然就冒出个念头:我能不能自己在屏幕上造一个会转的银河系?不是那种3A大作级别的,就是一个小小的、有星团旋臂的、拿鼠标能拖来拖去的玩意儿,第二天我就打开了编辑器,然后对着空白的屏幕发了十分钟呆。

一切的起点:你不需要是天文物理学家

费曼说过一句我特别受用的话:“我不能创造的,我就无法理解。”这话反过来也成立——你想理解银河系为什么长成旋涡状,最好的办法就是自己造一个,但别被吓到,我们不是要解纳维-斯托克斯方程,也不用搞暗物质模拟,我们要做的,是用最简单的规则,让几千个点自己组织出旋臂来。

核心原理一句话就能讲清楚:恒星绕着中心转,但转的速度和它离中心的距离不是简单的线性关系。这叫做“较差自转”——内侧转得快,外侧转得慢,如果一开始这些恒星是均匀散布在一个圆盘里,转着转着,它们自然就会被拉成旋臂的形状,这不是你画出来的图案,是转出来的结构。

动手做一个银河系游戏,从一行代码到旋转的星尘

第一步:在屏幕上撒一把星星

打开你手头的任何能画点的工具——Python加Pygame、JavaScript加Canvas、甚至Unity都行,我选的是P5.js,因为打开浏览器就能跑,先别想旋臂,先把星星撒上去。

怎么撒?不是完全随机的。银河系的恒星分布大致是一个圆盘,中心密、边缘稀。你可以在极坐标下生成位置:半径r用指数分布或者简单的随机加上一点点向心的权重,角度θ就均匀随机,初始速度呢?大致垂直于半径方向,速度大小取决于r,这里有个经验公式,文献里常管它叫“银河旋转曲线”——但咱先简化,让角速度差不多是r的某个幂次函数就行。

我第一版代码大概长这样(伪代码的感觉):

  • 创建5000个粒子,每个有x, y, vx, vy四个属性
  • 初始位置在半径2到15之间随机分布,用指数衰减让外围稀疏
  • 初始速度设为垂直于半径的切线方向,大小按r的-0.5次方来调
  • 每帧更新位置,加上一个简单的欧拉积分

跑起来之后,屏幕上是一团乱转的点,像个搅拌机里的芝麻糊,我盯着看了两分钟,差点关了电脑去睡觉。

第二步:旋臂是“转”出来的,不是“画”出来的

关键的一步来了,我上面说的初始条件其实藏着一个问题:如果你让恒星严格按圆形轨道转,它们转一百圈还是均匀分布,不会出现旋臂,旋臂本质上是一种密度波——恒星走进去、又走出来,但波的结构留住了。

我们不用模拟完整的密度波理论,那太复杂,一个取巧的办法是:初始时给恒星的位置加一点“扰动”,让它们不是完美的圆形分布,而是略微聚拢在几个角度附近,你可以把初始角度设成几个正态分布的叠加,每个分布的中心角度相差固定值,这样一转起来,这些聚集的区域就会被较差自转“拉伸”成旋臂。

我试了三种初始角度设置,效果对比如下:

初始角度分布 200帧后形态 是否像旋臂
完全均匀随机 均匀盘面,无明显结构 不像
两个高斯峰,相隔180° 两条模糊的棒状结构 有点像棒旋星系
四个高斯峰,相隔90° 四条清晰旋臂,逐渐缠绕 很像!

当我第一次看到屏幕上四条旋臂慢慢缠紧、像咖啡拉花一样散开的时候,后背是真的有点发麻。就几百行代码,一个缩微版的星系在你眼前活过来了。

第三步:加点颜色和交互,让它变成“游戏”

这时候它还只是个模拟器,不是游戏,游戏得能玩,我想了想,最低成本的互动方案是:让玩家控制星系中心的超大质量黑洞的引力强度,鼠标滚轮上调引力,所有恒星被拉得更紧,旋臂收缩;下调引力,恒星向外飘散,旋臂解体,你还可以加一个“吞噬”机制——某些倒霉的恒星飘太近就被吸进去,同时黑洞质量变大。

色彩上我做了个简单的映射:

  • 靠近中心的恒星偏蓝白色,代表年轻炽热的O型B型星
  • 旋臂中段的偏暖黄,像我们的太阳
  • 外围稀疏的偏暗红,像低温的红矮星

再加一个深空背景,撒上几百颗不动的背景星点,整个氛围一下子就出来了,鼠标拖动可以旋转视角,滚轮缩放,就这样,一个能看、能转、能拖、能调引力参数的银河系小玩具就算做完了。

动手做一个银河系游戏,从一行代码到旋转的星尘

那些卡住我的坑,你也会遇到

不说虚的,做这个过程中我踩了好几个坑,第一是积分精度——用简单的欧拉方法,恒星跑着跑着就飞出去了,后来换成半隐式欧拉才好一些,第二是性能,粒子数超过3000的时候我的老笔记本风扇狂转,后来发现是每帧都在重新计算所有粒子的距离矩阵,改成了空间哈希网格之后帧率从12蹦到了55,第三最蠢:旋臂缠太紧之后所有恒星挤成一团,是因为我忘了给半径方向加一个微小的随机速度弥散——真实的银河系里恒星轨道不是完美的圆,它们有一定的径向运动。

这些坑一个一个填过去,填到半夜两点,咖啡都凉透了,但星系在屏幕上安静地转着,几万光年的尺度被我缩在13寸屏幕里。那种感觉很难形容,就好像你真的造了个东西,哪怕它只是一堆像素。

做完之后我给一个学天体物理的朋友看,他拖了几下鼠标说:“旋臂缠绕角度偏大了,真实的银河系没那么紧。”我笑了笑没说话,心里想的是——这是我的银河系,旋臂缠成什么样我说了算。你的那个,也可以长成你喜欢的任何样子。

关键词: