Added node for Navigation links
This commit is contained in:
parent
4808d01b2b
commit
3dd59013f4
34 changed files with 2563 additions and 49 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
56
modules/navigation/nav_base.h
Normal file
56
modules/navigation/nav_base.h
Normal 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
|
||||
60
modules/navigation/nav_link.cpp
Normal file
60
modules/navigation/nav_link.cpp
Normal 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;
|
||||
}
|
||||
69
modules/navigation/nav_link.h
Normal file
69
modules/navigation/nav_link.h
Normal 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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue