Added node for Navigation links

This commit is contained in:
Josh Jones 2022-01-30 15:39:52 -08:00
parent 4808d01b2b
commit 3dd59013f4
34 changed files with 2563 additions and 49 deletions

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationLink2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Creates a link between two locations that [NavigationServer2D] can route agents through.
</brief_description>
<description>
Creates a link between two locations that [NavigationServer2D] can route agents through. Links can be used to express navigation methods that aren't just traveling along the surface of the navigation mesh, like zip-lines, teleporters, or jumping across gaps.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="set_navigation_layer_value">
<return type="void" />
<param index="0" name="layer_number" type="int" />
<param index="1" name="value" type="bool" />
<description>
Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
<members>
<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
Whether this link can be traveled in both directions or only from [member start_location] to [member end_location].
</member>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
Whether this link is currently active. If [code]false[/code], [method NavigationServer2D.map_get_path] will ignore this link.
</member>
<member name="end_location" type="Vector2" setter="set_end_location" getter="get_end_location" default="Vector2(0, 0)">
Ending position of the link.
This position will search out the nearest polygon in the navigation mesh to attach to.
The distance the link will search is controlled by [method NavigationServer2D.map_set_link_connection_radius].
</member>
<member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer2D.map_get_path].
</member>
<member name="start_location" type="Vector2" setter="set_start_location" getter="get_start_location" default="Vector2(0, 0)">
Starting position of the link.
This position will search out the nearest polygon in the navigation mesh to attach to.
The distance the link will search is controlled by [method NavigationServer2D.map_set_link_connection_radius].
</member>
<member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
When pathfinding moves along the link the traveled distance is multiplied with [code]travel_cost[/code] for determining the shortest path.
</member>
</members>
</class>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationLink3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Creates a link between two locations that [NavigationServer3D] can route agents through.
</brief_description>
<description>
Creates a link between two locations that [NavigationServer3D] can route agents through. Links can be used to express navigation methods that aren't just traveling along the surface of the navigation mesh, like zip-lines, teleporters, or jumping across gaps.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="set_navigation_layer_value">
<return type="void" />
<param index="0" name="layer_number" type="int" />
<param index="1" name="value" type="bool" />
<description>
Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
</methods>
<members>
<member name="bidirectional" type="bool" setter="set_bidirectional" getter="is_bidirectional" default="true">
Whether this link can be traveled in both directions or only from [member start_location] to [member end_location].
</member>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
Whether this link is currently active. If [code]false[/code], [method NavigationServer3D.map_get_path] will ignore this link.
</member>
<member name="end_location" type="Vector3" setter="set_end_location" getter="get_end_location" default="Vector3(0, 0, 0)">
Ending position of the link.
This position will search out the nearest polygon in the navigation mesh to attach to.
The distance the link will search is controlled by [method NavigationServer3D.map_set_link_connection_radius].
</member>
<member name="enter_cost" type="float" setter="set_enter_cost" getter="get_enter_cost" default="0.0">
When pathfinding enters this link from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
</member>
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining all navigation layers the link belongs to. These navigation layers will be checked when requesting a path with [method NavigationServer3D.map_get_path].
</member>
<member name="start_location" type="Vector3" setter="set_start_location" getter="get_start_location" default="Vector3(0, 0, 0)">
Starting position of the link.
This position will search out the nearest polygon in the navigation mesh to attach to.
The distance the link will search is controlled by [method NavigationServer3D.map_set_link_connection_radius].
</member>
<member name="travel_cost" type="float" setter="set_travel_cost" getter="get_travel_cost" default="1.0">
When pathfinding moves along the link the traveled distance is multiplied with [code]travel_cost[/code] for determining the shortest path.
</member>
</members>
</class>

View file

@ -133,6 +133,117 @@
Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them.
</description>
</method>
<method name="link_create" qualifiers="const">
<return type="RID" />
<description>
Create a new link between two locations on a map.
</description>
</method>
<method name="link_get_end_location" qualifiers="const">
<return type="Vector2" />
<param index="0" name="link" type="RID" />
<description>
Returns the ending location of this [code]link[/code].
</description>
</method>
<method name="link_get_enter_cost" qualifiers="const">
<return type="float" />
<param index="0" name="link" type="RID" />
<description>
Returns the [code]enter_cost[/code] of this [code]link[/code].
</description>
</method>
<method name="link_get_map" qualifiers="const">
<return type="RID" />
<param index="0" name="link" type="RID" />
<description>
Returns the navigation map [RID] the requested [code]link[/code] is currently assigned to.
</description>
</method>
<method name="link_get_navigation_layers" qualifiers="const">
<return type="int" />
<param index="0" name="link" type="RID" />
<description>
Returns the navigation layers for this [code]link[/code].
</description>
</method>
<method name="link_get_start_location" qualifiers="const">
<return type="Vector2" />
<param index="0" name="link" type="RID" />
<description>
Returns the starting location of this [code]link[/code].
</description>
</method>
<method name="link_get_travel_cost" qualifiers="const">
<return type="float" />
<param index="0" name="link" type="RID" />
<description>
Returns the [code]travel_cost[/code] of this [code]link[/code].
</description>
</method>
<method name="link_is_bidirectional" qualifiers="const">
<return type="bool" />
<param index="0" name="link" type="RID" />
<description>
Returns whether this [code]link[/code] can be travelled in both directions.
</description>
</method>
<method name="link_set_bidirectional" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="bidirectional" type="bool" />
<description>
Sets whether this [code]link[/code] can be travelled in both directions.
</description>
</method>
<method name="link_set_end_location" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="location" type="Vector2" />
<description>
Sets the exit location for the [code]link[/code].
</description>
</method>
<method name="link_set_enter_cost" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="enter_cost" type="float" />
<description>
Sets the [code]enter_cost[/code] for this [code]link[/code].
</description>
</method>
<method name="link_set_map" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="map" type="RID" />
<description>
Sets the navigation map [RID] for the link.
</description>
</method>
<method name="link_set_navigation_layers" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="navigation_layers" type="int" />
<description>
Set the links's navigation layers. This allows selecting links from a path request (when using [method NavigationServer2D.map_get_path]).
</description>
</method>
<method name="link_set_start_location" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="location" type="Vector2" />
<description>
Sets the entry location for this [code]link[/code].
</description>
</method>
<method name="link_set_travel_cost" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="travel_cost" type="float" />
<description>
Sets the [code]travel_cost[/code] for this [code]link[/code].
</description>
</method>
<method name="map_create" qualifiers="const">
<return type="RID" />
<description>
@ -186,6 +297,20 @@
Returns the edge connection margin of the map. The edge connection margin is a distance used to connect two regions.
</description>
</method>
<method name="map_get_link_connection_radius" qualifiers="const">
<return type="float" />
<param index="0" name="map" type="RID" />
<description>
Returns the link connection radius of the map. This distance is the maximum range any link will search for navigation mesh polygons to connect to.
</description>
</method>
<method name="map_get_links" qualifiers="const">
<return type="RID[]" />
<param index="0" name="map" type="RID" />
<description>
Returns all navigation link [RID]s that are currently assigned to the requested navigation [code]map[/code].
</description>
</method>
<method name="map_get_path" qualifiers="const">
<return type="PackedVector2Array" />
<param index="0" name="map" type="RID" />
@ -235,6 +360,14 @@
Set the map edge connection margin used to weld the compatible region edges.
</description>
</method>
<method name="map_set_link_connection_radius" qualifiers="const">
<return type="void" />
<param index="0" name="map" type="RID" />
<param index="1" name="radius" type="float" />
<description>
Set the map's link connection radius used to connect links to navigation polygons.
</description>
</method>
<method name="region_create" qualifiers="const">
<return type="RID" />
<description>

View file

@ -133,6 +133,117 @@
Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them.
</description>
</method>
<method name="link_create" qualifiers="const">
<return type="RID" />
<description>
Create a new link between two locations on a map.
</description>
</method>
<method name="link_get_end_location" qualifiers="const">
<return type="Vector3" />
<param index="0" name="link" type="RID" />
<description>
Returns the ending location of this [code]link[/code].
</description>
</method>
<method name="link_get_enter_cost" qualifiers="const">
<return type="float" />
<param index="0" name="link" type="RID" />
<description>
Returns the [code]enter_cost[/code] of this [code]link[/code].
</description>
</method>
<method name="link_get_map" qualifiers="const">
<return type="RID" />
<param index="0" name="link" type="RID" />
<description>
Returns the navigation map [RID] the requested [code]link[/code] is currently assigned to.
</description>
</method>
<method name="link_get_navigation_layers" qualifiers="const">
<return type="int" />
<param index="0" name="link" type="RID" />
<description>
Returns the navigation layers for this [code]link[/code].
</description>
</method>
<method name="link_get_start_location" qualifiers="const">
<return type="Vector3" />
<param index="0" name="link" type="RID" />
<description>
Returns the starting location of this [code]link[/code].
</description>
</method>
<method name="link_get_travel_cost" qualifiers="const">
<return type="float" />
<param index="0" name="link" type="RID" />
<description>
Returns the [code]travel_cost[/code] of this [code]link[/code].
</description>
</method>
<method name="link_is_bidirectional" qualifiers="const">
<return type="bool" />
<param index="0" name="link" type="RID" />
<description>
Returns whether this [code]link[/code] can be travelled in both directions.
</description>
</method>
<method name="link_set_bidirectional" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="bidirectional" type="bool" />
<description>
Sets whether this [code]link[/code] can be travelled in both directions.
</description>
</method>
<method name="link_set_end_location" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="location" type="Vector3" />
<description>
Sets the exit location for the [code]link[/code].
</description>
</method>
<method name="link_set_enter_cost" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="enter_cost" type="float" />
<description>
Sets the [code]enter_cost[/code] for this [code]link[/code].
</description>
</method>
<method name="link_set_map" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="map" type="RID" />
<description>
Sets the navigation map [RID] for the link.
</description>
</method>
<method name="link_set_navigation_layers" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="navigation_layers" type="int" />
<description>
Set the links's navigation layers. This allows selecting links from a path request (when using [method NavigationServer3D.map_get_path]).
</description>
</method>
<method name="link_set_start_location" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="location" type="Vector3" />
<description>
Sets the entry location for this [code]link[/code].
</description>
</method>
<method name="link_set_travel_cost" qualifiers="const">
<return type="void" />
<param index="0" name="link" type="RID" />
<param index="1" name="travel_cost" type="float" />
<description>
Sets the [code]travel_cost[/code] for this [code]link[/code].
</description>
</method>
<method name="map_create" qualifiers="const">
<return type="RID" />
<description>
@ -204,6 +315,20 @@
Returns the edge connection margin of the map. This distance is the minimum vertex distance needed to connect two edges from different regions.
</description>
</method>
<method name="map_get_link_connection_radius" qualifiers="const">
<return type="float" />
<param index="0" name="map" type="RID" />
<description>
Returns the link connection radius of the map. This distance is the maximum range any link will search for navigation mesh polygons to connect to.
</description>
</method>
<method name="map_get_links" qualifiers="const">
<return type="RID[]" />
<param index="0" name="map" type="RID" />
<description>
Returns all navigation link [RID]s that are currently assigned to the requested navigation [code]map[/code].
</description>
</method>
<method name="map_get_path" qualifiers="const">
<return type="PackedVector3Array" />
<param index="0" name="map" type="RID" />
@ -260,6 +385,14 @@
Set the map edge connection margin used to weld the compatible region edges.
</description>
</method>
<method name="map_set_link_connection_radius" qualifiers="const">
<return type="void" />
<param index="0" name="map" type="RID" />
<param index="1" name="radius" type="float" />
<description>
Set the map's link connection radius used to connect links to navigation polygons.
</description>
</method>
<method name="map_set_up" qualifiers="const">
<return type="void" />
<param index="0" name="map" type="RID" />

View file

@ -497,6 +497,12 @@
<member name="debug/shapes/navigation/enable_geometry_face_random_color" type="bool" setter="" getter="" default="true">
If enabled, colorizes each navigation mesh polygon face with a random color when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/enable_link_connections" type="bool" setter="" getter="" default="true">
If enabled, displays navigation link connections when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/enable_link_connections_xray" type="bool" setter="" getter="" default="true">
If enabled, displays navigation link connections through geometry when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
@ -512,6 +518,12 @@
<member name="debug/shapes/navigation/geometry_face_disabled_color" type="Color" setter="" getter="" default="Color(0.5, 0.5, 0.5, 0.4)">
Color to display disabled navigation mesh polygon faces, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/link_connection_color" type="Color" setter="" getter="" default="Color(1, 0.5, 1, 1)">
Color to use to display navigation link connections, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/navigation/link_connection_disabled_color" type="Color" setter="" getter="" default="Color(0.5, 0.5, 0.5, 1)">
Color to use to display disabled navigation link connections, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
<member name="debug/shapes/paths/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
Color of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu.
</member>
@ -1439,12 +1451,18 @@
<member name="navigation/2d/default_edge_connection_margin" type="int" setter="" getter="" default="1">
Default edge connection margin for 2D navigation maps. See [method NavigationServer2D.map_set_edge_connection_margin].
</member>
<member name="navigation/2d/default_link_connection_radius" type="int" setter="" getter="" default="4">
Default link connection radius for 2D navigation maps. See [method NavigationServer2D.map_set_link_connection_radius].
</member>
<member name="navigation/3d/default_cell_size" type="float" setter="" getter="" default="0.25">
Default cell size for 3D navigation maps. See [method NavigationServer3D.map_set_cell_size].
</member>
<member name="navigation/3d/default_edge_connection_margin" type="float" setter="" getter="" default="0.25">
Default edge connection margin for 3D navigation maps. See [method NavigationServer3D.map_set_edge_connection_margin].
</member>
<member name="navigation/3d/default_link_connection_radius" type="float" setter="" getter="" default="1.0">
Default link connection radius for 3D navigation maps. See [method NavigationServer3D.map_set_link_connection_radius].
</member>
<member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="32768">
Maximum number of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
</member>

View file

@ -170,6 +170,7 @@
#include "editor/plugins/mesh_instance_3d_editor_plugin.h"
#include "editor/plugins/mesh_library_editor_plugin.h"
#include "editor/plugins/multimesh_editor_plugin.h"
#include "editor/plugins/navigation_link_2d_editor_plugin.h"
#include "editor/plugins/navigation_polygon_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/occluder_instance_3d_editor_plugin.h"
@ -7293,6 +7294,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(GPUParticles2DEditorPlugin));
add_editor_plugin(memnew(LightOccluder2DEditorPlugin));
add_editor_plugin(memnew(Line2DEditorPlugin));
add_editor_plugin(memnew(NavigationLink2DEditorPlugin));
add_editor_plugin(memnew(NavigationPolygonEditorPlugin));
add_editor_plugin(memnew(Path2DEditorPlugin));
add_editor_plugin(memnew(Polygon2DEditorPlugin));

View file

@ -0,0 +1,4 @@
<svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#8ea6f4" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/>
<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#8ea6f4" fill-opacity=".99608"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,4 @@
<svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="m12.386 5.3097c-0.69157-0.021112-1.3071 0.36382-1.7492 0.86685-0.58 0.58-1.16 1.16-1.74 1.74 0.4588-0.28502 1.0599-0.064948 1.4771-0.037996 0.45549-0.44357 0.89024-0.91006 1.3596-1.3383 0.56256-0.44564 1.4906-0.15731 1.7028 0.52802 0.18967 0.4871-0.049221 1.0098-0.43284 1.3208-0.70048 0.68896-1.3789 1.4022-2.0935 2.0755-0.47999 0.3725-1.2044 0.226-1.5679-0.24034-0.38763-0.38194-1.0641 0.16031-0.78317 0.6241 0.6767 0.94379 2.1573 1.1282 3.0411 0.36751 0.80287-0.7704 1.5793-1.5696 2.3665-2.3564 0.79925-0.83719 0.70104-2.3112-0.19552-3.0393-0.38108-0.32877-0.8822-0.5119-1.385-0.51049zm-3.051 3.051c-0.69157-0.021106-1.3071 0.36382-1.7492 0.86685-0.67513 0.68452-1.37 1.3506-2.0319 2.0474-0.75433 0.87744-0.58087 2.3428 0.34933 3.0252 0.84748 0.68613 2.192 0.54839 2.8998-0.27341 0.63032-0.63031 1.2606-1.2606 1.8909-1.8909-0.4587 0.28554-1.0602 0.0659-1.477 0.038069-0.45445 0.44348-0.88773 0.91034-1.3564 1.3383-0.56256 0.44565-1.4906 0.15731-1.7028-0.52802-0.18967-0.4871 0.049229-1.0098 0.43284-1.3208 0.70048-0.68896 1.3789-1.4022 2.0935-2.0755 0.48-0.3725 1.2044-0.22601 1.5679 0.24036 0.38733 0.38325 1.064-0.16067 0.78313-0.6241-0.39353-0.52481-1.0429-0.84871-1.7002-0.8434z" fill="#fc7e7e" fill-opacity=".99608" stroke-linecap="round" stroke-linejoin="round" stroke-width=".013911"/>
<path d="m2 1c-0.61942-0.0066969-1.0877 0.60314-1 1.198 0.00345 3.968-0.006897 7.9364 0.00517 11.904 0.043388 0.62851 0.69346 0.98513 1.272 0.89776h2.5896c-0.77174-0.5015-1.2078-1.2613-1.3143-2.3356-0.11601-1.1701 0.63729-2.024 1.6748-3.1566 0.65335-0.71326 1.4757-1.5822 2.3587-2.3316 0.76308-0.64765 1.7509-1.679 2.9376-2.578 0.91259-0.69136 2.2893-0.74691 3.1014-0.33143 0.91184 0.46649 1.2635 1.1209 1.4067 1.3826-0.0052-2.335-0.02135-1.3526-0.03955-3.6863 5e-3 -0.64349-0.67497-1.0568-1.2694-0.96289z" fill="#fc7d7d" fill-opacity=".99608"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,191 @@
/*************************************************************************/
/* navigation_link_2d_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "navigation_link_2d_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "servers/navigation_server_3d.h"
void NavigationLink2DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
get_tree()->connect("node_removed", callable_mp(this, &NavigationLink2DEditor::_node_removed));
} break;
case NOTIFICATION_EXIT_TREE: {
get_tree()->disconnect("node_removed", callable_mp(this, &NavigationLink2DEditor::_node_removed));
} break;
}
}
void NavigationLink2DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
node = nullptr;
}
}
bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
if (!node || !node->is_visible_in_tree()) {
return false;
}
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
// Start location
if (xform.xform(node->get_start_location()).distance_to(mb->get_position()) < grab_threshold) {
start_grabbed = true;
original_start_location = node->get_start_location();
return true;
} else {
start_grabbed = false;
}
// End location
if (xform.xform(node->get_end_location()).distance_to(mb->get_position()) < grab_threshold) {
end_grabbed = true;
original_end_location = node->get_end_location();
return true;
} else {
end_grabbed = false;
}
} else {
if (start_grabbed) {
undo_redo->create_action(TTR("Set start_location"));
undo_redo->add_do_method(node, "set_start_location", node->get_start_location());
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(node, "set_start_location", original_start_location);
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
start_grabbed = false;
return true;
}
if (end_grabbed) {
undo_redo->create_action(TTR("Set end_location"));
undo_redo->add_do_method(node, "set_end_location", node->get_end_location());
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(node, "set_end_location", original_end_location);
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
end_grabbed = false;
return true;
}
}
}
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
Vector2 point = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position()));
point = node->get_global_transform().affine_inverse().xform(point);
if (start_grabbed) {
node->set_start_location(point);
canvas_item_editor->update_viewport();
return true;
}
if (end_grabbed) {
node->set_end_location(point);
canvas_item_editor->update_viewport();
return true;
}
}
return false;
}
void NavigationLink2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!node || !node->is_visible_in_tree()) {
return;
}
Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
Vector2 global_start_location = gt.xform(node->get_start_location());
Vector2 global_end_location = gt.xform(node->get_end_location());
// Only drawing the handles here, since the debug rendering will fill in the rest.
const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
p_overlay->draw_texture(handle, global_start_location - handle->get_size() / 2);
p_overlay->draw_texture(handle, global_end_location - handle->get_size() / 2);
}
void NavigationLink2DEditor::edit(NavigationLink2D *p_node) {
if (!canvas_item_editor) {
canvas_item_editor = CanvasItemEditor::get_singleton();
}
if (p_node) {
node = p_node;
} else {
node = nullptr;
}
canvas_item_editor->update_viewport();
}
NavigationLink2DEditor::NavigationLink2DEditor() {
undo_redo = EditorNode::get_undo_redo();
}
///////////////////////
void NavigationLink2DEditorPlugin::edit(Object *p_object) {
editor->edit(Object::cast_to<NavigationLink2D>(p_object));
}
bool NavigationLink2DEditorPlugin::handles(Object *p_object) const {
return Object::cast_to<NavigationLink2D>(p_object) != nullptr;
}
void NavigationLink2DEditorPlugin::make_visible(bool p_visible) {
if (!p_visible) {
edit(nullptr);
}
}
NavigationLink2DEditorPlugin::NavigationLink2DEditorPlugin() {
editor = memnew(NavigationLink2DEditor);
EditorNode::get_singleton()->get_gui_base()->add_child(editor);
}

View file

@ -0,0 +1,83 @@
/*************************************************************************/
/* navigation_link_2d_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
#define NAVIGATION_LINK_2D_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
#include "scene/2d/navigation_link_2d.h"
class CanvasItemEditor;
class EditorUndoRedoManager;
class NavigationLink2DEditor : public Control {
GDCLASS(NavigationLink2DEditor, Control);
Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
NavigationLink2D *node;
bool start_grabbed = false;
Vector2 original_start_location;
bool end_grabbed = false;
Vector2 original_end_location;
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
public:
bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
void forward_canvas_draw_over_viewport(Control *p_overlay);
void edit(NavigationLink2D *p_node);
NavigationLink2DEditor();
};
class NavigationLink2DEditorPlugin : public EditorPlugin {
GDCLASS(NavigationLink2DEditorPlugin, EditorPlugin);
NavigationLink2DEditor *editor = nullptr;
public:
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return editor->forward_canvas_gui_input(p_event); }
virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { editor->forward_canvas_draw_over_viewport(p_overlay); }
virtual String get_name() const override { return "NavigationLink2D"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
NavigationLink2DEditorPlugin();
};
#endif // NAVIGATION_LINK_2D_EDITOR_PLUGIN_H

View file

@ -54,6 +54,7 @@
#include "scene/3d/lightmap_probe.h"
#include "scene/3d/marker_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_link_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/occluder_instance_3d.h"
#include "scene/3d/ray_cast_3d.h"
@ -4998,6 +4999,175 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
////
NavigationLink3DGizmoPlugin::NavigationLink3DGizmoPlugin() {
create_material("navigation_link_material", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_color());
create_material("navigation_link_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_disabled_color());
create_handle_material("handles");
}
bool NavigationLink3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<NavigationLink3D>(p_spatial) != nullptr;
}
String NavigationLink3DGizmoPlugin::get_gizmo_name() const {
return "NavigationLink3D";
}
int NavigationLink3DGizmoPlugin::get_priority() const {
return -1;
}
void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
RID nav_map = link->get_world_3d()->get_navigation_map();
real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map);
Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map);
Vector3::Axis up_axis = up_vector.max_axis_index();
Vector3 start_location = link->get_start_location();
Vector3 end_location = link->get_end_location();
Ref<Material> link_material = get_material("navigation_link_material", p_gizmo);
Ref<Material> link_material_disabled = get_material("navigation_link_material_disabled", p_gizmo);
Ref<Material> handles_material = get_material("handles");
p_gizmo->clear();
// Draw line between the points.
Vector<Vector3> lines;
lines.append(start_location);
lines.append(end_location);
// Draw start location search radius
for (int i = 0; i < 30; i++) {
// Create a circle
const float ra = Math::deg_to_rad((float)(i * 12));
const float rb = Math::deg_to_rad((float)((i + 1) * 12));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
// Draw axis-aligned circle
switch (up_axis) {
case Vector3::AXIS_X:
lines.append(start_location + Vector3(0, a.x, a.y));
lines.append(start_location + Vector3(0, b.x, b.y));
break;
case Vector3::AXIS_Y:
lines.append(start_location + Vector3(a.x, 0, a.y));
lines.append(start_location + Vector3(b.x, 0, b.y));
break;
case Vector3::AXIS_Z:
lines.append(start_location + Vector3(a.x, a.y, 0));
lines.append(start_location + Vector3(b.x, b.y, 0));
break;
}
}
// Draw end location search radius
for (int i = 0; i < 30; i++) {
// Create a circle
const float ra = Math::deg_to_rad((float)(i * 12));
const float rb = Math::deg_to_rad((float)((i + 1) * 12));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
// Draw axis-aligned circle
switch (up_axis) {
case Vector3::AXIS_X:
lines.append(end_location + Vector3(0, a.x, a.y));
lines.append(end_location + Vector3(0, b.x, b.y));
break;
case Vector3::AXIS_Y:
lines.append(end_location + Vector3(a.x, 0, a.y));
lines.append(end_location + Vector3(b.x, 0, b.y));
break;
case Vector3::AXIS_Z:
lines.append(end_location + Vector3(a.x, a.y, 0));
lines.append(end_location + Vector3(b.x, b.y, 0));
break;
}
}
p_gizmo->add_lines(lines, link->is_enabled() ? link_material : link_material_disabled);
p_gizmo->add_collision_segments(lines);
Vector<Vector3> handles;
handles.append(start_location);
handles.append(end_location);
p_gizmo->add_handles(handles, handles_material);
}
String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
return p_id == 0 ? TTR("Start Location") : TTR("End Location");
}
Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
return p_id == 0 ? link->get_start_location() : link->get_end_location();
}
void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
Transform3D gt = link->get_global_transform();
Transform3D gi = gt.affine_inverse();
Transform3D ct = p_camera->get_global_transform();
Vector3 cam_dir = ct.basis.get_column(Vector3::AXIS_Z);
Vector3 ray_from = p_camera->project_ray_origin(p_point);
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
Vector3 location = p_id == 0 ? link->get_start_location() : link->get_end_location();
Plane move_plane = Plane(cam_dir, gt.xform(location));
Vector3 intersection;
if (!move_plane.intersects_ray(ray_from, ray_dir, &intersection)) {
return;
}
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
double snap = Node3DEditor::get_singleton()->get_translate_snap();
intersection.snap(Vector3(snap, snap, snap));
}
location = gi.xform(intersection);
if (p_id == 0) {
link->set_start_location(location);
} else if (p_id == 1) {
link->set_end_location(location);
}
}
void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
if (p_cancel) {
if (p_id == 0) {
link->set_start_location(p_restore);
} else {
link->set_end_location(p_restore);
}
return;
}
Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (p_id == 0) {
ur->create_action(TTR("Change Start Location"));
ur->add_do_method(link, "set_start_location", link->get_start_location());
ur->add_undo_method(link, "set_start_location", p_restore);
} else {
ur->create_action(TTR("Change End Location"));
ur->add_do_method(link, "set_end_location", link->get_end_location());
ur->add_undo_method(link, "set_end_location", p_restore);
}
ur->commit_action();
}
//////
#define BODY_A_RADIUS 0.25

View file

@ -631,6 +631,23 @@ public:
NavigationRegion3DGizmoPlugin();
};
class NavigationLink3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(NavigationLink3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
NavigationLink3DGizmoPlugin();
};
class JointGizmosDrawer {
public:
static Basis look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform);

View file

@ -7520,6 +7520,7 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<CollisionObject3DGizmoPlugin>(memnew(CollisionObject3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin)));
add_gizmo_plugin(Ref<CollisionPolygon3DGizmoPlugin>(memnew(CollisionPolygon3DGizmoPlugin)));
add_gizmo_plugin(Ref<NavigationLink3DGizmoPlugin>(memnew(NavigationLink3DGizmoPlugin)));
add_gizmo_plugin(Ref<NavigationRegion3DGizmoPlugin>(memnew(NavigationRegion3DGizmoPlugin)));
add_gizmo_plugin(Ref<Joint3DGizmoPlugin>(memnew(Joint3DGizmoPlugin)));
add_gizmo_plugin(Ref<PhysicalBone3DGizmoPlugin>(memnew(PhysicalBone3DGizmoPlugin)));

View file

@ -210,6 +210,20 @@ real_t GodotNavigationServer::map_get_edge_connection_margin(RID p_map) const {
return map->get_edge_connection_margin();
}
COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius) {
NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
map->set_link_connection_radius(p_connection_radius);
}
real_t GodotNavigationServer::map_get_link_connection_radius(RID p_map) const {
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, 0);
return map->get_link_connection_radius();
}
Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) const {
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>());
@ -245,6 +259,20 @@ RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3
return map->get_closest_point_owner(p_point);
}
TypedArray<RID> GodotNavigationServer::map_get_links(RID p_map) const {
TypedArray<RID> link_rids;
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, link_rids);
const LocalVector<NavLink *> links = map->get_links();
link_rids.resize(links.size());
for (uint32_t i = 0; i < links.size(); i++) {
link_rids[i] = links[i]->get_self();
}
return link_rids;
}
TypedArray<RID> GodotNavigationServer::map_get_regions(RID p_map) const {
TypedArray<RID> regions_rids;
const NavMap *map = map_owner.get_or_null(p_map);
@ -417,6 +445,131 @@ Vector3 GodotNavigationServer::region_get_connection_pathway_end(RID p_region, i
return region->get_connection_pathway_end(p_connection_id);
}
RID GodotNavigationServer::link_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
RID rid = link_owner.make_rid();
NavLink *link = link_owner.get_or_null(rid);
link->set_self(rid);
return rid;
}
COMMAND_2(link_set_map, RID, p_link, RID, p_map) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
if (link->get_map() != nullptr) {
if (link->get_map()->get_self() == p_map) {
return; // Pointless
}
link->get_map()->remove_link(link);
link->set_map(nullptr);
}
if (p_map.is_valid()) {
NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
map->add_link(link);
link->set_map(map);
}
}
RID GodotNavigationServer::link_get_map(const RID p_link) const {
const NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND_V(link == nullptr, RID());
if (link->get_map()) {
return link->get_map()->get_self();
}
return RID();
}
COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
link->set_bidirectional(p_bidirectional);
}
bool GodotNavigationServer::link_is_bidirectional(RID p_link) const {
const NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND_V(link == nullptr, false);
return link->is_bidirectional();
}
COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
link->set_navigation_layers(p_navigation_layers);
}
uint32_t GodotNavigationServer::link_get_navigation_layers(const RID p_link) const {
const NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND_V(link == nullptr, 0);
return link->get_navigation_layers();
}
COMMAND_2(link_set_start_location, RID, p_link, Vector3, p_location) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
link->set_start_location(p_location);
}
Vector3 GodotNavigationServer::link_get_start_location(RID p_link) const {
const NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND_V(link == nullptr, Vector3());
return link->get_start_location();
}
COMMAND_2(link_set_end_location, RID, p_link, Vector3, p_location) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
link->set_end_location(p_location);
}
Vector3 GodotNavigationServer::link_get_end_location(RID p_link) const {
const NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND_V(link == nullptr, Vector3());
return link->get_end_location();
}
COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
link->set_enter_cost(p_enter_cost);
}
real_t GodotNavigationServer::link_get_enter_cost(const RID p_link) const {
const NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND_V(link == nullptr, 0);
return link->get_enter_cost();
}
COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost) {
NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND(link == nullptr);
link->set_travel_cost(p_travel_cost);
}
real_t GodotNavigationServer::link_get_travel_cost(const RID p_link) const {
const NavLink *link = link_owner.get_or_null(p_link);
ERR_FAIL_COND_V(link == nullptr, 0);
return link->get_travel_cost();
}
RID GodotNavigationServer::agent_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
@ -549,6 +702,13 @@ COMMAND_1(free, RID, p_object) {
regions[i]->set_map(nullptr);
}
// Removes any assigned links
LocalVector<NavLink *> links = map->get_links();
for (uint32_t i = 0; i < links.size(); i++) {
map->remove_link(links[i]);
links[i]->set_map(nullptr);
}
// Remove any assigned agent
LocalVector<RvoAgent *> agents = map->get_agents();
for (uint32_t i = 0; i < agents.size(); i++) {
@ -572,6 +732,17 @@ COMMAND_1(free, RID, p_object) {
region_owner.free(p_object);
} else if (link_owner.owns(p_object)) {
NavLink *link = link_owner.get_or_null(p_object);
// Removes this link from the map if assigned
if (link->get_map() != nullptr) {
link->get_map()->remove_link(link);
link->set_map(nullptr);
}
link_owner.free(p_object);
} else if (agent_owner.owns(p_object)) {
RvoAgent *agent = agent_owner.get_or_null(p_object);

View file

@ -36,6 +36,7 @@
#include "core/templates/rid_owner.h"
#include "servers/navigation_server_3d.h"
#include "nav_link.h"
#include "nav_map.h"
#include "nav_region.h"
#include "rvo_agent.h"
@ -71,6 +72,7 @@ class GodotNavigationServer : public NavigationServer3D {
LocalVector<SetCommand *> commands;
mutable RID_Owner<NavLink> link_owner;
mutable RID_Owner<NavMap> map_owner;
mutable RID_Owner<NavRegion> region_owner;
mutable RID_Owner<RvoAgent> agent_owner;
@ -100,6 +102,9 @@ public:
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin);
virtual real_t map_get_edge_connection_margin(RID p_map) const override;
COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius);
virtual real_t map_get_link_connection_radius(RID p_map) const override;
virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override;
virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override;
@ -107,6 +112,7 @@ public:
virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override;
virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override;
virtual TypedArray<RID> map_get_links(RID p_map) const override;
virtual TypedArray<RID> map_get_regions(RID p_map) const override;
virtual TypedArray<RID> map_get_agents(RID p_map) const override;
@ -132,6 +138,22 @@ public:
virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
virtual RID link_create() const override;
COMMAND_2(link_set_map, RID, p_link, RID, p_map);
virtual RID link_get_map(RID p_link) const override;
COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional);
virtual bool link_is_bidirectional(RID p_link) const override;
COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers);
virtual uint32_t link_get_navigation_layers(RID p_link) const override;
COMMAND_2(link_set_start_location, RID, p_link, Vector3, p_location);
virtual Vector3 link_get_start_location(RID p_link) const override;
COMMAND_2(link_set_end_location, RID, p_link, Vector3, p_location);
virtual Vector3 link_get_end_location(RID p_link) const override;
COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost);
virtual real_t link_get_enter_cost(RID p_link) const override;
COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost);
virtual real_t link_get_travel_cost(RID p_link) const override;
virtual RID agent_create() const override;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
virtual RID agent_get_map(RID p_agent) const override;

View file

@ -0,0 +1,56 @@
/*************************************************************************/
/* nav_base.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef NAV_BASE_H
#define NAV_BASE_H
#include "nav_rid.h"
#include "nav_utils.h"
class NavMap;
class NavBase : public NavRid {
protected:
uint32_t navigation_layers = 1;
float enter_cost = 0.0;
float travel_cost = 1.0;
public:
void set_navigation_layers(uint32_t p_navigation_layers) { navigation_layers = p_navigation_layers; }
uint32_t get_navigation_layers() const { return navigation_layers; }
void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
float get_enter_cost() const { return enter_cost; }
void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
float get_travel_cost() const { return travel_cost; }
};
#endif // NAV_BASE_H

View file

@ -0,0 +1,60 @@
/*************************************************************************/
/* nav_link.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "nav_link.h"
#include "nav_map.h"
void NavLink::set_map(NavMap *p_map) {
map = p_map;
link_dirty = true;
}
void NavLink::set_bidirectional(bool p_bidirectional) {
bidirectional = p_bidirectional;
link_dirty = true;
}
void NavLink::set_start_location(const Vector3 p_location) {
start_location = p_location;
link_dirty = true;
}
void NavLink::set_end_location(const Vector3 p_location) {
end_location = p_location;
link_dirty = true;
}
bool NavLink::check_dirty() {
const bool was_dirty = link_dirty;
link_dirty = false;
return was_dirty;
}

View file

@ -0,0 +1,69 @@
/*************************************************************************/
/* nav_link.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef NAV_LINK_H
#define NAV_LINK_H
#include "nav_base.h"
#include "nav_utils.h"
class NavLink : public NavBase {
NavMap *map = nullptr;
bool bidirectional = true;
Vector3 start_location = Vector3();
Vector3 end_location = Vector3();
bool link_dirty = true;
public:
void set_map(NavMap *p_map);
NavMap *get_map() const {
return map;
}
void set_bidirectional(bool p_bidirectional);
bool is_bidirectional() const {
return bidirectional;
}
void set_start_location(Vector3 p_location);
Vector3 get_start_location() const {
return start_location;
}
void set_end_location(Vector3 p_location);
Vector3 get_end_location() const {
return end_location;
}
bool check_dirty();
};
#endif // NAV_LINK_H

View file

@ -31,6 +31,7 @@
#include "nav_map.h"
#include "core/object/worker_thread_pool.h"
#include "nav_link.h"
#include "nav_region.h"
#include "rvo_agent.h"
#include <algorithm>
@ -52,6 +53,11 @@ void NavMap::set_edge_connection_margin(float p_edge_connection_margin) {
regenerate_links = true;
}
void NavMap::set_link_connection_radius(float p_link_connection_radius) {
link_connection_radius = p_link_connection_radius;
regenerate_links = true;
}
gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
const int x = int(Math::floor(p_pos.x / cell_size));
const int y = int(Math::floor(p_pos.y / cell_size));
@ -158,17 +164,17 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
continue;
}
float region_enter_cost = 0.0;
float region_travel_cost = least_cost_poly->poly->owner->get_travel_cost();
float poly_enter_cost = 0.0;
float poly_travel_cost = least_cost_poly->poly->owner->get_travel_cost();
if (prev_least_cost_poly != nullptr && !(prev_least_cost_poly->poly->owner->get_self() == least_cost_poly->poly->owner->get_self())) {
region_enter_cost = least_cost_poly->poly->owner->get_enter_cost();
if (prev_least_cost_poly != nullptr && (prev_least_cost_poly->poly->owner->get_self() != least_cost_poly->poly->owner->get_self())) {
poly_enter_cost = least_cost_poly->poly->owner->get_enter_cost();
}
prev_least_cost_poly = least_cost_poly;
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * region_travel_cost) + region_enter_cost + least_cost_poly->traveled_distance;
const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * poly_travel_cost) + poly_enter_cost + least_cost_poly->traveled_distance;
int64_t already_visited_polygon_index = navigation_polys.find(gd::NavigationPoly(connection.polygon));
@ -360,10 +366,15 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Add mid points
int np_id = least_cost_id;
while (np_id != -1 && navigation_polys[np_id].back_navigation_poly_id != -1) {
int prev = navigation_polys[np_id].back_navigation_edge;
int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
path.push_back(point);
if (navigation_polys[np_id].back_navigation_edge != -1) {
int prev = navigation_polys[np_id].back_navigation_edge;
int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
path.push_back(point);
} else {
path.push_back(navigation_polys[np_id].entry);
}
np_id = navigation_polys[np_id].back_navigation_poly_id;
}
@ -475,6 +486,19 @@ void NavMap::remove_region(NavRegion *p_region) {
}
}
void NavMap::add_link(NavLink *p_link) {
links.push_back(p_link);
regenerate_links = true;
}
void NavMap::remove_link(NavLink *p_link) {
int64_t link_index = links.find(p_link);
if (link_index != -1) {
links.remove_at_unordered(link_index);
regenerate_links = true;
}
}
bool NavMap::has_agent(RvoAgent *agent) const {
return (agents.find(agent) != -1);
}
@ -526,6 +550,12 @@ void NavMap::sync() {
}
}
for (uint32_t l = 0; l < links.size(); l++) {
if (links[l]->check_dirty()) {
regenerate_links = true;
}
}
if (regenerate_links) {
// Remove regions connections.
for (uint32_t r = 0; r < regions.size(); r++) {
@ -651,7 +681,121 @@ void NavMap::sync() {
free_edge.polygon->edges[free_edge.edge].connections.push_back(new_connection);
// Add the connection to the region_connection map.
free_edge.polygon->owner->get_connections().push_back(new_connection);
((NavRegion *)free_edge.polygon->owner)->get_connections().push_back(new_connection);
}
}
uint32_t link_poly_idx = 0;
link_polygons.resize(links.size());
// Search for polygons within range of a nav link.
for (uint32_t l = 0; l < links.size(); l++) {
const NavLink *link = links[l];
const Vector3 start = link->get_start_location();
const Vector3 end = link->get_end_location();
gd::Polygon *closest_start_polygon = nullptr;
real_t closest_start_distance = link_connection_radius;
Vector3 closest_start_point;
gd::Polygon *closest_end_polygon = nullptr;
real_t closest_end_distance = link_connection_radius;
Vector3 closest_end_point;
// Create link to any polygons within the search radius of the start point.
for (uint32_t start_index = 0; start_index < polygons.size(); start_index++) {
gd::Polygon &start_poly = polygons[start_index];
// For each face check the distance to the start
for (uint32_t start_point_id = 2; start_point_id < start_poly.points.size(); start_point_id += 1) {
const Face3 start_face(start_poly.points[0].pos, start_poly.points[start_point_id - 1].pos, start_poly.points[start_point_id].pos);
const Vector3 start_point = start_face.get_closest_point_to(start);
const real_t start_distance = start_point.distance_to(start);
// Pick the polygon that is within our radius and is closer than anything we've seen yet.
if (start_distance <= link_connection_radius && start_distance < closest_start_distance) {
closest_start_distance = start_distance;
closest_start_point = start_point;
closest_start_polygon = &start_poly;
}
}
}
// Find any polygons within the search radius of the end point.
for (uint32_t end_index = 0; end_index < polygons.size(); end_index++) {
gd::Polygon &end_poly = polygons[end_index];
// For each face check the distance to the end
for (uint32_t end_point_id = 2; end_point_id < end_poly.points.size(); end_point_id += 1) {
const Face3 end_face(end_poly.points[0].pos, end_poly.points[end_point_id - 1].pos, end_poly.points[end_point_id].pos);
const Vector3 end_point = end_face.get_closest_point_to(end);
const real_t end_distance = end_point.distance_to(end);
// Pick the polygon that is within our radius and is closer than anything we've seen yet.
if (end_distance <= link_connection_radius && end_distance < closest_end_distance) {
closest_end_distance = end_distance;
closest_end_point = end_point;
closest_end_polygon = &end_poly;
}
}
}
// If we have both a start and end point, then create a synthetic polygon to route through.
if (closest_start_polygon && closest_end_polygon) {
gd::Polygon &new_polygon = link_polygons[link_poly_idx++];
new_polygon.owner = link;
new_polygon.edges.clear();
new_polygon.edges.resize(4);
new_polygon.points.clear();
new_polygon.points.reserve(4);
// Build a set of vertices that create a thin polygon going from the start to the end point.
new_polygon.points.push_back({ closest_start_point, get_point_key(closest_start_point) });
new_polygon.points.push_back({ closest_start_point, get_point_key(closest_start_point) });
new_polygon.points.push_back({ closest_end_point, get_point_key(closest_end_point) });
new_polygon.points.push_back({ closest_end_point, get_point_key(closest_end_point) });
Vector3 center;
for (int p = 0; p < 4; ++p) {
center += new_polygon.points[p].pos;
}
new_polygon.center = center / real_t(new_polygon.points.size());
new_polygon.clockwise = true;
// Setup connections to go forward in the link.
{
gd::Edge::Connection entry_connection;
entry_connection.polygon = &new_polygon;
entry_connection.edge = -1;
entry_connection.pathway_start = new_polygon.points[0].pos;
entry_connection.pathway_end = new_polygon.points[1].pos;
closest_start_polygon->edges[0].connections.push_back(entry_connection);
gd::Edge::Connection exit_connection;
exit_connection.polygon = closest_end_polygon;
exit_connection.edge = -1;
exit_connection.pathway_start = new_polygon.points[2].pos;
exit_connection.pathway_end = new_polygon.points[3].pos;
new_polygon.edges[2].connections.push_back(exit_connection);
}
// If the link is bi-directional, create connections from the end to the start.
if (link->is_bidirectional()) {
gd::Edge::Connection entry_connection;
entry_connection.polygon = &new_polygon;
entry_connection.edge = -1;
entry_connection.pathway_start = new_polygon.points[2].pos;
entry_connection.pathway_end = new_polygon.points[3].pos;
closest_end_polygon->edges[0].connections.push_back(entry_connection);
gd::Edge::Connection exit_connection;
exit_connection.polygon = closest_start_polygon;
exit_connection.edge = -1;
exit_connection.pathway_start = new_polygon.points[0].pos;
exit_connection.pathway_end = new_polygon.points[1].pos;
new_polygon.edges[0].connections.push_back(exit_connection);
}
}
}

View file

@ -40,9 +40,9 @@
#include <KdTree.h>
class NavLink;
class NavRegion;
class RvoAgent;
class NavRegion;
class NavMap : public NavRid {
/// Map Up
@ -55,11 +55,19 @@ class NavMap : public NavRid {
/// This value is used to detect the near edges to connect.
real_t edge_connection_margin = 0.25;
/// This value is used to limit how far links search to find polygons to connect to.
real_t link_connection_radius = 1.0;
bool regenerate_polygons = true;
bool regenerate_links = true;
/// Map regions
LocalVector<NavRegion *> regions;
/// Map links
LocalVector<NavLink *> links;
LocalVector<gd::Polygon> link_polygons;
/// Map polygons
LocalVector<gd::Polygon> polygons;
@ -100,6 +108,11 @@ public:
return edge_connection_margin;
}
void set_link_connection_radius(float p_link_connection_radius);
float get_link_connection_radius() const {
return link_connection_radius;
}
gd::PointKey get_point_key(const Vector3 &p_pos) const;
Vector<Vector3> get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
@ -115,6 +128,12 @@ public:
return regions;
}
void add_link(NavLink *p_link);
void remove_link(NavLink *p_link);
const LocalVector<NavLink *> &get_links() const {
return links;
}
bool has_agent(RvoAgent *agent) const;
void add_agent(RvoAgent *agent);
void remove_agent(RvoAgent *agent);

View file

@ -40,14 +40,6 @@ void NavRegion::set_map(NavMap *p_map) {
}
}
void NavRegion::set_navigation_layers(uint32_t p_navigation_layers) {
navigation_layers = p_navigation_layers;
}
uint32_t NavRegion::get_navigation_layers() const {
return navigation_layers;
}
void NavRegion::set_transform(Transform3D p_transform) {
transform = p_transform;
polygons_dirty = true;

View file

@ -33,21 +33,13 @@
#include "scene/resources/navigation_mesh.h"
#include "nav_rid.h"
#include "nav_base.h"
#include "nav_utils.h"
#include <vector>
class NavMap;
class NavRegion;
class NavRegion : public NavRid {
class NavRegion : public NavBase {
NavMap *map = nullptr;
Transform3D transform;
Ref<NavigationMesh> mesh;
uint32_t navigation_layers = 1;
float enter_cost = 0.0;
float travel_cost = 1.0;
Vector<gd::Edge::Connection> connections;
bool polygons_dirty = true;
@ -67,15 +59,6 @@ public:
return map;
}
void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
float get_enter_cost() const { return enter_cost; }
void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
float get_travel_cost() const { return travel_cost; }
void set_navigation_layers(uint32_t p_navigation_layers);
uint32_t get_navigation_layers() const;
void set_transform(Transform3D transform);
const Transform3D &get_transform() const {
return transform;

View file

@ -35,9 +35,8 @@
#include "core/templates/hash_map.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/local_vector.h"
#include <vector>
class NavRegion;
class NavBase;
namespace gd {
struct Polygon;
@ -79,26 +78,33 @@ struct Point {
};
struct Edge {
/// This edge ID
int this_edge = -1;
/// The gateway in the edge, as, in some case, the whole edge might not be navigable.
struct Connection {
/// Polygon that this connection leads to.
Polygon *polygon = nullptr;
/// Edge of the source polygon where this connection starts from.
int edge = -1;
/// Point on the edge where the gateway leading to the poly starts.
Vector3 pathway_start;
/// Point on the edge where the gateway leading to the poly ends.
Vector3 pathway_end;
};
/// Connections from this edge to other polygons.
Vector<Connection> connections;
};
struct Polygon {
NavRegion *owner = nullptr;
/// Navigation region or link that contains this polygon.
const NavBase *owner = nullptr;
/// The points of this `Polygon`
LocalVector<Point> points;
/// Are the points clockwise ?
/// Are the points clockwise?
bool clockwise;
/// The edges of this `Polygon`
@ -115,7 +121,7 @@ struct NavigationPoly {
/// Those 4 variables are used to travel the path backwards.
int back_navigation_poly_id = -1;
uint32_t back_navigation_edge = UINT32_MAX;
int back_navigation_edge = -1;
Vector3 back_navigation_edge_pathway_start;
Vector3 back_navigation_edge_pathway_end;

View file

@ -0,0 +1,284 @@
/*************************************************************************/
/* navigation_link_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "navigation_link_2d.h"
#include "core/math/geometry_2d.h"
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
void NavigationLink2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink2D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink2D::is_enabled);
ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink2D::set_bidirectional);
ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink2D::is_bidirectional);
ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationLink2D::set_navigation_layers);
ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationLink2D::get_navigation_layers);
ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink2D::set_navigation_layer_value);
ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink2D::get_navigation_layer_value);
ClassDB::bind_method(D_METHOD("set_start_location", "location"), &NavigationLink2D::set_start_location);
ClassDB::bind_method(D_METHOD("get_start_location"), &NavigationLink2D::get_start_location);
ClassDB::bind_method(D_METHOD("set_end_location", "location"), &NavigationLink2D::set_end_location);
ClassDB::bind_method(D_METHOD("get_end_location"), &NavigationLink2D::get_end_location);
ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink2D::set_enter_cost);
ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink2D::get_enter_cost);
ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationLink2D::set_travel_cost);
ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationLink2D::get_travel_cost);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "start_location"), "set_start_location", "get_start_location");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "end_location"), "set_end_location", "get_end_location");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
}
void NavigationLink2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
if (enabled) {
NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());
// Update global positions for the link.
Transform2D gt = get_global_transform();
NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
}
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
// Update global positions for the link.
Transform2D gt = get_global_transform();
NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
} break;
case NOTIFICATION_EXIT_TREE: {
NavigationServer2D::get_singleton()->link_set_map(link, RID());
} break;
case NOTIFICATION_DRAW: {
#ifdef DEBUG_ENABLED
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled())) {
Color color;
if (enabled) {
color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_color();
} else {
color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_disabled_color();
}
real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());
draw_line(get_start_location(), get_end_location(), color);
draw_arc(get_start_location(), radius, 0, Math_TAU, 10, color);
draw_arc(get_end_location(), radius, 0, Math_TAU, 10, color);
}
#endif // DEBUG_ENABLED
} break;
}
}
#ifdef TOOLS_ENABLED
Rect2 NavigationLink2D::_edit_get_rect() const {
real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());
Rect2 rect(get_start_location(), Size2());
rect.expand_to(get_end_location());
rect.grow_by(radius);
return rect;
}
bool NavigationLink2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
Point2 segment[2] = { get_start_location(), get_end_location() };
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, segment);
return p_point.distance_to(closest_point) < p_tolerance;
}
#endif // TOOLS_ENABLED
void NavigationLink2D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
}
enabled = p_enabled;
if (!is_inside_tree()) {
return;
}
if (!enabled) {
NavigationServer2D::get_singleton()->link_set_map(link, RID());
} else {
NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());
}
#ifdef DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
update();
}
#endif // DEBUG_ENABLED
}
void NavigationLink2D::set_bidirectional(bool p_bidirectional) {
if (bidirectional == p_bidirectional) {
return;
}
bidirectional = p_bidirectional;
NavigationServer2D::get_singleton()->link_set_bidirectional(link, bidirectional);
}
void NavigationLink2D::set_navigation_layers(uint32_t p_navigation_layers) {
if (navigation_layers == p_navigation_layers) {
return;
}
navigation_layers = p_navigation_layers;
NavigationServer2D::get_singleton()->link_set_navigation_layers(link, navigation_layers);
}
void NavigationLink2D::set_navigation_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
uint32_t _navigation_layers = get_navigation_layers();
if (p_value) {
_navigation_layers |= 1 << (p_layer_number - 1);
} else {
_navigation_layers &= ~(1 << (p_layer_number - 1));
}
set_navigation_layers(_navigation_layers);
}
bool NavigationLink2D::get_navigation_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
void NavigationLink2D::set_start_location(Vector2 p_location) {
if (start_location.is_equal_approx(p_location)) {
return;
}
start_location = p_location;
if (!is_inside_tree()) {
return;
}
Transform2D gt = get_global_transform();
NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
update_configuration_warnings();
#ifdef DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
update();
}
#endif // DEBUG_ENABLED
}
void NavigationLink2D::set_end_location(Vector2 p_location) {
if (end_location.is_equal_approx(p_location)) {
return;
}
end_location = p_location;
if (!is_inside_tree()) {
return;
}
Transform2D gt = get_global_transform();
NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
update_configuration_warnings();
#ifdef DEBUG_ENABLED
if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) {
update();
}
#endif // DEBUG_ENABLED
}
void NavigationLink2D::set_enter_cost(real_t p_enter_cost) {
ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
return;
}
enter_cost = p_enter_cost;
NavigationServer2D::get_singleton()->link_set_enter_cost(link, enter_cost);
}
void NavigationLink2D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
return;
}
travel_cost = p_travel_cost;
NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost);
}
TypedArray<String> NavigationLink2D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (start_location.is_equal_approx(end_location)) {
warnings.push_back(RTR("NavigationLink2D start location should be different than the end location to be useful."));
}
return warnings;
}
NavigationLink2D::NavigationLink2D() {
link = NavigationServer2D::get_singleton()->link_create();
set_notify_transform(true);
}
NavigationLink2D::~NavigationLink2D() {
NavigationServer2D::get_singleton()->free(link);
link = RID();
}

View file

@ -0,0 +1,88 @@
/*************************************************************************/
/* navigation_link_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef NAVIGATION_LINK_2D_H
#define NAVIGATION_LINK_2D_H
#include "scene/2d/node_2d.h"
class NavigationLink2D : public Node2D {
GDCLASS(NavigationLink2D, Node2D);
bool enabled = true;
RID link = RID();
bool bidirectional = true;
uint32_t navigation_layers = 1;
Vector2 end_location = Vector2();
Vector2 start_location = Vector2();
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
protected:
static void _bind_methods();
void _notification(int p_what);
public:
#ifdef TOOLS_ENABLED
virtual Rect2 _edit_get_rect() const override;
virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override;
#endif
void set_enabled(bool p_enabled);
bool is_enabled() const { return enabled; }
void set_bidirectional(bool p_bidirectional);
bool is_bidirectional() const { return bidirectional; }
void set_navigation_layers(uint32_t p_navigation_layers);
uint32_t get_navigation_layers() const { return navigation_layers; }
void set_navigation_layer_value(int p_layer_number, bool p_value);
bool get_navigation_layer_value(int p_layer_number) const;
void set_start_location(Vector2 p_location);
Vector2 get_start_location() const { return start_location; }
void set_end_location(Vector2 p_location);
Vector2 get_end_location() const { return end_location; }
void set_enter_cost(real_t p_enter_cost);
real_t get_enter_cost() const { return enter_cost; }
void set_travel_cost(real_t p_travel_cost);
real_t get_travel_cost() const { return travel_cost; }
TypedArray<String> get_configuration_warnings() const override;
NavigationLink2D();
~NavigationLink2D();
};
#endif // NAVIGATION_LINK_2D_H

View file

@ -0,0 +1,389 @@
/*************************************************************************/
/* navigation_link_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "navigation_link_3d.h"
#include "mesh_instance_3d.h"
#include "servers/navigation_server_3d.h"
#ifdef DEBUG_ENABLED
void NavigationLink3D::_update_debug_mesh() {
if (!is_inside_tree()) {
return;
}
if (Engine::get_singleton()->is_editor_hint()) {
// don't update inside Editor as node 3d gizmo takes care of this
// as collisions and selections for Editor Viewport need to be updated
return;
}
if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_instance, false);
}
return;
}
if (!debug_instance.is_valid()) {
debug_instance = RenderingServer::get_singleton()->instance_create();
}
if (!debug_mesh.is_valid()) {
debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
}
RID nav_map = get_world_3d()->get_navigation_map();
real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map);
Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map);
Vector3::Axis up_axis = up_vector.max_axis_index();
debug_mesh->clear_surfaces();
Vector<Vector3> lines;
// Draw line between the points.
lines.push_back(start_location);
lines.push_back(end_location);
// Draw start location search radius
for (int i = 0; i < 30; i++) {
// Create a circle
const float ra = Math::deg_to_rad((float)(i * 12));
const float rb = Math::deg_to_rad((float)((i + 1) * 12));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
// Draw axis-aligned circle
switch (up_axis) {
case Vector3::AXIS_X:
lines.append(start_location + Vector3(0, a.x, a.y));
lines.append(start_location + Vector3(0, b.x, b.y));
break;
case Vector3::AXIS_Y:
lines.append(start_location + Vector3(a.x, 0, a.y));
lines.append(start_location + Vector3(b.x, 0, b.y));
break;
case Vector3::AXIS_Z:
lines.append(start_location + Vector3(a.x, a.y, 0));
lines.append(start_location + Vector3(b.x, b.y, 0));
break;
}
}
// Draw end location search radius
for (int i = 0; i < 30; i++) {
// Create a circle
const float ra = Math::deg_to_rad((float)(i * 12));
const float rb = Math::deg_to_rad((float)((i + 1) * 12));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius;
// Draw axis-aligned circle
switch (up_axis) {
case Vector3::AXIS_X:
lines.append(end_location + Vector3(0, a.x, a.y));
lines.append(end_location + Vector3(0, b.x, b.y));
break;
case Vector3::AXIS_Y:
lines.append(end_location + Vector3(a.x, 0, a.y));
lines.append(end_location + Vector3(b.x, 0, b.y));
break;
case Vector3::AXIS_Z:
lines.append(end_location + Vector3(a.x, a.y, 0));
lines.append(end_location + Vector3(b.x, b.y, 0));
break;
}
}
Array mesh_array;
mesh_array.resize(Mesh::ARRAY_MAX);
mesh_array[Mesh::ARRAY_VERTEX] = lines;
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, mesh_array);
RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid());
RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree());
Ref<StandardMaterial3D> link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_material();
Ref<StandardMaterial3D> disabled_link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_disabled_material();
if (enabled) {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, link_material->get_rid());
} else {
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, disabled_link_material->get_rid());
}
}
#endif // DEBUG_ENABLED
void NavigationLink3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink3D::set_enabled);
ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink3D::is_enabled);
ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink3D::set_bidirectional);
ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink3D::is_bidirectional);
ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationLink3D::set_navigation_layers);
ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationLink3D::get_navigation_layers);
ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink3D::set_navigation_layer_value);
ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink3D::get_navigation_layer_value);
ClassDB::bind_method(D_METHOD("set_start_location", "location"), &NavigationLink3D::set_start_location);
ClassDB::bind_method(D_METHOD("get_start_location"), &NavigationLink3D::get_start_location);
ClassDB::bind_method(D_METHOD("set_end_location", "location"), &NavigationLink3D::set_end_location);
ClassDB::bind_method(D_METHOD("get_end_location"), &NavigationLink3D::get_end_location);
ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink3D::set_enter_cost);
ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink3D::get_enter_cost);
ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationLink3D::set_travel_cost);
ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationLink3D::get_travel_cost);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_location"), "set_start_location", "get_start_location");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "end_location"), "set_end_location", "get_end_location");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
}
void NavigationLink3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
if (enabled) {
NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map());
// Update global positions for the link.
Transform3D gt = get_global_transform();
NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
}
#ifdef DEBUG_ENABLED
_update_debug_mesh();
#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
// Update global positions for the link.
Transform3D gt = get_global_transform();
NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
#ifdef DEBUG_ENABLED
if (is_inside_tree() && debug_instance.is_valid()) {
RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
}
#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_EXIT_TREE: {
NavigationServer3D::get_singleton()->link_set_map(link, RID());
#ifdef DEBUG_ENABLED
if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_scenario(debug_instance, RID());
RS::get_singleton()->instance_set_visible(debug_instance, false);
}
#endif // DEBUG_ENABLED
} break;
}
}
NavigationLink3D::NavigationLink3D() {
link = NavigationServer3D::get_singleton()->link_create();
set_notify_transform(true);
}
NavigationLink3D::~NavigationLink3D() {
NavigationServer3D::get_singleton()->free(link);
link = RID();
#ifdef DEBUG_ENABLED
if (debug_instance.is_valid()) {
RenderingServer::get_singleton()->free(debug_instance);
}
if (debug_mesh.is_valid()) {
RenderingServer::get_singleton()->free(debug_mesh->get_rid());
}
#endif // DEBUG_ENABLED
}
void NavigationLink3D::set_enabled(bool p_enabled) {
if (enabled == p_enabled) {
return;
}
enabled = p_enabled;
if (!is_inside_tree()) {
return;
}
if (enabled) {
NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map());
} else {
NavigationServer3D::get_singleton()->link_set_map(link, RID());
}
#ifdef DEBUG_ENABLED
if (debug_instance.is_valid() && debug_mesh.is_valid()) {
if (enabled) {
Ref<StandardMaterial3D> link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_material();
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, link_material->get_rid());
} else {
Ref<StandardMaterial3D> disabled_link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_disabled_material();
RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, disabled_link_material->get_rid());
}
}
#endif // DEBUG_ENABLED
update_gizmos();
}
void NavigationLink3D::set_bidirectional(bool p_bidirectional) {
if (bidirectional == p_bidirectional) {
return;
}
bidirectional = p_bidirectional;
NavigationServer3D::get_singleton()->link_set_bidirectional(link, bidirectional);
}
void NavigationLink3D::set_navigation_layers(uint32_t p_navigation_layers) {
if (navigation_layers == p_navigation_layers) {
return;
}
navigation_layers = p_navigation_layers;
NavigationServer3D::get_singleton()->link_set_navigation_layers(link, navigation_layers);
}
void NavigationLink3D::set_navigation_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
uint32_t _navigation_layers = get_navigation_layers();
if (p_value) {
_navigation_layers |= 1 << (p_layer_number - 1);
} else {
_navigation_layers &= ~(1 << (p_layer_number - 1));
}
set_navigation_layers(_navigation_layers);
}
bool NavigationLink3D::get_navigation_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
void NavigationLink3D::set_start_location(Vector3 p_location) {
if (start_location.is_equal_approx(p_location)) {
return;
}
start_location = p_location;
if (!is_inside_tree()) {
return;
}
Transform3D gt = get_global_transform();
NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location));
#ifdef DEBUG_ENABLED
_update_debug_mesh();
#endif // DEBUG_ENABLED
update_gizmos();
update_configuration_warnings();
}
void NavigationLink3D::set_end_location(Vector3 p_location) {
if (end_location.is_equal_approx(p_location)) {
return;
}
end_location = p_location;
if (!is_inside_tree()) {
return;
}
Transform3D gt = get_global_transform();
NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location));
#ifdef DEBUG_ENABLED
_update_debug_mesh();
#endif // DEBUG_ENABLED
update_gizmos();
update_configuration_warnings();
}
void NavigationLink3D::set_enter_cost(real_t p_enter_cost) {
ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
if (Math::is_equal_approx(enter_cost, p_enter_cost)) {
return;
}
enter_cost = p_enter_cost;
NavigationServer3D::get_singleton()->link_set_enter_cost(link, enter_cost);
}
void NavigationLink3D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
if (Math::is_equal_approx(travel_cost, p_travel_cost)) {
return;
}
travel_cost = p_travel_cost;
NavigationServer3D::get_singleton()->link_set_travel_cost(link, travel_cost);
}
TypedArray<String> NavigationLink3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (start_location.is_equal_approx(end_location)) {
warnings.push_back(RTR("NavigationLink3D start location should be different than the end location to be useful."));
}
return warnings;
}

View file

@ -0,0 +1,90 @@
/*************************************************************************/
/* navigation_link_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef NAVIGATION_LINK_3D_H
#define NAVIGATION_LINK_3D_H
#include "scene/3d/node_3d.h"
class NavigationLink3D : public Node3D {
GDCLASS(NavigationLink3D, Node3D);
bool enabled = true;
RID link = RID();
bool bidirectional = true;
uint32_t navigation_layers = 1;
Vector3 end_location = Vector3();
Vector3 start_location = Vector3();
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
#ifdef DEBUG_ENABLED
RID debug_instance;
Ref<ArrayMesh> debug_mesh;
void _update_debug_mesh();
#endif // DEBUG_ENABLED
protected:
static void _bind_methods();
void _notification(int p_what);
public:
NavigationLink3D();
~NavigationLink3D();
void set_enabled(bool p_enabled);
bool is_enabled() const { return enabled; }
void set_bidirectional(bool p_bidirectional);
bool is_bidirectional() const { return bidirectional; }
void set_navigation_layers(uint32_t p_navigation_layers);
uint32_t get_navigation_layers() const { return navigation_layers; }
void set_navigation_layer_value(int p_layer_number, bool p_value);
bool get_navigation_layer_value(int p_layer_number) const;
void set_start_location(Vector3 p_location);
Vector3 get_start_location() const { return start_location; }
void set_end_location(Vector3 p_location);
Vector3 get_end_location() const { return end_location; }
void set_enter_cost(real_t p_enter_cost);
real_t get_enter_cost() const { return enter_cost; }
void set_travel_cost(real_t p_travel_cost);
real_t get_travel_cost() const { return travel_cost; }
TypedArray<String> get_configuration_warnings() const override;
};
#endif // NAVIGATION_LINK_3D_H

View file

@ -54,6 +54,7 @@
#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/multimesh_instance_2d.h"
#include "scene/2d/navigation_agent_2d.h"
#include "scene/2d/navigation_link_2d.h"
#include "scene/2d/navigation_obstacle_2d.h"
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
@ -236,6 +237,7 @@
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/navigation_agent_3d.h"
#include "scene/3d/navigation_link_3d.h"
#include "scene/3d/navigation_obstacle_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/node_3d.h"
@ -573,6 +575,7 @@ void register_scene_types() {
GDREGISTER_CLASS(NavigationRegion3D);
GDREGISTER_CLASS(NavigationAgent3D);
GDREGISTER_CLASS(NavigationObstacle3D);
GDREGISTER_CLASS(NavigationLink3D);
OS::get_singleton()->yield(); // may take time to init
#endif // _3D_DISABLED
@ -922,6 +925,7 @@ void register_scene_types() {
GDREGISTER_CLASS(NavigationRegion2D);
GDREGISTER_CLASS(NavigationAgent2D);
GDREGISTER_CLASS(NavigationObstacle2D);
GDREGISTER_CLASS(NavigationLink2D);
OS::get_singleton()->yield(); // may take time to init

View file

@ -85,6 +85,7 @@ World2D::World2D() {
NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 1));
NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 1));
NavigationServer2D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/2d/default_link_connection_radius", 4));
}
World2D::~World2D() {

View file

@ -151,6 +151,7 @@ World3D::World3D() {
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25));
NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25));
NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/3d/default_link_connection_radius", 1.0));
}
World3D::~World3D() {

View file

@ -53,6 +53,12 @@ NavigationServer2D *NavigationServer2D::singleton = nullptr;
return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
}
#define FORWARD_1_R_C(CONV_R, FUNC_NAME, T_0, D_0, CONV_0) \
NavigationServer2D::FUNC_NAME(T_0 D_0) \
const { \
return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0))); \
}
#define FORWARD_2_C(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
const { \
@ -190,6 +196,22 @@ Color NavigationServer2D::get_debug_navigation_geometry_face_disabled_color() co
return NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color();
}
void NavigationServer2D::set_debug_navigation_link_connection_color(const Color &p_color) {
NavigationServer3D::get_singleton_mut()->set_debug_navigation_link_connection_color(p_color);
}
Color NavigationServer2D::get_debug_navigation_link_connection_color() const {
return NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_color();
}
void NavigationServer2D::set_debug_navigation_link_connection_disabled_color(const Color &p_color) {
NavigationServer3D::get_singleton_mut()->set_debug_navigation_link_connection_disabled_color(p_color);
}
Color NavigationServer2D::get_debug_navigation_link_connection_disabled_color() const {
return NavigationServer3D::get_singleton()->get_debug_navigation_link_connection_disabled_color();
}
void NavigationServer2D::set_debug_navigation_enable_edge_connections(const bool p_value) {
NavigationServer3D::get_singleton_mut()->set_debug_navigation_enable_edge_connections(p_value);
}
@ -209,10 +231,13 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer2D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer2D::map_set_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer2D::map_get_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_set_link_connection_radius", "map", "radius"), &NavigationServer2D::map_set_link_connection_radius);
ClassDB::bind_method(D_METHOD("map_get_link_connection_radius", "map"), &NavigationServer2D::map_get_link_connection_radius);
ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer2D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer2D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer2D::map_get_closest_point_owner);
ClassDB::bind_method(D_METHOD("map_get_links", "map"), &NavigationServer2D::map_get_links);
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer2D::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents);
@ -234,6 +259,22 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer2D::link_create);
ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer2D::link_set_map);
ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer2D::link_get_map);
ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer2D::link_set_bidirectional);
ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer2D::link_is_bidirectional);
ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer2D::link_set_navigation_layers);
ClassDB::bind_method(D_METHOD("link_get_navigation_layers", "link"), &NavigationServer2D::link_get_navigation_layers);
ClassDB::bind_method(D_METHOD("link_set_start_location", "link", "location"), &NavigationServer2D::link_set_start_location);
ClassDB::bind_method(D_METHOD("link_get_start_location", "link"), &NavigationServer2D::link_get_start_location);
ClassDB::bind_method(D_METHOD("link_set_end_location", "link", "location"), &NavigationServer2D::link_set_end_location);
ClassDB::bind_method(D_METHOD("link_get_end_location", "link"), &NavigationServer2D::link_get_end_location);
ClassDB::bind_method(D_METHOD("link_set_enter_cost", "link", "enter_cost"), &NavigationServer2D::link_set_enter_cost);
ClassDB::bind_method(D_METHOD("link_get_enter_cost", "link"), &NavigationServer2D::link_get_enter_cost);
ClassDB::bind_method(D_METHOD("link_set_travel_cost", "link", "travel_cost"), &NavigationServer2D::link_set_travel_cost);
ClassDB::bind_method(D_METHOD("link_get_travel_cost", "link"), &NavigationServer2D::link_get_travel_cost);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer2D::agent_get_map);
@ -265,6 +306,8 @@ NavigationServer2D::~NavigationServer2D() {
TypedArray<RID> FORWARD_0_C(get_maps);
TypedArray<RID> FORWARD_1_C(map_get_links, RID, p_map, rid_to_rid);
TypedArray<RID> FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid);
TypedArray<RID> FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid);
@ -289,6 +332,9 @@ real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid);
void FORWARD_2_C(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_edge_connection_margin, RID, p_map, rid_to_rid);
void FORWARD_2_C(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_link_connection_radius, RID, p_map, rid_to_rid);
Vector<Vector2> FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, uint32_t, p_layers, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool, uint32_to_uint32);
Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
@ -315,6 +361,23 @@ int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
RID FORWARD_0_C(link_create);
void FORWARD_2_C(link_set_map, RID, p_link, RID, p_map, rid_to_rid, rid_to_rid);
RID FORWARD_1_C(link_get_map, RID, p_link, rid_to_rid);
void FORWARD_2_C(link_set_bidirectional, RID, p_link, bool, p_bidirectional, rid_to_rid, bool_to_bool);
bool FORWARD_1_C(link_is_bidirectional, RID, p_link, rid_to_rid);
void FORWARD_2_C(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
uint32_t FORWARD_1_C(link_get_navigation_layers, RID, p_link, rid_to_rid);
void FORWARD_2_C(link_set_start_location, RID, p_link, Vector2, p_location, rid_to_rid, v2_to_v3);
Vector2 FORWARD_1_R_C(v3_to_v2, link_get_start_location, RID, p_link, rid_to_rid);
void FORWARD_2_C(link_set_end_location, RID, p_link, Vector2, p_location, rid_to_rid, v2_to_v3);
Vector2 FORWARD_1_R_C(v3_to_v2, link_get_end_location, RID, p_link, rid_to_rid);
void FORWARD_2_C(link_set_enter_cost, RID, p_link, real_t, p_enter_cost, rid_to_rid, real_to_real);
real_t FORWARD_1_C(link_get_enter_cost, RID, p_link, rid_to_rid);
void FORWARD_2_C(link_set_travel_cost, RID, p_link, real_t, p_travel_cost, rid_to_rid, real_to_real);
real_t FORWARD_1_C(link_get_travel_cost, RID, p_link, rid_to_rid);
RID NavigationServer2D::agent_create() const {
RID agent = NavigationServer3D::get_singleton()->agent_create();
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, true);

View file

@ -76,12 +76,19 @@ public:
/// Returns the edge connection margin of this map.
virtual real_t map_get_edge_connection_margin(RID p_map) const;
/// Set the map link connection radius used to attach links to the nav mesh.
virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) const;
/// Returns the link connection radius of this map.
virtual real_t map_get_link_connection_radius(RID p_map) const;
/// Returns the navigation path to reach the destination from the origin.
virtual Vector<Vector2> map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const;
virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const;
virtual TypedArray<RID> map_get_links(RID p_map) const;
virtual TypedArray<RID> map_get_regions(RID p_map) const;
virtual TypedArray<RID> map_get_agents(RID p_map) const;
@ -119,6 +126,37 @@ public:
virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
/// Creates a new link between locations in the nav map.
virtual RID link_create() const;
/// Set the map of this link.
virtual void link_set_map(RID p_link, RID p_map) const;
virtual RID link_get_map(RID p_link) const;
/// Set whether this link travels in both directions.
virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) const;
virtual bool link_is_bidirectional(RID p_link) const;
/// Set the link's layers.
virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) const;
virtual uint32_t link_get_navigation_layers(RID p_link) const;
/// Set the start location of the link.
virtual void link_set_start_location(RID p_link, Vector2 p_location) const;
virtual Vector2 link_get_start_location(RID p_link) const;
/// Set the end location of the link.
virtual void link_set_end_location(RID p_link, Vector2 p_location) const;
virtual Vector2 link_get_end_location(RID p_link) const;
/// Set the enter cost of the link.
virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost) const;
virtual real_t link_get_enter_cost(RID p_link) const;
/// Set the travel cost of the link.
virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost) const;
virtual real_t link_get_travel_cost(RID p_link) const;
/// Creates the agent.
virtual RID agent_create() const;
@ -198,6 +236,12 @@ public:
void set_debug_navigation_geometry_face_disabled_color(const Color &p_color);
Color get_debug_navigation_geometry_face_disabled_color() const;
void set_debug_navigation_link_connection_color(const Color &p_color);
Color get_debug_navigation_link_connection_color() const;
void set_debug_navigation_link_connection_disabled_color(const Color &p_color);
Color get_debug_navigation_link_connection_disabled_color() const;
void set_debug_navigation_enable_edge_connections(const bool p_value);
bool get_debug_navigation_enable_edge_connections() const;
#endif // DEBUG_ENABLED

View file

@ -48,12 +48,15 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer3D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer3D::map_set_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer3D::map_get_edge_connection_margin);
ClassDB::bind_method(D_METHOD("map_set_link_connection_radius", "map", "radius"), &NavigationServer3D::map_set_link_connection_radius);
ClassDB::bind_method(D_METHOD("map_get_link_connection_radius", "map"), &NavigationServer3D::map_get_link_connection_radius);
ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer3D::map_get_path, DEFVAL(1));
ClassDB::bind_method(D_METHOD("map_get_closest_point_to_segment", "map", "start", "end", "use_collision"), &NavigationServer3D::map_get_closest_point_to_segment, DEFVAL(false));
ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer3D::map_get_closest_point);
ClassDB::bind_method(D_METHOD("map_get_closest_point_normal", "map", "to_point"), &NavigationServer3D::map_get_closest_point_normal);
ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer3D::map_get_closest_point_owner);
ClassDB::bind_method(D_METHOD("map_get_links", "map"), &NavigationServer3D::map_get_links);
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer3D::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer3D::map_get_agents);
@ -76,6 +79,22 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer3D::link_create);
ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer3D::link_set_map);
ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer3D::link_get_map);
ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer3D::link_set_bidirectional);
ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer3D::link_is_bidirectional);
ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer3D::link_set_navigation_layers);
ClassDB::bind_method(D_METHOD("link_get_navigation_layers", "link"), &NavigationServer3D::link_get_navigation_layers);
ClassDB::bind_method(D_METHOD("link_set_start_location", "link", "location"), &NavigationServer3D::link_set_start_location);
ClassDB::bind_method(D_METHOD("link_get_start_location", "link"), &NavigationServer3D::link_get_start_location);
ClassDB::bind_method(D_METHOD("link_set_end_location", "link", "location"), &NavigationServer3D::link_set_end_location);
ClassDB::bind_method(D_METHOD("link_get_end_location", "link"), &NavigationServer3D::link_get_end_location);
ClassDB::bind_method(D_METHOD("link_set_enter_cost", "link", "enter_cost"), &NavigationServer3D::link_set_enter_cost);
ClassDB::bind_method(D_METHOD("link_get_enter_cost", "link"), &NavigationServer3D::link_get_enter_cost);
ClassDB::bind_method(D_METHOD("link_set_travel_cost", "link", "travel_cost"), &NavigationServer3D::link_set_travel_cost);
ClassDB::bind_method(D_METHOD("link_get_travel_cost", "link"), &NavigationServer3D::link_get_travel_cost);
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer3D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer3D::agent_get_map);
@ -118,11 +137,16 @@ NavigationServer3D::NavigationServer3D() {
debug_navigation_geometry_face_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_color", Color(0.5, 1.0, 1.0, 0.4));
debug_navigation_geometry_edge_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_edge_disabled_color", Color(0.5, 0.5, 0.5, 1.0));
debug_navigation_geometry_face_disabled_color = GLOBAL_DEF("debug/shapes/navigation/geometry_face_disabled_color", Color(0.5, 0.5, 0.5, 0.4));
debug_navigation_link_connection_color = GLOBAL_DEF("debug/shapes/navigation/link_connection_color", Color(1.0, 0.5, 1.0, 1.0));
debug_navigation_link_connection_disabled_color = GLOBAL_DEF("debug/shapes/navigation/link_connection_disabled_color", Color(0.5, 0.5, 0.5, 1.0));
debug_navigation_enable_edge_connections = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections", true);
debug_navigation_enable_edge_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_connections_xray", true);
debug_navigation_enable_edge_lines = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines", true);
debug_navigation_enable_edge_lines_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines_xray", true);
debug_navigation_enable_geometry_face_random_color = GLOBAL_DEF("debug/shapes/navigation/enable_geometry_face_random_color", true);
debug_navigation_enable_link_connections = GLOBAL_DEF("debug/shapes/navigation/enable_link_connections", true);
debug_navigation_enable_link_connections_xray = GLOBAL_DEF("debug/shapes/navigation/enable_link_connections_xray", true);
if (Engine::get_singleton()->is_editor_hint()) {
// enable NavigationServer3D when in Editor or else navmesh edge connections are invisible
@ -261,6 +285,40 @@ Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_edge_connection
return debug_navigation_edge_connections_material;
}
Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_link_connections_material() {
if (debug_navigation_link_connections_material.is_valid()) {
return debug_navigation_link_connections_material;
}
Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
material->set_albedo(debug_navigation_link_connection_color);
if (debug_navigation_enable_link_connections_xray) {
material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MAX - 2);
debug_navigation_link_connections_material = material;
return debug_navigation_link_connections_material;
}
Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_link_connections_disabled_material() {
if (debug_navigation_link_connections_disabled_material.is_valid()) {
return debug_navigation_link_connections_disabled_material;
}
Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
material->set_albedo(debug_navigation_link_connection_disabled_color);
if (debug_navigation_enable_link_connections_xray) {
material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MAX - 2);
debug_navigation_link_connections_disabled_material = material;
return debug_navigation_link_connections_disabled_material;
}
void NavigationServer3D::set_debug_navigation_edge_connection_color(const Color &p_color) {
debug_navigation_edge_connection_color = p_color;
if (debug_navigation_edge_connections_material.is_valid()) {
@ -316,6 +374,28 @@ Color NavigationServer3D::get_debug_navigation_geometry_face_disabled_color() co
return debug_navigation_geometry_face_disabled_color;
}
void NavigationServer3D::set_debug_navigation_link_connection_color(const Color &p_color) {
debug_navigation_link_connection_color = p_color;
if (debug_navigation_link_connections_material.is_valid()) {
debug_navigation_link_connections_material->set_albedo(debug_navigation_link_connection_color);
}
}
Color NavigationServer3D::get_debug_navigation_link_connection_color() const {
return debug_navigation_link_connection_color;
}
void NavigationServer3D::set_debug_navigation_link_connection_disabled_color(const Color &p_color) {
debug_navigation_link_connection_disabled_color = p_color;
if (debug_navigation_link_connections_disabled_material.is_valid()) {
debug_navigation_link_connections_disabled_material->set_albedo(debug_navigation_link_connection_disabled_color);
}
}
Color NavigationServer3D::get_debug_navigation_link_connection_disabled_color() const {
return debug_navigation_link_connection_disabled_color;
}
void NavigationServer3D::set_debug_navigation_enable_edge_connections(const bool p_value) {
debug_navigation_enable_edge_connections = p_value;
debug_dirty = true;
@ -368,6 +448,27 @@ bool NavigationServer3D::get_debug_navigation_enable_geometry_face_random_color(
return debug_navigation_enable_geometry_face_random_color;
}
void NavigationServer3D::set_debug_navigation_enable_link_connections(const bool p_value) {
debug_navigation_enable_link_connections = p_value;
debug_dirty = true;
call_deferred("_emit_navigation_debug_changed_signal");
}
bool NavigationServer3D::get_debug_navigation_enable_link_connections() const {
return debug_navigation_enable_link_connections;
}
void NavigationServer3D::set_debug_navigation_enable_link_connections_xray(const bool p_value) {
debug_navigation_enable_link_connections_xray = p_value;
if (debug_navigation_link_connections_material.is_valid()) {
debug_navigation_link_connections_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, debug_navigation_enable_link_connections_xray);
}
}
bool NavigationServer3D::get_debug_navigation_enable_link_connections_xray() const {
return debug_navigation_enable_link_connections_xray;
}
void NavigationServer3D::set_debug_enabled(bool p_enabled) {
if (debug_enabled != p_enabled) {
debug_dirty = true;

View file

@ -85,6 +85,12 @@ public:
/// Returns the edge connection margin of this map.
virtual real_t map_get_edge_connection_margin(RID p_map) const = 0;
/// Set the map link connection radius used to attach links to the nav mesh.
virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) const = 0;
/// Returns the link connection radius of this map.
virtual real_t map_get_link_connection_radius(RID p_map) const = 0;
/// Returns the navigation path to reach the destination from the origin.
virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const = 0;
@ -93,6 +99,7 @@ public:
virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const = 0;
virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const = 0;
virtual TypedArray<RID> map_get_links(RID p_map) const = 0;
virtual TypedArray<RID> map_get_regions(RID p_map) const = 0;
virtual TypedArray<RID> map_get_agents(RID p_map) const = 0;
@ -133,6 +140,37 @@ public:
virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
/// Creates a new link between locations in the nav map.
virtual RID link_create() const = 0;
/// Set the map of this link.
virtual void link_set_map(RID p_link, RID p_map) const = 0;
virtual RID link_get_map(RID p_link) const = 0;
/// Set whether this link travels in both directions.
virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) const = 0;
virtual bool link_is_bidirectional(RID p_link) const = 0;
/// Set the link's layers.
virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) const = 0;
virtual uint32_t link_get_navigation_layers(RID p_link) const = 0;
/// Set the start location of the link.
virtual void link_set_start_location(RID p_link, Vector3 p_location) const = 0;
virtual Vector3 link_get_start_location(RID p_link) const = 0;
/// Set the end location of the link.
virtual void link_set_end_location(RID p_link, Vector3 p_location) const = 0;
virtual Vector3 link_get_end_location(RID p_link) const = 0;
/// Set the enter cost of the link.
virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost) const = 0;
virtual real_t link_get_enter_cost(RID p_link) const = 0;
/// Set the travel cost of the link.
virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost) const = 0;
virtual real_t link_get_travel_cost(RID p_link) const = 0;
/// Creates the agent.
virtual RID agent_create() const = 0;
@ -209,29 +247,38 @@ public:
virtual ~NavigationServer3D();
#ifdef DEBUG_ENABLED
private:
bool debug_enabled = false;
bool debug_dirty = true;
void _emit_navigation_debug_changed_signal();
void set_debug_enabled(bool p_enabled);
bool get_debug_enabled() const;
Color debug_navigation_edge_connection_color = Color(1.0, 0.0, 1.0, 1.0);
Color debug_navigation_geometry_edge_color = Color(0.5, 1.0, 1.0, 1.0);
Color debug_navigation_geometry_face_color = Color(0.5, 1.0, 1.0, 0.4);
Color debug_navigation_geometry_edge_disabled_color = Color(0.5, 0.5, 0.5, 1.0);
Color debug_navigation_geometry_face_disabled_color = Color(0.5, 0.5, 0.5, 0.4);
Color debug_navigation_link_connection_color = Color(1.0, 0.5, 1.0, 1.0);
Color debug_navigation_link_connection_disabled_color = Color(0.5, 0.5, 0.5, 1.0);
bool debug_navigation_enable_edge_connections = true;
bool debug_navigation_enable_edge_connections_xray = true;
bool debug_navigation_enable_edge_lines = true;
bool debug_navigation_enable_edge_lines_xray = true;
bool debug_navigation_enable_geometry_face_random_color = true;
bool debug_navigation_enable_link_connections = true;
bool debug_navigation_enable_link_connections_xray = true;
Ref<StandardMaterial3D> debug_navigation_geometry_edge_material;
Ref<StandardMaterial3D> debug_navigation_geometry_face_material;
Ref<StandardMaterial3D> debug_navigation_geometry_edge_disabled_material;
Ref<StandardMaterial3D> debug_navigation_geometry_face_disabled_material;
Ref<StandardMaterial3D> debug_navigation_edge_connections_material;
Ref<StandardMaterial3D> debug_navigation_link_connections_material;
Ref<StandardMaterial3D> debug_navigation_link_connections_disabled_material;
public:
void set_debug_enabled(bool p_enabled);
bool get_debug_enabled() const;
void set_debug_navigation_edge_connection_color(const Color &p_color);
Color get_debug_navigation_edge_connection_color() const;
@ -248,6 +295,12 @@ public:
void set_debug_navigation_geometry_face_disabled_color(const Color &p_color);
Color get_debug_navigation_geometry_face_disabled_color() const;
void set_debug_navigation_link_connection_color(const Color &p_color);
Color get_debug_navigation_link_connection_color() const;
void set_debug_navigation_link_connection_disabled_color(const Color &p_color);
Color get_debug_navigation_link_connection_disabled_color() const;
void set_debug_navigation_enable_edge_connections(const bool p_value);
bool get_debug_navigation_enable_edge_connections() const;
@ -263,11 +316,19 @@ public:
void set_debug_navigation_enable_geometry_face_random_color(const bool p_value);
bool get_debug_navigation_enable_geometry_face_random_color() const;
void set_debug_navigation_enable_link_connections(const bool p_value);
bool get_debug_navigation_enable_link_connections() const;
void set_debug_navigation_enable_link_connections_xray(const bool p_value);
bool get_debug_navigation_enable_link_connections_xray() const;
Ref<StandardMaterial3D> get_debug_navigation_geometry_face_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_edge_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_face_disabled_material();
Ref<StandardMaterial3D> get_debug_navigation_geometry_edge_disabled_material();
Ref<StandardMaterial3D> get_debug_navigation_edge_connections_material();
Ref<StandardMaterial3D> get_debug_navigation_link_connections_material();
Ref<StandardMaterial3D> get_debug_navigation_link_connections_disabled_material();
#endif // DEBUG_ENABLED
};