Fix fall-through (spawn on terrain after collision built) and B&W (assign sky env)
This commit is contained in:
@@ -2,27 +2,35 @@ extends Node3D
|
||||
## Terrain generator — M0 placeholder.
|
||||
##
|
||||
## Builds ONE heightmap chunk from deterministic noise, so the world already
|
||||
## looks like rolling ground rather than a flat plane. This is intentionally
|
||||
## simple: a single chunk, generated at _ready(). Chunk streaming, biomes and
|
||||
## server-side determinism (see docs/ARCHITECTURE.md §4) come in later milestones.
|
||||
## looks like rolling ground rather than a flat plane. Single chunk, generated at
|
||||
## _ready(). Chunk streaming, biomes and server-side determinism (see
|
||||
## docs/ARCHITECTURE.md §4) come in later milestones.
|
||||
##
|
||||
## The mesh is generated in code (no asset needed) so the project runs the moment
|
||||
## Godot opens it, with nothing to import.
|
||||
##
|
||||
## Exposes `sample_height(x, z)` so other systems (player spawn, prop placement)
|
||||
## can sit exactly on the surface instead of guessing a Y and falling through.
|
||||
|
||||
signal ready_built ## emitted once the mesh + collision exist
|
||||
|
||||
@export var size: int = 128 # chunk is size x size metres
|
||||
@export var resolution: int = 96 # vertices per side (higher = smoother/heavier)
|
||||
@export var height_scale: float = 10.0
|
||||
@export var noise_seed: int = 1337
|
||||
|
||||
var _noise: FastNoiseLite
|
||||
var built: bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
_build()
|
||||
|
||||
func _build() -> void:
|
||||
var noise := FastNoiseLite.new()
|
||||
noise.seed = noise_seed
|
||||
noise.noise_type = FastNoiseLite.TYPE_PERLIN
|
||||
noise.frequency = 0.012
|
||||
noise.fractal_octaves = 4
|
||||
_noise = FastNoiseLite.new()
|
||||
_noise.seed = noise_seed
|
||||
_noise.noise_type = FastNoiseLite.TYPE_PERLIN
|
||||
_noise.frequency = 0.012
|
||||
_noise.fractal_octaves = 4
|
||||
|
||||
var st := SurfaceTool.new()
|
||||
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||
@@ -40,21 +48,21 @@ func _build() -> void:
|
||||
var x1 := (x + 1) * step - half
|
||||
var z1 := (z + 1) * step - half
|
||||
|
||||
var p00 := Vector3(x0, _height(noise, x0, z0), z0)
|
||||
var p10 := Vector3(x1, _height(noise, x1, z0), z0)
|
||||
var p01 := Vector3(x0, _height(noise, x0, z1), z1)
|
||||
var p11 := Vector3(x1, _height(noise, x1, z1), z1)
|
||||
var p00 := Vector3(x0, sample_height(x0, z0), z0)
|
||||
var p10 := Vector3(x1, sample_height(x1, z0), z0)
|
||||
var p01 := Vector3(x0, sample_height(x0, z1), z1)
|
||||
var p11 := Vector3(x1, sample_height(x1, z1), z1)
|
||||
|
||||
_add_tri(st, p00, p01, p11, half, uv_scale)
|
||||
_add_tri(st, p00, p11, p10, half, uv_scale)
|
||||
|
||||
# Normals give the lighting its shape. Tangents are only needed for normal
|
||||
# maps, which this low-poly material doesn't use — so we skip them (and avoid
|
||||
# the "UVs required to generate tangents" error).
|
||||
# maps, which this low-poly material doesn't use — so we skip them.
|
||||
st.generate_normals()
|
||||
|
||||
var mesh := st.commit()
|
||||
var mi := MeshInstance3D.new()
|
||||
mi.name = "TerrainMesh"
|
||||
mi.mesh = mesh
|
||||
|
||||
# Simple ground material. Low-poly look = flat-ish colour + lighting does the rest.
|
||||
@@ -64,16 +72,28 @@ func _build() -> void:
|
||||
mi.material_override = mat
|
||||
add_child(mi)
|
||||
|
||||
# Collision so the player can walk on it.
|
||||
# Collision so the player can walk on it. Build the body BEFORE marking built
|
||||
# so anything spawning on ready_built already has ground under it.
|
||||
var body := StaticBody3D.new()
|
||||
body.name = "TerrainBody"
|
||||
var shape := CollisionShape3D.new()
|
||||
var col := mesh.create_trimesh_shape()
|
||||
shape.shape = col
|
||||
shape.shape = mesh.create_trimesh_shape()
|
||||
body.add_child(shape)
|
||||
add_child(body)
|
||||
|
||||
func _height(noise: FastNoiseLite, x: float, z: float) -> float:
|
||||
return noise.get_noise_2d(x, z) * height_scale
|
||||
built = true
|
||||
ready_built.emit()
|
||||
|
||||
## World-space ground height at (x, z). Safe to call before or after _build()
|
||||
## because it lazily creates the noise object.
|
||||
func sample_height(x: float, z: float) -> float:
|
||||
if _noise == null:
|
||||
_noise = FastNoiseLite.new()
|
||||
_noise.seed = noise_seed
|
||||
_noise.noise_type = FastNoiseLite.TYPE_PERLIN
|
||||
_noise.frequency = 0.012
|
||||
_noise.fractal_octaves = 4
|
||||
return _noise.get_noise_2d(x, z) * height_scale
|
||||
|
||||
func _add_tri(st: SurfaceTool, a: Vector3, b: Vector3, c: Vector3, half: float, uv_scale: float) -> void:
|
||||
st.set_uv(Vector2((a.x + half) * uv_scale, (a.z + half) * uv_scale))
|
||||
|
||||
Reference in New Issue
Block a user