GridMap 体素

运行时构建的 MeshLibrary 加上由高度图填充的 GridMap,每个格子一个立方体。

上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。

用到的 Godot 类

GridMapMeshLibraryBoxMesh

代码

scripts/main.gd
extends Node

const MAP: int = 28
const LEVELS: int = 8
const SEED: int = 20260814

const BLOCKS: Array = [
	{name = 'water', color = '#2a3a63'},
	{name = 'sand', color = '#f3d48d'},
	{name = 'grass', color = '#8eef97'},
	{name = 'forest', color = '#4c9c60'},
	{name = 'rock', color = '#2a2f3d'},
	{name = 'snow', color = '#e6ecff'},
]

var elapsed: float = 0.0
var camera: Camera3D


func _ready() -> void:
	_add_environment()
	_add_light()

	var grid: GridMap = GridMap.new()
	grid.mesh_library = _make_library()
	grid.cell_size = Vector3.ONE
	add_child(grid)

	_fill(grid)

	camera = Camera3D.new()
	add_child(camera)
	camera.current = true

	print('the MeshLibrary is built by code, change SEED for another map')


func _process(delta: float) -> void:
	elapsed += delta

	var angle: float = elapsed * 0.2
	camera.position = Vector3(sin(angle) * 24.5, 16.0, cos(angle) * 24.5)
	camera.look_at(Vector3(0, 2.5, 0), Vector3.UP)


func _make_library() -> MeshLibrary:
	var library: MeshLibrary = MeshLibrary.new()

	for i in BLOCKS.size():
		var material: StandardMaterial3D = StandardMaterial3D.new()
		material.albedo_color = Color(BLOCKS[i].color)
		material.roughness = 0.9

		var block: BoxMesh = BoxMesh.new()
		block.size = Vector3.ONE
		# the MeshLibrary keeps the mesh resource, a material_override on the instance never reaches it
		block.material = material

		library.create_item(i)
		library.set_item_name(i, BLOCKS[i].name)
		library.set_item_mesh(i, block)

	return library


func _fill(grid: GridMap) -> void:
	var noise: FastNoiseLite = FastNoiseLite.new()
	noise.seed = SEED
	noise.noise_type = FastNoiseLite.TYPE_SIMPLEX
	noise.fractal_octaves = 4
	noise.frequency = 0.045

	var half: int = roundi(MAP * 0.5)

	for x in MAP:
		for z in MAP:
			var value: float = noise.get_noise_2d(x, z) * 0.5 + 0.5
			var column: int = clampi(int(pow(value, 1.6) * LEVELS * 1.6), 1, LEVELS)

			for y in column:
				var item: int = clampi(int(float(y) / LEVELS * BLOCKS.size()), 0, BLOCKS.size() - 1)
				grid.set_cell_item(Vector3i(x - half, y, z - half), item)


func _add_environment() -> void:
	var sky_material: ProceduralSkyMaterial = ProceduralSkyMaterial.new()
	sky_material.sky_top_color = Color(0.04, 0.05, 0.1)
	sky_material.sky_horizon_color = Color(0.12, 0.14, 0.22)
	sky_material.ground_bottom_color = Color(0.02, 0.02, 0.04)
	sky_material.ground_horizon_color = Color(0.09, 0.1, 0.15)

	var sky: Sky = Sky.new()
	sky.sky_material = sky_material

	var env: Environment = Environment.new()
	env.background_mode = Environment.BG_SKY
	env.sky = sky
	env.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
	env.ambient_light_energy = 0.85

	var world: WorldEnvironment = WorldEnvironment.new()
	world.environment = env
	add_child(world)


func _add_light() -> void:
	var light: DirectionalLight3D = DirectionalLight3D.new()
	light.rotation_degrees = Vector3(-50, -35, 0)
	light.light_energy = 1.2
	add_child(light)

更多程序化生成示例