generated from krampus/template-godot4
Constrained grid generation layer
This commit is contained in:
parent
3352e24771
commit
5272ebdc0a
@ -3,7 +3,29 @@ class_name GenerationFeature extends Node3D
|
|||||||
##
|
##
|
||||||
## Layers contain features. Some features may contain layers.
|
## Layers contain features. Some features may contain layers.
|
||||||
|
|
||||||
|
@export var noise_scale := Vector3.ONE
|
||||||
|
@export var noise_offset := Vector3.ZERO
|
||||||
|
|
||||||
|
@export var sub_layers: Array[GenerationLayer]
|
||||||
|
|
||||||
|
var _generated := false
|
||||||
|
|
||||||
|
|
||||||
func probe() -> void:
|
func probe() -> void:
|
||||||
# TODO may want to make low-detail & high-detail probes distinct
|
# TODO may want to make low-detail & high-detail probes distinct
|
||||||
pass # Implemented in derived type.
|
if not _generated:
|
||||||
|
generate()
|
||||||
|
_generated = true
|
||||||
|
|
||||||
|
for layer in sub_layers:
|
||||||
|
layer.probe()
|
||||||
|
|
||||||
|
|
||||||
|
## Generate elements of this feature. Called by default on the first call to `probe`
|
||||||
|
func generate() -> void:
|
||||||
|
pass # Implemented in derived type
|
||||||
|
|
||||||
|
|
||||||
|
func sample_noise() -> float:
|
||||||
|
var sample_point := global_position * noise_scale + noise_offset
|
||||||
|
return WorldGenManager.noise.get_noise_3dv(sample_point)
|
||||||
|
|||||||
117
src/world/generation/layer/grid_layer/grid_layer.gd
Normal file
117
src/world/generation/layer/grid_layer/grid_layer.gd
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
@tool
|
||||||
|
class_name GridLayer extends GenerationLayer
|
||||||
|
## A layer that generates tiles in a locally-constrained grid.
|
||||||
|
|
||||||
|
## Bounding box for the grid on the local XZ plane.
|
||||||
|
##
|
||||||
|
## Note that only feature handles are checked to be within the bounding box.
|
||||||
|
## The Y component of this AABB is not used.
|
||||||
|
@export var bounding_box: AABB:
|
||||||
|
set(value):
|
||||||
|
bounding_box = value
|
||||||
|
if _debug_box:
|
||||||
|
_set_debug_box_shape(bounding_box)
|
||||||
|
|
||||||
|
## Size of a grid tile in the local XZ plane.
|
||||||
|
@export var grid_size: Vector2
|
||||||
|
|
||||||
|
@export_group("Debug Draw")
|
||||||
|
@export var draw_debug := true
|
||||||
|
@export var debug_color := Color("#a486006b"):
|
||||||
|
set(value):
|
||||||
|
debug_color = value
|
||||||
|
if _debug_box:
|
||||||
|
_set_debug_box_color(debug_color)
|
||||||
|
|
||||||
|
var _debug_meshinstance: MeshInstance3D
|
||||||
|
var _debug_box: BoxMesh
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
_init_debug_draw()
|
||||||
|
|
||||||
|
|
||||||
|
func probe() -> void:
|
||||||
|
var world_pos := WorldGenManager.get_generation_point()
|
||||||
|
probe_radius(world_pos, WorldGenManager.med_detail_radius)
|
||||||
|
# TODO high-detail & low-detail probes
|
||||||
|
|
||||||
|
|
||||||
|
func probe_radius(center: Vector3, radius: float) -> void:
|
||||||
|
var rad_diff := Vector3(radius, 0, radius)
|
||||||
|
|
||||||
|
# Translate probe box limits to grid space
|
||||||
|
var grid_low := world_to_local(center - rad_diff).floor()
|
||||||
|
var grid_high := world_to_local(center + rad_diff).floor()
|
||||||
|
var grid_max := _plane_size().floor()
|
||||||
|
|
||||||
|
# Constrain to bounding box
|
||||||
|
var x_min := maxf(grid_low.x, 0)
|
||||||
|
var x_max := minf(grid_high.x + 1, grid_max.x)
|
||||||
|
var y_min := maxf(grid_low.y, 0)
|
||||||
|
var y_max := minf(grid_high.y + 1, grid_max.y)
|
||||||
|
|
||||||
|
# Probe everything within radius
|
||||||
|
for i in range(x_min, x_max):
|
||||||
|
for j in range(y_min, y_max):
|
||||||
|
probe_grid(Vector2(i, j))
|
||||||
|
|
||||||
|
|
||||||
|
func probe_grid(_grid_pos: Vector2) -> void:
|
||||||
|
pass # Implement in derived type
|
||||||
|
|
||||||
|
|
||||||
|
func _plane_size() -> Vector2:
|
||||||
|
return Vector2(bounding_box.size.x / grid_size.x, bounding_box.size.z / grid_size.y)
|
||||||
|
|
||||||
|
|
||||||
|
func is_bounding_box_valid() -> bool:
|
||||||
|
return bounding_box.size.length_squared() > 0
|
||||||
|
|
||||||
|
|
||||||
|
func is_point_in_bounds(local_pos: Vector2) -> bool:
|
||||||
|
local_pos = local_pos.floor()
|
||||||
|
var grid_max := _plane_size()
|
||||||
|
return (
|
||||||
|
0 <= local_pos.x
|
||||||
|
and local_pos.x < grid_max.x
|
||||||
|
and 0 <= local_pos.y
|
||||||
|
and local_pos.y < grid_max.y
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func local_to_world(local_pos: Vector2) -> Vector3:
|
||||||
|
var v3_pos := Vector3(local_pos.x * grid_size.x, 0, local_pos.y * grid_size.y)
|
||||||
|
return global_transform * (bounding_box.position + v3_pos)
|
||||||
|
|
||||||
|
|
||||||
|
func world_to_local(world_pos: Vector3) -> Vector2:
|
||||||
|
var rel_pos := world_pos * global_transform - bounding_box.position
|
||||||
|
return Vector2(rel_pos.x / grid_size.x, rel_pos.z / grid_size.y)
|
||||||
|
|
||||||
|
|
||||||
|
#region debug draw
|
||||||
|
func _init_debug_draw() -> void:
|
||||||
|
_debug_box = BoxMesh.new()
|
||||||
|
var mat := StandardMaterial3D.new()
|
||||||
|
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
|
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||||
|
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
_debug_box.material = mat
|
||||||
|
_debug_meshinstance = MeshInstance3D.new()
|
||||||
|
_debug_meshinstance.mesh = _debug_box
|
||||||
|
add_child(_debug_meshinstance)
|
||||||
|
_set_debug_box_color(debug_color)
|
||||||
|
_set_debug_box_shape(bounding_box)
|
||||||
|
|
||||||
|
|
||||||
|
func _set_debug_box_color(color: Color) -> void:
|
||||||
|
var mat := _debug_box.material as StandardMaterial3D
|
||||||
|
mat.albedo_color = color
|
||||||
|
|
||||||
|
|
||||||
|
func _set_debug_box_shape(aabb: AABB) -> void:
|
||||||
|
_debug_meshinstance.position = aabb.position + aabb.size / 2
|
||||||
|
_debug_box.size = aabb.size
|
||||||
|
#endregion
|
||||||
Loading…
x
Reference in New Issue
Block a user