Use NavigationAgent3D in 3D Navigation demo (#975)

Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
This commit is contained in:
David Briscoe
2023-10-17 18:23:57 -07:00
committed by GitHub
parent 84b7f9ea36
commit 1b61bc4bb0
7 changed files with 95 additions and 123 deletions

View File

@@ -0,0 +1,45 @@
extends Marker3D
const Line3D = preload("res://line3d.gd")
@export var character_speed := 10.0
@export var show_path := true
@onready var _nav_agent := $NavigationAgent3D as NavigationAgent3D
var _nav_path_line : Line3D
func _ready():
_nav_path_line = Line3D.new()
add_child(_nav_path_line)
_nav_path_line.set_as_top_level(true)
func _physics_process(delta):
if _nav_agent.is_navigation_finished():
return
var next_position := _nav_agent.get_next_path_position()
var offset := next_position - global_position
global_position = global_position.move_toward(next_position, delta * character_speed)
# Make the robot look at the direction we're traveling.
# Clamp y to 0 so the robot only looks left and right, not up/down.
offset.y = 0
look_at(global_position + offset, Vector3.UP)
func set_target_position(target_position: Vector3):
_nav_agent.set_target_position(target_position)
# Get a full navigation path with the NavigationServer API.
if show_path:
var start_position := global_transform.origin
var optimize := true
var navigation_map := get_world_3d().get_navigation_map()
var path := NavigationServer3D.map_get_path(
navigation_map,
start_position,
target_position,
optimize)
_nav_path_line.draw_path(path)

22
3d/navigation/line3d.gd Normal file
View File

@@ -0,0 +1,22 @@
extends MeshInstance3D
func _ready():
set_mesh(ImmediateMesh.new())
var material := StandardMaterial3D.new()
material.flags_unshaded = true
material.albedo_color = Color.WHITE
set_material_override(material)
func draw_path(path):
var im: ImmediateMesh = mesh
im.clear_surfaces()
im.surface_begin(Mesh.PRIMITIVE_POINTS, null)
im.surface_add_vertex(path[0])
im.surface_add_vertex(path[path.size() - 1])
im.surface_end()
im.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, null)
for current_vector in path:
im.surface_add_vertex(current_vector)
im.surface_end()

View File

@@ -1,84 +1,30 @@
extends Node3D
const SPEED := 10.0
@export var show_path := true
const Character = preload("res://character.gd")
var cam_rotation := 0.0
var path: PackedVector3Array
@onready var _camera := $CameraBase/Camera3D as Camera3D
@onready var _robot := $RobotBase as Character
@onready var robot: Marker3D = $RobotBase
@onready var camera: Camera3D = $CameraBase/Camera3D
func _ready():
set_process_input(true)
func _physics_process(delta: float):
var direction := Vector3()
# We need to scale the movement speed by how much delta has passed,
# otherwise the motion won't be smooth.
var step_size := delta * SPEED
if not path.is_empty():
# Direction is the difference between where we are now
# and where we want to go.
var destination := path[0]
direction = destination - robot.position
# If the next node is closer than we intend to 'step', then
# take a smaller step. Otherwise we would go past it and
# potentially go through a wall or over a cliff edge!
if step_size > direction.length():
step_size = direction.length()
# We should also remove this node since we're about to reach it.
path.remove_at(0)
# Move the robot towards the path node, by how far we want to travel.
# TODO: This information should be set to the CharacterBody properties instead of arguments.
# Note: For a CharacterBody3D, we would instead use move_and_slide
# so collisions work properly.
robot.position += direction.normalized() * step_size
# Lastly let's make sure we're looking in the direction we're traveling.
# Clamp y to 0 so the robot only looks left and right, not up/down.
direction.y = 0
if direction:
# Direction is relative, so apply it to the robot's location to
# get a point we can actually look at.
var look_at_point := robot.position + direction.normalized()
# Make the robot look at the point.
robot.look_at(look_at_point, Vector3.UP)
var _cam_rotation := 0.0
func _unhandled_input(event: InputEvent):
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
var map := get_world_3d().navigation_map
var from := camera.project_ray_origin(event.position)
var to := from + camera.project_ray_normal(event.position) * 1000
var target_point := NavigationServer3D.map_get_closest_point_to_segment(map, from, to)
# Get closest point on navmesh for the current mouse cursor position.
var mouse_cursor_position = event.position
var camera_ray_length := 1000.0
var camera_ray_start := _camera.project_ray_origin(mouse_cursor_position)
var camera_ray_end := camera_ray_start + _camera.project_ray_normal(mouse_cursor_position) * camera_ray_length
# Set the path between the robot's current location and our target.
path = NavigationServer3D.map_get_path(map, robot.position, target_point, true)
if show_path:
draw_path(path)
var closest_point_on_navmesh := NavigationServer3D.map_get_closest_point_to_segment(
get_world_3d().navigation_map,
camera_ray_start,
camera_ray_end
)
_robot.set_target_position(closest_point_on_navmesh)
elif event is InputEventMouseMotion:
if event.button_mask & (MOUSE_BUTTON_MASK_MIDDLE + MOUSE_BUTTON_MASK_RIGHT):
cam_rotation += event.relative.x * 0.005
$CameraBase.set_rotation(Vector3(0, cam_rotation, 0))
func draw_path(path_array: PackedVector3Array) -> void:
var im: ImmediateMesh = $DrawPath.mesh
im.clear_surfaces()
im.surface_begin(Mesh.PRIMITIVE_POINTS, null)
im.surface_add_vertex(path_array[0])
im.surface_add_vertex(path_array[path_array.size() - 1])
im.surface_end()
im.surface_begin(Mesh.PRIMITIVE_LINE_STRIP, null)
for current_vector in path:
im.surface_add_vertex(current_vector)
im.surface_end()
_cam_rotation += event.relative.x * 0.005
$CameraBase.set_rotation(Vector3.UP * _cam_rotation)

Binary file not shown.

View File

@@ -1,9 +1,10 @@
[gd_scene load_steps=10 format=3 uid="uid://dkhg8e00d02f2"]
[gd_scene load_steps=9 format=3 uid="uid://dkhg8e00d02f2"]
[ext_resource type="Script" path="res://navmesh.gd" id="1"]
[ext_resource type="NavigationMesh" uid="uid://xl4o2ckjxava" path="res://navmesh.res" id="2_lcfvj"]
[ext_resource type="ArrayMesh" uid="uid://gmytdjp2bcsq" path="res://level_mesh.res" id="3_1cas0"]
[ext_resource type="ArrayMesh" uid="uid://prwe6io8p1iv" path="res://robot.res" id="5_ple0n"]
[ext_resource type="NavigationMesh" uid="uid://ii7ckx3dvrs2" path="res://navmesh.res" id="2_lcfvj"]
[ext_resource type="ArrayMesh" path="res://level_mesh.res" id="3_1cas0"]
[ext_resource type="Script" path="res://character.gd" id="4_u7d3d"]
[ext_resource type="ArrayMesh" path="res://robot.res" id="5_ple0n"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_ps07l"]
sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1)
@@ -18,11 +19,6 @@ sky = SubResource("Sky_baxfs")
tonemap_mode = 3
tonemap_white = 6.0
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_noou6"]
shading_mode = 0
[sub_resource type="ImmediateMesh" id="ImmediateMesh_dvj5w"]
[node name="Node3D" type="Node3D"]
_import_path = NodePath(".")
script = ExtResource("1")
@@ -31,24 +27,19 @@ script = ExtResource("1")
environment = SubResource("Environment_c0if4")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.623013, -0.733525, 0.271653, 0.321394, 0.55667, 0.766045, -0.713134, -0.389948, 0.582563, 10.0773, 5.02381, 0)
light_energy = 5.0
transform = Transform3D(-0.723713, -0.678436, -0.12635, -0.277002, 0.11789, 0.95361, -0.632068, 0.725139, -0.273247, 10.0773, 5.02381, 0)
shadow_enabled = true
directional_shadow_mode = 0
directional_shadow_fade_start = 1.0
directional_shadow_max_distance = 35.0
[node name="NavigationRegion3D" type="NavigationRegion3D" parent="."]
navmesh = ExtResource("2_lcfvj")
navigation_mesh = ExtResource("2_lcfvj")
[node name="LevelMesh" type="MeshInstance3D" parent="NavigationRegion3D"]
transform = Transform3D(2, 0, 0, 0, 2, 0, 0, 0, 2, 0, -0.0452547, 0)
mesh = ExtResource("3_1cas0")
[node name="DrawPath" type="MeshInstance3D" parent="."]
material_override = SubResource("StandardMaterial3D_noou6")
mesh = SubResource("ImmediateMesh_dvj5w")
[node name="CameraBase" type="Node3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.07475, 0, 1.96678)
@@ -58,8 +49,12 @@ fov = 50.0
near = 0.1
[node name="RobotBase" type="Marker3D" parent="."]
script = ExtResource("4_u7d3d")
[node name="Robot" type="MeshInstance3D" parent="RobotBase"]
transform = Transform3D(-0.5, 0, -7.54979e-08, 0, 1, 0, 7.54979e-08, 0, -0.5, 0, 1, 0)
gi_mode = 2
mesh = ExtResource("5_ple0n")
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="RobotBase"]
path_desired_distance = 0.1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 B

View File

@@ -1,36 +0,0 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c27ndr5sgvyr8"
path.s3tc="res://.godot/imported/particle.png-c2ba3d91e96c62035d672392a1197218.s3tc.ctex"
path.etc2="res://.godot/imported/particle.png-c2ba3d91e96c62035d672392a1197218.etc2.ctex"
metadata={
"imported_formats": ["s3tc", "etc2"],
"vram_texture": true
}
[deps]
source_file="res://particle.png"
dest_files=["res://.godot/imported/particle.png-c2ba3d91e96c62035d672392a1197218.s3tc.ctex", "res://.godot/imported/particle.png-c2ba3d91e96c62035d672392a1197218.etc2.ctex"]
[params]
compress/mode=2
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1