43

我将制作一个完全由程序生成的太空/交易/战斗游戏。但是,我知道将整个银河系的所有细节都存储在内存中是不可行的。结果,我一直认为我可以用一颗种子来生成一个太阳系,从那个太阳系,你可以使用跳跃门前往其他太阳系。问题是,如果我从起始太阳系跳到另一个太阳系,我需要能够回到具有完全相同特征(行星、小行星等)的完全相同的起始太阳系。

本质上,我需要能够从一个数字生成整个星系。从那个生成一个太阳系的数字中,我需要能够生成与第一个太阳系相连的所有其他太阳系,以及与这些太阳系相连的所有太阳系,依此类推。如果我回到它们,每个太阳系都必须保持完全相同的功能。此外,每个太阳系的链接数量可以是随机的,也可以是固定的,由您选择。不过随机会更好。

4

19 回答 19

23

如果你觉得勇敢,你可以做的比看看Ian Bell如何为最初版本的 Elite做的更糟糕

于 2008-12-07T23:39:30.183 回答
15

在 Gamasutra 上查看这个系列:

实时程序宇宙,前四个链接

另外,这个:无限宇宙的算法

于 2008-12-08T00:56:34.630 回答
7

这是我理解的基本思想。假设你已经到达星系#42,你需要找出里面有什么。它有nplanets行星——一个介于 0 和 10 之间的数字,比如:

>>> star_system = 42
>>> nplanets = hash('nplanets%d' % star_system) % (10 + 1)
>>> nplanets
4

好的,那么到 2 号行星,游戏开始时有多少空间站在轨道上?找出 0 到 3 之间的一个数:

>>> planet = 2
>>> nstations = hash('nstations%d/%d' % (star_system, planet)) % (3 + 1)
>>> nstations
1

等等。这些数字都是索引的散列函数(在这种情况下,星系统#42,行星#2),减少到适当的范围。由于散列函数是确定性但“随机”的,因此每次都是相同的,但对玩家来说是随机的。

当然,散列带有长序列的字符串(如“nstations”)并不是最快的方法,但它显示了这个想法。

于 2008-12-08T01:46:21.487 回答
6

看看原来的蠕虫游戏。我认为它声称有大约 40 亿个可能的级别。每个级别都是基于大约 20 个字符的短种子字符串生成的。这决定了

  • 关卡的主题(北极、森林等)
  • 景观的形状
  • 地面的滑溜
  • 预建关卡细节的放置(雪人、岩石……)
  • 你的蠕虫队、地雷和武器箱的位置。

如果您喜欢某个关卡,您可以记下种子字符串,并在以后使用它来重新生成相同的关卡。

这是一个非常复杂但具有确定性的函数的示例,只有一个输入参数。我认为这是您需要的基本概念。

于 2008-12-08T12:24:50.077 回答
5

我认为值得注意的是,

  1. 为相同的输入产生相同的随机输出的生成器称为伪随机数生成器“PRNG”。通常,您在一开始就给它一个“种子”输入数字,然后从中提取随机数字,无需进一步输入即可调用它。注意:你不能“回到”更早的号码,至少不能不从头开始。

  2. 使用坐标作为每次调用的输入调用的类似 PRNG 的函数通常是“噪声”函数。在这里,您没有“无法返回”的问题 - 只需再次使用“早期”输入进行调用。噪声函数使用 PRNG(作为后端;或者至少可以),它仍然可以在一开始就播种,因此您不会失去“一个数字中的宇宙”功能。

  3. 虽然您每次都可以只使用 PRNG 并将星系坐标组合为“种子”,但充其量只会得到“白噪声”,没有其他属性。噪声功能更适合这项工作,因为可以选择甚至调整它以使您具有平铺/平滑/螺旋状的外观/等。结果。例如,搜索使用 perlin 噪声制作的纹理图像。我希望您看到使用相同的噪声函数您可能会创建例如数千个随机云,但是通过根据您的需要调整噪声函数(不仅仅是种子或坐标),您可能会得到熔岩或星系。调整它可能不是微不足道的。

  4. 每次调用的输入坐标数决定了噪声函数的维数,因此对于二维地图(或纹理等),您可以使用二维噪声函数。然后你每次都称它为noise2d(x,y)。

在您的情况下,我会尝试使用 3 维单纯形噪声函数(单纯形来自 perlin noise 的作者,建议更好)。

然后,每个星系坐标三元组都会为您提供一个结果编号。下一个决定是:这个数字代表什么?为了充分利用单纯形噪声的平滑特性,我会将较低的数字映射到更空的太阳系,将较高的数字映射到质量更大的系统。或者,也许更好,对于每个系统调用单工噪声多次带有子坐标。中等大小的结果数字是行星,小数字是真空或小行星。大数字明星等。

该主题不活跃,而且很旧,但搜索可能会像我的一样在这里结束。

于 2012-10-03T17:09:16.517 回答
5

你不能只对星系 ID 进行 SHA1,例如:

银河一号

Sha1(1) = 356a192b7913b04c54574d18c28d46e6395428ab

银河 2

Sha1(2) = da4b9237bacccdf19c0760cab7aec4a8359010b0

银河 3

Sha1(3) = 77de68daecd823babbb58edb1c8e14d7106e83bb

然后你可以分段代码,IE:

前 4 个字符 = 行星数量

356a
da4b
77de

您将需要某种字符串到数字的算法,一个简单的算法是获取每个非数字字符的 ASCII 码,然后将它们全部相乘或其他东西。

那么现在我们知道我们的银河系中有多少行星,那么银河系的 x,y,z 维度呢?

接下来 9 个字符 = Galaxy 尺寸 (x,y,z)

原理同上,把代码变成大数。还要进行一些敏感性检查,您不想要一个 10milesx10milesx10miles 的星系,其中有 2000 万颗行星。有某种加权算法,例如最小大小是行星数 * 10000。您需要使用数字来确保范围都是兼容的,并且从哈希中选择的字符实际上会给您一个合理的范围。

或者,您可以用一个随机数代替这个,在星系的最小和最大大小之间选择一个数字,但使用一个恒定的 RNG 种子,例如星系 ID!这样,对于观察者来说,星系的大小基本上是“随机的”,但它们每次都是一样的。

等等等等!

这是获取宇宙属性的一种方式,但是行星属性呢?像人口和其他东西?

如果您拥有拥有 20,000 个行星的 Galaxy 1,您可以:

Sha1('1:340') = bc02ab36f163baee2a04cebaed8b141505cc26b5

也就是说,银河一号,行星 340。然后,您可以随意拼接该代码。使用哈希的好处是每个星球都应该有一个完全唯一的代码。

于 2011-03-30T15:28:10.843 回答
3

每个太阳系的随机种子是一个可行的解决方案,但我觉得你在这里找错了树。

玩家可以做些什么来改变那里的东西吗?(比如说,建造一些东西,开采一个可耗尽的资源等?)如果是这样,你无论如何都必须保存状态。

玩家是否可以在无需实际返回的情况下查看该地方的情况?(如果他不能,为什么不呢?!)你是要查找它还是要再生整个太阳系只是为了找出一条关于它的信息?(PRNG 解决方案不允许您只获得太阳系的一部分,您必须制作整个东西。)

到底有多少细节需要保存?

于 2008-12-08T02:43:52.400 回答
2

我用梅森捻线机。PRNG 接受任何长度的种子数组。
例如,我想在坐标 x=25,y=72 上生成星系。我用种子 [25,72] 重新启动捻线机。
如果我想在这个星系中生成第 1138 颗行星,我使用 [25,72,1138]。
国家?[25,72,1138,10]
城市?[25,72,1138,10,32]
等等。
使用这种方法,您只需使用一个数字(x 坐标之前的那个,在我们的例子中是 25 之前)就可以生成数十亿个对象。
现在有一些项目使用它。
Noctis:anynowhere.com/
Infiniverse: http: //www.infiniverse-game.com/

于 2010-12-03T09:00:58.577 回答
2

我不认为“星系”中真的有那么多信息是你无法将它存储在今天的计算机上的。假设一个星系有 100 颗恒星,每颗恒星有 10 颗行星,每颗行星有 3 颗卫星。那是 100 颗恒星 + 1,000 颗行星 + 3,000 颗卫星,您必须跟踪,即 4,100 颗天体。

这是我们可能想要跟踪的行星的事情。

质量 X,Y,Z 位置 一天的长度(在它自己的轴上旋转的时间) 年的长度 人口 50 种不同资源的资源量

假设每个值需要一个 double 来存储它,并且我们有 57 个值要存储(让我们四舍五入说 100),那么我们有 100 个值 * 8 个字节 * 4100 个主体 = 3,280,000 个字节。现在,这是 3 兆的数据。这可能看起来很多,但实际上并没有那么多。另外,我不认为你真的想在一个星系中有这么多恒星。游戏确实太大而无法探索,并且可能会变得难以控制,无法尝试实际模拟给定星系中正在发生的所有事情。

这样看。如果你拿 SimCity 这样的游戏,将城市网格上的每个方格视为潜在的星球,然后你就会意识到在一个小文件中可以存储多少信息,这样你就不必随机生成任何东西。

于 2008-12-08T01:05:09.713 回答
2

假设你从一个星系的种子开始,即1234,取这个种子,生成10000个随机数,每个随机数代表一个星系。当您接近恒星时,您获取恒星的随机数,并将其作为新随机函数的种子。为围绕恒星运行的天体数量生成一个随机数,并为每个天体生成一个数(始终使用第二个随机函数),依此类推。我不知道这是否对您有帮助,但您需要记住,随机函数内部是混乱的,对于初始条件,整个函数会发生变化。

银河系中恒星的种子必须始终产生相同的恒星,恒星的种子必须产生相同的物体,等等。

您总是可以使用统计数据、密度计算、改进结果来让事情变得更有趣。始终检查函数是否会为相同的输入产生相同的结果。

抱歉,如果我的英语很烂,我来自阿根廷,而且英语不是我受过训练的素质之一:p

PD:我在做同样类型的游戏;)

于 2011-03-30T15:18:22.940 回答
0

只要你用相同的种子调用 srandom(),你就会从 random() 中得到相同的值。因此,只需对 srandom() 的一次调用将星系统中的所有内容都建立在基础上……然后,您只需要为整个星系统存储 1 个整数(种子)。现在就是压缩!

于 2008-12-21T02:47:35.410 回答
0

这是我的第二个改进的解决方案。玩家将从一个随机生成的太阳系开始。每个系统都连接到 1 到 4 个其他系统。将它们视为北、南、东和西系统。如果玩家要通过北跳门,他将被带到一个种子比之前的系统多一个的系统。如果他往南走,那个系统的种子就会少一粒。2+ 和 2- 分别代表东和西。与这些系统的距离(以秒差距或光年为单位)是根据系统的种子和您到达的方向计算的。这样,星系的大小仅受用于容纳种子的数量的最大值和最小值的限制。

通往其他星系的曲速孔将放置在距起始系统一定距离的位置。下一个星系就像这个星系的延续,种子数量将以同样的方式增加,而位于星系曲速洞另一端的系统将只是“东”或“北” " 从启动系统连接。

顺便说一句,与上述解决方案不同,这种递增种子的使用会导致网络。此外,您可以看到此方法使用四边形,而上述解决方案使用六边形,这使得无法创建网络。

当然,所有这些都是基于这样的假设,即所有种子都会生成一个随机的数字序列,该序列不同于任何其他序列。这使得每个系统都是独一无二的。

于 2008-12-21T02:48:57.233 回答
0

如果您使用伪随机数生成器,则可以保证您生成的每个随机数都以相同的顺序出现在给定的种子中。生成由给定数字作为种子的系统的代码在您每次生成时都会显示相同。

使用伪随机数流中的第一个数字来生成“门”的数量。通过每个门并从数字流中获取一个值以分配给每个目标系统并为其播种。

根据该种子生成每个系统的特征。

有几种已知的算法用于生成随机种子。

梅森捻线机一个裂缝

于 2008-12-08T01:57:19.250 回答
0

我隐约记得以前做过这件事。在 90 年代初期,分形风靡一时,我记得有一家公司为游戏程序员提供世界。他们创造了一个完整的无限宇宙,充满了太阳和行星的星系,事件一直延伸到山谷和行星上地方的纹理。他们提议为游戏开发商寻找合适的虚拟房地产。游戏开发者将获得软件来渲染和使用它,以及在这个分形宇宙中他们的财产的确切坐标。

我已经用谷歌搜索了几分钟“分形游戏世界星球宇宙”等,但没有找到它们。可能是Pandromeda,但我不太记得了。

你应该为这个想法研究分形。您所需要的只是一个连续的数字字段,您可以从种子中重新创建这些数字,然后将这些数字呈现为具有不同属性的恒星、行星和卫星。

于 2008-12-08T00:01:51.400 回答
0

您可以从某个种子(“母数”)构建一个N位数的伪随机数。然后,您将数字分组并使用它们来回答您的问题。

示例:N =20

-> 一位数:有多少额外的跳跃门?
-> 三位数:生成每个可用跳跃的相应长度的
种子 -> 六位数:生成此太阳系的种子
-> 十位数:为每个链接的太阳系生成新的 20 位数种子的种子

然后递归。每个系统(具有稳定的轨道等)都是在时间 0 生成的,您必须计算它现在的样子。

当然,这种从母系统开始的方法意味着当前系统离母系统越远,生成数据所需的时间就越长。此外,这种方式可以制作一棵树,而不是一张网(这是我所期望的)。

我认为生成坐标会更好 - 使用平面中的极坐标,也许是三维的椭球。

于 2008-12-08T00:04:56.543 回答
0

如果您真的想返回到固定状态,我认为从单个值生成程序不是正确的方法。

假设,您在每个平面中有一个 256x256 系统的固定网格,在宇宙中有 16 个平面。每架飞机有多达 512 个交易站和多达 8 个与其他飞机的链接。所有的交易站和链接都在一个固定的位置。您的初始种子值必须至少为 2^76 才能对所有可能的宇宙进行编码。添加更多对象(行星、船舶……),数量呈指数增长。

编辑:如果您在每个系统中不允许多个交易站或链接,它会少一些。我会使用一些永久存储,可能是像 Firebird 或 sqlite 这样的嵌入式数据库。顺便说一句,我目前正在开发这样的游戏。

于 2008-12-08T00:22:49.707 回答
0

这就是我想出的。不知道它是否会是最终版本。

想象一个六边形网格,每个顶点都有一个太阳系。因为,我们在一个六边形网格上,所以从任何顶点只有三条线。一个总是水平的,另外两个是对角线的。如果我们给起始种子一个值n,我们可以给水平连接到起始点的太阳系一个值n+1,其他的得到n+2和n-2的值。

哦,废话。我们不一定会得到一个网格。该死的。让我们再试一次。

于 2008-12-08T01:04:24.490 回答
0

我怀疑你将面临的最大问题是拥有一个命名系统,以一种对玩家来说一致且有意义的方式命名所有这些对象——尽管我们确实有系统地命名真实对象的方案。我忘记了 Elite 的命名约定是否在某个时间点后失效了......

于 2010-12-03T09:28:43.440 回答
0

从数学上讲,您想随机/伪随机生成一个无向的连通图。在这个图中,每个节点都是一个太阳系,每条边都是一个跳门。

1)创建N个节点并随机分配一个空间坐标。这些节点最终将成为你的太阳系。

2)使用Deluanay三角剖分算法生成边缘。我建议使用 Deluanay 三角剖分,因为它会创建一个外观相当漂亮的地图,并且没有任何门相互交叉,但您实际上可以使用任何您想要的算法。我真的不知道你在找什么。

3)如果您使用了Deluanay三角剖分,我建议您消除一定数量的边以创建“稀疏性”。这将使地图更有趣,因为某些地点将成为交通枢纽,而其他地点则只是进站。

4) 保存此图。这是你的宇宙。不要放错地方或扔掉你的宇宙。尽可能高效地存储它,但不要删除任何信息。

5) 为每个节点分配一个种子,并使用这个种子生成每个太阳系。

6) 恭喜,您现在拥有一个包含任意数量的太阳系和跳跃门的宇宙。

于 2016-05-31T15:06:15.750 回答