3Dであなたが望んでいるものに似たシステムを作成しました。ここに簡単な仕組みを示す短いビデオと、ここにブログ投稿があります。
これは、目に見えない壁(高速で再生)の背後にある圧力力学から作成した小さなgifです。
システムの機能のいくつかのアイデアを与えるために、関連するデータを説明しましょう。現在のシステムでは、水の各ブロックには2バイトで次のものが含まれています。
//Data2 Data
//______________________________ _____________________________________
//|0 |0 |000 |000 | |0 |0 |000 |000 |
//|Extra|FlowOut|Active|Largest| |HasSource|IsSource|Direction|Height|
//------------------------------ -------------------------------------
Height
キューブ内の水の量は、あなたの圧力に似ていますが、私のシステムには8つのレベルしかありません。
Direction
フローが進む方向です。次に水が流れる場所を決定するとき、現在の方向で継続する可能性が高くなります。これは、必要に応じて、ソースキューブまでのフローをすばやくトレースするためにも使用されます。
IsSource
このキューブがソースキューブであるかどうかを示します。つまり、水がなくなることはありません。河川、湧水などの水源に使用されます。上記のgifの左側の立方体は、たとえば水源立方体です。
HasSource
このキューブがソースキューブに接続されているかどうかを示します。ソースに接続されると、キューブはソースをタップしてより多くの水を求めてから、他の「より充実した」ソース以外のキューブを探します。
Largest
このキューブに、そのキューブとそのソースキューブ間の最大フローを通知します。これは、水が狭い隙間を流れる場合、この立方体への流れを制限することを意味します。
Active
カウンターです。このキューブにアクティブなフローがあり、そこを通過したり、そこからアクティブなフローが流れたりすると、アクティブが増加します。それ以外の場合、アクティブはランダムに減少します。アクティブになるとゼロになります(アクティブではないことを意味します)。このキューブでは水の量が減少し始めます。この種の行為は、蒸発や地面への浸透のようなものです。(フローがある場合は、引き潮があるはずです!)
FlowOut
このキューブが世界の端にあるキューブに接続されているかどうかを示します。世界の端への道が作られると、水は他の道よりもその道を選ぶ傾向があります。
Extra
将来使用するための余分なビットです。
データがわかったので、アルゴリズムの概要を見てみましょう。システムの基本的な考え方は、フローダウンとフローアウトを優先することです。ビデオで説明しているように、私はボトムアップで仕事をしています。水の各層は、y軸で一度に1レベル処理されます。各レベルのキューブはランダムに処理され、各キューブは各反復でソースから水を引き出そうとします。
フローキューブは、ソースキューブまたは親のないフローキューブに到達するまで、フローの方向を逆にたどることにより、ソースから水を引き出します。各キューブにフローの方向を格納すると、リンクリストをたどるのと同じくらい簡単にソースへのパスをたどることができます。
アルゴリズムの擬似コードは次のとおりです。
for i = 0 to topOfWorld //from the bottom to the top
while flowouts[i].hasitems() //while this layer has flow outs
flowout = removeRandom(flowouts[i]) //select one randomly
srcpath = getPathToParent(flowout) //get the path to its parent
//set cubes as active and update their "largest" value
//also removes flow from the source for this flow cycle
srcpath.setActiveAndFlux()
//now we deal with regular flow
for i = 0 to topOfWorld //from the bottom to the top
while activeflows[i].hasitems() //while this layer has water
flowcube = removeRandom(activeflows[i]) //select one randomly
//if the current cube is already full, try to distribute to immediate neighbors
flowamt = 0
if flowcube.isfull
flowamt = flowcube.settleToSurrounding
else
srcpath = getPathToParent(flowcube) //get the path to its parent
flowamt = srcpath.setActiveAndFlux()
flowcube.addflow(flowamt)
//if we didn't end up moving any flow this iteration, reduce the activity
//if activity is 0 already, use a small random chance of removing flow
if flowamt == 0
flowcube.reduceActive()
refillSourceCubes()
フローを拡張するための基本的なルールは次のとおりです(優先度順):
- 下の立方体の水が少ない場合は、流下します
- 同じレベルの隣接するキューブの水量が少ない場合、横方向に流れます。
- 上のキューブの水が少なく、ソースキューブが上のキューブよりも高い場合、上に流れます。
かなり高いレベルです。しかし、詳細に道を譲ることなく、より詳細に取り組むことは困難です。
このシステムは非常にうまく機能します。私は簡単に水の穴を埋めることができます。上のgifにあるように、U字型のトンネルを埋めることができます。しかし、私が言ったように、システムは不完全であり、まだすべてを解決していません。私は長い間フローシステムに取り組んでいませんでした(アルファには必要ないと判断し、保留にしました)。ただし、保留にしたときに対処していた問題は次のとおりです。
プール。大きなプールを得るとき、子供から親へのポインタは、どんな方向に流れるように選択されたどんなランダムな立方体の狂った混乱のようです。浴槽に馬鹿げた糸を入れるようなものです。浴槽から水を排出したいときは、愚かなひもの経路をたどって元に戻りますか?または、あなたは最も近いものをとるべきですか?そのため、キューブが大きなプールにある状況では、キューブは単に親フローを無視し、キューブの上にあるものからプルする必要があります。私はこのためにいくつかの基本的な動作コードを思いつきましたが、満足できるエレガントなソリューションはありませんでした。
複数の親。子ストリームは、複数の親ストリームから簡単にフィードできます。しかし、単一の親へのポインタを持つ子供はそれを許可しません。これは、可能な親の方向ごとにビットを使用できるように十分なビットを使用することで修正できます。また、複数の親の場合、アルゴリズムを変更してパスをランダムに選択する可能性があります。しかし、他のどのような問題が公開されるかをテストして確認するために、私はそれを回避しませんでした。