113 lines
3.7 KiB
GDScript
113 lines
3.7 KiB
GDScript
extends Node3D
|
|
## Gelaende, Vegetation und Umgebung. Baeume laufen ueber MultiMesh,
|
|
## damit auch mehrere hundert Stueck guenstig bleiben.
|
|
|
|
const Mat = preload("res://scripts/mat.gd")
|
|
const Deco = preload("res://scripts/deco.gd")
|
|
|
|
const GRASS := Color("7cb85a")
|
|
const GRASS_DARK := Color("74b054")
|
|
const WATER := Color("4f9fd6")
|
|
const SAND := Color("e0c98a")
|
|
const EXTENT := 360.0
|
|
|
|
var _rng: RandomNumberGenerator
|
|
|
|
func build(rng: RandomNumberGenerator, track, stations: Array) -> void:
|
|
_rng = rng
|
|
_ground()
|
|
_scatter(track, stations)
|
|
|
|
func _flat_disc(pos: Vector3, radius: float, color: Color, height := 0.06) -> void:
|
|
var m := MeshInstance3D.new()
|
|
m.mesh = Deco.cyl(radius, height, 24)
|
|
m.material_override = Mat.flat(color)
|
|
m.position = pos
|
|
add_child(m)
|
|
|
|
func _ground() -> void:
|
|
var plane := PlaneMesh.new()
|
|
plane.size = Vector2(1000, 1000)
|
|
var g := MeshInstance3D.new()
|
|
g.mesh = plane
|
|
g.material_override = Mat.flat(GRASS)
|
|
add_child(g)
|
|
|
|
_flat_disc(Vector3(-230, 0.02, 150), 72.0, SAND, 0.05)
|
|
_flat_disc(Vector3(-230, 0.04, 150), 60.0, WATER, 0.05)
|
|
for i in 18:
|
|
var p := Vector2(_rng.randf_range(-EXTENT, EXTENT), _rng.randf_range(-EXTENT, EXTENT))
|
|
_flat_disc(Vector3(p.x, 0.01, p.y), _rng.randf_range(18.0, 44.0), GRASS_DARK, 0.03)
|
|
|
|
func _multi(mesh: Mesh, items: Array) -> void:
|
|
if items.is_empty():
|
|
return
|
|
var mm := MultiMesh.new()
|
|
mm.transform_format = MultiMesh.TRANSFORM_3D
|
|
mm.use_colors = true
|
|
mm.mesh = mesh
|
|
mm.instance_count = items.size()
|
|
for i in items.size():
|
|
var it: Dictionary = items[i]
|
|
mm.set_instance_transform(i, it["xf"])
|
|
# Instanzfarben gehen roh in den Shader, deshalb hier nach Linear wandeln.
|
|
mm.set_instance_color(i, (it["color"] as Color).srgb_to_linear())
|
|
var mmi := MultiMeshInstance3D.new()
|
|
mmi.multimesh = mm
|
|
mmi.material_override = Mat.flat(Color.WHITE)
|
|
add_child(mmi)
|
|
|
|
func _scatter(track, stations: Array) -> void:
|
|
var trunks: Array = []
|
|
var cones: Array = []
|
|
var blobs: Array = []
|
|
var rocks: Array = []
|
|
|
|
var placed := 0
|
|
var tries := 0
|
|
while placed < 620 and tries < 12000:
|
|
tries += 1
|
|
var p := Vector2(_rng.randf_range(-EXTENT, EXTENT), _rng.randf_range(-EXTENT, EXTENT))
|
|
if track.distance_to_track(p) < 11.0:
|
|
continue
|
|
if p.distance_to(Vector2(-230, 150)) < 78.0:
|
|
continue
|
|
var blocked := false
|
|
for st in stations:
|
|
if p.distance_to(Vector2(st.global_position.x, st.global_position.z)) < 30.0:
|
|
blocked = true
|
|
break
|
|
if blocked:
|
|
continue
|
|
placed += 1
|
|
var yaw := _rng.randf() * TAU
|
|
if _rng.randf() < 0.6:
|
|
var h := _rng.randf_range(4.0, 8.5)
|
|
var col: Color = Deco.PINE[_rng.randi() % Deco.PINE.size()]
|
|
trunks.append(_item(p, h * 0.16, Vector3(1, h * 0.3, 1), yaw, Deco.TRUNK))
|
|
var tiers := 3 if h > 6.0 else 2
|
|
for i in tiers:
|
|
var f := float(i) / float(tiers)
|
|
var r := lerpf(h * 0.3, h * 0.14, f)
|
|
var th := h * 0.44
|
|
var y := h * 0.26 + f * h * 0.32 + th * 0.5
|
|
cones.append(_item(p, y, Vector3(r, th, r), yaw, col))
|
|
elif _rng.randf() < 0.85:
|
|
var h := _rng.randf_range(3.2, 6.0)
|
|
var col: Color = Deco.LEAF[_rng.randi() % Deco.LEAF.size()]
|
|
trunks.append(_item(p, h * 0.28, Vector3(0.9, h * 0.55, 0.9), yaw, Deco.TRUNK))
|
|
var r := h * 0.44
|
|
blobs.append(_item(p, h * 0.55 + r * 0.5, Vector3(r, r, r), yaw, col))
|
|
else:
|
|
var r := _rng.randf_range(0.7, 2.0)
|
|
rocks.append(_item(p, r * 0.35, Vector3(r, r * 0.55, r * 1.1), yaw, Deco.ROCK))
|
|
|
|
_multi(Deco.cyl(0.18, 1.0, 6), trunks)
|
|
_multi(Deco.cone(1.0, 1.0, 7), cones)
|
|
_multi(Deco.blob(1.0), blobs)
|
|
_multi(Deco.blob(1.0), rocks)
|
|
|
|
func _item(p: Vector2, y: float, scale: Vector3, yaw: float, color: Color) -> Dictionary:
|
|
var b := Basis(Vector3.UP, yaw).scaled(scale)
|
|
return {"xf": Transform3D(b, Vector3(p.x, y, p.y)), "color": color}
|