badidea wrote:Thanks, I did think of cellular automata yet. If I decide to go to an 'infinite' map (not sure yet), cellular automata is not optimal I think.

...

Why not? Simply generate the map in chunks. Note that the noise functions used are

*deterministic*, that is, they always return the same 'noise' value whenever queried with the same parameters. To seed them, just add a displacement. Of course, chunking the map is pretty easy if your miner can only go down (ala Namco's Mr. Driller). If you allow movement in any direction, you'll be in for a world of trouble (quite literally).

badidea wrote:...

I was thinking about Perlin noise as well, in combination with a 1d-gaussian distribution for depth.

...

Not really needed:

Code: Select all

`/'`

-1 .. 1 range

'/

function _

noise1( _

byval x as integer ) _

as single

x => ( x shl 13 ) xor x

return( ( 1.0! - ( ( x * ( x * x * 15731 + 789221) + 1376312589) and &h7fffffff) / 1073741824.0! ) )

end function

/'

0 .. 1 range

'/

function _

noise1n( _

byval x as integer ) _

as single

return( ( noise1( x ) / 2.0! ) + 0.5! )

end function

/'

-1 .. 1 range

'/

function _

noise2( _

byval x as integer, _

byval y as integer ) _

as single

dim as integer _

n => x + y * 57

n => ( n shl 13 ) xor n

return( ( 1.0! - ( ( n * ( n * n * 15731 + 789221 ) + 1376312589 ) and &h7fffffff ) / 1073741824.0! ) )

end function

/'

0 .. 1 range

'/

function _

noise2n( _

byval x as integer, _

byval y as integer ) _

as single

return( ( noise2( x, y ) / 2.0! ) + 0.5! )

end function

/'

Smooths the noise with bilinear interpolation.

-1 .. 1 range

'/

function _

smoothedNoise( _

byval x as single, _

byval y as single ) _

as single

dim as single _

fractX => x - int( x ), _

fractY => y - int( y )

dim as integer _

x1 => int( x ), _

y1 => int( y ), _

x2 => int( x - 1 ), _

y2 => int( y - 1 )

dim as single _

value => _

fractX * fractY * noise2( x1, y1 ) + _

fractX * ( 1.0! - fractY ) * noise2( x1, y2 ) + _

( 1.0! - fractX ) * fractY * noise2( x2, y1 ) + _

( 1.0! - fractX ) * ( 1.0! - fractY ) * noise2( x2, y2 )

return( value )

end function

/'

Creates a turbulence texture (aka Perlin Noise).

-1 .. 1 range

'/

function _

turbulence( _

byval x as single, _

byval y as single, _

byval size as single ) _

as single

dim as single _

value => 0.0!, _

initialSize => size

do while( size >= 1.0! )

value +=> smoothedNoise( x / size, y / size ) * size

size /=> 2.0!

loop

value => value / initialSize

return( iif( value < -1.0, -1.0, _

iif( value > 1.0, 1.0, value ) ) )

end function

dim as integer _

w => 256, _

h => 256

screenRes( w, h, 32 )

windowTitle( "Noise playground" )

for _

y as integer => 0 _

to h - 1

for _

x as integer => 0 _

to w - 1

dim as single _

n => turbulence( x, y, 32 )

dim as ulong _

c

/'

Remap the texture to colors

'/

if( n < 0.0! ) then

dim as ubyte _

p => 255 - abs( n ) * 255

c => rgba( 0, 0, p, 255 )

else

dim as ubyte _

p => n * 255

c => rgba( 0, p, 0, 255 )

end if

pset _

( x, y ), _

c

next

next

sleep()

All you need to do to add 'depth' is simply generate random numbers between -1 and 1, and interpret everything below 0 as depth. The above example shows this technique for a 2D map.

badidea wrote:...

Another idea that came up was random walks with some direction preference to create veins.

...

The random walk is certainly doable, but you'll find that it is very hard to coax it into something akin to veins (being essentially, well, random). One way you can achieve this is by weighting the direction chosen with a vector as you suggest. That way, it will still be random, but will

*tend* to the direction you specify. However, this will be taken by the algorithm as a mere

*suggestion*, since the variance of the distribution will still play itself out and you could wind up with a vein that goes clearly up even when you specified the direction to be down (if it just so happens that you get a distribution that's heavy on the tails).

Isn't this a bit overkill for such a simple game? Here's another example, showing a simple way to achieve the same effect:

Code: Select all

`/'`

-1 .. 1 range

'/

function _

noise1( _

byval x as integer ) _

as single

x => ( x shl 13 ) xor x

return( ( 1.0! - ( ( x * ( x * x * 15731 + 789221) + 1376312589) and &h7fffffff) / 1073741824.0! ) )

end function

/'

0 .. 1 range

'/

function _

noise1n( _

byval x as integer ) _

as single

return( ( noise1( x ) / 2.0! ) + 0.5! )

end function

/'

-1 .. 1 range

'/

function _

noise2( _

byval x as integer, _

byval y as integer ) _

as single

dim as integer _

n => x + y * 57

n => ( n shl 13 ) xor n

return( ( 1.0! - ( ( n * ( n * n * 15731 + 789221 ) + 1376312589 ) and &h7fffffff ) / 1073741824.0! ) )

end function

/'

0 .. 1 range

'/

function _

noise2n( _

byval x as integer, _

byval y as integer ) _

as single

return( ( noise2( x, y ) / 2.0! ) + 0.5! )

end function

/'

Smooths the noise with bilinear interpolation.

-1 .. 1 range

'/

function _

smoothedNoise( _

byval x as single, _

byval y as single ) _

as single

dim as single _

fractX => x - int( x ), _

fractY => y - int( y )

dim as integer _

x1 => int( x ), _

y1 => int( y ), _

x2 => int( x - 1 ), _

y2 => int( y - 1 )

dim as single _

value => _

fractX * fractY * noise2( x1, y1 ) + _

fractX * ( 1.0! - fractY ) * noise2( x1, y2 ) + _

( 1.0! - fractX ) * fractY * noise2( x2, y1 ) + _

( 1.0! - fractX ) * ( 1.0! - fractY ) * noise2( x2, y2 )

return( value )

end function

/'

Creates a turbulence texture (aka Perlin Noise).

-1 .. 1 range

'/

function _

turbulence( _

byval x as single, _

byval y as single, _

byval size as single ) _

as single

dim as single _

value => 0.0!, _

initialSize => size

do while( size >= 1.0! )

value +=> smoothedNoise( x / size, y / size ) * size

size /=> 2.0!

loop

value => value / initialSize

return( iif( value < -1.0, -1.0, _

iif( value > 1.0, 1.0, value ) ) )

end function

/'

Creates a sinusoidal noise pattern.

-1 .. 1 range

'/

function _

sinNoise( _

byval x as single, _

byval y as single, _

byval xPeriod as single, _

byval yPeriod as single, _

byval size as single, _

byval turbSize as single, _

byval turbPower as single ) _

as single

return( sin( _

( x * xPeriod / size + _

y * yPeriod / size + _

turbulence( x, y, turbSize ) * turbPower ) ) )

end function

dim as integer _

w => 256, _

h => 256

screenRes( w, h, 32 )

windowTitle( "Noise playground" )

for _

y as integer => 0 _

to h - 1

for _

x as integer => 0 _

to w - 1

dim as single _

n => ( sinNoise( x, y, 2, 40, w, 16, 2.0 ) / 2.0! ) + 0.5!

dim as ubyte _

p => n * 255

pset _

( x, y ), _

rgba( p, p, p, 255 )

next

next

sleep()

Play around with the parameters to see if they're useful somehow.