mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2025-12-16 13:30:07 +01:00
* General proofreading for grammar and spelling * General formatting * Addition of appropriate literals where appropriate, i.e. `&"foo"` for `StringName` cases and `^"foo/bar"` for `NodePath` cases
122 lines
4.7 KiB
GDScript
122 lines
4.7 KiB
GDScript
extends Node2D
|
|
|
|
|
|
static var map_cell_size: float = 1.0
|
|
static var chunk_size: int = 256
|
|
static var cell_size: float = 1.0
|
|
static var agent_radius: float = 10.0
|
|
static var chunk_id_to_region: Dictionary = {}
|
|
|
|
|
|
var path_start_position: Vector2
|
|
|
|
|
|
func _ready() -> void:
|
|
NavigationServer2D.set_debug_enabled(true)
|
|
|
|
path_start_position = %DebugPaths.global_position
|
|
|
|
var map: RID = get_world_2d().navigation_map
|
|
NavigationServer2D.map_set_cell_size(map, map_cell_size)
|
|
|
|
# Disable performance costly edge connection margin feature.
|
|
# This feature is not needed to merge navigation mesh edges.
|
|
# If edges are well aligned they will merge just fine by edge key.
|
|
NavigationServer2D.map_set_use_edge_connections(map, false)
|
|
|
|
# Parse the collision shapes below our parse root node.
|
|
var source_geometry: NavigationMeshSourceGeometryData2D = NavigationMeshSourceGeometryData2D.new()
|
|
var parse_settings: NavigationPolygon = NavigationPolygon.new()
|
|
parse_settings.parsed_geometry_type = NavigationPolygon.PARSED_GEOMETRY_STATIC_COLLIDERS
|
|
NavigationServer2D.parse_source_geometry_data(parse_settings, source_geometry, %ParseRootNode)
|
|
|
|
# Add an outline to define the traversable surface that the parsed collision shapes can "cut" into.
|
|
var traversable_outline: PackedVector2Array = PackedVector2Array([
|
|
Vector2(0.0, 0.0),
|
|
Vector2(1920.0, 0.0),
|
|
Vector2(1920.0, 1080.0),
|
|
Vector2(0.0, 1080.0),
|
|
])
|
|
source_geometry.add_traversable_outline(traversable_outline)
|
|
|
|
create_region_chunks(%ChunksContainer, source_geometry, chunk_size * cell_size, agent_radius)
|
|
|
|
|
|
static func create_region_chunks(chunks_root_node: Node, p_source_geometry: NavigationMeshSourceGeometryData2D, p_chunk_size: float, p_agent_radius: float) -> void:
|
|
# We need to know how many chunks are required for the input geometry.
|
|
# So first get an axis aligned bounding box that covers all vertices.
|
|
var input_geometry_bounds: Rect2 = p_source_geometry.get_bounds()
|
|
|
|
# Rasterize bounding box into chunk grid to know range of required chunks.
|
|
var start_chunk: Vector2 = floor(
|
|
input_geometry_bounds.position / p_chunk_size
|
|
)
|
|
var end_chunk: Vector2 = floor(
|
|
(input_geometry_bounds.position + input_geometry_bounds.size)
|
|
/ p_chunk_size
|
|
)
|
|
|
|
for chunk_y in range(start_chunk.y, end_chunk.y + 1):
|
|
for chunk_x in range(start_chunk.x, end_chunk.x + 1):
|
|
var chunk_id: Vector2i = Vector2i(chunk_x, chunk_y)
|
|
|
|
var chunk_bounding_box: Rect2 = Rect2(
|
|
Vector2(chunk_x, chunk_y) * p_chunk_size,
|
|
Vector2(p_chunk_size, p_chunk_size),
|
|
)
|
|
# We grow the chunk bounding box to include geometry
|
|
# from all the neighbor chunks so edges can align.
|
|
# The border size is the same value as our grow amount so
|
|
# the final navigation mesh ends up with the intended chunk size.
|
|
var baking_bounds: Rect2 = chunk_bounding_box.grow(p_chunk_size)
|
|
|
|
var chunk_navmesh: NavigationPolygon = NavigationPolygon.new()
|
|
chunk_navmesh.parsed_geometry_type = NavigationPolygon.PARSED_GEOMETRY_STATIC_COLLIDERS
|
|
chunk_navmesh.baking_rect = baking_bounds
|
|
chunk_navmesh.border_size = p_chunk_size
|
|
chunk_navmesh.agent_radius = p_agent_radius
|
|
NavigationServer2D.bake_from_source_geometry_data(chunk_navmesh, p_source_geometry)
|
|
|
|
# The only reason we reset the baking bounds here is to not render its debug.
|
|
chunk_navmesh.baking_rect = Rect2()
|
|
|
|
# Snap vertex positions to avoid most rasterization issues with float precision.
|
|
var navmesh_vertices: PackedVector2Array = chunk_navmesh.vertices
|
|
for i in navmesh_vertices.size():
|
|
var vertex: Vector2 = navmesh_vertices[i]
|
|
navmesh_vertices[i] = vertex.snappedf(map_cell_size * 0.1)
|
|
chunk_navmesh.vertices = navmesh_vertices
|
|
|
|
var chunk_region: NavigationRegion2D = NavigationRegion2D.new()
|
|
chunk_region.navigation_polygon = chunk_navmesh
|
|
chunks_root_node.add_child(chunk_region)
|
|
|
|
chunk_id_to_region[chunk_id] = chunk_region
|
|
|
|
|
|
func _process(_delta: float) -> void:
|
|
var mouse_cursor_position: Vector2 = get_global_mouse_position()
|
|
|
|
var map: RID = get_world_2d().navigation_map
|
|
# Do not query when the map has never synchronized and is empty.
|
|
if NavigationServer2D.map_get_iteration_id(map) == 0:
|
|
return
|
|
|
|
var closest_point_on_navmesh: Vector2 = NavigationServer2D.map_get_closest_point(
|
|
map,
|
|
mouse_cursor_position
|
|
)
|
|
|
|
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
|
|
path_start_position = closest_point_on_navmesh
|
|
|
|
%DebugPaths.global_position = path_start_position
|
|
|
|
%PathDebugCorridorFunnel.target_position = closest_point_on_navmesh
|
|
%PathDebugEdgeCentered.target_position = closest_point_on_navmesh
|
|
%PathDebugNoPostProcessing.target_position = closest_point_on_navmesh
|
|
|
|
%PathDebugCorridorFunnel.get_next_path_position()
|
|
%PathDebugEdgeCentered.get_next_path_position()
|
|
%PathDebugNoPostProcessing.get_next_path_position()
|