Make some test with terrain generator
This commit is contained in:
153
proc-terrain/terrain_props_data.gd
Normal file
153
proc-terrain/terrain_props_data.gd
Normal file
@@ -0,0 +1,153 @@
|
||||
@tool
|
||||
class_name TerrainPropsData
|
||||
extends RefCounted
|
||||
|
||||
## Data structure containing terrain information for props placement.
|
||||
## Generated by TerrainGenerator after terrain generation.
|
||||
|
||||
var resolution: Vector2i = Vector2i(128, 128)
|
||||
var terrain_size: Vector2 = Vector2(200, 200)
|
||||
var heights: Array[float] = []
|
||||
var biome_ids: Array[int] = []
|
||||
var slope_values: Array[float] = []
|
||||
var rail_distances: Array[float] = []
|
||||
var station_distances: Array[float] = []
|
||||
var mask_values: Array[Array] = []
|
||||
|
||||
|
||||
func get_index(x: int, z: int) -> int:
|
||||
return z * resolution.x + x
|
||||
|
||||
|
||||
func get_uv(x: int, z: int) -> Vector2:
|
||||
return Vector2(float(x) / float(resolution.x - 1), float(z) / float(resolution.y - 1))
|
||||
|
||||
|
||||
func get_world_position(x: int, z: int) -> Vector3:
|
||||
var half_x := terrain_size.x / 2.0
|
||||
var half_z := terrain_size.y / 2.0
|
||||
var step_x := terrain_size.x / float(resolution.x - 1)
|
||||
var step_z := terrain_size.y / float(resolution.y - 1)
|
||||
var idx := get_index(x, z)
|
||||
return Vector3(
|
||||
x * step_x - half_x,
|
||||
heights[idx] if idx < heights.size() else 0.0,
|
||||
z * step_z - half_z
|
||||
)
|
||||
|
||||
|
||||
func get_height(x: int, z: int) -> float:
|
||||
var idx := get_index(x, z)
|
||||
if idx < 0 or idx >= heights.size():
|
||||
return 0.0
|
||||
return heights[idx]
|
||||
|
||||
|
||||
func get_biome_id(x: int, z: int) -> int:
|
||||
var idx := get_index(x, z)
|
||||
if idx < 0 or idx >= biome_ids.size():
|
||||
return 0
|
||||
return biome_ids[idx]
|
||||
|
||||
|
||||
func get_slope_limit(x: int, z: int) -> float:
|
||||
var idx := get_index(x, z)
|
||||
if idx < 0 or idx >= slope_values.size():
|
||||
return 45.0
|
||||
return slope_values[idx]
|
||||
|
||||
|
||||
func get_rail_distance(x: int, z: int) -> float:
|
||||
var idx := get_index(x, z)
|
||||
if idx < 0 or idx >= rail_distances.size():
|
||||
return INF
|
||||
return rail_distances[idx]
|
||||
|
||||
|
||||
func get_station_distance(x: int, z: int) -> float:
|
||||
var idx := get_index(x, z)
|
||||
if idx < 0 or idx >= station_distances.size():
|
||||
return INF
|
||||
return station_distances[idx]
|
||||
|
||||
|
||||
func get_mask_value(mask_index: int, x: int, z: int) -> float:
|
||||
if mask_index < 0 or mask_index >= mask_values.size():
|
||||
return 0.0
|
||||
var mask_arr: Array = mask_values[mask_index]
|
||||
var idx := get_index(x, z)
|
||||
if idx < 0 or idx >= mask_arr.size():
|
||||
return 0.0
|
||||
return mask_arr[idx]
|
||||
|
||||
|
||||
func get_calculated_slope(x: int, z: int) -> float:
|
||||
if x <= 0 or x >= resolution.x - 1 or z <= 0 or z >= resolution.y - 1:
|
||||
return 0.0
|
||||
|
||||
var step_x := terrain_size.x / float(resolution.x - 1)
|
||||
var step_z := terrain_size.y / float(resolution.y - 1)
|
||||
|
||||
var h := get_height(x, z)
|
||||
var h_xm := get_height(x - 1, z)
|
||||
var h_xp := get_height(x + 1, z)
|
||||
var h_zm := get_height(x, z - 1)
|
||||
var h_zp := get_height(x, z + 1)
|
||||
|
||||
var dx := (h_xp - h_xm) / (2.0 * step_x)
|
||||
var dz := (h_zp - h_zm) / (2.0 * step_z)
|
||||
|
||||
return rad_to_deg(atan(sqrt(dx * dx + dz * dz)))
|
||||
|
||||
|
||||
func can_place_prop(x: int, z: int, rules: Dictionary) -> bool:
|
||||
var slope := get_calculated_slope(x, z)
|
||||
var rail_dist := get_rail_distance(x, z)
|
||||
var station_dist := get_station_distance(x, z)
|
||||
var biome := get_biome_id(x, z)
|
||||
|
||||
if rules.has("max_slope") and slope > rules["max_slope"]:
|
||||
return false
|
||||
if rules.has("min_rail_distance") and rail_dist < rules["min_rail_distance"]:
|
||||
return false
|
||||
if rules.has("min_station_distance") and station_dist < rules["min_station_distance"]:
|
||||
return false
|
||||
if rules.has("allowed_biomes") and not biome in rules["allowed_biomes"]:
|
||||
return false
|
||||
if rules.has("excluded_biomes") and biome in rules["excluded_biomes"]:
|
||||
return false
|
||||
|
||||
if rules.has("required_mask"):
|
||||
var mask_idx: int = rules["required_mask"]
|
||||
var threshold: float = rules.get("mask_threshold", 0.5)
|
||||
if get_mask_value(mask_idx, x, z) < threshold:
|
||||
return false
|
||||
|
||||
if rules.has("excluded_mask"):
|
||||
var mask_idx: int = rules["excluded_mask"]
|
||||
var threshold: float = rules.get("exclude_threshold", 0.5)
|
||||
if get_mask_value(mask_idx, x, z) >= threshold:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func get_density_multiplier(x: int, z: int, rules: Dictionary) -> float:
|
||||
var multiplier := 1.0
|
||||
|
||||
if rules.has("slope_density_curve"):
|
||||
var slope := get_calculated_slope(x, z)
|
||||
var curve: Curve = rules["slope_density_curve"]
|
||||
multiplier *= curve.sample(clampf(slope / 90.0, 0.0, 1.0))
|
||||
|
||||
if rules.has("rail_distance_curve"):
|
||||
var dist := get_rail_distance(x, z)
|
||||
var curve: Curve = rules["rail_distance_curve"]
|
||||
var max_dist: float = rules.get("rail_distance_max", 100.0)
|
||||
multiplier *= curve.sample(clampf(dist / max_dist, 0.0, 1.0))
|
||||
|
||||
if rules.has("density_mask"):
|
||||
var mask_idx: int = rules["density_mask"]
|
||||
multiplier *= get_mask_value(mask_idx, x, z)
|
||||
|
||||
return multiplier
|
||||
Reference in New Issue
Block a user