算法。地形生成 - 蒸发计算问题
Algo. terrain generation - evaporation calculation issue
创建程序地形我无法获得蒸发矩阵并找到我的算法错误的原因。我的程序如何工作:
- 用户加载地图块。
- 如果存在,则加载其数据。
- 如果它不存在,它会创建块和 returns 生成的数据。
块创建步骤:
- 创建一个高度场(菱形方块算法)。
- 创建 [0,3] 条河流(如果河流需要在不同的区块上继续,则创建更多区块)。
- 计算蒸发。
生成地形时我使用以下常量:
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 脚本和我的 Rivers 脚本都按预期工作。我尝试更新给定块的蒸发文件:
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'];
}
这里有一些解释:
- 我加载了所有区块邻居(我假设到水的最大距离小于 0.5 x chunkSize)并且我也加载了目标区块。
- 我将它们存储在
$chunks
数组中,并将它们自己的坐标作为键。
- 对于每个块,我在有水的地方用 0 更新蒸发矩阵:所以在有河流的地方(0 = 没有河流,1 = 河流矩阵中的河流)或者高度场在海平面以下的地方(高度 <= 0).
- 否则,我用
null
填写其他值。
这是第一个主循环。在此之后,我有一个 $chunks
列表,其中包含所有块的高度场、河流矩阵和不完整的蒸发矩阵(其中蒸发值为 0 或 null)。
我的第二个主循环:
- 循环所有存储块的所有坐标(如果该块存在),具有给定级别(级别从 0 = 海或河)。
- 在给定级别的位置旁边的所有邻居上循环。
- 如果邻居蒸发为空(因此尚未计算)将蒸发设置为水平 + 1。
- 将等级提高 1 并重新开始循环。
- 一旦水平高于最大蒸发水平,我就停止循环并保存文件。当当前水平不再有蒸发更新时,我曾经停止第二个循环(但它在循环中只进行了 2 次)。
加载 1 个块后的结果:
这里的白色部分是$pEvaporation[$y][$x] == null
的位置,其余部分是从(rgb( 0, 0, 0 )
到rgb( 255, 0, 0 )
)的蒸发率。仅生成海洋(和河流)(由于我生成和获取数据的顺序,河流不可见)。打印的文字对应<level I'm checking> => [<number of null neighbors found>]
.
其他矩阵预览:
- 左侧,高度场、海平面和河流。
- 右边海域(蓝色)和河流域(绿色)。
你知道我的脚本出了什么问题吗?
我发现了我的错误:
PHP 考虑 0 == null
但 0 !== null
,我在我的脚本中更正了这个(用于蒸发测试)。
创建程序地形我无法获得蒸发矩阵并找到我的算法错误的原因。我的程序如何工作:
- 用户加载地图块。
- 如果存在,则加载其数据。
- 如果它不存在,它会创建块和 returns 生成的数据。
块创建步骤:
- 创建一个高度场(菱形方块算法)。
- 创建 [0,3] 条河流(如果河流需要在不同的区块上继续,则创建更多区块)。
- 计算蒸发。
生成地形时我使用以下常量:
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 脚本和我的 Rivers 脚本都按预期工作。我尝试更新给定块的蒸发文件:
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'];
}
这里有一些解释:
- 我加载了所有区块邻居(我假设到水的最大距离小于 0.5 x chunkSize)并且我也加载了目标区块。
- 我将它们存储在
$chunks
数组中,并将它们自己的坐标作为键。 - 对于每个块,我在有水的地方用 0 更新蒸发矩阵:所以在有河流的地方(0 = 没有河流,1 = 河流矩阵中的河流)或者高度场在海平面以下的地方(高度 <= 0).
- 否则,我用
null
填写其他值。
这是第一个主循环。在此之后,我有一个 $chunks
列表,其中包含所有块的高度场、河流矩阵和不完整的蒸发矩阵(其中蒸发值为 0 或 null)。
我的第二个主循环:
- 循环所有存储块的所有坐标(如果该块存在),具有给定级别(级别从 0 = 海或河)。
- 在给定级别的位置旁边的所有邻居上循环。
- 如果邻居蒸发为空(因此尚未计算)将蒸发设置为水平 + 1。
- 将等级提高 1 并重新开始循环。
- 一旦水平高于最大蒸发水平,我就停止循环并保存文件。当当前水平不再有蒸发更新时,我曾经停止第二个循环(但它在循环中只进行了 2 次)。
加载 1 个块后的结果:
这里的白色部分是$pEvaporation[$y][$x] == null
的位置,其余部分是从(rgb( 0, 0, 0 )
到rgb( 255, 0, 0 )
)的蒸发率。仅生成海洋(和河流)(由于我生成和获取数据的顺序,河流不可见)。打印的文字对应<level I'm checking> => [<number of null neighbors found>]
.
其他矩阵预览:
- 左侧,高度场、海平面和河流。
- 右边海域(蓝色)和河流域(绿色)。
你知道我的脚本出了什么问题吗?
我发现了我的错误:
PHP 考虑 0 == null
但 0 !== null
,我在我的脚本中更正了这个(用于蒸发测试)。