78 lines
2.4 KiB
GDScript
78 lines
2.4 KiB
GDScript
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.
|
|
##
|
|
## The mesh is generated in code (no asset needed) so the project runs the moment
|
|
## Godot opens it, with nothing to import.
|
|
|
|
@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
|
|
|
|
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
|
|
|
|
var st := SurfaceTool.new()
|
|
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
|
|
|
var step := float(size) / float(resolution)
|
|
var half := size * 0.5
|
|
|
|
# Build a grid of quads, two triangles each.
|
|
for z in range(resolution):
|
|
for x in range(resolution):
|
|
var x0 := x * step - half
|
|
var z0 := z * step - half
|
|
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)
|
|
|
|
_add_tri(st, p00, p01, p11)
|
|
_add_tri(st, p00, p11, p10)
|
|
|
|
st.generate_normals()
|
|
st.generate_tangents()
|
|
|
|
var mesh := st.commit()
|
|
var mi := MeshInstance3D.new()
|
|
mi.mesh = mesh
|
|
|
|
# Simple ground material. Low-poly look = flat-ish colour + lighting does the rest.
|
|
var mat := StandardMaterial3D.new()
|
|
mat.albedo_color = Color(0.33, 0.45, 0.22) # mossy green
|
|
mat.roughness = 0.95
|
|
mi.material_override = mat
|
|
add_child(mi)
|
|
|
|
# Collision so the player can walk on it.
|
|
var body := StaticBody3D.new()
|
|
var shape := CollisionShape3D.new()
|
|
var col := mesh.create_trimesh_shape()
|
|
shape.shape = col
|
|
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
|
|
|
|
func _add_tri(st: SurfaceTool, a: Vector3, b: Vector3, c: Vector3) -> void:
|
|
st.add_vertex(a)
|
|
st.add_vertex(b)
|
|
st.add_vertex(c)
|