Creating procedural terrain I cannot get an evaporation matrix and find why my algorithm is wrong. How my program works:
Creation of chunk steps:
When generating the terrain I use the following constants:
private const chunkHeights = array( 'max' => 64, 'min' => -64 ); // min and max height
private const chunkSize = 129; // width = height for 1 chunk
private const chunkVariation = 1; // max variation from a position to its neighbor
Heightfield script and my rivers script are both working as expected. I try updating the evaporation file of a given chunk:
private static function updateEvaporation( $pChunkX, $pChunkY ) {
$chunks = array();
$seaOrRiver = 0;
for( $y = ( $pChunkY - 1 ); $y <= ( $pChunkY + 1 ); $y++ ) {
for( $x = ( $pChunkX - 1 ); $x <= ( $pChunkX + 1 ); $x++ ) {
$chunkFolder = 'terrain/chunk'.$x.'x'.$y.'/';
$tmpChunkFolder = 'terrain/tmp_chunk'.$x.'x'.$y.'/';
$chunkHf = null;
$chunkRivers = null;
$chunkEvaporation = null;
if( file_exists( $chunkFolder ) ) {
$chunkHf = new HeightField();
$chunkHfData = file_get_contents( $chunkFolder.'heightfield.json' );
$chunkHf->fromString( $chunkHfData );
$chunkRivers = json_decode( file_get_contents( $chunkFolder.'rivers.json' ), true );
$chunkEvaporation = json_decode( file_get_contents( $chunkFolder.'evaporation.json' ), true );
} elseif( file_exists( $tmpChunkFolder ) ) {
$chunkHf = new HeightField();
$chunkHfData = file_get_contents( $tmpChunkFolder.'heightfield.json' );
$chunkHf->fromString( $chunkHfData );
$chunkRivers = json_decode( file_get_contents( $tmpChunkFolder.'rivers.json' ), true );
$chunkEvaporation = json_decode( file_get_contents( $tmpChunkFolder.'evaporation.json' ), true );
}
if( ( $chunkHf != null ) && ( $chunkRivers != null ) && ( $chunkEvaporation != null ) ) {
for( $chunkY = 0; $chunkY < self::chunkSize; $chunkY++ ) {
for( $chunkX = 0; $chunkX < self::chunkSize; $chunkX++ ) {
if( ( $chunkHf->getHeight( $chunkX, $chunkY ) <= 0 ) || ( $chunkRivers[$chunkY][$chunkX] == 1 ) ) {
$chunkEvaporation[$chunkY][$chunkX] = 0;
$seaOrRiver++;
} else {
$chunkEvaporation[$chunkY][$chunkX] = null;
}
}
}
$chunks[$x.'x'.$y] = array(
'hf' => $chunkHf,
'rivers' => $chunkRivers,
'evaporation' => $chunkEvaporation
);
}
}
}
echo '<br>0 => ['.$seaOrRiver.']<br>';
$eLevel = 0;
while( $eLevel <= max( 0, self::chunkHeights['max'] ) ) {
$byLevel = 0;
for( $y = 0; $y < ( 3 * self::chunkSize ); $y++ ) {
for( $x = 0; $x < ( 3 * self::chunkSize ); $x++ ) {
$chunkX = floor( $x / self::chunkSize ) + $pChunkX - 1;
$chunkY = floor( $y / self::chunkSize ) + $pChunkY - 1;
$chunkXx = $x % self::chunkSize;
$chunkYy = $y % self::chunkSize;
if( isset( $chunks[$chunkX.'x'.$chunkY] ) ) {
if( $chunks[$chunkX.'x'.$chunkY]['evaporation'][$chunkYy][$chunkXx] == $eLevel ) {
for( $yy = ( $y - 1 ); $yy <= ( $y + 1 ); $yy++ ) {
for( $xx = ( $x - 1 ); $xx <= ( $x + 1 ); $xx++ ) {
$chunkXX = floor( $xx / self::chunkSize ) + $pChunkX - 1;
$chunkYY = floor( $yy / self::chunkSize ) + $pChunkY - 1;
$chunkXXx = $xx % self::chunkSize;
$chunkYYy = $yy % self::chunkSize;
if( isset( $chunks[$chunkXX.'x'.$chunkYY]['evaporation'][$chunkYYy][$chunkXXx] ) ) {
if( $chunks[$chunkXX.'x'.$chunkYY]['evaporation'][$chunkYYy][$chunkXXx] == null ) {
$chunks[$chunkXX.'x'.$chunkYY]['evaporation'][$chunkYYy][$chunkXXx] = ( $eLevel + 1 );
$byLevel++;
}
}
}
}
}
}
}
}
echo ( $eLevel + 1 ).' => ['.$byLevel.']<br>';
$eLevel++;
}
if( file_exists( 'terrain/chunk'.$pChunkX.'x'.$pChunkY ) ) {
file_put_contents( 'terrain/chunk'.$pChunkX.'x'.$pChunkY.'/evaporation.json', json_encode( $chunks[$pChunkX.'x'.$pChunkY]['evaporation'] ) );
} else {
file_put_contents( 'terrain/tmp_chunk'.$pChunkX.'x'.$pChunkY.'/evaporation.json', json_encode( $chunks[$pChunkX.'x'.$pChunkY]['evaporation'] ) );
}
return $chunks[$pChunkX.'x'.$pChunkY]['evaporation'];
}
Here are some explanations:
$chunks
array with their own coordinates as key.null
.This is the first main loop. After this I have a $chunks
list with for all chunks a heightfield, rivers matrix and incomplete evaporation matrix (where evaporation values are 0 or null).
My second main loop :
Result once I load 1 chunk :
Here white parts are positions where $pEvaporation[$y][$x] == null
and the rest is the evaporation ratio from ( rgb( 0, 0, 0 )
to rgb( 255, 0, 0 )
). Only the sea (and rivers) are generated (river is not visible because of the order I generate and get the data). Printed text corresponds to <level I'm checking> => [<number of null neighbors found>]
.
Others matrix previewing:
Do you know what is going wrong with my script?
I found my mistake:
PHP considers 0 == null
but 0 !== null
, I corrected this on my script (for evaporation testing).