diff options
Diffstat (limited to 'scene/2d')
53 files changed, 1019 insertions, 459 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 221d52bc20..177f587f4f 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -104,12 +104,12 @@ Rect2 AnimatedSprite2D::_get_rect() const { return Rect2(ofs, s); } -void AnimatedSprite2D::_validate_property(PropertyInfo &property) const { +void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const { if (!frames.is_valid()) { return; } - if (property.name == "animation") { - property.hint = PROPERTY_HINT_ENUM; + if (p_property.name == "animation") { + p_property.hint = PROPERTY_HINT_ENUM; List<StringName> names; frames->get_animation_list(&names); names.sort_custom<StringName::AlphCompare>(); @@ -118,30 +118,33 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &property) const { for (List<StringName>::Element *E = names.front(); E; E = E->next()) { if (E->prev()) { - property.hint_string += ","; + p_property.hint_string += ","; } - property.hint_string += String(E->get()); + p_property.hint_string += String(E->get()); if (animation == E->get()) { current_found = true; } } if (!current_found) { - if (property.hint_string.is_empty()) { - property.hint_string = String(animation); + if (p_property.hint_string.is_empty()) { + p_property.hint_string = String(animation); } else { - property.hint_string = String(animation) + "," + property.hint_string; + p_property.hint_string = String(animation) + "," + p_property.hint_string; } } } - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; - if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) { - property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; + if (p_property.name == "frame") { + p_property.hint = PROPERTY_HINT_RANGE; + if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) { + p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; + } else { + // Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`. + p_property.hint_string = "0,0,1"; } - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } } diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index 3a41f810dc..0a19e250d8 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -62,7 +62,7 @@ class AnimatedSprite2D : public Node2D { protected: static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: #ifdef TOOLS_ENABLED @@ -114,4 +114,4 @@ public: AnimatedSprite2D(); }; -#endif // ANIMATED_SPRITE_H +#endif // ANIMATED_SPRITE_2D_H diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 02d9198e43..75f1497edc 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -184,8 +184,8 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i E->value.rc = 0; E->value.in_tree = node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree), make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree), make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree).bind(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree).bind(objid)); if (E->value.in_tree) { emit_signal(SceneStringNames::get_singleton()->body_entered, node); } @@ -277,8 +277,8 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i E->value.rc = 0; E->value.in_tree = node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_area_enter_tree), make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_area_exit_tree), make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_area_enter_tree).bind(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_area_exit_tree).bind(objid)); if (E->value.in_tree) { emit_signal(SceneStringNames::get_singleton()->area_entered, node); } @@ -498,8 +498,8 @@ StringName Area2D::get_audio_bus_name() const { return "Master"; } -void Area2D::_validate_property(PropertyInfo &property) const { - if (property.name == "audio_bus_name") { +void Area2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "audio_bus_name") { String options; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (i > 0) { @@ -509,28 +509,28 @@ void Area2D::_validate_property(PropertyInfo &property) const { options += name; } - property.hint_string = options; - } else if (property.name.begins_with("gravity") && property.name != "gravity_space_override") { + p_property.hint_string = options; + } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") { if (gravity_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } else { if (gravity_is_point) { - if (property.name == "gravity_direction") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "gravity_direction") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else { - if (property.name.begins_with("gravity_point_")) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with("gravity_point_")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } - } else if (property.name.begins_with("linear_damp") && property.name != "linear_damp_space_override") { + } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") { if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - } else if (property.name.begins_with("angular_damp") && property.name != "angular_damp_space_override") { + } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") { if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } @@ -605,7 +605,7 @@ void Area2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "gravity_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_space_override_mode", "get_gravity_space_override_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_is_point", "is_gravity_a_point"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_point_center"), "set_gravity_point_center", "get_gravity_point_center"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:px"), "set_gravity_point_center", "get_gravity_point_center"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_direction"), "set_gravity_direction", "get_gravity_direction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_lesser,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity"); diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index a584420ced..3d8d77eabb 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -135,7 +135,7 @@ private: protected: void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_gravity_space_override_mode(SpaceOverride p_mode); diff --git a/scene/2d/audio_listener_2d.h b/scene/2d/audio_listener_2d.h index 172d388efc..5cd1bfb251 100644 --- a/scene/2d/audio_listener_2d.h +++ b/scene/2d/audio_listener_2d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef LISTENER_2D_H -#define LISTENER_2D_H +#ifndef AUDIO_LISTENER_2D_H +#define AUDIO_LISTENER_2D_H #include "scene/2d/node_2d.h" #include "scene/main/window.h" @@ -56,4 +56,4 @@ public: bool is_current() const; }; -#endif +#endif // AUDIO_LISTENER_2D_H diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index e7f1740f0b..fa49552085 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -30,6 +30,7 @@ #include "audio_stream_player_2d.h" +#include "core/config/project_settings.h" #include "scene/2d/area_2d.h" #include "scene/2d/audio_listener_2d.h" #include "scene/main/window.h" @@ -68,7 +69,7 @@ void AudioStreamPlayer2D::_notification(int p_what) { if (setplay.get() >= 0 && stream.is_valid()) { active.set(); - Ref<AudioStreamPlayback> new_playback = stream->instance_playback(); + Ref<AudioStreamPlayback> new_playback = stream->instantiate_playback(); ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale); stream_playbacks.push_back(new_playback); @@ -186,7 +187,14 @@ void AudioStreamPlayer2D::_update_panning() { float multiplier = Math::pow(1.0f - dist / max_distance, attenuation); multiplier *= Math::db2linear(volume_db); //also apply player volume! - float pan = CLAMP((relative_to_listener.x + screen_size.x * 0.5) / screen_size.x, 0.0, 1.0); + float pan = relative_to_listener.x / screen_size.x; + // Don't let the panning effect extend (too far) beyond the screen. + pan = CLAMP(pan, -1, 1); + + // Bake in a constant factor here to allow the project setting defaults for 2d and 3d to be normalized to 1.0. + pan *= panning_strength * cached_global_panning_strength * 0.5f; + + pan = CLAMP(pan + 0.5, 0.0, 1.0); float l = 1.0 - pan; float r = pan; @@ -315,8 +323,8 @@ bool AudioStreamPlayer2D::_is_active() const { return active.is_set(); } -void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { - if (property.name == "bus") { +void AudioStreamPlayer2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "bus") { String options; for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (i > 0) { @@ -326,7 +334,7 @@ void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { options += name; } - property.hint_string = options; + p_property.hint_string = options; } } @@ -391,6 +399,15 @@ int AudioStreamPlayer2D::get_max_polyphony() const { return max_polyphony; } +void AudioStreamPlayer2D::set_panning_strength(float p_panning_strength) { + ERR_FAIL_COND_MSG(p_panning_strength < 0, "Panning strength must be a positive number."); + panning_strength = p_panning_strength; +} + +float AudioStreamPlayer2D::get_panning_strength() const { + return panning_strength; +} + void AudioStreamPlayer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream); ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer2D::get_stream); @@ -432,6 +449,9 @@ void AudioStreamPlayer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_max_polyphony", "max_polyphony"), &AudioStreamPlayer2D::set_max_polyphony); ClassDB::bind_method(D_METHOD("get_max_polyphony"), &AudioStreamPlayer2D::get_max_polyphony); + ClassDB::bind_method(D_METHOD("set_panning_strength", "panning_strength"), &AudioStreamPlayer2D::set_panning_strength); + ClassDB::bind_method(D_METHOD("get_panning_strength"), &AudioStreamPlayer2D::get_panning_strength); + ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); @@ -443,6 +463,7 @@ void AudioStreamPlayer2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp,suffix:px"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "panning_strength", PROPERTY_HINT_RANGE, "0,3,0.01,or_greater"), "set_panning_strength", "get_panning_strength"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); @@ -451,6 +472,7 @@ void AudioStreamPlayer2D::_bind_methods() { AudioStreamPlayer2D::AudioStreamPlayer2D() { AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_bus_layout_changed)); + cached_global_panning_strength = ProjectSettings::get_singleton()->get("audio/general/2d_panning_strength"); } AudioStreamPlayer2D::~AudioStreamPlayer2D() { diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index 73b09e432f..616d7fdb60 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -81,8 +81,11 @@ private: float max_distance = 2000.0; float attenuation = 1.0; + float panning_strength = 1.0f; + float cached_global_panning_strength = 1.0f; + protected: - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); @@ -123,10 +126,13 @@ public: void set_max_polyphony(int p_max_polyphony); int get_max_polyphony() const; + void set_panning_strength(float p_panning_strength); + float get_panning_strength() const; + Ref<AudioStreamPlayback> get_stream_playback(); AudioStreamPlayer2D(); ~AudioStreamPlayer2D(); }; -#endif +#endif // AUDIO_STREAM_PLAYER_2D_H diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp index c411aaf411..aa4ae01fd9 100644 --- a/scene/2d/back_buffer_copy.cpp +++ b/scene/2d/back_buffer_copy.cpp @@ -85,7 +85,7 @@ void BackBufferCopy::_bind_methods() { ClassDB::bind_method(D_METHOD("get_copy_mode"), &BackBufferCopy::get_copy_mode); ADD_PROPERTY(PropertyInfo(Variant::INT, "copy_mode", PROPERTY_HINT_ENUM, "Disabled,Rect,Viewport"), "set_copy_mode", "get_copy_mode"); - ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), "set_rect", "get_rect"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect", PROPERTY_HINT_NONE, "suffix:px"), "set_rect", "get_rect"); BIND_ENUM_CONSTANT(COPY_MODE_DISABLED); BIND_ENUM_CONSTANT(COPY_MODE_RECT); diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h index 4e7cac1f3e..1f2d5810b0 100644 --- a/scene/2d/back_buffer_copy.h +++ b/scene/2d/back_buffer_copy.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BACKBUFFERCOPY_H -#define BACKBUFFERCOPY_H +#ifndef BACK_BUFFER_COPY_H +#define BACK_BUFFER_COPY_H #include "scene/2d/node_2d.h" @@ -71,4 +71,4 @@ public: VARIANT_ENUM_CAST(BackBufferCopy::CopyMode); -#endif // BACKBUFFERCOPY_H +#endif // BACK_BUFFER_COPY_H diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index f61dbc071d..88f9c2a4a6 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -247,8 +247,8 @@ void Camera2D::_notification(int p_what) { add_to_group(canvas_group_name); _update_process_callback(); - _update_scroll(); first = true; + _update_scroll(); } break; case NOTIFICATION_EXIT_TREE: { @@ -439,7 +439,9 @@ void Camera2D::clear_current() { void Camera2D::set_limit(Side p_side, int p_limit) { ERR_FAIL_INDEX((int)p_side, 4); limit[p_side] = p_limit; - update(); + Point2 old_smoothed_camera_pos = smoothed_camera_pos; + _update_scroll(); + smoothed_camera_pos = old_smoothed_camera_pos; } int Camera2D::get_limit(Side p_side) const { @@ -653,9 +655,9 @@ bool Camera2D::is_margin_drawing_enabled() const { return margin_drawing_enabled; } -void Camera2D::_validate_property(PropertyInfo &property) const { - if (!smoothing_enabled && property.name == "smoothing_speed") { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Camera2D::_validate_property(PropertyInfo &p_property) const { + if (!smoothing_enabled && p_property.name == "smoothing_speed") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } @@ -729,24 +731,24 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_margin_drawing_enabled", "margin_drawing_enabled"), &Camera2D::set_margin_drawing_enabled); ClassDB::bind_method(D_METHOD("is_margin_drawing_enabled"), &Camera2D::is_margin_drawing_enabled); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom"), "set_zoom", "get_zoom"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom", PROPERTY_HINT_LINK), "set_zoom", "get_zoom"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback"); ADD_GROUP("Limit", "limit_"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left"), "set_limit", "get_limit", SIDE_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_top"), "set_limit", "get_limit", SIDE_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_right"), "set_limit", "get_limit", SIDE_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_bottom"), "set_limit", "get_limit", SIDE_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_top", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_right", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_BOTTOM); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "limit_smoothed"), "set_limit_smoothing_enabled", "is_limit_smoothing_enabled"); ADD_GROUP("Smoothing", "smoothing_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smoothing_enabled"), "set_enable_follow_smoothing", "is_follow_smoothing_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_speed"), "set_follow_smoothing", "get_follow_smoothing"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_follow_smoothing", "get_follow_smoothing"); ADD_GROUP("Drag", "drag_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_horizontal_enabled"), "set_drag_horizontal_enabled", "is_drag_horizontal_enabled"); diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 294a6fcb80..78654ee606 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -100,7 +100,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_offset(const Vector2 &p_offset); diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp index 37a858330c..bbf3fff0ad 100644 --- a/scene/2d/canvas_group.cpp +++ b/scene/2d/canvas_group.cpp @@ -75,8 +75,8 @@ void CanvasGroup::_bind_methods() { ClassDB::bind_method(D_METHOD("is_using_mipmaps"), &CanvasGroup::is_using_mipmaps); ADD_GROUP("Tweaks", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fit_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater"), "set_fit_margin", "get_fit_margin"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clear_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater"), "set_clear_margin", "get_clear_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fit_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater,suffix:px"), "set_fit_margin", "get_fit_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clear_margin", PROPERTY_HINT_RANGE, "0,1024,1.0,or_greater,suffix:px"), "set_clear_margin", "get_clear_margin"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_mipmaps"), "set_use_mipmaps", "is_using_mipmaps"); } diff --git a/scene/2d/canvas_group.h b/scene/2d/canvas_group.h index 9bc1772ee2..557e7e23dc 100644 --- a/scene/2d/canvas_group.h +++ b/scene/2d/canvas_group.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CANVASGROUP_H -#define CANVASGROUP_H +#ifndef CANVAS_GROUP_H +#define CANVAS_GROUP_H #include "scene/2d/node_2d.h" @@ -56,4 +56,4 @@ public: ~CanvasGroup(); }; -#endif // CANVASGROUP_H +#endif // CANVAS_GROUP_H diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h index ec37449f8f..1fd54898f8 100644 --- a/scene/2d/canvas_modulate.h +++ b/scene/2d/canvas_modulate.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CANVASMODULATE_H -#define CANVASMODULATE_H +#ifndef CANVAS_MODULATE_H +#define CANVAS_MODULATE_H #include "scene/2d/node_2d.h" @@ -52,4 +52,4 @@ public: ~CanvasModulate(); }; -#endif // CANVASMODULATE_H +#endif // CANVAS_MODULATE_H diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index a8c12f4893..85de1fedee 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -186,6 +186,17 @@ bool CollisionObject2D::get_collision_mask_value(int p_layer_number) const { return get_collision_mask() & (1 << (p_layer_number - 1)); } +void CollisionObject2D::set_collision_priority(real_t p_priority) { + collision_priority = p_priority; + if (!area) { + PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), p_priority); + } +} + +real_t CollisionObject2D::get_collision_priority() const { + return collision_priority; +} + void CollisionObject2D::set_disable_mode(DisableMode p_mode) { if (disable_mode == p_mode) { return; @@ -350,8 +361,8 @@ void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) { } } -Array CollisionObject2D::_get_shape_owners() { - Array ret; +PackedInt32Array CollisionObject2D::_get_shape_owners() { + PackedInt32Array ret; for (const KeyValue<uint32_t, ShapeData> &E : shapes) { ret.push_back(E.key); } @@ -574,6 +585,8 @@ void CollisionObject2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject2D::get_collision_layer_value); ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject2D::set_collision_mask_value); ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject2D::get_collision_mask_value); + ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CollisionObject2D::set_collision_priority); + ClassDB::bind_method(D_METHOD("get_collision_priority"), &CollisionObject2D::get_collision_priority); ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode); ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode); ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable); @@ -611,6 +624,7 @@ void CollisionObject2D::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority"); ADD_GROUP("Input", "input_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable"); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 997afee6c4..af216edc98 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -49,6 +49,7 @@ public: private: uint32_t collision_layer = 1; uint32_t collision_mask = 1; + real_t collision_priority = 1.0; bool area = false; RID rid; @@ -115,13 +116,16 @@ public: void set_collision_mask_value(int p_layer_number, bool p_value); bool get_collision_mask_value(int p_layer_number) const; + void set_collision_priority(real_t p_priority); + real_t get_collision_priority() const; + void set_disable_mode(DisableMode p_mode); DisableMode get_disable_mode() const; uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); - Array _get_shape_owners(); + PackedInt32Array _get_shape_owners(); void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform); Transform2D shape_owner_get_transform(uint32_t p_owner) const; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 20840f5aea..8df29851e5 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -315,7 +315,7 @@ void CollisionPolygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "one_way_collision_margin", PROPERTY_HINT_RANGE, "0,128,0.1"), "set_one_way_collision_margin", "get_one_way_collision_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "one_way_collision_margin", PROPERTY_HINT_RANGE, "0,128,0.1,suffix:px"), "set_one_way_collision_margin", "get_one_way_collision_margin"); BIND_ENUM_CONSTANT(BUILD_SOLIDS); BIND_ENUM_CONSTANT(BUILD_SEGMENTS); diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 07b58e9721..40f74d3f50 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -243,7 +243,7 @@ bool CPUParticles2D::get_fractional_delta() const { } TypedArray<String> CPUParticles2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); + TypedArray<String> warnings = Node2D::get_configuration_warnings(); CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); @@ -314,6 +314,8 @@ void CPUParticles2D::set_param_max(Parameter p_param, real_t p_value) { if (parameters_min[p_param] > parameters_max[p_param]) { set_param_min(p_param, p_value); } + + update_configuration_warnings(); } real_t CPUParticles2D::get_param_max(Parameter p_param) const { @@ -374,6 +376,8 @@ void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv default: { } } + + update_configuration_warnings(); } Ref<Curve> CPUParticles2D::get_param_curve(Parameter p_param) const { @@ -499,32 +503,32 @@ bool CPUParticles2D::get_split_scale() { return split_scale; } -void CPUParticles2D::_validate_property(PropertyInfo &property) const { - if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { - property.usage = PROPERTY_USAGE_NONE; +void CPUParticles2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) { + p_property.usage = PROPERTY_USAGE_NONE; } - if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { - property.usage = PROPERTY_USAGE_NONE; + if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { + p_property.usage = PROPERTY_USAGE_NONE; } - if (property.name.begins_with("scale_curve_") && !split_scale) { - property.usage = PROPERTY_USAGE_NONE; + if (p_property.name.begins_with("scale_curve_") && !split_scale) { + p_property.usage = PROPERTY_USAGE_NONE; } } @@ -1362,9 +1366,9 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles); ADD_GROUP("Emission Shape", "emission_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,Rectangle,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,suffix:px"), "set_emission_sphere_radius", "get_emission_sphere_radius"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "emission_rect_extents"), "set_emission_rect_extents", "get_emission_rect_extents"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "emission_rect_extents", PROPERTY_HINT_NONE, "suffix:px"), "set_emission_rect_extents", "get_emission_rect_extents"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "emission_normals"), "set_emission_normals", "get_emission_normals"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "emission_colors"), "set_emission_colors", "get_emission_colors"); @@ -1466,7 +1470,7 @@ CPUParticles2D::CPUParticles2D() { set_emitting(true); set_amount(8); - set_use_local_coordinates(true); + set_use_local_coordinates(false); set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param_min(PARAM_ANGULAR_VELOCITY, 0); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 51d58723b4..8f1671d280 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -193,7 +193,7 @@ private: protected: static void _bind_methods(); void _notification(int p_what); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_emitting(bool p_emitting); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index d1b5f16e08..e4354a69e2 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -141,7 +141,6 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) { void GPUParticles2D::set_trail_enabled(bool p_enabled) { trail_enabled = p_enabled; RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); - update_configuration_warnings(); update(); RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED); @@ -297,7 +296,7 @@ bool GPUParticles2D::get_interpolate() const { } TypedArray<String> GPUParticles2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); + TypedArray<String> warnings = Node2D::get_configuration_warnings(); if (RenderingServer::get_singleton()->is_low_end()) { warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose.")); @@ -341,7 +340,7 @@ Ref<Texture2D> GPUParticles2D::get_texture() const { return texture; } -void GPUParticles2D::_validate_property(PropertyInfo &property) const { +void GPUParticles2D::_validate_property(PropertyInfo &p_property) const { } void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { @@ -617,12 +616,12 @@ void GPUParticles2D::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,suffix:px"), "set_collision_base_size", "get_collision_base_size"); ADD_GROUP("Drawing", ""); - ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect"), "set_visibility_rect", "get_visibility_rect"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_visibility_rect", "get_visibility_rect"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime"), "set_draw_order", "get_draw_order"); ADD_GROUP("Trails", "trail_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_trail_length", "get_trail_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length"); ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections"); ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions"); ADD_GROUP("Process Material", "process_"); @@ -661,7 +660,7 @@ GPUParticles2D::GPUParticles2D() { set_explosiveness_ratio(0); set_randomness_ratio(0); set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200))); - set_use_local_coordinates(true); + set_use_local_coordinates(false); set_draw_order(DRAW_ORDER_LIFETIME); set_speed_scale(1); set_fixed_fps(30); diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 3c7f4cd9b5..7eece32898 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PARTICLES_2D_H -#define PARTICLES_2D_H +#ifndef GPU_PARTICLES_2D_H +#define GPU_PARTICLES_2D_H #include "scene/2d/node_2d.h" @@ -84,7 +84,7 @@ private: protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); void _update_collision_size(); @@ -167,4 +167,4 @@ public: VARIANT_ENUM_CAST(GPUParticles2D::DrawOrder) VARIANT_ENUM_CAST(GPUParticles2D::EmitFlags) -#endif // PARTICLES_2D_H +#endif // GPU_PARTICLES_2D_H diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 28d9b284e6..7eb6b43af7 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -30,6 +30,11 @@ #include "light_2d.h" +void Light2D::owner_changed_notify() { + // For cases where owner changes _after_ entering tree (as example, editor editing). + _update_light_visibility(); +} + void Light2D::_update_light_visibility() { if (!is_inside_tree()) { return; @@ -222,9 +227,9 @@ real_t Light2D::get_shadow_smooth() const { return shadow_smooth; } -void Light2D::_validate_property(PropertyInfo &property) const { - if (!shadow && (property.name == "shadow_color" || property.name == "shadow_filter" || property.name == "shadow_filter_smooth" || property.name == "shadow_item_cull_mask")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Light2D::_validate_property(PropertyInfo &p_property) const { + if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index f7b1f420e3..373cfe59fd 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -73,11 +73,13 @@ private: void _update_light_visibility(); + virtual void owner_changed_notify() override; + protected: _FORCE_INLINE_ RID _get_light() const { return canvas_light; } void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: void set_enabled(bool p_enabled); diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index 4acfeaf781..b61e23464a 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef LIGHTOCCLUDER2D_H -#define LIGHTOCCLUDER2D_H +#ifndef LIGHT_OCCLUDER_2D_H +#define LIGHT_OCCLUDER_2D_H #include "scene/2d/node_2d.h" @@ -111,4 +111,4 @@ public: ~LightOccluder2D(); }; -#endif // LIGHTOCCLUDER2D_H +#endif // LIGHT_OCCLUDER_2D_H diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 06e5cbc97e..837f3061f1 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -346,13 +346,13 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_points", "points"), &Line2D::set_points); ClassDB::bind_method(D_METHOD("get_points"), &Line2D::get_points); - ClassDB::bind_method(D_METHOD("set_point_position", "i", "position"), &Line2D::set_point_position); - ClassDB::bind_method(D_METHOD("get_point_position", "i"), &Line2D::get_point_position); + ClassDB::bind_method(D_METHOD("set_point_position", "index", "position"), &Line2D::set_point_position); + ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Line2D::get_point_position); ClassDB::bind_method(D_METHOD("get_point_count"), &Line2D::get_point_count); - ClassDB::bind_method(D_METHOD("add_point", "position", "at_position"), &Line2D::add_point, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point); + ClassDB::bind_method(D_METHOD("add_point", "position", "index"), &Line2D::add_point, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("remove_point", "index"), &Line2D::remove_point); ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points); diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 5322c5a5fe..27c510171a 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef LINE2D_H -#define LINE2D_H +#ifndef LINE_2D_H +#define LINE_2D_H #include "node_2d.h" @@ -138,4 +138,4 @@ private: bool _antialiased = false; }; -#endif // LINE2D_H +#endif // LINE_2D_H diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 00082b321e..a5f7faffef 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -40,6 +40,9 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationAgent2D::set_avoidance_enabled); ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationAgent2D::get_avoidance_enabled); + ClassDB::bind_method(D_METHOD("set_path_desired_distance", "desired_distance"), &NavigationAgent2D::set_path_desired_distance); + ClassDB::bind_method(D_METHOD("get_path_desired_distance"), &NavigationAgent2D::get_path_desired_distance); + ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent2D::set_target_desired_distance); ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent2D::get_target_desired_distance); @@ -61,8 +64,14 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_path_max_distance", "max_speed"), &NavigationAgent2D::set_path_max_distance); ClassDB::bind_method(D_METHOD("get_path_max_distance"), &NavigationAgent2D::get_path_max_distance); - ClassDB::bind_method(D_METHOD("set_navigable_layers", "navigable_layers"), &NavigationAgent2D::set_navigable_layers); - ClassDB::bind_method(D_METHOD("get_navigable_layers"), &NavigationAgent2D::get_navigable_layers); + ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationAgent2D::set_navigation_layers); + ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationAgent2D::get_navigation_layers); + + ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent2D::set_navigation_layer_value); + ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent2D::get_navigation_layer_value); + + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent2D::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent2D::get_navigation_map); ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent2D::set_target_location); ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent2D::get_target_location); @@ -78,15 +87,19 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent2D::_avoidance_done); + ADD_GROUP("Pathfinding", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_path_desired_distance", "get_path_desired_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_target_desired_distance", "get_target_desired_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + + ADD_GROUP("Avoidance", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,500,0.01,suffix:px"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px"), "set_neighbor_dist", "get_neighbor_dist"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:s"), "set_time_horizon", "get_time_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px/s"), "set_max_speed", "get_max_speed"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "navigable_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigable_layers", "get_navigable_layers"); ADD_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); @@ -96,16 +109,30 @@ void NavigationAgent2D::_bind_methods() { void NavigationAgent2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - agent_parent = Object::cast_to<Node2D>(get_parent()); - if (agent_parent != nullptr) { - // place agent on navigation map first or else the RVO agent callback creation fails silently later - NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); - set_avoidance_enabled(avoidance_enabled); - } + case NOTIFICATION_POST_ENTER_TREE: { + // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready. + // cannot use READY as ready does not get called if Node is readded to SceneTree + set_agent_parent(get_parent()); set_physics_process_internal(true); } break; + case NOTIFICATION_PARENTED: { + if (is_inside_tree() && (get_parent() != agent_parent)) { + // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around + // PARENTED notification fires also when Node is added in scripts to a parent + // this would spam transforms fails and world fails while Node is outside SceneTree + // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this + set_agent_parent(get_parent()); + set_physics_process_internal(true); + } + } break; + + case NOTIFICATION_UNPARENTED: { + // if agent has no parent no point in processing it until reparented + set_agent_parent(nullptr); + set_physics_process_internal(false); + } break; + case NOTIFICATION_PAUSED: { if (agent_parent && !agent_parent->can_process()) { map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid()); @@ -133,7 +160,11 @@ void NavigationAgent2D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { - NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); + if (avoidance_enabled) { + // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding + // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used + NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); + } _check_distance_to_target(); } } break; @@ -167,16 +198,72 @@ bool NavigationAgent2D::get_avoidance_enabled() const { return avoidance_enabled; } -void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) { - bool layers_changed = navigable_layers != p_layers; - navigable_layers = p_layers; - if (layers_changed) { +void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) { + // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map + NavigationServer2D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done"); + if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) { + // place agent on navigation map first or else the RVO agent callback creation fails silently later + agent_parent = Object::cast_to<Node2D>(p_agent_parent); + if (map_override.is_valid()) { + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_override); + } else { + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); + } + // create new avoidance callback if enabled + set_avoidance_enabled(avoidance_enabled); + } else { + agent_parent = nullptr; + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID()); + } +} + +void NavigationAgent2D::set_navigation_layers(uint32_t p_navigation_layers) { + bool navigation_layers_changed = navigation_layers != p_navigation_layers; + navigation_layers = p_navigation_layers; + if (navigation_layers_changed) { _request_repath(); } } -uint32_t NavigationAgent2D::get_navigable_layers() const { - return navigable_layers; +uint32_t NavigationAgent2D::get_navigation_layers() const { + return navigation_layers; +} + +void NavigationAgent2D::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 NavigationAgent2D::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 NavigationAgent2D::set_navigation_map(RID p_navigation_map) { + map_override = p_navigation_map; + NavigationServer2D::get_singleton()->agent_set_map(agent, map_override); + _request_repath(); +} + +RID NavigationAgent2D::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (agent_parent != nullptr) { + return agent_parent->get_world_2d()->get_navigation_map(); + } + return RID(); +} + +void NavigationAgent2D::set_path_desired_distance(real_t p_dd) { + path_desired_distance = p_dd; } void NavigationAgent2D::set_target_desired_distance(real_t p_dd) { @@ -327,7 +414,11 @@ void NavigationAgent2D::update_navigation() { } if (reload_path) { - navigation_path = NavigationServer2D::get_singleton()->map_get_path(agent_parent->get_world_2d()->get_navigation_map(), o, target_location, true, navigable_layers); + if (map_override.is_valid()) { + navigation_path = NavigationServer2D::get_singleton()->map_get_path(map_override, o, target_location, true, navigation_layers); + } else { + navigation_path = NavigationServer2D::get_singleton()->map_get_path(agent_parent->get_world_2d()->get_navigation_map(), o, target_location, true, navigation_layers); + } navigation_finished = false; nav_path_index = 0; emit_signal(SNAME("path_changed")); @@ -340,7 +431,7 @@ void NavigationAgent2D::update_navigation() { // Check if we can advance the navigation path if (navigation_finished == false) { // Advances to the next far away location. - while (o.distance_to(navigation_path[nav_path_index]) < target_desired_distance) { + while (o.distance_to(navigation_path[nav_path_index]) < path_desired_distance) { nav_path_index += 1; if (nav_path_index == navigation_path.size()) { _check_distance_to_target(); diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 5ab4cdba5d..76eba20058 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -42,10 +42,12 @@ class NavigationAgent2D : public Node { RID agent; RID map_before_pause; + RID map_override; bool avoidance_enabled = false; - uint32_t navigable_layers = 1; + uint32_t navigation_layers = 1; + real_t path_desired_distance = 1.0; real_t target_desired_distance = 1.0; real_t radius = 0.0; real_t neighbor_dist = 0.0; @@ -82,8 +84,21 @@ public: void set_avoidance_enabled(bool p_enabled); bool get_avoidance_enabled() const; - void set_navigable_layers(uint32_t p_layers); - uint32_t get_navigable_layers() const; + void set_agent_parent(Node *p_agent_parent); + + void set_navigation_layers(uint32_t p_navigation_layers); + uint32_t get_navigation_layers() const; + + void set_navigation_layer_value(int p_layer_number, bool p_value); + bool get_navigation_layer_value(int p_layer_number) const; + + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + + void set_path_desired_distance(real_t p_dd); + real_t get_path_desired_distance() const { + return path_desired_distance; + } void set_target_desired_distance(real_t p_dd); real_t get_target_desired_distance() const { @@ -148,4 +163,4 @@ private: void _check_distance_to_target(); }; -#endif +#endif // NAVIGATION_AGENT_2D_H diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index 948cf5b61a..5795c6c94f 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -46,7 +46,7 @@ class NavigationObstacle2D : public Node { protected: static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); public: @@ -74,4 +74,4 @@ private: real_t estimate_agent_radius() const; }; -#endif +#endif // NAVIGATION_OBSTACLE_2D_H diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 260faf1d68..00aa4b0b59 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" +#include "servers/navigation_server_3d.h" #include "thirdparty/misc/polypartition.h" @@ -331,6 +332,7 @@ void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count); ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon); ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons); + ClassDB::bind_method(D_METHOD("get_mesh"), &NavigationPolygon::get_mesh); ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline); ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index); @@ -370,21 +372,61 @@ void NavigationRegion2D::set_enabled(bool p_enabled) { NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } - if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) { +#ifdef DEBUG_ENABLED + if (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) { update(); } +#endif // DEBUG_ENABLED } bool NavigationRegion2D::is_enabled() const { return enabled; } -void NavigationRegion2D::set_layers(uint32_t p_layers) { - NavigationServer2D::get_singleton()->region_set_layers(region, p_layers); +void NavigationRegion2D::set_navigation_layers(uint32_t p_navigation_layers) { + NavigationServer2D::get_singleton()->region_set_navigation_layers(region, p_navigation_layers); } -uint32_t NavigationRegion2D::get_layers() const { - return NavigationServer2D::get_singleton()->region_get_layers(region); +uint32_t NavigationRegion2D::get_navigation_layers() const { + return NavigationServer2D::get_singleton()->region_get_navigation_layers(region); +} + +void NavigationRegion2D::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 NavigationRegion2D::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 NavigationRegion2D::set_enter_cost(real_t p_enter_cost) { + ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); + enter_cost = MAX(p_enter_cost, 0.0); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost); +} + +real_t NavigationRegion2D::get_enter_cost() const { + return enter_cost; +} + +void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) { + ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); + travel_cost = MAX(p_travel_cost, 0.0); + NavigationServer2D::get_singleton()->region_set_travel_cost(region, travel_cost); +} + +real_t NavigationRegion2D::get_travel_cost() const { + return travel_cost; } RID NavigationRegion2D::get_region_rid() const { @@ -423,7 +465,8 @@ void NavigationRegion2D::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) { +#ifdef DEBUG_ENABLED + if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) && navpoly.is_valid()) { Vector<Vector2> verts = navpoly->get_vertices(); if (verts.size() < 3) { return; @@ -431,11 +474,11 @@ void NavigationRegion2D::_notification(int p_what) { Color color; if (enabled) { - color = get_tree()->get_debug_navigation_color(); + color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(); } else { - color = get_tree()->get_debug_navigation_disabled_color(); + color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color(); } - Color doors_color = color.lightened(0.2); + Color doors_color = NavigationServer3D::get_singleton()->get_debug_navigation_edge_connection_color(); RandomPCG rand; @@ -451,7 +494,7 @@ void NavigationRegion2D::_notification(int p_what) { // Generate the polygon color, slightly randomly modified from the settings one. Color random_variation_color; - random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1); + random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.1, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.2); random_variation_color.a = color.a; Vector<Color> colors; colors.push_back(random_variation_color); @@ -477,6 +520,7 @@ void NavigationRegion2D::_notification(int p_what) { draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color); } } +#endif // DEBUG_ENABLED } break; } } @@ -513,10 +557,13 @@ void NavigationRegion2D::_navpoly_changed() { NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); } } + void NavigationRegion2D::_map_changed(RID p_map) { - if (enabled && get_world_2d()->get_navigation_map() == p_map) { +#ifdef DEBUG_ENABLED + if (is_inside_tree() && get_world_2d()->get_navigation_map() == p_map) { update(); } +#endif // DEBUG_ENABLED } TypedArray<String> NavigationRegion2D::get_configuration_warnings() const { @@ -538,23 +585,46 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion2D::is_enabled); - ClassDB::bind_method(D_METHOD("set_layers", "layers"), &NavigationRegion2D::set_layers); - ClassDB::bind_method(D_METHOD("get_layers"), &NavigationRegion2D::get_layers); + ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationRegion2D::set_navigation_layers); + ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationRegion2D::get_navigation_layers); + + ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationRegion2D::set_navigation_layer_value); + ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationRegion2D::get_navigation_layer_value); ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion2D::get_region_rid); + ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion2D::set_enter_cost); + ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion2D::get_enter_cost); + + ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion2D::set_travel_cost); + ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion2D::get_travel_cost); + ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_layers", "get_layers"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + 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"); } NavigationRegion2D::NavigationRegion2D() { set_notify_transform(true); region = NavigationServer2D::get_singleton()->region_create(); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); + NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); + +#ifdef DEBUG_ENABLED + NavigationServer3D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer3D::get_singleton_mut()->connect("navigation_debug_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); +#endif // DEBUG_ENABLED } NavigationRegion2D::~NavigationRegion2D() { NavigationServer2D::get_singleton()->free(region); + +#ifdef DEBUG_ENABLED + NavigationServer3D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer3D::get_singleton_mut()->disconnect("navigation_debug_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); +#endif // DEBUG_ENABLED } diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 3c4a4e81d9..3c9df91fe3 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -98,6 +98,9 @@ class NavigationRegion2D : public Node2D { RID region; Ref<NavigationPolygon> navpoly; + real_t enter_cost = 0.0; + real_t travel_cost = 1.0; + void _navpoly_changed(); void _map_changed(RID p_RID); @@ -114,11 +117,20 @@ public: void set_enabled(bool p_enabled); bool is_enabled() const; - void set_layers(uint32_t p_layers); - uint32_t get_layers() const; + void set_navigation_layers(uint32_t p_navigation_layers); + uint32_t get_navigation_layers() const; + + void set_navigation_layer_value(int p_layer_number, bool p_value); + bool get_navigation_layer_value(int p_layer_number) const; RID get_region_rid() const; + void set_enter_cost(real_t p_enter_cost); + real_t get_enter_cost() const; + + void set_travel_cost(real_t p_travel_cost); + real_t get_travel_cost() const; + void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly); Ref<NavigationPolygon> get_navigation_polygon() const; diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 2ed5ef905a..4599785ce4 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -244,9 +244,9 @@ Point2 Node2D::get_global_position() const { } void Node2D::set_global_position(const Point2 &p_pos) { - CanvasItem *pi = get_parent_item(); - if (pi) { - Transform2D inv = pi->get_global_transform().affine_inverse(); + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D inv = parent->get_global_transform().affine_inverse(); set_position(inv.xform(p_pos)); } else { set_position(p_pos); @@ -257,25 +257,48 @@ real_t Node2D::get_global_rotation() const { return get_global_transform().get_rotation(); } -void Node2D::set_global_rotation(real_t p_radians) { - CanvasItem *pi = get_parent_item(); - if (pi) { - const real_t parent_global_rot = pi->get_global_transform().get_rotation(); - set_rotation(p_radians - parent_global_rot); +real_t Node2D::get_global_skew() const { + return get_global_transform().get_skew(); +} + +void Node2D::set_global_rotation(const real_t p_radians) { + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_rotation(p_radians); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_rotation(new_transform.get_rotation()); } else { set_rotation(p_radians); } } +void Node2D::set_global_skew(const real_t p_radians) { + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_skew(p_radians); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_skew(new_transform.get_skew()); + } else { + set_skew(p_radians); + } +} + Size2 Node2D::get_global_scale() const { return get_global_transform().get_scale(); } void Node2D::set_global_scale(const Size2 &p_scale) { - CanvasItem *pi = get_parent_item(); - if (pi) { - const Size2 parent_global_scale = pi->get_global_transform().get_scale(); - set_scale(p_scale / parent_global_scale); + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_scale(p_scale); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_scale(new_transform.get_scale()); } else { set_scale(p_scale); } @@ -295,9 +318,9 @@ void Node2D::set_transform(const Transform2D &p_transform) { } void Node2D::set_global_transform(const Transform2D &p_transform) { - CanvasItem *pi = get_parent_item(); - if (pi) { - set_transform(pi->get_global_transform().affine_inverse() * p_transform); + CanvasItem *parent = get_parent_item(); + if (parent) { + set_transform(parent->get_global_transform().affine_inverse() * p_transform); } else { set_transform(p_transform); } @@ -388,6 +411,8 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_position"), &Node2D::get_global_position); ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node2D::set_global_rotation); ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node2D::get_global_rotation); + ClassDB::bind_method(D_METHOD("set_global_skew", "radians"), &Node2D::set_global_skew); + ClassDB::bind_method(D_METHOD("get_global_skew"), &Node2D::get_global_skew); ClassDB::bind_method(D_METHOD("set_global_scale", "scale"), &Node2D::set_global_scale); ClassDB::bind_method(D_METHOD("get_global_scale"), &Node2D::get_global_scale); @@ -412,15 +437,16 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,noslider,suffix:px"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,no_slider,suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_scale", "get_global_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_skew", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_skew", "get_global_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); ADD_GROUP("Ordering", ""); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 69d14f82ad..0d8a31e6bb 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef NODE2D_H -#define NODE2D_H +#ifndef NODE_2D_H +#define NODE_2D_H #include "scene/main/canvas_item.h" @@ -92,12 +92,14 @@ public: Point2 get_global_position() const; real_t get_global_rotation() const; + real_t get_global_skew() const; Size2 get_global_scale() const; void set_transform(const Transform2D &p_transform); void set_global_transform(const Transform2D &p_transform); void set_global_position(const Point2 &p_pos); - void set_global_rotation(real_t p_radians); + void set_global_rotation(const real_t p_radians); + void set_global_skew(const real_t p_radians); void set_global_scale(const Size2 &p_scale); void set_z_index(int p_z); @@ -122,4 +124,4 @@ public: Node2D() {} }; -#endif // NODE2D_H +#endif // NODE_2D_H diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 506761d959..bd5a01f5a4 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -179,7 +179,7 @@ void ParallaxBackground::_bind_methods() { ADD_GROUP("Scroll", "scroll_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_offset", "get_scroll_offset"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_base_offset", "get_scroll_base_offset"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_scale"), "set_scroll_base_scale", "get_scroll_base_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_scale", PROPERTY_HINT_LINK), "set_scroll_base_scale", "get_scroll_base_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_limit_begin", PROPERTY_HINT_NONE, "suffix:px"), "set_limit_begin", "get_limit_begin"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_limit_end", PROPERTY_HINT_NONE, "suffix:px"), "set_limit_end", "get_limit_end"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_ignore_camera_zoom"), "set_ignore_camera_zoom", "is_ignore_camera_zoom"); diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index d716f01a82..f0aad1b8a4 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -158,7 +158,7 @@ void ParallaxLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mirroring"), &ParallaxLayer::get_mirroring); ADD_GROUP("Motion", "motion_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_scale"), "set_motion_scale", "get_motion_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_scale", PROPERTY_HINT_LINK), "set_motion_scale", "get_motion_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_motion_offset", "get_motion_offset"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_mirroring"), "set_mirroring", "get_mirroring"); } diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index ba90a275e6..3c393f9752 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -87,13 +87,13 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc void Path2D::_notification(int p_what) { switch (p_what) { - // Draw the curve if navigation debugging is enabled. + // Draw the curve if path debugging is enabled. case NOTIFICATION_DRAW: { if (!curve.is_valid()) { break; } - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) { + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) { return; } @@ -102,12 +102,10 @@ void Path2D::_notification(int p_what) { } #ifdef TOOLS_ENABLED - const real_t line_width = 2 * EDSCALE; + const real_t line_width = get_tree()->get_debug_paths_width() * EDSCALE; #else - const real_t line_width = 2; + const real_t line_width = get_tree()->get_debug_paths_width(); #endif - const Color color = Color(0.5, 0.6, 1.0, 0.7); - _cached_draw_pts.resize(curve->get_point_count() * 8); int count = 0; @@ -119,7 +117,7 @@ void Path2D::_notification(int p_what) { } } - draw_polyline(_cached_draw_pts, color, line_width, true); + draw_polyline(_cached_draw_pts, get_tree()->get_debug_paths_color(), line_width, true); } break; } } @@ -129,7 +127,7 @@ void Path2D::_curve_changed() { return; } - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) { + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) { return; } @@ -247,14 +245,14 @@ bool PathFollow2D::get_cubic_interpolation() const { return cubic; } -void PathFollow2D::_validate_property(PropertyInfo &property) const { - if (property.name == "offset") { +void PathFollow2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "offset") { real_t max = 10000.0; if (path && path->get_curve().is_valid()) { max = path->get_curve()->get_baked_length(); } - property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; + p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; } } @@ -306,6 +304,7 @@ void PathFollow2D::_bind_methods() { } void PathFollow2D::set_offset(real_t p_offset) { + ERR_FAIL_COND(!isfinite(p_offset)); offset = p_offset; if (path) { if (path->get_curve().is_valid()) { diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index bc55f84831..1f3ee08a2b 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -76,7 +76,7 @@ private: void _update_transform(); protected: - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp index 2999736d64..62f4d855ef 100644 --- a/scene/2d/physical_bone_2d.cpp +++ b/scene/2d/physical_bone_2d.cpp @@ -158,6 +158,7 @@ void PhysicalBone2D::_start_physics_simulation() { // Apply the layers and masks. PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority()); // Apply the correct mode. _apply_body_mode(); @@ -176,6 +177,7 @@ void PhysicalBone2D::_stop_physics_simulation() { set_physics_process_internal(false); PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0); PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), 1.0); PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC); } } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index e7ac6432c6..797f08058f 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -222,8 +222,8 @@ void StaticBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_constant_linear_velocity", "get_constant_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity", PROPERTY_HINT_NONE, U"radians,suffix:\u00B0/s"), "set_constant_angular_velocity", "get_constant_angular_velocity"); } StaticBody2D::StaticBody2D(PhysicsServer2D::BodyMode p_mode) : @@ -387,8 +387,8 @@ void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p //E->value.rc=0; E->value.in_scene = node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody2D::_body_enter_tree), make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody2D::_body_exit_tree), make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody2D::_body_enter_tree).bind(objid)); + node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody2D::_body_exit_tree).bind(objid)); if (E->value.in_scene) { emit_signal(SceneStringNames::get_singleton()->body_entered, node); } @@ -1062,10 +1062,10 @@ void RigidDynamicBody2D::_bind_methods() { BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE); } -void RigidDynamicBody2D::_validate_property(PropertyInfo &property) const { +void RigidDynamicBody2D::_validate_property(PropertyInfo &p_property) const { if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { - if (property.name == "center_of_mass") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "center_of_mass") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } @@ -1761,7 +1761,7 @@ void CharacterBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_floor_snap_length", "get_floor_snap_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater,suffix:px"), "set_floor_snap_length", "get_floor_snap_length"); ADD_GROUP("Moving Platform", "moving_platform"); ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave"); ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers"); @@ -1776,14 +1776,14 @@ void CharacterBody2D::_bind_methods() { BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER); } -void CharacterBody2D::_validate_property(PropertyInfo &property) const { +void CharacterBody2D::_validate_property(PropertyInfo &p_property) const { if (motion_mode == MOTION_MODE_FLOATING) { - if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } else { - if (property.name == "wall_min_slide_angle") { - property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + if (p_property.name == "wall_min_slide_angle") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } } @@ -1823,6 +1823,10 @@ real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const { return result.get_angle(p_up_direction); } +real_t KinematicCollision2D::get_depth() const { + return result.collision_depth; +} + Object *KinematicCollision2D::get_local_shape() const { if (!owner) { return nullptr; @@ -1874,6 +1878,7 @@ void KinematicCollision2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel); ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder); ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0))); + ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision2D::get_depth); ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape); ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider); ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 7401fc7578..75ea535424 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -216,7 +216,7 @@ protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *) @@ -450,7 +450,7 @@ private: protected: void _notification(int p_what); static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; }; VARIANT_ENUM_CAST(CharacterBody2D::MotionMode); @@ -473,6 +473,7 @@ public: Vector2 get_travel() const; Vector2 get_remainder() const; real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const; + real_t get_depth() const; Object *get_local_shape() const; Object *get_collider() const; ObjectID get_collider_id() const; diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 4752d3148b..cb918ecb8b 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -90,9 +90,9 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler } #endif -void Polygon2D::_validate_property(PropertyInfo &property) const { - if (!invert && property.name == "invert_border") { - property.usage = PROPERTY_USAGE_NO_EDITOR; +void Polygon2D::_validate_property(PropertyInfo &p_property) const { + if (!invert && p_property.name == "invert_border") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } @@ -635,18 +635,19 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased"); - ADD_GROUP("Texture2D", ""); + + ADD_GROUP("Texture", "texture_"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_GROUP("Texture2D", "texture_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale", PROPERTY_HINT_LINK), "set_texture_scale", "get_texture_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_texture_rotation", "get_texture_rotation"); + ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); ADD_GROUP("Invert", "invert_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1"), "set_invert_border", "get_invert_border"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1,suffix:px"), "set_invert_border", "get_invert_border"); ADD_GROUP("Data", ""); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index d6a1be0f6d..d333152f62 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -77,7 +77,7 @@ class Polygon2D : public Node2D { protected: void _notification(int p_what); static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: #ifdef TOOLS_ENABLED diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 8953813452..c4036faa79 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -82,6 +82,10 @@ Object *RayCast2D::get_collider() const { return ObjectDB::get_instance(against); } +RID RayCast2D::get_collider_rid() const { + return against_rid; +} + int RayCast2D::get_collider_shape() const { return against_shape; } @@ -203,12 +207,14 @@ void RayCast2D::_update_raycast_state() { if (dss->intersect_ray(ray_params, rr)) { collided = true; against = rr.collider_id; + against_rid = rr.rid; collision_point = rr.position; collision_normal = rr.normal; against_shape = rr.shape; } else { collided = false; against = ObjectID(); + against_rid = RID(); against_shape = 0; } @@ -240,7 +246,7 @@ void RayCast2D::_draw_debug_shape() { Transform2D xf; xf.rotate(target_position.angle()); - xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); + xf.translate_local(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); Vector<Vector2> pts = { xf.xform(Vector2(arrow_size, 0)), @@ -321,6 +327,7 @@ void RayCast2D::_bind_methods() { ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast2D::force_raycast_update); ClassDB::bind_method(D_METHOD("get_collider"), &RayCast2D::get_collider); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &RayCast2D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast2D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast2D::get_collision_point); ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast2D::get_collision_normal); diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index 1fb97d89fe..57f993fe8d 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -41,6 +41,7 @@ class RayCast2D : public Node2D { bool enabled = true; bool collided = false; ObjectID against; + RID against_rid; int against_shape = 0; Vector2 collision_point; Vector2 collision_normal; @@ -91,6 +92,7 @@ public: bool is_colliding() const; Object *get_collider() const; + RID get_collider_rid() const; int get_collider_shape() const; Vector2 get_collision_point() const; Vector2 get_collision_normal() const; diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index a2f4b16ed3..316988d298 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -217,7 +217,7 @@ void ShapeCast2D::_notification(int p_what) { if (shape.is_null()) { break; } - Color draw_col = get_tree()->get_debug_collisions_color(); + Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color(); if (!enabled) { float g = draw_col.get_v(); draw_col.r = g; @@ -235,18 +235,25 @@ void ShapeCast2D::_notification(int p_what) { // Draw an arrow indicating where the ShapeCast is pointing to. if (target_position != Vector2()) { - Transform2D xf; - xf.rotate(target_position.angle()); - xf.translate(Vector2(target_position.length(), 0)); + const real_t max_arrow_size = 6; + const real_t line_width = 1.4; + bool no_line = target_position.length() < line_width; + real_t arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size); - draw_line(Vector2(), target_position, draw_col, 2); + if (no_line) { + arrow_size = target_position.length(); + } else { + draw_line(Vector2(), target_position - target_position.normalized() * arrow_size, draw_col, line_width); + } - float tsize = 8; + Transform2D xf; + xf.rotate(target_position.angle()); + xf.translate_local(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); Vector<Vector2> pts = { - xf.xform(Vector2(tsize, 0)), - xf.xform(Vector2(0, Math_SQRT12 * tsize)), - xf.xform(Vector2(0, -Math_SQRT12 * tsize)) + xf.xform(Vector2(arrow_size, 0)), + xf.xform(Vector2(0, 0.5 * arrow_size)), + xf.xform(Vector2(0, -0.5 * arrow_size)) }; Vector<Color> cols = { draw_col, draw_col, draw_col }; @@ -291,6 +298,8 @@ void ShapeCast2D::_update_shapecast_state() { collision_safe_fraction = 0.0; collision_unsafe_fraction = 0.0; + bool prev_collision_state = collided; + if (target_position != Vector2()) { dss->cast_motion(params, collision_safe_fraction, collision_unsafe_fraction); if (collision_unsafe_fraction < 1.0) { @@ -314,6 +323,10 @@ void ShapeCast2D::_update_shapecast_state() { } } collided = !result.is_empty(); + + if (prev_collision_state != collided) { + update(); + } } void ShapeCast2D::force_shapecast_update() { @@ -444,8 +457,8 @@ void ShapeCast2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_parent"), "set_exclude_parent_body", "get_exclude_parent_body"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position", PROPERTY_HINT_NONE, "suffix:px"), "set_target_position", "get_target_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01,suffix:px"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_results"), "set_max_results", "get_max_results"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "collision_result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "", "_get_collision_result"); diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/shape_cast_2d.h index 7ff080aed0..660e52f189 100644 --- a/scene/2d/shape_cast_2d.h +++ b/scene/2d/shape_cast_2d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SHAPE_CAST_2D -#define SHAPE_CAST_2D +#ifndef SHAPE_CAST_2D_H +#define SHAPE_CAST_2D_H #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" @@ -120,4 +120,4 @@ public: TypedArray<String> get_configuration_warnings() const override; }; -#endif +#endif // SHAPE_CAST_2D_H diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index b3062ca02a..e1983f9cb9 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -368,19 +368,19 @@ Rect2 Sprite2D::get_rect() const { return Rect2(ofs, s); } -void Sprite2D::_validate_property(PropertyInfo &property) const { - if (property.name == "frame") { - property.hint = PROPERTY_HINT_RANGE; - property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; +void Sprite2D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "frame") { + p_property.hint = PROPERTY_HINT_RANGE; + p_property.hint_string = "0," + itos(vframes * hframes - 1) + ",1"; + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - if (property.name == "frame_coords") { - property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; + if (p_property.name == "frame_coords") { + p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - if (!region_enabled && (property.name == "region_rect" || property.name == "region_filter_clip")) { - property.usage = PROPERTY_USAGE_NO_EDITOR; + if (!region_enabled && (p_property.name == "region_rect" || p_property.name == "region_filter_clip")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h index 6893e92d4a..60f5940cfe 100644 --- a/scene/2d/sprite_2d.h +++ b/scene/2d/sprite_2d.h @@ -64,7 +64,7 @@ protected: static void _bind_methods(); - virtual void _validate_property(PropertyInfo &property) const override; + void _validate_property(PropertyInfo &p_property) const; public: #ifdef TOOLS_ENABLED @@ -125,4 +125,4 @@ public: ~Sprite2D(); }; -#endif // SPRITE_H +#endif // SPRITE_2D_H diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index c4b923ff34..13bdd2bd5f 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -36,43 +36,34 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping_coords_and_peering_bits() const { HashMap<Vector2i, TileSet::CellNeighbor> output; + + ERR_FAIL_COND_V(is_center_bit(), output); + Ref<TileSet> tile_set = tile_map->get_tileset(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); TileSet::TileShape shape = tile_set->get_tile_shape(); if (shape == TileSet::TILE_SHAPE_SQUARE) { switch (bit) { - case 0: + case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; break; - case 1: + case 2: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; break; - case 2: + case 3: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; break; - case 3: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; - break; default: ERR_FAIL_V(output); } } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { switch (bit) { - case 0: - output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_CORNER)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; - output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; - break; case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; @@ -95,25 +86,25 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis(); if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { switch (bit) { - case 0: + case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_SIDE; break; - case 1: + case 2: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_CORNER; break; - case 2: + case 3: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; break; - case 3: + case 4: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER; break; - case 4: + case 5: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; break; @@ -122,25 +113,25 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap } } else { switch (bit) { - case 0: + case 1: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_RIGHT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; break; - case 1: + case 2: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE; break; - case 2: + case 3: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)] = TileSet::CELL_NEIGHBOR_LEFT_CORNER; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER; break; - case 3: + case 4: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_SIDE; break; - case 4: + case 5: output[base_cell_coords] = TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE; output[tile_map->get_neighbor_cell(base_cell_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)] = TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE; break; @@ -152,6 +143,17 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap return output; } +TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) { + tile_map = p_tile_map; + + Ref<TileSet> tile_set = tile_map->get_tileset(); + ERR_FAIL_COND(!tile_set.is_valid()); + + bit = 0; + base_cell_coords = p_position; + terrain = p_terrain; +} + TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain) { // The way we build the constraint make it easy to detect conflicting constraints. tile_map = p_tile_map; @@ -163,35 +165,35 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V if (shape == TileSet::TILE_SHAPE_SQUARE) { switch (p_bit) { case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - bit = 0; + bit = 1; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - bit = 2; + bit = 3; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - bit = 0; + bit = 1; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); break; case TileSet::CELL_NEIGHBOR_TOP_SIDE: - bit = 2; + bit = 3; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; default: @@ -201,35 +203,35 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { switch (p_bit) { case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - bit = 0; + bit = 1; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - bit = 2; + bit = 3; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - bit = 0; + bit = 1; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_CORNER); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - bit = 2; + bit = 3; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; default: @@ -242,51 +244,51 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { switch (p_bit) { case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - bit = 0; + bit = 1; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - bit = 2; + bit = 3; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - bit = 3; + bit = 4; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - bit = 4; + bit = 5; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - bit = 0; + bit = 1; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit = 3; + bit = 4; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - bit = 2; + bit = 3; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_CORNER: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - bit = 4; + bit = 5; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit = 3; + bit = 4; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; default: @@ -296,51 +298,51 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V } else { switch (p_bit) { case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - bit = 0; + bit = 1; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - bit = 1; + bit = 2; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit = 2; + bit = 3; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - bit = 3; + bit = 4; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit = 0; + bit = 1; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - bit = 4; + bit = 5; base_cell_coords = p_position; break; case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - bit = 2; + bit = 3; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - bit = 1; + bit = 2; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit = 0; + bit = 1; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_SIDE: - bit = 3; + bit = 4; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit = 2; + bit = 3; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_SIDE); break; case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - bit = 4; + bit = 5; base_cell_coords = p_tile_map->get_neighbor_cell(p_position, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); break; default: @@ -1088,7 +1090,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List q.occluders.clear(); // Those allow to group cell per material or z-index. - Ref<ShaderMaterial> prev_material; + Ref<Material> prev_material; int prev_z_index = 0; RID prev_canvas_item; @@ -1127,7 +1129,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } - Ref<ShaderMaterial> mat = tile_data->get_material(); + Ref<Material> mat = tile_data->get_material(); int z_index = tile_data->get_z_index(); // Quandrant pos. @@ -1156,6 +1158,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List rs->canvas_item_set_transform(canvas_item, xform); rs->canvas_item_set_light_mask(canvas_item, get_light_mask()); + rs->canvas_item_set_z_as_relative_to_parent(canvas_item, true); rs->canvas_item_set_z_index(canvas_item, z_index); rs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(get_texture_filter())); @@ -2060,6 +2063,18 @@ int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bo return E->value.alternative_tile; } +TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { + int source_id = get_cell_source_id(p_layer, p_coords, p_use_proxies); + ERR_FAIL_COND_V_MSG(source_id == TileSet::INVALID_SOURCE, nullptr, vformat("Invalid TileSetSource at cell %s. Make sure a tile exists at this cell.", p_coords)); + + Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); + if (source.is_valid()) { + return source->get_tile_data(get_cell_atlas_coords(p_layer, p_coords, p_use_proxies), get_cell_alternative_tile(p_layer, p_coords, p_use_proxies)); + } + + return nullptr; +} + Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) { ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr); ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); @@ -2149,37 +2164,75 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat } } -RBSet<TileSet::TerrainsPattern> TileMap::_get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) { +TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) { if (!tile_set.is_valid()) { - return RBSet<TileSet::TerrainsPattern>(); + return TileSet::TerrainsPattern(); } // Returns all tiles compatible with the given constraints. - RBSet<TileSet::TerrainsPattern> compatible_terrain_tile_patterns; - for (TileSet::TerrainsPattern &terrain_pattern : tile_set->get_terrains_pattern_set(p_terrain_set)) { - int valid = true; + RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score; + RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set); + ERR_FAIL_COND_V(pattern_set.is_empty(), TileSet::TerrainsPattern()); + for (TileSet::TerrainsPattern &terrain_pattern : pattern_set) { + int score = 0; + + // Check the center bit constraint + TerrainConstraint terrain_constraint = TerrainConstraint(this, p_position, terrain_pattern.get_terrain()); + RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint); + if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) { + score += in_set_constraint_element->get().get_priority(); + } + + // Check the surrounding bits for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); - if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) { + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { // Check if the bit is compatible with the constraints. - TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain(bit)); - RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_bit_constraint); + TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit)); + in_set_constraint_element = p_constraints.find(terrain_bit_constraint); if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) { - valid = false; - break; + score += in_set_constraint_element->get().get_priority(); } } } - if (valid) { - compatible_terrain_tile_patterns.insert(terrain_pattern); + terrain_pattern_score[terrain_pattern] = score; + } + + // Compute the minimum score + TileSet::TerrainsPattern min_score_pattern; + int min_score = INT32_MAX; + for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) { + if (E.value < min_score) { + min_score_pattern = E.key; + min_score = E.value; } } - return compatible_terrain_tile_patterns; + return min_score_pattern; } -RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_cells_list(int p_layer, const RBSet<Vector2i> &p_to_replace, int p_terrain_set, bool p_ignore_empty_terrains) const { +RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { + if (!tile_set.is_valid()) { + return RBSet<TerrainConstraint>(); + } + + // Compute the constraints needed from the surrounding tiles. + RBSet<TerrainConstraint> output; + output.insert(TerrainConstraint(this, p_position, p_terrains_pattern.get_terrain())); + + for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor side = TileSet::CellNeighbor(i); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, side)) { + TerrainConstraint c = TerrainConstraint(this, p_position, side, p_terrains_pattern.get_terrain_peering_bit(side)); + output.insert(c); + } + } + + return output; +} + +RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_cell_list, int p_terrain_set, bool p_ignore_empty_terrains) const { if (!tile_set.is_valid()) { return RBSet<TerrainConstraint>(); } @@ -2187,12 +2240,12 @@ RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), RBSet<TerrainConstraint>()); ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), RBSet<TerrainConstraint>()); - // Build a set of dummy constraints get the constrained points. + // Build a set of dummy constraints to get the constrained points. RBSet<TerrainConstraint> dummy_constraints; - for (const Vector2i &E : p_to_replace) { + for (const Vector2i &E : p_cell_list) { for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides. TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); - if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) { + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { dummy_constraints.insert(TerrainConstraint(this, E, bit, -1)); } } @@ -2200,35 +2253,31 @@ RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ // For each constrained point, we get all overlapping tiles, and select the most adequate terrain for it. RBSet<TerrainConstraint> constraints; - for (const TerrainConstraint &E : dummy_constraints) { - TerrainConstraint c = E; - + for (const TerrainConstraint &E_constraint : dummy_constraints) { HashMap<int, int> terrain_count; // Count the number of occurrences per terrain. - HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits(); + HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = E_constraint.get_overlapping_coords_and_peering_bits(); for (const KeyValue<Vector2i, TileSet::CellNeighbor> &E_overlapping : overlapping_terrain_bits) { - if (!p_to_replace.has(E_overlapping.key)) { - TileData *neighbor_tile_data = nullptr; - TileMapCell neighbor_cell = get_cell(p_layer, E_overlapping.key); - if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) { - Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id); - Ref<TileSetAtlasSource> atlas_source = source; - if (atlas_source.is_valid()) { - TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile); - if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { - neighbor_tile_data = tile_data; - } + TileData *neighbor_tile_data = nullptr; + TileMapCell neighbor_cell = get_cell(p_layer, E_overlapping.key); + if (neighbor_cell.source_id != TileSet::INVALID_SOURCE) { + Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id); + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + TileData *tile_data = atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + neighbor_tile_data = tile_data; } } + } - int terrain = neighbor_tile_data ? neighbor_tile_data->get_peering_bit_terrain(TileSet::CellNeighbor(E_overlapping.value)) : -1; - if (!p_ignore_empty_terrains || terrain >= 0) { - if (!terrain_count.has(terrain)) { - terrain_count[terrain] = 0; - } - terrain_count[terrain] += 1; + int terrain = neighbor_tile_data ? neighbor_tile_data->get_terrain_peering_bit(TileSet::CellNeighbor(E_overlapping.value)) : -1; + if (!p_ignore_empty_terrains || terrain >= 0) { + if (!terrain_count.has(terrain)) { + terrain_count[terrain] = 0; } + terrain_count[terrain] += 1; } } @@ -2244,33 +2293,34 @@ RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ // Set the adequate terrain. if (max > 0) { + TerrainConstraint c = E_constraint; c.set_terrain(max_terrain); constraints.insert(c); } } - return constraints; -} - -RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { - if (!tile_set.is_valid()) { - return RBSet<TerrainConstraint>(); - } + // Add the centers as constraints + for (Vector2i E_coords : p_cell_list) { + TileData *tile_data = nullptr; + TileMapCell cell = get_cell(p_layer, E_coords); + if (cell.source_id != TileSet::INVALID_SOURCE) { + Ref<TileSetSource> source = tile_set->get_source(cell.source_id); + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + } + } - // Compute the constraints needed from the surrounding tiles. - RBSet<TerrainConstraint> output; - for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { - TileSet::CellNeighbor side = TileSet::CellNeighbor(i); - if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) { - TerrainConstraint c = TerrainConstraint(this, p_position, side, p_terrains_pattern.get_terrain(side)); - output.insert(c); + int terrain = (tile_data && tile_data->get_terrain_set() == p_terrain_set) ? tile_data->get_terrain() : -1; + if (!p_ignore_empty_terrains || terrain >= 0) { + constraints.insert(TerrainConstraint(this, E_coords, terrain)); } } - return output; + return constraints; } -HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse(const RBSet<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) { +HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) { if (!tile_set.is_valid()) { return HashMap<Vector2i, TileSet::TerrainsPattern>(); } @@ -2278,110 +2328,287 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_colla // Copy the constraints set. RBSet<TerrainConstraint> constraints = p_constraints; - // Compute all acceptable patterns for each cell. - HashMap<Vector2i, RBSet<TileSet::TerrainsPattern>> per_cell_acceptable_tiles; - for (Vector2i cell : p_to_replace) { - per_cell_acceptable_tiles[cell] = _get_valid_terrains_patterns_for_constraints(p_terrain_set, cell, constraints); - } - // Output map. HashMap<Vector2i, TileSet::TerrainsPattern> output; // Add all positions to a set. - RBSet<Vector2i> to_replace = RBSet<Vector2i>(p_to_replace); - while (!to_replace.is_empty()) { - // Compute the minimum number of tile possibilities for each cell. - int min_nb_possibilities = 100000000; - for (const KeyValue<Vector2i, RBSet<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) { - min_nb_possibilities = MIN(min_nb_possibilities, E.value.size()); - } - - // Get the set of possible cells to fill, out of the most constrained ones. - LocalVector<Vector2i> to_choose_from; - for (const KeyValue<Vector2i, RBSet<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) { - if (E.value.size() == min_nb_possibilities) { - to_choose_from.push_back(E.key); - } - } - - // Randomly a cell to fill out of the most constrained. - Vector2i selected_cell_to_replace = to_choose_from[Math::random(0, to_choose_from.size() - 1)]; - - // Get the list of acceptable patterns for the given cell. - RBSet<TileSet::TerrainsPattern> valid_tiles = per_cell_acceptable_tiles[selected_cell_to_replace]; - if (valid_tiles.is_empty()) { - break; // No possibilities :/ - } - - // Out of the possible patterns, prioritize the one which have the least amount of different terrains. - LocalVector<TileSet::TerrainsPattern> valid_tiles_with_least_amount_of_terrains; - int min_terrain_count = 10000; - LocalVector<int> terrains_counts; - int pattern_index = 0; - for (const TileSet::TerrainsPattern &pattern : valid_tiles) { - RBSet<int> terrains; - for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { - TileSet::CellNeighbor side = TileSet::CellNeighbor(i); - if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) { - terrains.insert(pattern.get_terrain(side)); + for (int i = 0; i < p_to_replace.size(); i++) { + const Vector2i &coords = p_to_replace[i]; + + // Select the best pattern for the given constraints + TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints); + + // Update the constraint set with the new ones + RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern); + for (const TerrainConstraint &E_constraint : new_constraints) { + if (constraints.has(E_constraint)) { + constraints.erase(E_constraint); + } + TerrainConstraint c = E_constraint; + c.set_priority(5); + constraints.insert(c); + } + + output[coords] = pattern; + } + return output; +} + +HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { + HashMap<Vector2i, TileSet::TerrainsPattern> output; + ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); + + // Build list and set of tiles that can be modified (painted and their surroundings) + Vector<Vector2i> can_modify_list; + RBSet<Vector2i> can_modify_set; + RBSet<Vector2i> painted_set; + for (int i = p_coords_array.size() - 1; i >= 0; i--) { + const Vector2i &coords = p_coords_array[i]; + can_modify_list.push_back(coords); + can_modify_set.insert(coords); + painted_set.insert(coords); + } + for (Vector2i coords : p_coords_array) { + // Find the adequate neighbor + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + Vector2i neighbor = get_neighbor_cell(coords, bit); + if (!can_modify_set.has(neighbor)) { + can_modify_list.push_back(neighbor); + can_modify_set.insert(neighbor); + } + } + } + } + + // Build a set, out of the possibly modified tiles, of the one with a center bit that is set (or will be) to the painted terrain + RBSet<Vector2i> cells_with_terrain_center_bit; + for (Vector2i coords : can_modify_set) { + bool connect = false; + if (painted_set.has(coords)) { + connect = true; + } else { + // Get the center bit of the cell + TileData *tile_data = nullptr; + TileMapCell cell = get_cell(p_layer, coords); + if (cell.source_id != TileSet::INVALID_SOURCE) { + Ref<TileSetSource> source = tile_set->get_source(cell.source_id); + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); } } - min_terrain_count = MIN(min_terrain_count, terrains.size()); - terrains_counts.push_back(terrains.size()); - pattern_index++; + + if (tile_data && tile_data->get_terrain_set() == p_terrain_set && tile_data->get_terrain() == p_terrain) { + connect = true; + } } - pattern_index = 0; - for (const TileSet::TerrainsPattern &pattern : valid_tiles) { - if (terrains_counts[pattern_index] == min_terrain_count) { - valid_tiles_with_least_amount_of_terrains.push_back(pattern); + if (connect) { + cells_with_terrain_center_bit.insert(coords); + } + } + + RBSet<TerrainConstraint> constraints; + + // Add new constraints from the path drawn. + for (Vector2i coords : p_coords_array) { + // Constraints on the center bit. + TerrainConstraint c = TerrainConstraint(this, coords, p_terrain); + c.set_priority(10); + constraints.insert(c); + + // Constraints on the connecting bits. + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + c = TerrainConstraint(this, coords, bit, p_terrain); + c.set_priority(10); + if ((int(bit) % 2) == 0) { + // Side peering bits: add the constraint if the center is of the same terrain + Vector2i neighbor = get_neighbor_cell(coords, bit); + if (cells_with_terrain_center_bit.has(neighbor)) { + constraints.insert(c); + } + } else { + // Corner peering bits: add the constraint if all tiles on the constraint has the same center bit + HashMap<Vector2i, TileSet::CellNeighbor> overlapping_terrain_bits = c.get_overlapping_coords_and_peering_bits(); + bool valid = true; + for (KeyValue<Vector2i, TileSet::CellNeighbor> kv : overlapping_terrain_bits) { + if (!cells_with_terrain_center_bit.has(kv.key)) { + valid = false; + break; + } + } + if (valid) { + constraints.insert(c); + } + } } - pattern_index++; } + } - // Randomly select a pattern out of the remaining ones. - TileSet::TerrainsPattern selected_terrain_tile_pattern = valid_tiles_with_least_amount_of_terrains[Math::random(0, valid_tiles_with_least_amount_of_terrains.size() - 1)]; + // Fills in the constraint list from existing tiles. + for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) { + constraints.insert(c); + } - // Set the selected cell into the output. - output[selected_cell_to_replace] = selected_terrain_tile_pattern; - to_replace.erase(selected_cell_to_replace); - per_cell_acceptable_tiles.erase(selected_cell_to_replace); + // Fill the terrains. + output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + return output; +} - // Add the new constraints from the added tiles. - RBSet<TerrainConstraint> new_constraints = get_terrain_constraints_from_added_tile(selected_cell_to_replace, p_terrain_set, selected_terrain_tile_pattern); - for (const TerrainConstraint &E_constraint : new_constraints) { - constraints.insert(E_constraint); +HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_layer, const Vector<Vector2i> &p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { + HashMap<Vector2i, TileSet::TerrainsPattern> output; + ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); + + // Make sure the path is correct and build the peering bit list while doing it. + Vector<TileSet::CellNeighbor> neighbor_list; + for (int i = 0; i < p_path.size() - 1; i++) { + // Find the adequate neighbor + TileSet::CellNeighbor found_bit = TileSet::CELL_NEIGHBOR_MAX; + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + if (get_neighbor_cell(p_path[i], bit) == p_path[i + 1]) { + found_bit = bit; + break; + } + } + } + ERR_FAIL_COND_V_MSG(found_bit == TileSet::CELL_NEIGHBOR_MAX, output, vformat("Invalid terrain path, %s is not a neighbouring tile of %s", p_path[i + 1], p_path[i])); + neighbor_list.push_back(found_bit); + } + + // Build list and set of tiles that can be modified (painted and their surroundings) + Vector<Vector2i> can_modify_list; + RBSet<Vector2i> can_modify_set; + for (int i = p_path.size() - 1; i >= 0; i--) { + const Vector2i &coords = p_path[i]; + can_modify_list.push_back(coords); + can_modify_set.insert(coords); + } + for (Vector2i coords : p_path) { + // Find the adequate neighbor + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + Vector2i neighbor = get_neighbor_cell(coords, bit); + if (!can_modify_set.has(neighbor)) { + can_modify_list.push_back(neighbor); + can_modify_set.insert(neighbor); + } + } } + } + + RBSet<TerrainConstraint> constraints; + + // Add new constraints from the path drawn. + for (Vector2i coords : p_path) { + // Constraints on the center bit + TerrainConstraint c = TerrainConstraint(this, coords, p_terrain); + c.set_priority(10); + constraints.insert(c); + } + for (int i = 0; i < p_path.size() - 1; i++) { + // Constraints on the peering bits. + TerrainConstraint c = TerrainConstraint(this, p_path[i], neighbor_list[i], p_terrain); + c.set_priority(10); + constraints.insert(c); + } + + // Fills in the constraint list from existing tiles. + for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) { + constraints.insert(c); + } + + // Fill the terrains. + output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + return output; +} - // Compute valid tiles again for neighbors. - for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { - TileSet::CellNeighbor side = TileSet::CellNeighbor(i); - if (is_existing_neighbor(side)) { - Vector2i neighbor = get_neighbor_cell(selected_cell_to_replace, side); - if (to_replace.has(neighbor)) { - per_cell_acceptable_tiles[neighbor] = _get_valid_terrains_patterns_for_constraints(p_terrain_set, neighbor, constraints); +HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) { + HashMap<Vector2i, TileSet::TerrainsPattern> output; + ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); + + // Build list and set of tiles that can be modified (painted and their surroundings). + Vector<Vector2i> can_modify_list; + RBSet<Vector2i> can_modify_set; + for (int i = p_coords_array.size() - 1; i >= 0; i--) { + const Vector2i &coords = p_coords_array[i]; + can_modify_list.push_back(coords); + can_modify_set.insert(coords); + } + for (Vector2i coords : p_coords_array) { + // Find the adequate neighbor + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { + Vector2i neighbor = get_neighbor_cell(coords, bit); + if (!can_modify_set.has(neighbor)) { + can_modify_list.push_back(neighbor); + can_modify_set.insert(neighbor); } } } } + + // Add constraint by the new ones. + RBSet<TerrainConstraint> constraints; + + // Add new constraints from the path drawn. + for (Vector2i coords : p_coords_array) { + // Constraints on the center bit + RBSet<TerrainConstraint> added_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, p_terrains_pattern); + for (TerrainConstraint c : added_constraints) { + c.set_priority(10); + constraints.insert(c); + } + } + + // Fills in the constraint list from modified tiles border. + for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) { + constraints.insert(c); + } + + // Fill the terrains. + output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); return output; } -void TileMap::set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector2i> p_coords_array, int p_terrain_set, bool p_ignore_empty_terrains) { +void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { ERR_FAIL_COND(!tile_set.is_valid()); ERR_FAIL_INDEX(p_layer, (int)layers.size()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); - RBSet<Vector2i> coords_set; - for (int i = 0; i < p_coords_array.size(); i++) { - coords_set.insert(p_coords_array[i]); + Vector<Vector2i> vector_cells; + for (int i = 0; i < p_cells.size(); i++) { + vector_cells.push_back(p_cells[i]); + } + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, vector_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains); + for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) { + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value); + set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); } +} - RBSet<TileMap::TerrainConstraint> constraints = get_terrain_constraints_from_removed_cells_list(p_layer, coords_set, p_terrain_set, p_ignore_empty_terrains); +void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { + ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_INDEX(p_layer, (int)layers.size()); + ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); - HashMap<Vector2i, TileSet::TerrainsPattern> wfc_output = terrain_wave_function_collapse(coords_set, p_terrain_set, constraints); - for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : wfc_output) { - TileMapCell cell = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); - set_cell(p_layer, kv.key, cell.source_id, cell.get_atlas_coords(), cell.alternative_tile); + Vector<Vector2i> vector_path; + for (int i = 0; i < p_path.size(); i++) { + vector_path.push_back(p_path[i]); + } + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(p_layer, vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains); + for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) { + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value); + set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); } } @@ -2437,7 +2664,7 @@ void TileMap::clear_layer(int p_layer) { // Remove all tiles. _clear_layer_internals(p_layer); layers[p_layer].tile_map.clear(); - + _recreate_layer_internals(p_layer); used_rect_cache_dirty = true; } @@ -2447,6 +2674,7 @@ void TileMap::clear() { for (unsigned int i = 0; i < layers.size(); i++) { layers[i].tile_map.clear(); } + _recreate_internals(); used_rect_cache_dirty = true; } @@ -2729,7 +2957,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/enabled", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::COLOR, vformat("layer_%d/modulate", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/y_sort_enabled", i), PROPERTY_HINT_NONE)); - p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/y_sort_origin", i), PROPERTY_HINT_NONE)); + p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/y_sort_origin", i), PROPERTY_HINT_NONE, "suffix:px")); p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/z_index", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("layer_%d/tile_data", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); } @@ -3630,9 +3858,10 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0)); ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell); - ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id); - ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords); - ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile); + ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_cell_tile_data", "layer", "coords", "use_proxies"), &TileMap::get_cell_tile_data, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMap::get_coords_for_body_rid); @@ -3640,7 +3869,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("map_pattern", "position_in_tilemap", "coords_in_pattern", "pattern"), &TileMap::map_pattern); ClassDB::bind_method(D_METHOD("set_pattern", "layer", "position", "pattern"), &TileMap::set_pattern); - ClassDB::bind_method(D_METHOD("set_cells_from_surrounding_terrains", "layer", "cells", "terrain_set", "ignore_empty_terrains"), &TileMap::set_cells_from_surrounding_terrains, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("set_cells_terrain_connect", "layer", "cells", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMap::set_cells_terrain_connect, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("set_cells_terrain_path", "layer", "path", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMap::set_cells_terrain_path, DEFVAL(true)); ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles); ClassDB::bind_method(D_METHOD("clear_layer", "layer"), &TileMap::clear_layer); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 02a2b3a1c6..ecc6ee1d59 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -119,6 +119,8 @@ public: int bit = -1; int terrain = -1; + int priority = 1; + public: bool operator<(const TerrainConstraint &p_other) const { if (base_cell_coords == p_other.base_cell_coords) { @@ -128,13 +130,17 @@ public: } String to_string() const { - return vformat("Constraint {pos:%s, bit:%d, terrain:%d}", base_cell_coords, bit, terrain); + return vformat("Constraint {pos:%s, bit:%d, terrain:%d, priority:%d}", base_cell_coords, bit, terrain, priority); } Vector2i get_base_cell_coords() const { return base_cell_coords; } + bool is_center_bit() const { + return bit == 0; + } + HashMap<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const; void set_terrain(int p_terrain) { @@ -145,8 +151,17 @@ public: return terrain; } - TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); - TerrainConstraint() {} + void set_priority(int p_priority) { + priority = p_priority; + } + + int get_priority() { + return priority; + } + + TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain); // For the center terrain bit + TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, const TileSet::CellNeighbor &p_bit, int p_terrain); // For peering bits + TerrainConstraint(){}; }; enum VisibilityMode { @@ -251,7 +266,9 @@ private: void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant); // Terrains. - RBSet<TileSet::TerrainsPattern> _get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints); + TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints); + RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; + RBSet<TerrainConstraint> _get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_on_map, int p_terrain_set, bool p_ignore_empty_terrains) const; // Set and get tiles from data arrays. void _set_tile_data(int p_layer, const Vector<int> &p_data); @@ -326,6 +343,8 @@ public: int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; + // Helper method to make accessing the data easier. + TileData *get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; // Patterns. Ref<TileMapPattern> get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array); @@ -333,10 +352,13 @@ public: void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern); // Terrains. - RBSet<TerrainConstraint> get_terrain_constraints_from_removed_cells_list(int p_layer, const RBSet<Vector2i> &p_to_replace, int p_terrain_set, bool p_ignore_empty_terrains = true) const; // Not exposed. - RBSet<TerrainConstraint> get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; // Not exposed. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_wave_function_collapse(const RBSet<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed. - void set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector2i> p_coords_array, int p_terrain_set, bool p_ignore_empty_terrains = true); + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed. + + void set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); + void set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed to users TileMapCell get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; @@ -365,7 +387,7 @@ public: // For finding tiles from collision. Vector2i get_coords_for_body_rid(RID p_physics_body); - // Fixing a nclearing methods. + // Fixing and clearing methods. void fix_invalid_tiles(); // Clears tiles from a given layer diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index 4a4a2a1da0..9dea69cd64 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -131,7 +131,7 @@ void TouchScreenButton::_notification(int p_what) { pos = texture_normal->get_size() * 0.5; } - draw_set_transform_matrix(get_canvas_transform().translated(pos)); + draw_set_transform_matrix(get_canvas_transform().translated_local(pos)); shape->draw(get_canvas_item(), draw_col); } } break; @@ -258,7 +258,7 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { pos = texture_normal->get_size() * 0.5; } - touched = shape->collide(Transform2D().translated(pos), unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); + touched = shape->collide(Transform2D().translated_local(pos), unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); } if (bitmask.is_valid()) { diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp index 33dd737416..1971dc1240 100644 --- a/scene/2d/visible_on_screen_notifier_2d.cpp +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -66,6 +66,7 @@ void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) { if (is_inside_tree()) { RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit)); } + update(); } Rect2 VisibleOnScreenNotifier2D::get_rect() const { diff --git a/scene/2d/visible_on_screen_notifier_2d.h b/scene/2d/visible_on_screen_notifier_2d.h index 38b508e2f6..ac7fad95a5 100644 --- a/scene/2d/visible_on_screen_notifier_2d.h +++ b/scene/2d/visible_on_screen_notifier_2d.h @@ -102,4 +102,4 @@ public: VARIANT_ENUM_CAST(VisibleOnScreenEnabler2D::EnableMode); -#endif // VISIBILITY_NOTIFIER_2D_H +#endif // VISIBLE_ON_SCREEN_NOTIFIER_2D_H |