3D olarak takip ettiğinize benzer bir sistem yarattım. Burada basit mekaniğini gösteren kısa bir videom ve burada bir blog yazısı var .
İşte görünmez bir duvarın arkasındaki basınç mekaniğinden (yüksek hızda oynandı) yaptığım küçük bir gif:
Sistemin bazı özellikleri hakkında fikir vermek için ilgili verileri açıklamama izin verin. Mevcut sistemde, her su bloğu 2 Bayt'ta aşağıdakileri içerir:
//Data2 Data
//______________________________ _____________________________________
//|0 |0 |000 |000 | |0 |0 |000 |000 |
//|Extra|FlowOut|Active|Largest| |HasSource|IsSource|Direction|Height|
//------------------------------ -------------------------------------
Height
basınçtaki gibi, küpteki su miktarıdır, ancak sistemimin sadece 8 seviyesi vardır.
Direction
akışın gittiği yöndür. Suyun bundan sonra nereye akacağına karar verirken, mevcut yönünde devam etmesi daha olasıdır. Bu, gerektiğinde kaynak küpüne giden bir akışı hızla izlemek için de kullanılır.
IsSource
bu küpün bir kaynak küp olup olmadığını gösterir, yani hiç su tükenmez. Nehirlerin, kaynakların, vb. Kaynakları için kullanılır. Yukarıdaki gifte soldaki küp, örneğin bir kaynak küpüdür.
HasSource
bu küpün bir kaynak küpüne bağlı olup olmadığını gösterir. Bir kaynağa bağlandığınızda, küpler, diğer "dolgun" kaynak olmayan küpleri aramadan önce kaynağa daha fazla su için dokunmaya çalışacaktır.
Largest
Bu küpe, kendisiyle kaynak küp arasındaki en büyük akışın ne olduğunu söyler. Bu, suyun dar bir boşluktan akması durumunda, bu küpün akışını sınırlar.
Active
bir sayaçtır. Bu küp, içinden, içinden veya içinden geçen aktif bir akışa sahip olduğunda, aktif artar. Aksi halde aktif rastgele azalır. Aktif sıfıra ulaştığında (yani aktif değil), bu küpte su miktarı azalmaya başlayacaktır. Bu tür buharlaşma veya toprağa batırma gibi davranır. ( Akışınız varsa, ebb olmalıydı! )
FlowOut
bu küpün dünyanın kenarında bir küpe bağlı olup olmadığını gösterir. Dünyanın kenarına giden bir yol yapıldıktan sonra, su bu yolu diğerlerinden seçmeye meyillidir.
Extra
gelecekteki kullanım için ekstra bir bit.
Şimdi verileri bildiğimize göre, algoritmaya üst düzey bir bakış atalım. Sistemin temel fikri, aşağı ve dışarı akan önceliği belirlemektir. Videoda açıkladığım gibi, aşağıdan yukarıya doğru çalışıyorum. Her su katmanı, y ekseninde bir seferde bir seviye işlenir. Her seviye için küpler rastgele işlenir, her küp her bir iterasyonda kaynağından su çekmeye çalışır.
Akış küpleri, akış yönlerini izleyerek bir kaynak küpüne veya ebeveynsiz bir akış küpüne erişinceye kadar suyu kaynağından alır. Akış yönünü her bir küpte saklamak, kaynağa giden yolu izlemeyi bağlantılı bir listeyi dolaşmak kadar kolay hale getirir.
Algoritmanın sözde kodu aşağıdaki gibidir:
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()
Bir akışı genişletmek için temel kurallar (öncelik sırasına göre sıralanmıştır):
- Alttaki küpün suyu daha azsa, aşağı akın
- Aynı seviyedeki bitişik küp daha az su içeriyorsa, yanal olarak akın.
- Yukarıdaki küp daha az su içeriyorsa ve kaynak küp yukarıdaki küpten daha yüksekse, yukarı akın.
Biliyorum, bu oldukça yüksek bir seviye. Ama almadan daha detaya almak zor yolu detaya.
Bu sistem oldukça iyi çalışıyor. Dışarıya doğru devam etmek için taşan su birikintilerini kolayca doldurabilirim. Yukarıdaki gifte gördüğünüz gibi U şeklindeki tünelleri doldurabilirim. Ancak dediğim gibi, sistem eksik ve henüz her şeyi çözmedim. Akış sistemi üzerinde uzun zamandır çalışmadım (alfa için gerek olmadığına karar verdim ve beklemeye aldım). Ancak, beklettiğimde uğraştığım konular nerede kaldı:
Havuzlar . Büyük bir su havuzu elde edildiğinde, çocuktan ebeveyne kadar olan işaretçiler, hangi yöne akacak olursa olsun, rastgele bir küpün seçildiği çılgın bir karmaşa gibidir. Aptal ip ile bir küvet doldurmak gibi. Küveti boşaltmak istediğinizde, saçma ipin yolunu kaynağına geri mi götürmelisiniz? Yoksa en yakın olanı mı almalısın? Bu nedenle, küplerin büyük bir havuzda olduğu durumlarda, ebeveynlerin akışlarını görmezden gelmeleri ve üstlerindeki her şeyden çekmeleri gerekir. Bunun için bazı temel çalışma kodları buldum, ancak hiçbir zaman mutlu olabileceğim zarif bir çözüm olmadı.
Birden ebeveynler . Bir çocuk akışı, birden fazla ana akım tarafından kolayca beslenebilir. Ancak, tek bir ebeveyne imleci olan çocuk buna izin vermez. Bu, her olası ebeveyn yönü için bir bit bırakacak kadar bit kullanarak düzeltilebilir. Muhtemelen çoklu ebeveynler durumunda rastgele bir yol seçmek için algoritma değiştirme. Ancak, başka hangi sorunları ortaya çıkarabileceğini test etmek ve görmek için hiç bir zaman bu işe girmedim.