Editor/TerrainShapes/Islands.cs
using Editor;
using Sandbox;
using System;
namespace Sturnus.TerrainGenerationTool;
public static class Islands
{
public static float Default( int x, int y, int width, int height, long seed, float minHeight, bool warp, float warpSize = 0.1f, float warpStrength = 0.5f )
{
float nx = (x / (float)width) * 2 - 1; // Normalize x to range [-1, 1]
float ny = (y / (float)height) * 2 - 1; // Normalize y to range [-1, 1]
float warpX;
float warpY;
float warpedNx;
float warpedNy;
float noise;
if ( warp )
{
// Generate warp offsets using additional noise
warpX = OpenSimplex2S.Noise2( seed + 10, nx * warpSize, ny * warpSize ) * warpStrength;
warpY = OpenSimplex2S.Noise2( seed + 11, nx * warpSize, ny * warpSize ) * warpStrength;
// Apply domain warping
warpedNx = nx + warpX;
warpedNy = ny + warpY;
}
else
{
warpedNx = nx;
warpedNy = ny;
}
// Radial distance from the center
float distance = (float)Math.Sqrt( nx * nx + ny * ny );
float falloff = 1.0f - Math.Clamp( distance, 0.25f, 1 ); // Smooth taper from center to edge
// Central mountain shape (parabolic for smooth curvature)
float centralMountain = (1.0f - distance * distance) * falloff;
// Beach-style taper near the edges
float beachStart = 0.5f; // Start of the beach region (distance normalized)
float beachEnd = 0.98f; // End of the beach region (ocean level)
float beachFalloff = Math.Clamp( (distance - beachStart) / (beachEnd - beachStart), 0.1f, 1 );
float beachTaper = (1.0f - beachFalloff) * 0.25f; // Smooth transition to flat region
// Add subtle noise for terrain variation
if ( warp )
{
noise = OpenSimplex2S.Noise2( seed, warpedNx * 2, warpedNy * 2 ) * 0.4f;
}
else
{
noise = OpenSimplex2S.Noise2( seed, nx * 6, ny * 6 ) * 0.05f; // Low-frequency noise
}
// Combine components: central mountain, beach taper, and noise
float output = centralMountain * (1.0f - beachFalloff) + beachTaper + noise;
// Combine all effects
float heightValue = output;
// Add a baseline value to ensure no flat zero areas
float baseline = minHeight; // Minimum height
float heightValueCombined = MathF.Max( heightValue, baseline );
// Clamp the final height to valid range
return heightValueCombined;
}
public static float Archipelagos( int x, int y, int width, int height, long seed, float minHeight, bool warp, float warpSize, float warpStrength )
{
Random random = new Random( (int)(seed & 0xFFFFFFFF) );
float nx = (x / (float)width) * 2 - 1;
float ny = (y / (float)height) * 2 - 1;
// Apply domain warping
if ( warp )
{
float warpX = OpenSimplex2S.Noise2( seed + 10, nx * warpSize, ny * warpSize ) * warpStrength;
float warpY = OpenSimplex2S.Noise2( seed + 11, nx * warpSize, ny * warpSize ) * warpStrength;
nx += warpX;
ny += warpY;
}
// Use noise layers to create clusters of small islands
float baseNoise = OpenSimplex2S.Noise2( seed, nx * 1.5f, ny * 1.5f );
float secondaryNoise = OpenSimplex2S.Noise2( seed + 1, nx * 3.0f, ny * 3.0f ) * 0.5f;
float archipelagoHeight = baseNoise + secondaryNoise;
// Apply radial falloff to form rounded island clusters
float distance = MathF.Sqrt( nx * nx + ny * ny );
float falloff = Math.Clamp( 1 - distance * 1.2f, 0, 1 );
float heightValue = Math.Clamp( archipelagoHeight * falloff, 0, 1 );
// Add a baseline value to ensure no flat zero areas
float baseline = minHeight; // Minimum height
float heightValueCombined = MathF.Max( heightValue, baseline );
// Clamp the final height to valid range
return heightValueCombined;
}
public static float Atoll( int x, int y, int width, int height, long seed, float minHeight, bool warp, float warpSize, float warpStrength )
{
Random random = new Random( (int)(seed & 0xFFFFFFFF) );
float nx = (x / (float)width) * 2 - 1; // Normalize x to range [-1, 1]
float ny = (y / (float)height) * 2 - 1; // Normalize y to range [-1, 1]
// Apply domain warping
if ( warp )
{
float warpX = OpenSimplex2S.Noise2( seed + 20, nx * warpSize, ny * warpSize ) * warpStrength;
float warpY = OpenSimplex2S.Noise2( seed + 21, nx * warpSize, ny * warpSize ) * warpStrength;
nx += warpX;
ny += warpY;
}
// Calculate distance from the center
float distance = MathF.Sqrt( nx * nx + ny * ny );
// Define parameters for the single ring
float ringCenter = 0.6f; // Center of the ring
float ringWidth = 0.1f; // Width of the ring
// Create a single ring using a Gaussian-like function
float ring = MathF.Exp( -MathF.Pow( (distance - ringCenter) / ringWidth, 2 ) );
// Add some noise for variation
float baseNoise = OpenSimplex2S.Noise2( seed, nx * 1.0f, ny * 1.0f ) * 0.4f;
// Introduce a beach-like area (reduce noise and height for one side of the map)
float beachEffect = Math.Clamp( (1 - nx) * 0.5f, 0.2f, 1.0f ); // Reduces height on one side of the map
float beachNoise = OpenSimplex2S.Noise2( seed + 30, nx * 2.0f, ny * 2.0f ) * 0.2f;
// Combine the ring, noise, and beach effect
float heightValue = (ring + baseNoise * beachEffect + beachNoise) * beachEffect;
// Add a baseline value to ensure no flat zero areas
float baseline = minHeight; // Minimum height
float heightValueCombined = MathF.Max( heightValue, baseline );
// Clamp the final height to valid range
return heightValueCombined;
}
public static float Islets( int x, int y, int width, int height, long seed, float minHeight, bool warp, float warpSize, float warpStrength )
{
Random random = new Random( (int)(seed & 0xFFFFFFFF) );
float nx = (x / (float)width) * 2 - 1;
float ny = (y / (float)height) * 2 - 1;
// Apply domain warping
if ( warp )
{
float warpX = OpenSimplex2S.Noise2( seed + 30, nx * warpSize, ny * warpSize ) * warpStrength;
float warpY = OpenSimplex2S.Noise2( seed + 31, nx * warpSize, ny * warpSize ) * warpStrength;
nx += warpX;
ny += warpY;
}
// Generate scattered small islands
float scatterNoise = OpenSimplex2S.Noise2( seed, nx * 6.0f, ny * 6.0f );
float baseNoise = OpenSimplex2S.Noise2( seed + 1, nx * 3.0f, ny * 3.0f ) * 0.5f;
float isletHeight = scatterNoise + baseNoise;
// Apply distance falloff to create isolated islets
float distance = MathF.Sqrt( nx * nx + ny * ny );
float falloff = Math.Clamp( 1 - distance * 1.5f, 0, 1 );
float heightValue = Math.Clamp( isletHeight * falloff, 0, 1 );
// Add a baseline value to ensure no flat zero areas
float baseline = minHeight; // Minimum height
float heightValueCombined = MathF.Max( heightValue, baseline );
// Clamp the final height to valid range
return heightValueCombined;
}
public static float Oceanic( int x, int y, int width, int height, long seed, float minHeight, bool warp, float warpSize, float warpStrength )
{
Random random = new Random( (int)(seed & 0xFFFFFFFF) );
float nx = (x / (float)width) * 2 - 1;
float ny = (y / (float)height) * 2 - 1;
// Apply domain warping
if ( warp )
{
float warpX = OpenSimplex2S.Noise2( seed + 40, nx * warpSize, ny * warpSize ) * warpStrength;
float warpY = OpenSimplex2S.Noise2( seed + 41, nx * warpSize, ny * warpSize ) * warpStrength;
nx += warpX;
ny += warpY;
}
// Generate large, continuous landmass with a few scattered features
float baseNoise = OpenSimplex2S.Noise2( seed, nx * 1.0f, ny * 1.0f );
float featureNoise = OpenSimplex2S.Noise2( seed + 1, nx * 2.0f, ny * 2.0f ) * 0.5f;
float oceanicHeight = baseNoise + featureNoise;
// Apply radial falloff for a natural ocean/land mix
float distance = MathF.Sqrt( nx * nx + ny * ny );
float falloff = Math.Clamp( 1 - distance * 1.0f, 0, 1 );
float heightValue = Math.Clamp( oceanicHeight * falloff, 0, 1 );
float baseline = minHeight; // Minimum height
float heightValueCombined = MathF.Max( heightValue, baseline );
// Clamp the final height to valid range
return heightValueCombined;
}
}