M0 scaffold: Godot 4 survival game skeleton + architecture/addon-SDK docs

This commit is contained in:
dev
2026-11-03 22:23:20 +00:00
commit 180b776392
13 changed files with 724 additions and 0 deletions

65
scripts/world/props.gd Normal file
View File

@@ -0,0 +1,65 @@
extends Node3D
## M0 mood props — a few low-poly trees and rocks built from primitives in code,
## so the scene looks "alive" with no imported assets. These are placeholders;
## real low-poly models (free asset packs, see docs/ROADMAP.md M0) replace them.
func _ready() -> void:
# A deterministic scattering so it looks intentional, not random each run.
var rng := RandomNumberGenerator.new()
rng.seed = 42
for i in range(18):
var x := rng.randf_range(-55.0, 55.0)
var z := rng.randf_range(-55.0, 55.0)
if rng.randf() < 0.65:
_make_tree(Vector3(x, 0, z), rng)
else:
_make_rock(Vector3(x, 0, z), rng)
func _make_tree(pos: Vector3, rng: RandomNumberGenerator) -> void:
var root := Node3D.new()
root.position = pos
add_child(root)
var trunk := MeshInstance3D.new()
var tm := CylinderMesh.new()
tm.top_radius = 0.18
tm.bottom_radius = 0.28
tm.height = 3.0
trunk.mesh = tm
trunk.position = Vector3(0, 1.5, 0)
trunk.material_override = _mat(Color(0.33, 0.24, 0.16))
root.add_child(trunk)
# Low-poly conifer canopy: stacked cones.
var h := 3.0
for j in range(3):
var cone := MeshInstance3D.new()
var cm := CylinderMesh.new()
cm.top_radius = 0.0
cm.bottom_radius = 1.6 - j * 0.4
cm.height = 1.6
cm.radial_segments = 6 # low-poly
cone.mesh = cm
cone.position = Vector3(0, h + j * 1.0, 0)
cone.material_override = _mat(Color(0.16, 0.34, 0.2))
root.add_child(cone)
root.rotate_y(rng.randf_range(0, TAU))
var s := rng.randf_range(0.85, 1.35)
root.scale = Vector3(s, s, s)
func _make_rock(pos: Vector3, rng: RandomNumberGenerator) -> void:
var rock := MeshInstance3D.new()
var bm := BoxMesh.new()
bm.size = Vector3(rng.randf_range(0.8, 1.8), rng.randf_range(0.6, 1.2), rng.randf_range(0.8, 1.8))
rock.mesh = bm
rock.position = pos + Vector3(0, 0.3, 0)
rock.rotation = Vector3(rng.randf_range(-0.2, 0.2), rng.randf_range(0, TAU), rng.randf_range(-0.2, 0.2))
rock.material_override = _mat(Color(0.42, 0.42, 0.45))
add_child(rock)
func _mat(c: Color) -> StandardMaterial3D:
var m := StandardMaterial3D.new()
m.albedo_color = c
m.roughness = 0.95
return m

77
scripts/world/terrain.gd Normal file
View File

@@ -0,0 +1,77 @@
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)