web-dev-qa-db-ja.com

数学的質問:銀河の手続き型生成

完全に手続き的に生成される宇宙/取引/戦闘ゲームを作成します。しかし、銀河全体の詳細をすべてメモリに保存することは不可能であることを私は知っています。その結果、私は種を使って太陽系を生成することができ、その太陽系からジャンプゲートを使って他の太陽系に移動できると考えてきました。問題は、最初の太陽系から別の太陽系にジャンプした場合、まったく同じ機能(惑星、小惑星など)を備えたまったく同じ太陽系に戻ることができる必要があるということです。

基本的に、私は1つの数から銀河全体を生成できる必要があります。そして、1つの太陽系を生成するその1つの数値から、最初の太陽系からリンクする他のすべての太陽系と、それらからリンクするすべての太陽系を生成できる必要があります。そして、私がそれらに戻るならば、各太陽系は機能的にまったく同じままでなければなりません。また、各太陽系からのリンクの数は、ランダムまたは固定のいずれかを選択できます。ただし、ランダムの方が良いでしょう。

43
Dove

あなたが勇気を感じているなら、あなたはどのように見るよりも悪いことをするかもしれません イアンベルはそれをしました エリートの元のバージョンのために

23
Gareth

Gamasutraでこのシリーズをチェックしてください:

リアルタイム手続き型ユニバース、最初の4つのリンク

また、これ: 無限の宇宙のアルゴリズム

15
TraumaPony

これが私が理解している基本的な考え方です。星系#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」のような長いシーケンスを含む文字列をハッシュすることは、それを実行するための最速の方法ではありませんが、それはアイデアを示しています。

7
Darius Bacon

オリジナルの Worms ゲームを見てください。私はそれが約40億の可能なレベルを持っていると主張したと思います。各レベルは、おそらく20文字の短いシード文字列に基づいて生成されました。これが決定しました

  • レベルのテーマ(北極、森など)
  • 風景の形
  • 地面の滑りやすさ
  • 事前に作成されたレベルの詳細(雪だるま、岩など)の配置
  • ワーム、地雷、武器箱のチームの配置。

レベルを楽しんだ場合は、シード文字列を書き留めて、後日同じレベルを再生成するために使用できます。

これは、単一の入力パラメーターを持つ非常に複雑ですが決定論的な関数の例です。これがあなたが必要としているものの本質的な概念だと思います。

6
Liam

銀河IDをSHA1するだけではいけません、EG:

ギャラクシー1

Sha1(1) = 356a192b7913b04c54574d18c28d46e6395428ab

ギャラクシー2

Sha1(2) = da4b9237bacccdf19c0760cab7aec4a8359010b0

ギャラクシー3

Sha1(3) = 77de68daecd823babbb58edb1c8e14d7106e83bb

次に、コードIEをセグメント化できます。

最初の4文字=惑星の数

356a
da4b
77de

ある種の文字列から数値へのアルゴリズムが必要になります。簡単な方法の1つは、すべての非数値文字のASCIIコードを取得し、それらをすべて一緒に乗算することです。

これで、銀河にいくつの惑星があるかがわかりました。銀河のx、y、z次元はどうでしょうか。

次の9文字=銀河の寸法(x、y、z)

上記と同じ原理で、コードを多数に変換します。いくつかの感性チェックもあります。2000万個の惑星が含まれている10milesx10milesx10milesの銀河は必要ありません。最小サイズが惑星の数* 10000であるなど、ある種の加重アルゴリズムを使用します。範囲がすべて互換性があり、ハッシュから選択した文字が実際に妥当な範囲を提供することを確認するために、数値を試す必要があります。

または、これの代わりに、乱数で銀河の最小サイズと最大サイズの間の数値を選択することができますが、銀河IDなどの一定のRNGシードを使用してください。このように、銀河のサイズは観測者にとって本質的に「ランダム」ですが、それらは毎回同じになります。

などなど!

それはあなたの宇宙の特性を取得する一つの方法ですが、惑星の特性はどうですか?人口や他のもののように?

20,000の惑星を持つGalaxy1がある場合は、次のことができます。

Sha1('1:340') = bc02ab36f163baee2a04cebaed8b141505cc26b5

つまり、ギャラクシー1、惑星340です。その後、そのコードを好きなようにつなぎ合わせることができます。ハッシュを使用する利点は、すべての惑星が完全に一意のコードを持つ必要があることです。

5
Tom Gullen

注目に値すると思います

  1. 同じ入力に対して同じランダムに見える出力を生成するジェネレータは、疑似乱数ジェネレータ「PRNG」と呼ばれます。通常、最初に1つの「シード」入力番号を指定し、それから乱数を取得して、それ以上入力せずに呼び出します。注:少なくとも最初から始めない限り、以前の番号に「戻る」ことはできません。

  2. 各呼び出しの入力として座標を使用して呼び出されるPRNGのような関数は、通常、「ノイズ」関数です。ここでは、「戻ることができない」という問題はありません。「以前の」入力でもう一度呼び出すだけです。ノイズ関数はPRNG(バックエンドとして;または少なくとも可能)を使用しますが、これは最初からシードできるため、「1つの数値からの宇宙」機能を失うことはありません。 。

  3. PRNGを使用して、毎回銀河座標を「シード」に組み合わせることができますが、それ以上の属性はなく、せいぜい「ホワイトノイズ」しか得られません。ノイズ関数はタイル化可能/滑らかな/らせん状の外観などの結果を提供するように選択または調整できるため、仕事にはるかに適しています。たとえば、パーリンノイズを使用して作成されたテクスチャ画像を検索します。同じノイズ関数を作成できます。たとえば、何千ものランダムクラウドを作成できますが、ノイズ関数をニーズ(シードや座標だけでなく)に合わせて調整すると、代わりに溶岩や銀河が得られる場合があります。調整は簡単ではない場合があります。

  4. 各呼び出しの入力座標の数によってノイズ関数の次元数が決まるため、2次元マップ(またはテクスチャなど)の場合は、2次元ノイズ関数を使用できます。次に、毎回noise2d(x、y)のように呼び出します。

あなたの状況では、3次元のシンプレックスノイズ関数を試してみます(シンプレックスはパーリンノイズの作者によるもので、より良いものとして推奨されています)。

次に、各星系の座標トリプレットは、1つの結果番号を提供します。次の決定は次のようになります:数字は何を表していますか?シンプレックスノイズの平滑化機能を有効に活用するために、小さい数値を空の太陽系にマッピングし、大きい数値をより質量の大きいシステムにマッピングします。または、システムごとに、サブ座標を使用してシンプレックスノイズを複数回呼び出す方がよいでしょう。中規模の結果の数は惑星であり、少数は真空または小惑星です。大きな星など.

トピックはアクティブではなく、古いものですが、私のように検索がここで終了する可能性があります。

5
klaus thorn

各太陽系のランダムシードは実行可能な解決策ですが、ここで間違った木を吠えているような気がします。

プレイヤーはそこにあるものを変えるために何かをすることができますか? (たとえば、何かを構築したり、枯渇可能なリソースをマイニングしたりしますか?)そうであれば、とにかく状態を保存する必要があります。

プレイヤーは実際にそこに戻らなくても、その場所がどのようなものであったかを調べることができますか? (そして、彼ができないのなら、なぜですか?!)あなたはそれを調べるつもりですか、それともそれについての情報を見つけるためだけに太陽系全体を再生するつもりですか? (PRNGソリューションでは、太陽系の一部のみを取得することはできません。すべてを作成する必要があります。)

とにかく保存する必要がある詳細はどれくらいありますか?

3
Loren Pechtel

「銀河」には、今日のコンピューターに保存できないほど多くの情報があるとは思いません。銀河には100個の星があり、各星には10個の惑星があり、各惑星には3個の衛星があると仮定します。それはあなたが追跡しなければならない100の星+1,000の惑星+3,000の衛星、つまり4,100の体です。

これが私たちが惑星のために追跡したいと思うかもしれないものです。

質量X、Y、Z位置1日の長さ(それ自体の軸を中心に回転する時間)年の長さ人口50の異なるリソースのリソースの量

各値を格納するためにdoubleが必要であり、格納する値が57あると仮定すると(切り上げて100としましょう)、100個の値* 8バイト* 4100個の本体= 3,280,000バイトになります。さて、それは3メガのデータです。それは多くのように思えるかもしれませんが、実際にはそれほど多くはありません。また、1つの銀河にこれほど多くの星を持ちたいとは思わないでしょう。ゲームは実際には大きすぎて探索できず、おそらく、特定の銀河で起こっているすべてのことを実際にシミュレートしようとすると、手に負えないほど大きくなるでしょう。

このように見てください。 SimCityのようなゲームをプレイし、都市グリッドの各正方形を潜在的な惑星と見なすと、小さなファイルにどれだけの情報を保存できるかがわかり、ランダムに何かを生成する必要がなくなります。

2
Kibbee

銀河の種、つまり1234から始めて、この種を取り、10000個の乱数を生成するとします。それぞれが、星系を表しています。星に近づくと、星の乱数を受け取り、それを新しいランダム関数のシードとして使用します。星を周回する天体の数の乱数を生成し、(常に2番目のランダム関数を使用して)各天体に対して1つの数を生成します。これが役立つかどうかはわかりませんが、ランダム関数は内部的にカオス的であり、初期条件では関数全体が変化することを覚えておく必要があります。

銀河の星の種は常に同じ星を生成する必要があり、星の種は同じ体を生成する必要があります。

統計、密度計算を使用して、結果を改善することで、いつでも物事をより面白くすることができます。関数が同じ入力に対して同じ結果を生成することを常に確認してください。

私の英語がひどい場合は申し訳ありませんが、私はアルゼンチン出身で、英語は私の訓練された資質の1つではありません:p

PD:私は同じタイプのゲームをやっています;)

2
Pablo Ordóñez

メルセンヌツイスターを使用しています。任意の長さのシード配列として受け入れるのはPRNGです。
たとえば、座標x = 25、y = 72で銀河を生成したいとします。ツイスターをシードで再初期化します[25,72]。
この銀河で1138番目の惑星を生成したい場合は、[25,72,1138]を使用します。
国? [25,72,1138,10]
市? [25,72,1138,10,32]
等々。
この方法では、1つの数値(x座標の前の数値、この場合は25の前の数値)を使用して、数十億兆兆のオブジェクトを生成できます。
現在、それを使用しているプロジェクトがいくつかあります。
ノクティス:anynowhere.com/
Infiniverse: http://www.infiniverse-game.com/

1
shinkarom

数学的には、無向接続グラフをランダム/疑似ランダムに生成する必要があります。このグラフでは、各ノードは太陽系であり、各エッジはジャンプゲートです。

1)N個のノードを作成し、それぞれに空間座標をランダムに割り当てます。これらのノードは、最終的にはソーラーシステムになります。

2)Deluanay三角形分割アルゴリズムを使用してエッジを生成します。 Deluanay三角測量をお勧めします。これは、ゲートが互いに交差することなく、かなり見栄えの良いマップを作成するためですが、実際には任意のアルゴリズムを使用できます。私はあなたが何を探しているのか本当にわかりません。

3)Deluanay三角形分割を使用した場合は、特定の数のエッジを削除して「スパースネス」を作成することをお勧めします。これにより、特定の場所が交通ハブになり、他の場所は単なるピットストップになるため、地図がより面白くなります。

4)このグラフを保存します。これがあなたの宇宙です。宇宙を置き忘れたり、捨てたりしないでください。必要に応じて効率的に保存しますが、情報を削除しないでください。

5)各ノードにシードを割り当て、このシードを使用して各太陽系を生成します。

6)おめでとうございます。これで、任意の数の太陽系とジャンプゲートを備えた宇宙ができました。

0
CGravelle

これが私が思いついたものです。それが最終バージョンになるかどうかは分からない。

六角形のグリッドと、各頂点にある太陽系を想像してみてください。六角形のグリッド上にあるため、どの頂点からも3本の線しかありません。 1つは常に水平で、他の2つは対角線です。開始シードにnの値を与えると、開始点に水平に接続されている太陽系にn + 1の値を与えることができ、他のシステムはn +2とn-2の値を得ることができます。

やばい。必ずしもグリッドを取得する必要はありません。畜生。もう一度やり直してみましょう。

0
Dove

同じシードでsrandom()を呼び出す限り、random()から同じ値を取得します。したがって、srandom()への1回の呼び出しに基づいて、スターシステムのすべてをベースにするだけです...次に、スターシステム全体に対して1つの整数(シード)を格納するだけで済みます。これで圧縮です!

0
dicroce

これは私の2番目の改善されたソリューションです。プレイヤーはランダムに生成された太陽系から始めます。各システムは、1〜4個の他のシステムに接続されています。それらを北、南、東、西のシステムと考えてください。プレイヤーが北のジャンプゲートを通過する場合、シードが以前のシステムより1つ多いシステムに移動します。彼が南に行くと、そのシステムの種は1つ少なくなります。 2+と2-それぞれ東と西。これらのシステムまでの距離(パーセクや光年など)は、システムのシードと到着する方向を使用して計算されます。このように、銀河のサイズは、種子を保持するために使用される数の最大値と最小値によってのみ制限されます。

他の銀河に行くためのワープホールは、開始システムから一定の距離に配置されます。次の銀河は、シード数が同じように増加し、銀河のワープホールの反対側にあるシステムが「東」または「北」になるという点で、この銀河の続きのようになります。 「起動システムからの接続。

ちなみに、上記のソリューションとは異なり、シードをインクリメントするこの使用はウェブにつながります。また、この方法では四角形を使用しますが、上記のソリューションでは六角形を使用しているため、ウェブを作成できませんでした。

もちろん、これはすべて、すべてのシードが他のシーケンスとは異なるランダムな数のシーケンスを生成するという仮定に基づいています。これにより、各システムが一意になります。

0
Dove

あなたが直面する最大の問題は、プレイヤーにとって一貫性があり意味のある方法でこれらすべてのオブジェクトに名前を付ける命名システムを持っていることだと思います 実際のオブジェクトに体系的に名前を付けるためのスキームはありますが =エリートの命名規則が特定の時点の後に崩壊したかどうかを忘れています...

0
Tim Barrass

疑似乱数ジェネレーターを使用する場合、生成する各乱数が特定のシードから同じ順序で表示されることを保証できます。指定された番号でシードされたシステムを生成するコードは、生成するたびに同じように表示されます。

疑似乱数ストリームの最初の番号を使用して、「ゲート」の数を生成します。各ゲートを通過し、番号ストリームから値を取得して、各ターゲットシステムに割り当ててシードします。

そのシードに基づいて、各システムの機能を生成します。

ランダムシードを生成するための既知のアルゴリズムがいくつかあります。

メルセンヌツイスター 亀裂を与える

0
Nat

これが以前に行われたことを漠然と思い出すことができます。 90年代初頭にはフラクタルが大流行し、ゲームプログラマーに世界を提供している会社を覚えています。は、太陽と惑星のある銀河でいっぱいの無限の宇宙全体を作成し、惑星の谷と場所のテクスチャに至るまでの出来事を引き起こしました。彼らはゲーム開発者に適した仮想不動産を見つけることを提案していました。ゲーム開発者は、このフラクタル宇宙でのプロパティへの正確な座標とともに、これをレンダリングして使用するソフトウェアを入手します。

「フラクタルゲーム世界惑星宇宙」などを数分間ググってみましたが、見つかりませんでした。 パンドロメダ だったかもしれませんが、よく覚えていません。

このアイデアのフラクタルを勉強する必要があります。必要なのは、シードから再作成し、それらの数値をさまざまなプロパティを持つ星、惑星、衛星として提示できる連続した数値フィールドです。

0
Guge

特定のシード(「母番号」)から[〜#〜] n [〜#〜]桁の疑似乱数を作成できます。次に、数字をグループに分割し、それらを使用して質問に答えます。

例:[〜#〜] n [〜#〜]= 20

-> 1桁:追加のジャンプゲートはいくつありますか?
-> 3桁:利用可能な各ジャンプのそれぞれの長さを生成するためのシード
-> 6桁:この太陽系を生成するためのシード
-> 10桁:リンクされた太陽系ごとに新しい20桁のシードを生成するためのシード

その後、再帰します。各システム(安定した軌道など)は時間0で生成され、どのように見えるかを計算する必要があります

もちろん、マザーシステムから始まるこのアプローチは、現在のシステムがマザーシステムから離れているほど、データの生成に時間がかかることを意味します。また、この方法では、ネットではなくツリーが作成されます(私が期待することです)。

座標を生成する方が良いと思います。平面では極座標を使用し、おそらく3次元では楕円体を使用します。

0
Svante

本当に固定状態に戻したいのであれば、単一の値からの手続き型生成が正しい方法だとは思いません。

各平面に256x256システムの固定グリッドがあり、宇宙に16の平面があると仮定します。各飛行機には最大512の交易所があり、他の飛行機へのリンクは最大8つあります。すべてのトレーディングステーションとリンクは固定位置にあります。可能なすべてのユニバースをエンコードするには、初期シード値が少なくとも2 ^ 76である必要があります。さらにいくつかのオブジェクト(惑星、船など)を追加すると、その数は指数関数的に増加します。

編集:各システムで複数のトレーディングステーションまたはリンクを許可しない場合は、少し少なくなります。永続的なストレージ、おそらくFirebirdやsqliteなどの組み込みデータベースを使用します。ちなみに私は現在そのようなゲームを開発しています。

0
Bong Bong