Path: blob/master/scene/2d/navigation/navigation_link_2d.cpp
9904 views
/**************************************************************************/1/* navigation_link_2d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "navigation_link_2d.h"3132#include "core/math/geometry_2d.h"33#include "scene/resources/world_2d.h"34#include "servers/navigation_server_2d.h"3536void NavigationLink2D::_bind_methods() {37ClassDB::bind_method(D_METHOD("get_rid"), &NavigationLink2D::get_rid);3839ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink2D::set_enabled);40ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink2D::is_enabled);4142ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationLink2D::set_navigation_map);43ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationLink2D::get_navigation_map);4445ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink2D::set_bidirectional);46ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink2D::is_bidirectional);4748ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationLink2D::set_navigation_layers);49ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationLink2D::get_navigation_layers);5051ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink2D::set_navigation_layer_value);52ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink2D::get_navigation_layer_value);5354ClassDB::bind_method(D_METHOD("set_start_position", "position"), &NavigationLink2D::set_start_position);55ClassDB::bind_method(D_METHOD("get_start_position"), &NavigationLink2D::get_start_position);5657ClassDB::bind_method(D_METHOD("set_end_position", "position"), &NavigationLink2D::set_end_position);58ClassDB::bind_method(D_METHOD("get_end_position"), &NavigationLink2D::get_end_position);5960ClassDB::bind_method(D_METHOD("set_global_start_position", "position"), &NavigationLink2D::set_global_start_position);61ClassDB::bind_method(D_METHOD("get_global_start_position"), &NavigationLink2D::get_global_start_position);6263ClassDB::bind_method(D_METHOD("set_global_end_position", "position"), &NavigationLink2D::set_global_end_position);64ClassDB::bind_method(D_METHOD("get_global_end_position"), &NavigationLink2D::get_global_end_position);6566ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink2D::set_enter_cost);67ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink2D::get_enter_cost);6869ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationLink2D::set_travel_cost);70ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationLink2D::get_travel_cost);7172ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");73ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional");74ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");75ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "start_position"), "set_start_position", "get_start_position");76ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "end_position"), "set_end_position", "get_end_position");77ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");78ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");79}8081#ifndef DISABLE_DEPRECATED82bool NavigationLink2D::_set(const StringName &p_name, const Variant &p_value) {83if (p_name == "start_location") {84set_start_position(p_value);85return true;86}87if (p_name == "end_location") {88set_end_position(p_value);89return true;90}91return false;92}9394bool NavigationLink2D::_get(const StringName &p_name, Variant &r_ret) const {95if (p_name == "start_location") {96r_ret = get_start_position();97return true;98}99if (p_name == "end_location") {100r_ret = get_end_position();101return true;102}103return false;104}105#endif // DISABLE_DEPRECATED106107void NavigationLink2D::_notification(int p_what) {108switch (p_what) {109case NOTIFICATION_ENTER_TREE: {110_link_enter_navigation_map();111} break;112113case NOTIFICATION_TRANSFORM_CHANGED: {114set_physics_process_internal(true);115} break;116117case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {118set_physics_process_internal(false);119_link_update_transform();120} break;121122case NOTIFICATION_EXIT_TREE: {123_link_exit_navigation_map();124} break;125case NOTIFICATION_DRAW: {126#ifdef DEBUG_ENABLED127_update_debug_mesh();128#endif // DEBUG_ENABLED129} break;130}131}132133#ifdef DEBUG_ENABLED134Rect2 NavigationLink2D::_edit_get_rect() const {135if (!is_inside_tree()) {136return Rect2();137}138139real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());140141Rect2 rect(get_start_position(), Size2());142rect.expand_to(get_end_position());143rect.grow_by(radius);144return rect;145}146147bool NavigationLink2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {148Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, get_start_position(), get_end_position());149return p_point.distance_to(closest_point) < p_tolerance;150}151#endif // DEBUG_ENABLED152153RID NavigationLink2D::get_rid() const {154return link;155}156157void NavigationLink2D::set_enabled(bool p_enabled) {158if (enabled == p_enabled) {159return;160}161162enabled = p_enabled;163164NavigationServer2D::get_singleton()->link_set_enabled(link, enabled);165166#ifdef DEBUG_ENABLED167queue_redraw();168#endif // DEBUG_ENABLED169}170171void NavigationLink2D::set_navigation_map(RID p_navigation_map) {172if (map_override == p_navigation_map) {173return;174}175176map_override = p_navigation_map;177178NavigationServer2D::get_singleton()->link_set_map(link, map_override);179}180181RID NavigationLink2D::get_navigation_map() const {182if (map_override.is_valid()) {183return map_override;184} else if (is_inside_tree()) {185return get_world_2d()->get_navigation_map();186}187return RID();188}189190void NavigationLink2D::set_bidirectional(bool p_bidirectional) {191if (bidirectional == p_bidirectional) {192return;193}194195bidirectional = p_bidirectional;196197NavigationServer2D::get_singleton()->link_set_bidirectional(link, bidirectional);198199#ifdef DEBUG_ENABLED200queue_redraw();201#endif // DEBUG_ENABLED202}203204void NavigationLink2D::set_navigation_layers(uint32_t p_navigation_layers) {205if (navigation_layers == p_navigation_layers) {206return;207}208209navigation_layers = p_navigation_layers;210211NavigationServer2D::get_singleton()->link_set_navigation_layers(link, navigation_layers);212}213214void NavigationLink2D::set_navigation_layer_value(int p_layer_number, bool p_value) {215ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");216ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");217218uint32_t _navigation_layers = get_navigation_layers();219220if (p_value) {221_navigation_layers |= 1 << (p_layer_number - 1);222} else {223_navigation_layers &= ~(1 << (p_layer_number - 1));224}225226set_navigation_layers(_navigation_layers);227}228229bool NavigationLink2D::get_navigation_layer_value(int p_layer_number) const {230ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");231ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");232233return get_navigation_layers() & (1 << (p_layer_number - 1));234}235236void NavigationLink2D::set_start_position(Vector2 p_position) {237if (start_position.is_equal_approx(p_position)) {238return;239}240241start_position = p_position;242243if (!is_inside_tree()) {244return;245}246247NavigationServer2D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));248249update_configuration_warnings();250251#ifdef DEBUG_ENABLED252queue_redraw();253#endif // DEBUG_ENABLED254}255256void NavigationLink2D::set_end_position(Vector2 p_position) {257if (end_position.is_equal_approx(p_position)) {258return;259}260261end_position = p_position;262263if (!is_inside_tree()) {264return;265}266267NavigationServer2D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));268269update_configuration_warnings();270271#ifdef DEBUG_ENABLED272queue_redraw();273#endif // DEBUG_ENABLED274}275276void NavigationLink2D::set_global_start_position(Vector2 p_position) {277if (is_inside_tree()) {278set_start_position(to_local(p_position));279} else {280set_start_position(p_position);281}282}283284Vector2 NavigationLink2D::get_global_start_position() const {285if (is_inside_tree()) {286return to_global(start_position);287} else {288return start_position;289}290}291292void NavigationLink2D::set_global_end_position(Vector2 p_position) {293if (is_inside_tree()) {294set_end_position(to_local(p_position));295} else {296set_end_position(p_position);297}298}299300Vector2 NavigationLink2D::get_global_end_position() const {301if (is_inside_tree()) {302return to_global(end_position);303} else {304return end_position;305}306}307308void NavigationLink2D::set_enter_cost(real_t p_enter_cost) {309ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");310if (Math::is_equal_approx(enter_cost, p_enter_cost)) {311return;312}313314enter_cost = p_enter_cost;315316NavigationServer2D::get_singleton()->link_set_enter_cost(link, enter_cost);317}318319void NavigationLink2D::set_travel_cost(real_t p_travel_cost) {320ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");321if (Math::is_equal_approx(travel_cost, p_travel_cost)) {322return;323}324325travel_cost = p_travel_cost;326327NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost);328}329330PackedStringArray NavigationLink2D::get_configuration_warnings() const {331PackedStringArray warnings = Node2D::get_configuration_warnings();332333if (start_position.is_equal_approx(end_position)) {334warnings.push_back(RTR("NavigationLink2D start position should be different than the end position to be useful."));335}336337return warnings;338}339340void NavigationLink2D::_link_enter_navigation_map() {341if (!is_inside_tree()) {342return;343}344345if (map_override.is_valid()) {346NavigationServer2D::get_singleton()->link_set_map(link, map_override);347} else {348NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map());349}350351current_global_transform = get_global_transform();352353NavigationServer2D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));354NavigationServer2D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));355NavigationServer2D::get_singleton()->link_set_enabled(link, enabled);356357queue_redraw();358}359360void NavigationLink2D::_link_exit_navigation_map() {361NavigationServer2D::get_singleton()->link_set_map(link, RID());362}363364void NavigationLink2D::_link_update_transform() {365if (!is_inside_tree()) {366return;367}368369Transform2D new_global_transform = get_global_transform();370if (current_global_transform != new_global_transform) {371current_global_transform = new_global_transform;372NavigationServer2D::get_singleton()->link_set_start_position(link, current_global_transform.xform(start_position));373NavigationServer2D::get_singleton()->link_set_end_position(link, current_global_transform.xform(end_position));374queue_redraw();375}376}377378#ifdef DEBUG_ENABLED379void NavigationLink2D::_update_debug_mesh() {380if (!is_inside_tree()) {381return;382}383384if (!Engine::get_singleton()->is_editor_hint() && !NavigationServer2D::get_singleton()->get_debug_enabled()) {385return;386}387388Color color;389if (enabled) {390color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_color();391} else {392color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_disabled_color();393}394395real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map());396397draw_line(get_start_position(), get_end_position(), color);398draw_arc(get_start_position(), radius, 0, Math::TAU, 10, color);399draw_arc(get_end_position(), radius, 0, Math::TAU, 10, color);400401const Vector2 link_segment = end_position - start_position;402const float arror_len = 5.0;403404{405Vector2 anchor = start_position + (link_segment * 0.75);406Vector2 direction = start_position.direction_to(end_position);407Vector2 arrow_dir = -direction.orthogonal();408draw_line(anchor, anchor + (arrow_dir - direction) * arror_len, color);409410arrow_dir = direction.orthogonal();411draw_line(anchor, anchor + (arrow_dir - direction) * arror_len, color);412}413414if (is_bidirectional()) {415Vector2 anchor = start_position + (link_segment * 0.25);416Vector2 direction = end_position.direction_to(start_position);417Vector2 arrow_dir = -direction.orthogonal();418draw_line(anchor, anchor + (arrow_dir - direction) * arror_len, color);419420arrow_dir = direction.orthogonal();421draw_line(anchor, anchor + (arrow_dir - direction) * arror_len, color);422}423}424#endif // DEBUG_ENABLED425426NavigationLink2D::NavigationLink2D() {427link = NavigationServer2D::get_singleton()->link_create();428429NavigationServer2D::get_singleton()->link_set_owner_id(link, get_instance_id());430NavigationServer2D::get_singleton()->link_set_enter_cost(link, enter_cost);431NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost);432NavigationServer2D::get_singleton()->link_set_navigation_layers(link, navigation_layers);433NavigationServer2D::get_singleton()->link_set_bidirectional(link, bidirectional);434NavigationServer2D::get_singleton()->link_set_enabled(link, enabled);435436set_notify_transform(true);437set_hide_clip_children(true);438}439440NavigationLink2D::~NavigationLink2D() {441ERR_FAIL_NULL(NavigationServer2D::get_singleton());442NavigationServer2D::get_singleton()->free(link);443link = RID();444}445446447