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
카운터입니다. 이 큐브가 큐브를 통과하거나 큐브를 통과하는 활성 흐름을 가지면 활성이 증가합니다. 그렇지 않으면 활성이 임의로 감소합니다. 활성이 0에 도달하면 (활성이 아님)이 큐브에서 물의 양이 감소하기 시작합니다. 이런 종류의 증발이나 땅에 몸을 담그는 것과 같은 작용을합니다. ( 흐름이 있으면 썰물이 있어야합니다! )
FlowOut
이 큐브가 세계 가장자리에있는 큐브에 연결되어 있는지 나타냅니다. 세상의 가장자리로가는 길이 만들어지면 물은 다른 길보다 그 길을 선택하는 경향이 있습니다.
Extra
나중에 사용하기위한 추가 비트입니다.
이제 데이터를 알았으므로 알고리즘에 대한 높은 수준의 개요를 살펴 보겠습니다. 시스템의 기본 아이디어는 아래로 흐르는 것을 우선 순위 화하는 것입니다. 비디오에서 설명 하듯이, 나는 아래에서 위로 일합니다. 각 층의 물은 y 축에서 한 번에 한 수준 씩 처리됩니다. 각 레벨의 큐브는 무작위로 처리되며 각 큐브는 각 반복마다 소스에서 물을 끌어 오려고 시도합니다.
플로우 큐브는 소스 큐브 또는 상위가없는 플로우 큐브에 도달 할 때까지 플로우 방향을 따라 소스에서 물을 끌어옵니다. 각 큐브에 흐름 방향을 저장하면 연결된 목록을 순회하는 것처럼 소스 경로를 쉽게 따라갈 수 있습니다.
알고리즘의 의사 코드는 다음과 같습니다.
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 자형 터널을 채울 수 있습니다. 그러나 내가 말했듯이 시스템이 불완전하고 아직 모든 것을 해결하지 못했습니다. 나는 오랫동안 흐름 시스템에서 일하지 않았습니다 (알파에 필요하지 않다고 결정하고 보류했습니다). 그러나 내가 어디에서 처리 할 때 다루어야 할 문제는 다음과 같습니다.
수영장 . 큰 물웅덩이를 얻을 때, 아이에서 부모로가는 포인터는 임의의 방향으로 흐르기 위해 임의의 큐브가 선택되었다는 미친 혼란과 같습니다. 바보 같은 끈으로 욕조를 채우는 것처럼. 욕조를 비우고 싶을 때 바보 같은 줄의 경로를 따라 다시 소스로 가야합니까? 아니면 가장 가까운 것을 가져 가야합니까? 따라서 큐브가 큰 풀에있는 상황에서는 부모 흐름을 무시하고 위에있는 모든 것에서 가져와야합니다. 나는 이것에 대한 기본 작업 코드를 생각해 냈지만 결코 만족할 수있는 우아한 해결책을 찾지 못했습니다.
여러 부모 . 자식 스트림은 둘 이상의 부모 스트림에 의해 쉽게 공급 될 수 있습니다. 그러나 한 부모에게 포인터를 가진 아이는 그것을 허용하지 않을 것입니다. 가능한 각 부모 방향에 대해 비트를 허용하기에 충분한 비트를 사용하여이를 해결할 수 있습니다. 부모가 여러 명인 경우 경로를 임의로 선택하도록 알고리즘을 변경했을 수 있습니다. 그러나 다른 문제가 무엇인지 테스트하고 확인하기 위해 결코 그것을 찾지 못했습니다.