summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp5
-rw-r--r--scene/2d/audio_stream_player_2d.h2
-rw-r--r--scene/2d/camera_2d.cpp2
-rw-r--r--scene/2d/gpu_particles_2d.cpp22
-rw-r--r--scene/2d/gpu_particles_2d.h8
-rw-r--r--scene/2d/joint_2d.cpp14
-rw-r--r--scene/2d/light_2d.cpp5
-rw-r--r--scene/2d/navigation_agent_2d.cpp6
-rw-r--r--scene/2d/navigation_link_2d.h6
-rw-r--r--scene/2d/navigation_region_2d.cpp4
-rw-r--r--scene/2d/node_2d.cpp54
-rw-r--r--scene/2d/node_2d.h13
-rw-r--r--scene/2d/path_2d.cpp45
-rw-r--r--scene/2d/physics_body_2d.cpp18
-rw-r--r--scene/2d/physics_body_2d.h4
-rw-r--r--scene/2d/polygon_2d.cpp4
-rw-r--r--scene/2d/shape_cast_2d.cpp6
-rw-r--r--scene/2d/shape_cast_2d.h1
-rw-r--r--scene/2d/skeleton_2d.cpp16
-rw-r--r--scene/2d/tile_map.cpp229
-rw-r--r--scene/2d/tile_map.h10
21 files changed, 257 insertions, 217 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 85ec745aee..2ded209180 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -284,6 +284,9 @@ bool AudioStreamPlayer2D::is_playing() const {
return true;
}
}
+ if (setplay.get() >= 0) {
+ return true; // play() has been called this frame, but no playback exists just yet.
+ }
return false;
}
@@ -477,7 +480,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");
+ cached_global_panning_strength = GLOBAL_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 616d7fdb60..5bc9083488 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -82,7 +82,7 @@ private:
float attenuation = 1.0;
float panning_strength = 1.0f;
- float cached_global_panning_strength = 1.0f;
+ float cached_global_panning_strength = 0.5f;
protected:
void _validate_property(PropertyInfo &p_property) const;
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index aa7df4ea9c..4b31bbddac 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -559,7 +559,7 @@ Point2 Camera2D::get_camera_screen_center() const {
Size2 Camera2D::_get_camera_screen_size() const {
// special case if the camera2D is in the root viewport
if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) {
- return Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
}
return get_viewport_rect().size;
}
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 9786b01058..c8f5d7f5a6 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -141,16 +141,16 @@ 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);
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
queue_redraw();
RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED);
}
-void GPUParticles2D::set_trail_length(double p_seconds) {
+void GPUParticles2D::set_trail_lifetime(double p_seconds) {
ERR_FAIL_COND(p_seconds < 0.001);
- trail_length = p_seconds;
- RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
+ trail_lifetime = p_seconds;
+ RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime);
queue_redraw();
}
@@ -181,8 +181,8 @@ bool GPUParticles2D::is_trail_enabled() const {
return trail_enabled;
}
-double GPUParticles2D::get_trail_length() const {
- return trail_length;
+double GPUParticles2D::get_trail_lifetime() const {
+ return trail_lifetime;
}
void GPUParticles2D::_update_collision_size() {
@@ -299,10 +299,6 @@ bool GPUParticles2D::get_interpolate() const {
PackedStringArray GPUParticles2D::get_configuration_warnings() const {
PackedStringArray 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."));
- }
-
if (process_material.is_null()) {
warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} else {
@@ -614,10 +610,10 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles2D::emit_particle);
ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled);
- ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length);
+ ClassDB::bind_method(D_METHOD("set_trail_lifetime", "secs"), &GPUParticles2D::set_trail_lifetime);
ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles2D::is_trail_enabled);
- ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles2D::get_trail_length);
+ ClassDB::bind_method(D_METHOD("get_trail_lifetime"), &GPUParticles2D::get_trail_lifetime);
ClassDB::bind_method(D_METHOD("set_trail_sections", "sections"), &GPUParticles2D::set_trail_sections);
ClassDB::bind_method(D_METHOD("get_trail_sections"), &GPUParticles2D::get_trail_sections);
@@ -647,7 +643,7 @@ void GPUParticles2D::_bind_methods() {
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,suffix:s"), "set_trail_length", "get_trail_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_lifetime", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater,suffix:s"), "set_trail_lifetime", "get_trail_lifetime");
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_");
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index d613b4ef51..94555e0bb0 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -64,7 +64,7 @@ private:
#endif
Ref<Material> process_material;
- DrawOrder draw_order;
+ DrawOrder draw_order = DRAW_ORDER_LIFETIME;
Ref<Texture2D> texture;
@@ -74,7 +74,7 @@ private:
real_t collision_base_size = 1.0;
bool trail_enabled = false;
- double trail_length = 0.3;
+ double trail_lifetime = 0.3;
int trail_sections = 8;
int trail_section_subdivisions = 4;
@@ -104,7 +104,7 @@ public:
void set_speed_scale(double p_scale);
void set_collision_base_size(real_t p_ratio);
void set_trail_enabled(bool p_enabled);
- void set_trail_length(double p_seconds);
+ void set_trail_lifetime(double p_seconds);
void set_trail_sections(int p_sections);
void set_trail_section_subdivisions(int p_subdivisions);
@@ -126,7 +126,7 @@ public:
real_t get_collision_base_size() const;
bool is_trail_enabled() const;
- double get_trail_length() const;
+ double get_trail_lifetime() const;
int get_trail_sections() const;
int get_trail_section_subdivisions() const;
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp
index 6000508f36..8de4c281f4 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -133,7 +133,13 @@ void Joint2D::set_node_a(const NodePath &p_node_a) {
}
a = p_node_a;
- _update_joint();
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // When in editor, the setter may be called as a result of node rename.
+ // It happens before the node actually changes its name, which triggers false warning.
+ callable_mp(this, &Joint2D::_update_joint).call_deferred();
+ } else {
+ _update_joint();
+ }
}
NodePath Joint2D::get_node_a() const {
@@ -150,7 +156,11 @@ void Joint2D::set_node_b(const NodePath &p_node_b) {
}
b = p_node_b;
- _update_joint();
+ if (Engine::get_singleton()->is_editor_hint()) {
+ callable_mp(this, &Joint2D::_update_joint).call_deferred();
+ } else {
+ _update_joint();
+ }
}
NodePath Joint2D::get_node_b() const {
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 80169bc80c..78b5199358 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -172,6 +172,7 @@ void Light2D::set_shadow_filter(ShadowFilter p_filter) {
ERR_FAIL_INDEX(p_filter, SHADOW_FILTER_MAX);
shadow_filter = p_filter;
RS::get_singleton()->canvas_light_set_shadow_filter(canvas_light, RS::CanvasLightShadowFilter(p_filter));
+ notify_property_list_changed();
}
Light2D::ShadowFilter Light2D::get_shadow_filter() const {
@@ -231,6 +232,10 @@ 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;
}
+
+ if (shadow && p_property.name == "shadow_filter_smooth" && shadow_filter == SHADOW_FILTER_NONE) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
void Light2D::_bind_methods() {
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index f077f7f5e6..1a62c9bb6c 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -75,6 +75,7 @@ void NavigationAgent2D::_bind_methods() {
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);
+
ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location);
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent2D::distance_to_target);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent2D::set_velocity);
@@ -88,6 +89,7 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent2D::_avoidance_done);
ADD_GROUP("Pathfinding", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_location", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_location", "get_target_location");
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");
@@ -104,7 +106,7 @@ void NavigationAgent2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
ADD_SIGNAL(MethodInfo("navigation_finished"));
- ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
+ ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR2, "safe_velocity")));
}
void NavigationAgent2D::_notification(int p_what) {
@@ -478,8 +480,8 @@ void NavigationAgent2D::_request_repath() {
void NavigationAgent2D::_check_distance_to_target() {
if (!target_reached) {
if (distance_to_target() < target_desired_distance) {
- emit_signal(SNAME("target_reached"));
target_reached = true;
+ emit_signal(SNAME("target_reached"));
}
}
}
diff --git a/scene/2d/navigation_link_2d.h b/scene/2d/navigation_link_2d.h
index 2a5092216d..9d36f80dd6 100644
--- a/scene/2d/navigation_link_2d.h
+++ b/scene/2d/navigation_link_2d.h
@@ -37,11 +37,11 @@ class NavigationLink2D : public Node2D {
GDCLASS(NavigationLink2D, Node2D);
bool enabled = true;
- RID link = RID();
+ RID link;
bool bidirectional = true;
uint32_t navigation_layers = 1;
- Vector2 end_location = Vector2();
- Vector2 start_location = Vector2();
+ Vector2 end_location;
+ Vector2 start_location;
real_t enter_cost = 0.0;
real_t travel_cost = 1.0;
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 6e8ecb13b1..13d371042b 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -296,7 +296,9 @@ void NavigationPolygon::make_polygons_from_outlines() {
TPPLPartition tpart;
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
- ERR_PRINT("NavigationPolygon: Convex partition failed!");
+ ERR_PRINT("NavigationPolygon: Convex partition failed! Failed to convert outlines to a valid NavigationMesh."
+ "\nNavigationPolygon outlines can not overlap vertices or edges inside same outline or with other outlines or have any intersections."
+ "\nAdd the outmost and largest outline first. To add holes inside this outline add the smaller outlines with opposite winding order.");
return;
}
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 2518069b78..4788a1b813 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -30,6 +30,8 @@
#include "node_2d.h"
+#include "scene/main/viewport.h"
+
#ifdef TOOLS_ENABLED
Dictionary Node2D::_edit_get_state() const {
Dictionary state;
@@ -326,29 +328,6 @@ void Node2D::set_global_transform(const Transform2D &p_transform) {
}
}
-void Node2D::set_z_index(int p_z) {
- ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN);
- ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX);
- z_index = p_z;
- RS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index);
-}
-
-void Node2D::set_z_as_relative(bool p_enabled) {
- if (z_relative == p_enabled) {
- return;
- }
- z_relative = p_enabled;
- RS::get_singleton()->canvas_item_set_z_as_relative_to_parent(get_canvas_item(), p_enabled);
-}
-
-bool Node2D::is_z_relative() const {
- return z_relative;
-}
-
-int Node2D::get_z_index() const {
- return z_index;
-}
-
Transform2D Node2D::get_relative_transform_to_parent(const Node *p_parent) const {
if (p_parent == this) {
return Transform2D();
@@ -380,13 +359,14 @@ Point2 Node2D::to_global(Point2 p_local) const {
return get_global_transform().xform(p_local);
}
-void Node2D::set_y_sort_enabled(bool p_enabled) {
- y_sort_enabled = p_enabled;
- RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_enabled);
-}
-
-bool Node2D::is_y_sort_enabled() const {
- return y_sort_enabled;
+void Node2D::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_MOVED_IN_PARENT: {
+ if (get_viewport()) {
+ get_viewport()->gui_set_root_order_dirty();
+ }
+ } break;
+ }
}
void Node2D::_bind_methods() {
@@ -425,15 +405,6 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node2D::to_local);
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node2D::to_global);
- ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &Node2D::set_z_index);
- ClassDB::bind_method(D_METHOD("get_z_index"), &Node2D::get_z_index);
-
- ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative);
- ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative);
-
- ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &Node2D::set_y_sort_enabled);
- ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &Node2D::is_y_sort_enabled);
-
ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent);
ADD_GROUP("Transform", "");
@@ -448,9 +419,4 @@ void Node2D::_bind_methods() {
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", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sort_enabled"), "set_y_sort_enabled", "is_y_sort_enabled");
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 0d8a31e6bb..76707dc422 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -40,9 +40,6 @@ class Node2D : public CanvasItem {
real_t rotation = 0.0;
Size2 scale = Vector2(1, 1);
real_t skew = 0.0;
- int z_index = 0;
- bool z_relative = true;
- bool y_sort_enabled = false;
Transform2D transform;
@@ -53,6 +50,7 @@ class Node2D : public CanvasItem {
void _update_xform_values();
protected:
+ void _notification(int p_notification);
static void _bind_methods();
public:
@@ -102,21 +100,12 @@ public:
void set_global_skew(const real_t p_radians);
void set_global_scale(const Size2 &p_scale);
- void set_z_index(int p_z);
- int get_z_index() const;
-
void look_at(const Vector2 &p_pos);
real_t get_angle_to(const Vector2 &p_pos) const;
Point2 to_local(Point2 p_global) const;
Point2 to_global(Point2 p_local) const;
- void set_z_as_relative(bool p_enabled);
- bool is_z_relative() const;
-
- virtual void set_y_sort_enabled(bool p_enabled);
- virtual bool is_y_sort_enabled() const;
-
Transform2D get_relative_transform_to_parent(const Node *p_parent) const;
Transform2D get_transform() const override;
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index c1044fdf5b..b68a8fb031 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -175,51 +175,18 @@ void PathFollow2D::_update_transform() {
if (path_length == 0) {
return;
}
- Vector2 pos = c->sample_baked(progress, cubic);
if (rotates) {
- real_t ahead = progress + lookahead;
-
- if (loop && ahead >= path_length) {
- // If our lookahead will loop, we need to check if the path is closed.
- int point_count = c->get_point_count();
- if (point_count > 0) {
- Vector2 start_point = c->get_point_position(0);
- Vector2 end_point = c->get_point_position(point_count - 1);
- if (start_point == end_point) {
- // Since the path is closed we want to 'smooth off'
- // the corner at the start/end.
- // So we wrap the lookahead back round.
- ahead = Math::fmod(ahead, path_length);
- }
- }
- }
-
- Vector2 ahead_pos = c->sample_baked(ahead, cubic);
-
- Vector2 tangent_to_curve;
- if (ahead_pos == pos) {
- // This will happen at the end of non-looping or non-closed paths.
- // We'll try a look behind instead, in order to get a meaningful angle.
- tangent_to_curve =
- (pos - c->sample_baked(progress - lookahead, cubic)).normalized();
- } else {
- tangent_to_curve = (ahead_pos - pos).normalized();
- }
-
- Vector2 normal_of_curve = -tangent_to_curve.orthogonal();
-
- pos += tangent_to_curve * h_offset;
- pos += normal_of_curve * v_offset;
-
- set_rotation(tangent_to_curve.angle());
-
+ Transform2D xform = c->sample_baked_with_rotation(progress, cubic);
+ xform.translate_local(v_offset, h_offset);
+ set_rotation(xform[1].angle());
+ set_position(xform[2]);
} else {
+ Vector2 pos = c->sample_baked(progress, cubic);
pos.x += h_offset;
pos.y += v_offset;
+ set_position(pos);
}
-
- set_position(pos);
}
void PathFollow2D::_notification(int p_what) {
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 0f3e6c7529..7f5b5d1ea4 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -34,8 +34,8 @@
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "motion", "test_only", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "motion", "collision", "safe_margin", "recovery_as_collision"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -54,8 +54,8 @@ PhysicsBody2D::~PhysicsBody2D() {
}
}
-Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) {
- PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_distance, p_margin);
+Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin, bool p_recovery_as_collision) {
+ PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_motion, p_margin);
parameters.recovery_as_collision = p_recovery_as_collision;
PhysicsServer2D::MotionResult result;
@@ -128,7 +128,7 @@ bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_
return colliding;
}
-bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) {
+bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin, bool p_recovery_as_collision) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer2D::MotionResult *r = nullptr;
@@ -140,7 +140,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distan
r = &temp_result;
}
- PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin);
+ PhysicsServer2D::MotionParameters parameters(p_from, p_motion, p_margin);
parameters.recovery_as_collision = p_recovery_as_collision;
return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
@@ -162,14 +162,14 @@ TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
void PhysicsBody2D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node);
- ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type.");
+ ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D.");
PhysicsServer2D::get_singleton()->body_add_collision_exception(get_rid(), physics_body->get_rid());
}
void PhysicsBody2D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
PhysicsBody2D *physics_body = Object::cast_to<PhysicsBody2D>(p_node);
- ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two objects of PhysicsBody2D type.");
+ ERR_FAIL_COND_MSG(!physics_body, "Collision exception only works between two nodes that inherit from PhysicsBody2D.");
PhysicsServer2D::get_singleton()->body_remove_collision_exception(get_rid(), physics_body->get_rid());
}
@@ -1761,7 +1761,7 @@ void CharacterBody2D::_bind_methods() {
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,suffix:px"), "set_floor_snap_length", "get_floor_snap_length");
- ADD_GROUP("Moving Platform", "platform");
+ ADD_GROUP("Moving Platform", "platform_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave");
ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers");
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 932ec1de16..504e1dc333 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -47,11 +47,11 @@ protected:
Ref<KinematicCollision2D> motion_cache;
- Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08, bool p_recovery_as_collision = false);
public:
bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
- bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false);
+ bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08, bool p_recovery_as_collision = false);
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 5e77902977..e41664b006 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -114,7 +114,7 @@ void Polygon2D::_notification(int p_what) {
ObjectID new_skeleton_id;
- if (skeleton_node) {
+ if (skeleton_node && !invert && bone_weights.size()) {
RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton());
new_skeleton_id = skeleton_node->get_instance_id();
} else {
@@ -663,5 +663,7 @@ Polygon2D::Polygon2D() {
}
Polygon2D::~Polygon2D() {
+ // This will free the internally-allocated mesh instance, if allocated.
+ RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID());
RS::get_singleton()->free(mesh);
}
diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp
index 6222b0db14..4c2e9e4c19 100644
--- a/scene/2d/shape_cast_2d.cpp
+++ b/scene/2d/shape_cast_2d.cpp
@@ -107,6 +107,11 @@ Object *ShapeCast2D::get_collider(int p_idx) const {
return ObjectDB::get_instance(result[p_idx].collider_id);
}
+RID ShapeCast2D::get_collider_rid(int p_idx) const {
+ ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), RID(), "No collider RID found.");
+ return result[p_idx].rid;
+}
+
int ShapeCast2D::get_collider_shape(int p_idx) const {
ERR_FAIL_INDEX_V_MSG(p_idx, result.size(), -1, "No collider shape found.");
return result[p_idx].shape;
@@ -422,6 +427,7 @@ void ShapeCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_shapecast_update"), &ShapeCast2D::force_shapecast_update);
ClassDB::bind_method(D_METHOD("get_collider", "index"), &ShapeCast2D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_rid", "index"), &ShapeCast2D::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider_shape", "index"), &ShapeCast2D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point", "index"), &ShapeCast2D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal", "index"), &ShapeCast2D::get_collision_normal);
diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/shape_cast_2d.h
index 7b55566b01..134f236d3b 100644
--- a/scene/2d/shape_cast_2d.h
+++ b/scene/2d/shape_cast_2d.h
@@ -104,6 +104,7 @@ public:
int get_collision_count() const;
Object *get_collider(int p_idx) const;
+ RID get_collider_rid(int p_idx) const;
int get_collider_shape(int p_idx) const;
Vector2 get_collision_point(int p_idx) const;
Vector2 get_collision_normal(int p_idx) const;
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index f80b2a07c9..62787d4488 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -213,15 +213,15 @@ void Bone2D::_notification(int p_what) {
}
// Undo scaling
- Transform2D editor_gizmo_trans = Transform2D();
+ Transform2D editor_gizmo_trans;
editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale());
RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans);
- Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
- Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
- Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
- Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
- Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
+ Color bone_color1 = EDITOR_GET("editors/2d/bone_color1");
+ Color bone_color2 = EDITOR_GET("editors/2d/bone_color2");
+ Color bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
+ Color bone_outline_color = EDITOR_GET("editors/2d/bone_outline_color");
+ Color bone_selected_color = EDITOR_GET("editors/2d/bone_selected_color");
bool Bone2D_found = false;
for (int i = 0; i < get_child_count(); i++) {
@@ -317,8 +317,8 @@ void Bone2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone) {
- int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width");
- int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
+ int bone_width = EDITOR_GET("editors/2d/bone_width");
+ int bone_outline_width = EDITOR_GET("editors/2d/bone_outline_size");
if (!is_inside_tree()) {
return false; //may have been removed
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 26627a4fca..0159e9f313 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1097,8 +1097,8 @@ void TileMap::_rendering_update_layer(int p_layer) {
rs->canvas_item_set_sort_children_by_y(ci, layers[p_layer].y_sort_enabled);
rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
rs->canvas_item_set_z_index(ci, layers[p_layer].z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
rs->canvas_item_set_light_mask(ci, get_light_mask());
}
@@ -1208,8 +1208,8 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
rs->canvas_item_set_z_as_relative_to_parent(ci, true);
rs->canvas_item_set_z_index(ci, tile_z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
q.canvas_items.push_back(ci);
@@ -1297,7 +1297,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
return;
}
- // Draw a placeholder for scenes needing one.
+ // Draw a placeholder for tiles needing one.
RenderingServer *rs = RenderingServer::get_singleton();
Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
@@ -1330,9 +1330,9 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
0.8);
// Draw a placeholder tile.
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
}
@@ -1632,13 +1632,13 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
color.push_back(debug_collision_color);
Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
- Transform2D qudrant_xform;
- qudrant_xform.set_origin(quadrant_pos);
- Transform2D global_transform_inv = (get_global_transform() * qudrant_xform).affine_inverse();
+ Transform2D quadrant_to_local;
+ quadrant_to_local.set_origin(quadrant_pos);
+ Transform2D global_to_quadrant = (get_global_transform() * quadrant_to_local).affine_inverse();
for (RID body : p_quadrant->bodies) {
- Transform2D xform = Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM)) * global_transform_inv;
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D body_to_quadrant = global_to_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM));
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, body_to_quadrant);
for (int shape_index = 0; shape_index < ps->body_get_shape_count(body); shape_index++) {
const RID &shape = ps->body_get_shape(body, shape_index);
PhysicsServer2D::ShapeType type = ps->shape_get_type(shape);
@@ -1815,9 +1815,9 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
}
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
Ref<NavigationPolygon> navpoly = tile_data->get_navigation_polygon(layer_index);
@@ -1859,11 +1859,13 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
while (q_list_element) {
TileMapQuadrant &q = *q_list_element->self();
- // Clear the scenes.
- for (const KeyValue<Vector2i, String> &E : q.scenes) {
- Node *node = get_node_or_null(E.value);
- if (node) {
- node->queue_delete();
+ // Clear the scenes if instance cache was cleared.
+ if (instantiated_scenes.is_empty()) {
+ for (const KeyValue<Vector2i, String> &E : q.scenes) {
+ Node *node = get_node_or_null(E.value);
+ if (node) {
+ node->queue_free();
+ }
}
}
@@ -1871,6 +1873,15 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
// Recreate the scenes.
for (const Vector2i &E_cell : q.cells) {
+ Vector3i cell_coords = Vector3i(q.layer, E_cell.x, E_cell.y);
+ if (instantiated_scenes.has(cell_coords)) {
+ // Skip scene if the instance was cached (to avoid recreating scenes unnecessarily).
+ continue;
+ }
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ instantiated_scenes.insert(cell_coords);
+ }
+
const TileMapCell &c = get_cell(q.layer, E_cell, true);
TileSetSource *source;
@@ -1907,15 +1918,16 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
}
void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
- // Clear the scenes.
- for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) {
- Node *node = get_node_or_null(E.value);
- if (node) {
- node->queue_delete();
+ // Clear the scenes if instance cache was cleared.
+ if (instantiated_scenes.is_empty()) {
+ for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) {
+ Node *node = get_node_or_null(E.value);
+ if (node) {
+ node->queue_free();
+ }
}
+ p_quadrant->scenes.clear();
}
-
- p_quadrant->scenes.clear();
}
void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
@@ -1956,9 +1968,9 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
0.8);
// Draw a placeholder tile.
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
}
@@ -2206,11 +2218,10 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat
}
}
-TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_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, TileSet::TerrainsPattern p_current_pattern) {
if (!tile_set.is_valid()) {
return TileSet::TerrainsPattern();
}
-
// Returns all tiles compatible with the given constraints.
RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score;
RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set);
@@ -2221,28 +2232,41 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
// 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();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) {
+ continue; // Ignore a pattern that cannot keep bits without constraints unmodified.
}
// Check the surrounding bits
+ bool invalid_pattern = false;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
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_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()) {
- score += in_set_constraint_element->get().get_priority();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) {
+ invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified.
+ break;
}
}
}
+ if (invalid_pattern) {
+ continue;
+ }
terrain_pattern_score[terrain_pattern] = score;
}
// Compute the minimum score
- TileSet::TerrainsPattern min_score_pattern;
+ TileSet::TerrainsPattern min_score_pattern = p_current_pattern;
int min_score = INT32_MAX;
for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) {
if (E.value < min_score) {
@@ -2274,7 +2298,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_p
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 {
+RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const {
if (!tile_set.is_valid()) {
return RBSet<TerrainConstraint>();
}
@@ -2284,8 +2308,8 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
// Build a set of dummy constraints to get the constrained points.
RBSet<TerrainConstraint> dummy_constraints;
- for (const Vector2i &E : p_cell_list) {
- for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides.
+ for (const Vector2i &E : p_painted) {
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits.
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
dummy_constraints.insert(TerrainConstraint(this, E, bit, -1));
@@ -2342,7 +2366,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
}
// Add the centers as constraints
- for (Vector2i E_coords : p_cell_list) {
+ for (Vector2i E_coords : p_painted) {
TileData *tile_data = nullptr;
TileMapCell cell = get_cell(p_layer, E_coords);
if (cell.source_id != TileSet::INVALID_SOURCE) {
@@ -2362,7 +2386,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
return constraints;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, 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>();
}
@@ -2378,7 +2402,20 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(co
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);
+ TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, coords);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ current_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern);
// Update the constraint set with the new ones
RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern);
@@ -2415,7 +2452,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
// 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)) {
+ if (is_existing_neighbor(bit)) {
Vector2i neighbor = get_neighbor_cell(coords, bit);
if (!can_modify_set.has(neighbor)) {
can_modify_list.push_back(neighbor);
@@ -2492,12 +2529,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
}
// 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)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_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);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2513,7 +2550,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
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 (is_existing_neighbor(bit)) {
if (get_neighbor_cell(p_path[i], bit) == p_path[i + 1]) {
found_bit = bit;
break;
@@ -2527,10 +2564,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
// 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_path.size() - 1; i >= 0; i--) {
const Vector2i &coords = p_path[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
+ painted_set.insert(coords);
}
for (Vector2i coords : p_path) {
// Find the adequate neighbor
@@ -2563,12 +2602,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
}
// 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)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_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);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2580,10 +2619,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
// 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
@@ -2613,12 +2654,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
}
// 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)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_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);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2627,14 +2668,38 @@ void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cell
ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
- Vector<Vector2i> vector_cells;
+ Vector<Vector2i> cells_vector;
+ HashSet<Vector2i> painted_set;
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);
+ cells_vector.push_back(p_cells[i]);
+ painted_set.insert(p_cells[i]);
+ }
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -2644,13 +2709,38 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
Vector<Vector2i> vector_path;
+ HashSet<Vector2i> painted_set;
for (int i = 0; i < p_path.size(); i++) {
vector_path.push_back(p_path[i]);
+ painted_set.insert(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);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -3717,13 +3807,14 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) {
}
void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
- // Set a default texture filter for the whole tilemap
+ // Set a default texture filter for the whole tilemap.
CanvasItem::set_texture_filter(p_texture_filter);
+ TextureFilter target_filter = get_texture_filter_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(p_texture_filter));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(target_filter));
_make_quadrant_dirty(F);
}
}
@@ -3732,13 +3823,14 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
}
void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
- // Set a default texture repeat for the whole tilemap
+ // Set a default texture repeat for the whole tilemap.
CanvasItem::set_texture_repeat(p_texture_repeat);
+ TextureRepeat target_repeat = get_texture_repeat_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(p_texture_repeat));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(target_repeat));
_make_quadrant_dirty(F);
}
}
@@ -3957,6 +4049,7 @@ void TileMap::_bind_methods() {
void TileMap::_tile_set_changed() {
emit_signal(SNAME("changed"));
_tile_set_changed_deferred_update_needed = true;
+ instantiated_scenes.clear();
call_deferred(SNAME("_tile_set_changed_deferred_update"));
}
@@ -3976,9 +4069,5 @@ TileMap::TileMap() {
}
TileMap::~TileMap() {
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- }
-
_clear_internals();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index d468675e91..68a5d3c80b 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -115,7 +115,7 @@ public:
class TerrainConstraint {
private:
const TileMap *tile_map;
- Vector2i base_cell_coords = Vector2i();
+ Vector2i base_cell_coords;
int bit = -1;
int terrain = -1;
@@ -236,6 +236,8 @@ private:
void _clear_layer_internals(int p_layer);
void _clear_internals();
+ HashSet<Vector3i> instantiated_scenes;
+
// Rect caching.
void _recompute_rect_cache();
@@ -266,9 +268,9 @@ private:
void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
// Terrains.
- TileSet::TerrainsPattern _get_best_terrain_pattern_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, TileSet::TerrainsPattern p_current_pattern);
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;
+ RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, 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);
@@ -352,7 +354,7 @@ public:
void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern);
// Terrains.
- 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_constraints(int p_layer, 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.