mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2026-01-05 23:40:07 +01:00
Use NavigationAgent3D in 3D Navigation demo (#975)
Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
This commit is contained in:
45
3d/navigation/character.gd
Normal file
45
3d/navigation/character.gd
Normal 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
22
3d/navigation/line3d.gd
Normal 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()
|
||||
@@ -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.
@@ -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 |
@@ -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
|
||||
Reference in New Issue
Block a user