120 lines
5.6 KiB
C#
120 lines
5.6 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Game.WorldGen
|
|
{
|
|
public enum IslandShape { Radial, Square }
|
|
|
|
/// <summary>
|
|
/// All parameters for one world. Stored as an asset so you can version several
|
|
/// presets (test island, final island, flat playground, ...) side by side.
|
|
/// </summary>
|
|
[CreateAssetMenu(fileName = "WorldGenSettings", menuName = "Game/World Gen Settings")]
|
|
public class WorldGenSettings : ScriptableObject
|
|
{
|
|
[Header("Output")]
|
|
[Tooltip("Name of the root GameObject that will hold all terrain tiles.")]
|
|
public string worldRootName = "GeneratedWorld";
|
|
[Tooltip("Project folder where TerrainData + shared material assets are saved.")]
|
|
public string outputFolder = "Assets/GAME/World/Generated";
|
|
|
|
[Header("World layout")]
|
|
public int seed = 12345;
|
|
[Tooltip("World edge length in meters (square). 6000 = 6 km like ARK: The Island.")]
|
|
public float worldSizeMeters = 6000f;
|
|
[Tooltip("Tiles per side. 6 -> 36 tiles of 1 km.")]
|
|
[Range(1, 16)] public int tilesPerSide = 6;
|
|
[Tooltip("Heightmap resolution per tile. Must be 2^n + 1 (513 / 1025 / 2049 / 4097).")]
|
|
public int heightmapResolution = 1025;
|
|
[Tooltip("Max terrain height in meters (the terrain's Y size).")]
|
|
public float maxHeightMeters = 1000f;
|
|
[Tooltip("Reference sea level as a height fraction. Used for the water plane + splat rules.")]
|
|
[Range(0f, 1f)] public float seaLevel01 = 0.30f;
|
|
|
|
[Header("Base terrain noise")]
|
|
[Tooltip("Approx size of the largest land features, in meters.")]
|
|
public float baseFeatureSizeMeters = 1500f;
|
|
[Range(1, 10)] public int baseOctaves = 6;
|
|
[Range(1.5f, 3f)] public float lacunarity = 2f;
|
|
[Range(0.2f, 0.8f)] public float gain = 0.5f;
|
|
[Tooltip("Remaps the raw [0,1] base height -> lets you flatten lowlands or sharpen peaks.")]
|
|
public AnimationCurve heightCurve = AnimationCurve.Linear(0, 0, 1, 1);
|
|
|
|
[Header("Domain warp (organic, less grid-like coastlines)")]
|
|
public bool domainWarp = true;
|
|
[Range(0f, 1f)] public float warpStrength = 0.35f;
|
|
|
|
[Header("Procedural mountains (ridged)")]
|
|
[Range(0f, 1f), Tooltip("How strongly ridged mountains rise above the base.")]
|
|
public float mountainAmplitude = 0.55f;
|
|
public float mountainFeatureSizeMeters = 2200f;
|
|
[Range(1, 8)] public int mountainOctaves = 5;
|
|
[Tooltip("Size of the regions where mountains are allowed to appear.")]
|
|
public float mountainMaskFeatureSizeMeters = 3500f;
|
|
[Range(0f, 1f), Tooltip("Higher = mountains confined to fewer, tighter ranges.")]
|
|
public float mountainThreshold = 0.55f;
|
|
|
|
[Header("Island falloff")]
|
|
public bool island = true;
|
|
public IslandShape islandShape = IslandShape.Radial;
|
|
[Tooltip("Maps normalised distance-from-center (0..1) to a height multiplier (1 center -> 0 edge).")]
|
|
public AnimationCurve falloffCurve = new AnimationCurve(
|
|
new Keyframe(0f, 1f), new Keyframe(0.55f, 1f), new Keyframe(1f, 0f));
|
|
|
|
[Header("Hand-placed features")]
|
|
public List<TerrainFeature> features = new List<TerrainFeature>();
|
|
|
|
[Header("Auto texturing by height (optional)")]
|
|
[Tooltip("Enable height/slope based auto texturing at bake (and via the Apply button).")]
|
|
public bool autoTexture = false;
|
|
[Tooltip("Alphamap (splatmap) resolution per tile. Higher = smoother blends but more VRAM.")]
|
|
public int alphamapResolution = 1024;
|
|
[Tooltip("Height/slope bands, painted bottom-to-top. Heights are in world meters.")]
|
|
public List<SplatRule> splatRules = new List<SplatRule>();
|
|
|
|
[Header("Detail / grass painting")]
|
|
[Tooltip("Grid resolution for painted details (grass meshes). 0 = details disabled. " +
|
|
"1024 over a 1 km tile ≈ 1 detail cell/m. Must be a multiple of 'per patch'.")]
|
|
public int detailResolution = 1024;
|
|
[Tooltip("Detail cells per patch. detailResolution / this = number of patches per axis.")]
|
|
[Range(8, 128)] public int detailResolutionPerPatch = 32;
|
|
|
|
[Header("Terrain quality")]
|
|
[Range(1f, 50f)] public float heightmapPixelError = 5f;
|
|
public float basemapDistance = 1000f;
|
|
public bool drawInstanced = true;
|
|
|
|
void Reset()
|
|
{
|
|
heightCurve = AnimationCurve.Linear(0, 0, 1, 1);
|
|
falloffCurve = new AnimationCurve(
|
|
new Keyframe(0f, 1f), new Keyframe(0.55f, 1f), new Keyframe(1f, 0f));
|
|
}
|
|
|
|
/// <summary>Validates / repairs values; returns false with a reason if unusable.</summary>
|
|
public bool Validate(out string error)
|
|
{
|
|
error = null;
|
|
if (tilesPerSide < 1) { error = "tilesPerSide must be >= 1."; return false; }
|
|
if (worldSizeMeters <= 0f) { error = "worldSizeMeters must be > 0."; return false; }
|
|
if (!IsPowerOfTwoPlusOne(heightmapResolution))
|
|
{
|
|
error = $"heightmapResolution ({heightmapResolution}) must be 2^n + 1 (e.g. 513, 1025, 2049, 4097).";
|
|
return false;
|
|
}
|
|
if (string.IsNullOrWhiteSpace(outputFolder) || !outputFolder.StartsWith("Assets"))
|
|
{
|
|
error = "outputFolder must be a project path starting with 'Assets'.";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool IsPowerOfTwoPlusOne(int v)
|
|
{
|
|
int n = v - 1;
|
|
return n >= 32 && (n & (n - 1)) == 0;
|
|
}
|
|
}
|
|
}
|