summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/animated_sprite_2d.cpp19
-rw-r--r--scene/2d/animated_sprite_2d.h2
-rw-r--r--scene/2d/area_2d.cpp108
-rw-r--r--scene/2d/area_2d.h6
-rw-r--r--scene/2d/audio_listener_2d.cpp2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp30
-rw-r--r--scene/2d/audio_stream_player_2d.h6
-rw-r--r--scene/2d/back_buffer_copy.cpp2
-rw-r--r--scene/2d/camera_2d.cpp22
-rw-r--r--scene/2d/canvas_group.cpp4
-rw-r--r--scene/2d/collision_object_2d.cpp2
-rw-r--r--scene/2d/collision_object_2d.h2
-rw-r--r--scene/2d/collision_polygon_2d.cpp7
-rw-r--r--scene/2d/collision_shape_2d.cpp7
-rw-r--r--scene/2d/cpu_particles_2d.cpp68
-rw-r--r--scene/2d/cpu_particles_2d.h2
-rw-r--r--scene/2d/gpu_particles_2d.cpp39
-rw-r--r--scene/2d/gpu_particles_2d.h26
-rw-r--r--scene/2d/joint_2d.cpp10
-rw-r--r--scene/2d/light_2d.cpp13
-rw-r--r--scene/2d/light_2d.h2
-rw-r--r--scene/2d/light_occluder_2d.cpp1
-rw-r--r--scene/2d/light_occluder_2d.h5
-rw-r--r--scene/2d/line_2d.cpp2
-rw-r--r--scene/2d/navigation_agent_2d.cpp180
-rw-r--r--scene/2d/navigation_agent_2d.h40
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp37
-rw-r--r--scene/2d/navigation_obstacle_2d.h1
-rw-r--r--scene/2d/navigation_region_2d.cpp81
-rw-r--r--scene/2d/navigation_region_2d.h18
-rw-r--r--scene/2d/node_2d.cpp72
-rw-r--r--scene/2d/node_2d.h4
-rw-r--r--scene/2d/parallax_background.cpp18
-rw-r--r--scene/2d/parallax_layer.cpp4
-rw-r--r--scene/2d/path_2d.cpp19
-rw-r--r--scene/2d/physics_body_2d.cpp126
-rw-r--r--scene/2d/physics_body_2d.h6
-rw-r--r--scene/2d/polygon_2d.cpp11
-rw-r--r--scene/2d/position_2d.cpp2
-rw-r--r--scene/2d/ray_cast_2d.cpp2
-rw-r--r--scene/2d/ray_cast_2d.h2
-rw-r--r--scene/2d/shape_cast_2d.cpp4
-rw-r--r--scene/2d/shape_cast_2d.h2
-rw-r--r--scene/2d/skeleton_2d.cpp12
-rw-r--r--scene/2d/sprite_2d.cpp4
-rw-r--r--scene/2d/tile_map.cpp820
-rw-r--r--scene/2d/tile_map.h68
-rw-r--r--scene/2d/visible_on_screen_notifier_2d.cpp5
-rw-r--r--scene/2d/visible_on_screen_notifier_2d.h2
49 files changed, 1264 insertions, 663 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index d3783aadd1..d56c7b8811 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -138,8 +138,11 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
if (property.name == "frame") {
property.hint = PROPERTY_HINT_RANGE;
- if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) {
+ if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
+ } else {
+ // Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`.
+ property.hint_string = "0,0,1";
}
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
@@ -388,6 +391,7 @@ void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backward
}
}
+ is_over = false;
set_playing(true);
}
@@ -443,6 +447,17 @@ TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const {
return warnings;
}
+void AnimatedSprite2D::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ if (p_idx == 0 && p_function == "play" && frames.is_valid()) {
+ List<StringName> al;
+ frames->get_animation_list(&al);
+ for (const StringName &name : al) {
+ r_options->push_back(String(name).quote());
+ }
+ }
+ Node::get_argument_options(p_function, p_idx, r_options);
+}
+
void AnimatedSprite2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite2D::set_sprite_frames);
ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite2D::get_sprite_frames);
@@ -485,7 +500,7 @@ void AnimatedSprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "set_playing", "is_playing");
ADD_GROUP("Offset", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
- 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::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index b3af931ea2..3a41f810dc 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -109,6 +109,8 @@ public:
bool is_flipped_v() const;
TypedArray<String> get_configuration_warnings() const override;
+ virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
+
AnimatedSprite2D();
};
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 70b9b769cd..dfc1016c84 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -137,14 +137,14 @@ void Area2D::_body_enter_tree(ObjectID p_id) {
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
- Map<ObjectID, BodyState>::Element *E = body_map.find(p_id);
+ HashMap<ObjectID, BodyState>::Iterator E = body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_tree);
+ ERR_FAIL_COND(E->value.in_tree);
- E->get().in_tree = true;
+ E->value.in_tree = true;
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ for (int i = 0; i < E->value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].area_shape);
}
}
@@ -152,13 +152,13 @@ void Area2D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
- Map<ObjectID, BodyState>::Element *E = body_map.find(p_id);
+ HashMap<ObjectID, BodyState>::Iterator E = body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_tree);
- E->get().in_tree = false;
+ ERR_FAIL_COND(!E->value.in_tree);
+ E->value.in_tree = false;
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].area_shape);
+ for (int i = 0; i < E->value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].area_shape);
}
}
@@ -169,7 +169,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
Object *obj = ObjectDB::get_instance(objid);
Node *node = Object::cast_to<Node>(obj);
- Map<ObjectID, BodyState>::Element *E = body_map.find(objid);
+ HashMap<ObjectID, BodyState>::Iterator E = body_map.find(objid);
if (!body_in && !E) {
return; //does not exist because it was likely removed from the tree
@@ -180,36 +180,36 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
if (body_in) {
if (!E) {
E = body_map.insert(objid, BodyState());
- E->get().rid = p_body;
- E->get().rc = 0;
- E->get().in_tree = node && node->is_inside_tree();
+ E->value.rid = p_body;
+ 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));
- if (E->get().in_tree) {
+ if (E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
}
}
- E->get().rc++;
+ E->value.rc++;
if (node) {
- E->get().shapes.insert(ShapePair(p_body_shape, p_area_shape));
+ E->value.shapes.insert(ShapePair(p_body_shape, p_area_shape));
}
- if (!node || E->get().in_tree) {
+ if (!node || E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_area_shape);
}
} else {
- E->get().rc--;
+ E->value.rc--;
if (node) {
- E->get().shapes.erase(ShapePair(p_body_shape, p_area_shape));
+ E->value.shapes.erase(ShapePair(p_body_shape, p_area_shape));
}
- bool in_tree = E->get().in_tree;
- if (E->get().rc == 0) {
- body_map.erase(E);
+ bool in_tree = E->value.in_tree;
+ if (E->value.rc == 0) {
+ body_map.remove(E);
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_body_enter_tree));
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_body_exit_tree));
@@ -231,14 +231,14 @@ void Area2D::_area_enter_tree(ObjectID p_id) {
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
- Map<ObjectID, AreaState>::Element *E = area_map.find(p_id);
+ HashMap<ObjectID, AreaState>::Iterator E = area_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_tree);
+ ERR_FAIL_COND(E->value.in_tree);
- E->get().in_tree = true;
+ E->value.in_tree = true;
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ for (int i = 0; i < E->value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->area_shape_entered, E->value.rid, node, E->value.shapes[i].area_shape, E->value.shapes[i].self_shape);
}
}
@@ -246,13 +246,13 @@ void Area2D::_area_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
- Map<ObjectID, AreaState>::Element *E = area_map.find(p_id);
+ HashMap<ObjectID, AreaState>::Iterator E = area_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_tree);
- E->get().in_tree = false;
+ ERR_FAIL_COND(!E->value.in_tree);
+ E->value.in_tree = false;
emit_signal(SceneStringNames::get_singleton()->area_exited, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->get().rid, node, E->get().shapes[i].area_shape, E->get().shapes[i].self_shape);
+ for (int i = 0; i < E->value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->area_shape_exited, E->value.rid, node, E->value.shapes[i].area_shape, E->value.shapes[i].self_shape);
}
}
@@ -263,7 +263,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
Object *obj = ObjectDB::get_instance(objid);
Node *node = Object::cast_to<Node>(obj);
- Map<ObjectID, AreaState>::Element *E = area_map.find(objid);
+ HashMap<ObjectID, AreaState>::Iterator E = area_map.find(objid);
if (!area_in && !E) {
return; //likely removed from the tree
@@ -273,36 +273,36 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
if (area_in) {
if (!E) {
E = area_map.insert(objid, AreaState());
- E->get().rid = p_area;
- E->get().rc = 0;
- E->get().in_tree = node && node->is_inside_tree();
+ E->value.rid = p_area;
+ 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));
- if (E->get().in_tree) {
+ if (E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
}
}
}
- E->get().rc++;
+ E->value.rc++;
if (node) {
- E->get().shapes.insert(AreaShapePair(p_area_shape, p_self_shape));
+ E->value.shapes.insert(AreaShapePair(p_area_shape, p_self_shape));
}
- if (!node || E->get().in_tree) {
+ if (!node || E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_shape_entered, p_area, node, p_area_shape, p_self_shape);
}
} else {
- E->get().rc--;
+ E->value.rc--;
if (node) {
- E->get().shapes.erase(AreaShapePair(p_area_shape, p_self_shape));
+ E->value.shapes.erase(AreaShapePair(p_area_shape, p_self_shape));
}
- bool in_tree = E->get().in_tree;
- if (E->get().rc == 0) {
- area_map.erase(E);
+ bool in_tree = E->value.in_tree;
+ if (E->value.rc == 0) {
+ area_map.remove(E);
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &Area2D::_area_enter_tree));
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Area2D::_area_exit_tree));
@@ -323,7 +323,7 @@ void Area2D::_clear_monitoring() {
ERR_FAIL_COND_MSG(locked, "This function can't be used during the in/out signal.");
{
- Map<ObjectID, BodyState> bmcopy = body_map;
+ HashMap<ObjectID, BodyState> bmcopy = body_map;
body_map.clear();
//disconnect all monitored stuff
@@ -351,7 +351,7 @@ void Area2D::_clear_monitoring() {
}
{
- Map<ObjectID, AreaState> bmcopy = area_map;
+ HashMap<ObjectID, AreaState> bmcopy = area_map;
area_map.clear();
//disconnect all monitored stuff
@@ -461,20 +461,20 @@ TypedArray<Area2D> Area2D::get_overlapping_areas() const {
bool Area2D::overlaps_area(Node *p_area) const {
ERR_FAIL_NULL_V(p_area, false);
- const Map<ObjectID, AreaState>::Element *E = area_map.find(p_area->get_instance_id());
+ HashMap<ObjectID, AreaState>::ConstIterator E = area_map.find(p_area->get_instance_id());
if (!E) {
return false;
}
- return E->get().in_tree;
+ return E->value.in_tree;
}
bool Area2D::overlaps_body(Node *p_body) const {
ERR_FAIL_NULL_V(p_body, false);
- const Map<ObjectID, BodyState>::Element *E = body_map.find(p_body->get_instance_id());
+ HashMap<ObjectID, BodyState>::ConstIterator E = body_map.find(p_body->get_instance_id());
if (!E) {
return false;
}
- return E->get().in_tree;
+ return E->value.in_tree;
}
void Area2D::set_audio_bus_override(bool p_override) {
@@ -605,9 +605,9 @@ 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, "-4096,4096,0.001,or_lesser,or_greater"), "set_gravity", "get_gravity");
+ 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");
ADD_GROUP("Linear Damp", "linear_damp_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode");
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index 68047ccebf..a584420ced 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -49,7 +49,7 @@ public:
private:
SpaceOverride gravity_space_override = SPACE_OVERRIDE_DISABLED;
Vector2 gravity_vec;
- real_t gravity;
+ real_t gravity = 0.0;
bool gravity_is_point = false;
real_t gravity_distance_scale = 0.0;
@@ -94,7 +94,7 @@ private:
VSet<ShapePair> shapes;
};
- Map<ObjectID, BodyState> body_map;
+ HashMap<ObjectID, BodyState> body_map;
void _area_inout(int p_status, const RID &p_area, ObjectID p_instance, int p_area_shape, int p_self_shape);
@@ -126,7 +126,7 @@ private:
VSet<AreaShapePair> shapes;
};
- Map<ObjectID, AreaState> area_map;
+ HashMap<ObjectID, AreaState> area_map;
void _clear_monitoring();
bool audio_bus_override = false;
diff --git a/scene/2d/audio_listener_2d.cpp b/scene/2d/audio_listener_2d.cpp
index eb463864e1..f7dd20d7c0 100644
--- a/scene/2d/audio_listener_2d.cpp
+++ b/scene/2d/audio_listener_2d.cpp
@@ -57,7 +57,7 @@ bool AudioListener2D::_get(const StringName &p_name, Variant &r_ret) const {
}
void AudioListener2D::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("current")));
}
void AudioListener2D::_notification(int p_what) {
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index c1328badfb..eaab58c4ae 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"
@@ -148,7 +149,7 @@ void AudioStreamPlayer2D::_update_panning() {
Vector2 global_pos = get_global_position();
- Set<Viewport *> viewports = world_2d->get_viewports();
+ HashSet<Viewport *> viewports = world_2d->get_viewports();
viewports.insert(get_viewport()); // TODO: This is a mediocre workaround for #50958. Remove when that bug is fixed!
volume_vector.resize(4);
@@ -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;
@@ -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,17 +449,21 @@ 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");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,suffix:dB"), "set_volume_db", "get_volume_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance");
+ 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..a22782fe44 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -81,6 +81,9 @@ 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 _notification(int p_what);
@@ -123,6 +126,9 @@ 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();
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/camera_2d.cpp b/scene/2d/camera_2d.cpp
index efde8d8a2b..76b354805c 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -57,7 +57,7 @@ void Camera2D::_update_scroll() {
Size2 screen_size = _get_camera_screen_size();
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2());
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_camera_moved", xform, screen_offset);
+ get_tree()->call_group(group_name, "_camera_moved", xform, screen_offset);
};
}
@@ -421,7 +421,7 @@ bool Camera2D::is_current() const {
void Camera2D::make_current() {
if (is_inside_tree()) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", this);
+ get_tree()->call_group(group_name, "_make_current", this);
} else {
current = true;
}
@@ -430,7 +430,7 @@ void Camera2D::make_current() {
void Camera2D::clear_current() {
if (is_inside_tree()) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", (Object *)nullptr);
+ get_tree()->call_group(group_name, "_make_current", (Object *)nullptr);
} else {
current = false;
}
@@ -439,7 +439,7 @@ 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();
+ _update_scroll();
}
int Camera2D::get_limit(Side p_side) const {
@@ -729,24 +729,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/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/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 50863f2c4d..a8c12f4893 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -606,7 +606,7 @@ void CollisionObject2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("mouse_shape_entered", PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_shape_exited", PropertyInfo(Variant::INT, "shape_idx")));
- ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,MakeStatic,KeepActive"), "set_disable_mode", "get_disable_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,Make Static,Keep Active"), "set_disable_mode", "get_disable_mode");
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index f2b7eecc7b..997afee6c4 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -75,7 +75,7 @@ private:
int total_subshapes = 0;
- Map<uint32_t, ShapeData> shapes;
+ RBMap<uint32_t, ShapeData> shapes;
bool only_update_transform_changes = false; // This is used for sync to physics.
void _apply_disabled();
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index c8986e3c94..8df29851e5 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -32,6 +32,7 @@
#include "collision_object_2d.h"
#include "core/math/geometry_2d.h"
+#include "scene/2d/area_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
@@ -254,6 +255,9 @@ TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
warnings.push_back(RTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode."));
}
}
+ if (one_way_collision && Object::cast_to<Area2D>(get_parent())) {
+ warnings.push_back(RTR("The One Way Collision property will be ignored when the parent is an Area2D."));
+ }
return warnings;
}
@@ -276,6 +280,7 @@ void CollisionPolygon2D::set_one_way_collision(bool p_enable) {
if (parent) {
parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
+ update_configuration_warnings();
}
bool CollisionPolygon2D::is_one_way_collision_enabled() const {
@@ -310,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/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index dd47ae6cb5..9c0c26f6d9 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -31,6 +31,7 @@
#include "collision_shape_2d.h"
#include "collision_object_2d.h"
+#include "scene/2d/area_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
@@ -176,6 +177,9 @@ TypedArray<String> CollisionShape2D::get_configuration_warnings() const {
if (!shape.is_valid()) {
warnings.push_back(RTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"));
}
+ if (one_way_collision && Object::cast_to<Area2D>(get_parent())) {
+ warnings.push_back(RTR("The One Way Collision property will be ignored when the parent is an Area2D."));
+ }
Ref<ConvexPolygonShape2D> convex = shape;
Ref<ConcavePolygonShape2D> concave = shape;
@@ -204,6 +208,7 @@ void CollisionShape2D::set_one_way_collision(bool p_enable) {
if (parent) {
parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
+ update_configuration_warnings();
}
bool CollisionShape2D::is_one_way_collision_enabled() const {
@@ -234,7 +239,7 @@ void CollisionShape2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape");
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");
}
CollisionShape2D::CollisionShape2D() {
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index bad1488d5a..4155d0797f 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 {
@@ -743,7 +747,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
real_t angle1_rad = direction.angle() + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
- p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)Math::randf());
+ p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)Math::randf());
real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
p.rotation = Math::deg2rad(base_angle);
@@ -788,8 +792,8 @@ void CPUParticles2D::_particles_process(double p_delta) {
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS && emission_normals.size() == pc) {
Vector2 normal = emission_normals.get(random_idx);
Transform2D m2;
- m2.set_axis(0, normal);
- m2.set_axis(1, normal.orthogonal());
+ m2.columns[0] = normal;
+ m2.columns[1] = normal.orthogonal();
p.velocity = m2.basis_xform(p.velocity);
}
@@ -969,13 +973,13 @@ void CPUParticles2D::_particles_process(double p_delta) {
if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) {
if (p.velocity.length() > 0.0) {
- p.transform.elements[1] = p.velocity.normalized();
- p.transform.elements[0] = p.transform.elements[1].orthogonal();
+ p.transform.columns[1] = p.velocity.normalized();
+ p.transform.columns[0] = p.transform.columns[1].orthogonal();
}
} else {
- p.transform.elements[0] = Vector2(Math::cos(p.rotation), -Math::sin(p.rotation));
- p.transform.elements[1] = Vector2(Math::sin(p.rotation), Math::cos(p.rotation));
+ p.transform.columns[0] = Vector2(Math::cos(p.rotation), -Math::sin(p.rotation));
+ p.transform.columns[1] = Vector2(Math::sin(p.rotation), Math::cos(p.rotation));
}
//scale by scale
@@ -986,8 +990,8 @@ void CPUParticles2D::_particles_process(double p_delta) {
if (base_scale.y < 0.00001) {
base_scale.y = 0.00001;
}
- p.transform.elements[0] *= base_scale.x;
- p.transform.elements[1] *= base_scale.y;
+ p.transform.columns[0] *= base_scale.x;
+ p.transform.columns[1] *= base_scale.y;
p.transform[2] += p.velocity * local_delta;
}
@@ -1029,14 +1033,14 @@ void CPUParticles2D::_update_particle_data_buffer() {
}
if (r[idx].active) {
- ptr[0] = t.elements[0][0];
- ptr[1] = t.elements[1][0];
+ ptr[0] = t.columns[0][0];
+ ptr[1] = t.columns[1][0];
ptr[2] = 0;
- ptr[3] = t.elements[2][0];
- ptr[4] = t.elements[0][1];
- ptr[5] = t.elements[1][1];
+ ptr[3] = t.columns[2][0];
+ ptr[4] = t.columns[0][1];
+ ptr[5] = t.columns[1][1];
ptr[6] = 0;
- ptr[7] = t.elements[2][1];
+ ptr[7] = t.columns[2][1];
} else {
memset(ptr, 0, sizeof(float) * 8);
@@ -1137,14 +1141,14 @@ void CPUParticles2D::_notification(int p_what) {
Transform2D t = inv_emission_transform * r[i].transform;
if (r[i].active) {
- ptr[0] = t.elements[0][0];
- ptr[1] = t.elements[1][0];
+ ptr[0] = t.columns[0][0];
+ ptr[1] = t.columns[1][0];
ptr[2] = 0;
- ptr[3] = t.elements[2][0];
- ptr[4] = t.elements[0][1];
- ptr[5] = t.elements[1][1];
+ ptr[3] = t.columns[2][0];
+ ptr[4] = t.columns[0][1];
+ ptr[5] = t.columns[1][1];
ptr[6] = 0;
- ptr[7] = t.elements[2][1];
+ ptr[7] = t.columns[2][1];
} else {
memset(ptr, 0, sizeof(float) * 8);
@@ -1282,14 +1286,14 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,suffix:s"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,suffix:s"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Drawing", "");
// No visibility_rect property contrarily to Particles2D, it's updated automatically.
@@ -1305,7 +1309,7 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_direction", "direction"), &CPUParticles2D::set_direction);
ClassDB::bind_method(D_METHOD("get_direction"), &CPUParticles2D::get_direction);
- ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles2D::set_spread);
+ ClassDB::bind_method(D_METHOD("set_spread", "spread"), &CPUParticles2D::set_spread);
ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles2D::get_spread);
ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &CPUParticles2D::set_param_min);
@@ -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::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01"), "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::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", 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");
@@ -1374,10 +1378,10 @@ void CPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "direction"), "set_direction", "get_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spread", PROPERTY_HINT_RANGE, "0,180,0.01"), "set_spread", "get_spread");
ADD_GROUP("Gravity", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity"), "set_gravity", "get_gravity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity", PROPERTY_HINT_NONE, U"suffix:px/s\u00B2"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 7ae51e3966..51d58723b4 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -137,7 +137,7 @@ private:
real_t randomness_ratio = 0.0;
double lifetime_randomness = 0.0;
double speed_scale = 1.0;
- bool local_coords;
+ bool local_coords = false;
int fixed_fps = 0;
bool fractional_delta = true;
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index c69eeb52a8..a869cf2525 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -114,8 +114,8 @@ void GPUParticles2D::set_use_local_coordinates(bool p_enable) {
void GPUParticles2D::_update_particle_emission_transform() {
Transform2D xf2d = get_global_transform();
Transform3D xf;
- xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0));
- xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0));
+ xf.basis.set_column(0, Vector3(xf2d.columns[0].x, xf2d.columns[0].y, 0));
+ xf.basis.set_column(1, Vector3(xf2d.columns[1].x, xf2d.columns[1].y, 0));
xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0));
RS::get_singleton()->particles_set_emission_transform(particles, xf);
@@ -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);
@@ -287,8 +286,17 @@ bool GPUParticles2D::get_fractional_delta() const {
return fractional_delta;
}
+void GPUParticles2D::set_interpolate(bool p_enable) {
+ interpolate = p_enable;
+ RS::get_singleton()->particles_set_interpolate(particles, p_enable);
+}
+
+bool GPUParticles2D::get_interpolate() const {
+ return interpolate;
+}
+
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."));
@@ -337,8 +345,8 @@ void GPUParticles2D::_validate_property(PropertyInfo &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) {
Transform3D transform;
- transform.basis.set_axis(0, Vector3(p_transform2d.get_axis(0).x, p_transform2d.get_axis(0).y, 0));
- transform.basis.set_axis(1, Vector3(p_transform2d.get_axis(1).x, p_transform2d.get_axis(1).y, 0));
+ transform.basis.set_column(0, Vector3(p_transform2d.columns[0].x, p_transform2d.columns[0].y, 0));
+ transform.basis.set_column(1, Vector3(p_transform2d.columns[1].x, p_transform2d.columns[1].y, 0));
transform.set_origin(Vector3(p_transform2d.get_origin().x, p_transform2d.get_origin().y, 0));
Vector3 velocity = Vector3(p_velocity2d.x, p_velocity2d.y, 0);
@@ -543,6 +551,7 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &GPUParticles2D::set_use_local_coordinates);
ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &GPUParticles2D::set_fixed_fps);
ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &GPUParticles2D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_interpolate", "enable"), &GPUParticles2D::set_interpolate);
ClassDB::bind_method(D_METHOD("set_process_material", "material"), &GPUParticles2D::set_process_material);
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &GPUParticles2D::set_speed_scale);
ClassDB::bind_method(D_METHOD("set_collision_base_size", "size"), &GPUParticles2D::set_collision_base_size);
@@ -558,6 +567,7 @@ void GPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &GPUParticles2D::get_use_local_coordinates);
ClassDB::bind_method(D_METHOD("get_fixed_fps"), &GPUParticles2D::get_fixed_fps);
ClassDB::bind_method(D_METHOD("get_fractional_delta"), &GPUParticles2D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_interpolate"), &GPUParticles2D::get_interpolate);
ClassDB::bind_method(D_METHOD("get_process_material"), &GPUParticles2D::get_process_material);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &GPUParticles2D::get_speed_scale);
ClassDB::bind_method(D_METHOD("get_collision_base_size"), &GPUParticles2D::get_collision_base_size);
@@ -594,23 +604,24 @@ void GPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles2D"), "set_sub_emitter", "get_sub_emitter");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,suffix:s"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,suffix:s"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1,suffix:FPS"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interpolate"), "set_interpolate", "get_interpolate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
+ 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_");
@@ -644,6 +655,7 @@ GPUParticles2D::GPUParticles2D() {
set_lifetime(1);
set_fixed_fps(0);
set_fractional_delta(true);
+ set_interpolate(true);
set_pre_process_time(0);
set_explosiveness_ratio(0);
set_randomness_ratio(0);
@@ -653,9 +665,6 @@ GPUParticles2D::GPUParticles2D() {
set_speed_scale(1);
set_fixed_fps(30);
set_collision_base_size(collision_base_size);
-#ifdef TOOLS_ENABLED
- show_visibility_rect = false;
-#endif
}
GPUParticles2D::~GPUParticles2D() {
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index fc95ae27b2..3c7f4cd9b5 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -47,19 +47,20 @@ public:
private:
RID particles;
- bool one_shot;
- int amount;
- double lifetime;
- double pre_process_time;
- real_t explosiveness_ratio;
- real_t randomness_ratio;
- double speed_scale;
+ bool one_shot = false;
+ int amount = 0;
+ double lifetime = 0.0;
+ double pre_process_time = 0.0;
+ real_t explosiveness_ratio = 0.0;
+ real_t randomness_ratio = 0.0;
+ double speed_scale = 0.0;
Rect2 visibility_rect;
- bool local_coords;
- int fixed_fps;
- bool fractional_delta;
+ bool local_coords = false;
+ int fixed_fps = 0;
+ bool fractional_delta = false;
+ bool interpolate = true;
#ifdef TOOLS_ENABLED
- bool show_visibility_rect;
+ bool show_visibility_rect = false;
#endif
Ref<Material> process_material;
@@ -133,6 +134,9 @@ public:
void set_fractional_delta(bool p_enable);
bool get_fractional_delta() const;
+ void set_interpolate(bool p_enable);
+ bool get_interpolate() const;
+
void set_draw_order(DrawOrder p_order);
DrawOrder get_draw_order() const;
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp
index cd82b47333..7b9f7e14ca 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -50,6 +50,7 @@ void Joint2D::_disconnect_signals() {
void Joint2D::_body_exit_tree() {
_disconnect_signals();
_update_joint(true);
+ update_configuration_warnings();
}
void Joint2D::_update_joint(bool p_only_free) {
@@ -64,7 +65,6 @@ void Joint2D::_update_joint(bool p_only_free) {
if (p_only_free || !is_inside_tree()) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = String();
- update_configuration_warnings();
return;
}
@@ -343,8 +343,8 @@ void GrooveJoint2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_initial_offset", "offset"), &GrooveJoint2D::set_initial_offset);
ClassDB::bind_method(D_METHOD("get_initial_offset"), &GrooveJoint2D::get_initial_offset);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp"), "set_length", "get_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "initial_offset", PROPERTY_HINT_RANGE, "1,65535,1,exp"), "set_initial_offset", "get_initial_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "initial_offset", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_initial_offset", "get_initial_offset");
}
GrooveJoint2D::GrooveJoint2D() {
@@ -440,8 +440,8 @@ void DampedSpringJoint2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_damping", "damping"), &DampedSpringJoint2D::set_damping);
ClassDB::bind_method(D_METHOD("get_damping"), &DampedSpringJoint2D::get_damping);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp"), "set_length", "get_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rest_length", PROPERTY_HINT_RANGE, "0,65535,1,exp"), "set_rest_length", "get_rest_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp,suffix:px"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rest_length", PROPERTY_HINT_RANGE, "0,65535,1,exp,suffix:px"), "set_rest_length", "get_rest_length");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness", PROPERTY_HINT_RANGE, "0.1,64,0.1,exp"), "set_stiffness", "get_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0.01,16,0.01,exp"), "set_damping", "get_damping");
}
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index b09b1b5047..0481a58431 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;
@@ -425,9 +430,9 @@ void PointLight2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture_scale"), &PointLight2D::get_texture_scale);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_texture_offset", "get_texture_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_scale", PROPERTY_HINT_RANGE, "0.01,50,0.01"), "set_texture_scale", "get_texture_scale");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1024,1,or_greater,suffix:px"), "set_height", "get_height");
}
PointLight2D::PointLight2D() {
@@ -449,8 +454,8 @@ void DirectionalLight2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &DirectionalLight2D::set_max_distance);
ClassDB::bind_method(D_METHOD("get_max_distance"), &DirectionalLight2D::get_max_distance);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_height", "get_height");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384.0,1.0,or_greater"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01,suffix:px"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384.0,1.0,or_greater,suffix:px"), "set_max_distance", "get_max_distance");
}
DirectionalLight2D::DirectionalLight2D() {
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index f7b1f420e3..a84b6516c0 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -73,6 +73,8 @@ 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);
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index c4e57b375d..14188d7120 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -285,7 +285,6 @@ void LightOccluder2D::_bind_methods() {
LightOccluder2D::LightOccluder2D() {
occluder = RS::get_singleton()->canvas_light_occluder_create();
- mask = 1;
set_notify_transform(true);
set_as_sdf_collision(true);
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index 4f8c6d20df..4acfeaf781 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -81,10 +81,9 @@ class LightOccluder2D : public Node2D {
GDCLASS(LightOccluder2D, Node2D);
RID occluder;
- bool enabled;
- int mask;
+ int mask = 1;
Ref<OccluderPolygon2D> occluder_polygon;
- bool sdf_collision;
+ bool sdf_collision = false;
void _poly_changed();
protected:
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 8cbcc9acf6..06e5cbc97e 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -393,7 +393,7 @@ void Line2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_antialiased"), &Line2D::get_antialiased);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "points"), "set_points", "get_points");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_NONE, "suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "width_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color");
ADD_GROUP("Fill", "");
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 91549d75f0..a5f7faffef 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -37,6 +37,12 @@
void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent2D::get_rid);
+ 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);
@@ -58,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);
@@ -75,14 +87,19 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent2D::_avoidance_done);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_target_desired_distance", "get_target_desired_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,500,0.01"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,100000,0.01"), "set_neighbor_dist", "get_neighbor_dist");
+ 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"), "set_time_horizon", "get_time_horizon");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,100000,0.01"), "set_max_speed", "get_max_speed");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1"), "set_path_max_distance", "get_path_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "navigable_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigable_layers", "get_navigable_layers");
+ 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_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
@@ -92,16 +109,50 @@ 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());
- NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
- }
+ 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());
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
+ } else if (agent_parent && agent_parent->can_process() && !(map_before_pause == RID())) {
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
+ map_before_pause = RID();
+ }
+ } break;
+
+ case NOTIFICATION_UNPAUSED: {
+ if (agent_parent && !agent_parent->can_process()) {
+ map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
+ } else if (agent_parent && agent_parent->can_process() && !(map_before_pause == RID())) {
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
+ map_before_pause = RID();
+ }
+ } break;
+
case NOTIFICATION_EXIT_TREE: {
agent_parent = nullptr;
set_physics_process_internal(false);
@@ -109,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;
@@ -130,16 +185,85 @@ NavigationAgent2D::~NavigationAgent2D() {
agent = RID(); // Pointless
}
-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_avoidance_enabled(bool p_enabled) {
+ avoidance_enabled = p_enabled;
+ if (avoidance_enabled) {
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ } else {
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+ }
+}
+
+bool NavigationAgent2D::get_avoidance_enabled() const {
+ return avoidance_enabled;
+}
+
+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) {
@@ -248,7 +372,7 @@ TypedArray<String> NavigationAgent2D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) {
- warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D node."));
+ warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D inheriting parent node."));
}
return warnings;
@@ -290,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"));
@@ -303,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 2fb6fab91c..032a15cad2 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -41,21 +41,25 @@ class NavigationAgent2D : public Node {
Node2D *agent_parent = nullptr;
RID agent;
+ RID map_before_pause;
+ RID map_override;
- uint32_t navigable_layers = 1;
+ bool avoidance_enabled = false;
+ uint32_t navigation_layers = 1;
+ real_t path_desired_distance = 1.0;
real_t target_desired_distance = 1.0;
- real_t radius;
- real_t neighbor_dist;
- int max_neighbors;
- real_t time_horizon;
- real_t max_speed;
+ real_t radius = 0.0;
+ real_t neighbor_dist = 0.0;
+ int max_neighbors = 0;
+ real_t time_horizon = 0.0;
+ real_t max_speed = 0.0;
real_t path_max_distance = 3.0;
Vector2 target_location;
Vector<Vector2> navigation_path;
- int nav_path_index;
+ int nav_path_index = 0;
bool velocity_submitted = false;
Vector2 prev_safe_velocity;
/// The submitted target velocity
@@ -63,7 +67,7 @@ class NavigationAgent2D : public Node {
bool target_reached = false;
bool navigation_finished = true;
// No initialized on purpose
- uint32_t update_frame_id;
+ uint32_t update_frame_id = 0;
protected:
static void _bind_methods();
@@ -77,8 +81,24 @@ public:
return agent;
}
- void set_navigable_layers(uint32_t p_layers);
- uint32_t get_navigable_layers() const;
+ void set_avoidance_enabled(bool p_enabled);
+ bool get_avoidance_enabled() 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 {
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index d1e5bc11bc..0320c6c917 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -31,10 +31,13 @@
#include "navigation_obstacle_2d.h"
#include "scene/2d/collision_shape_2d.h"
+#include "scene/2d/physics_body_2d.h"
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
void NavigationObstacle2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle2D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle2D::set_estimate_radius);
ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle2D::is_radius_estimated);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle2D::set_radius);
@@ -78,8 +81,28 @@ void NavigationObstacle2D::_notification(int p_what) {
parent_node2d = nullptr;
} break;
+ case NOTIFICATION_PAUSED: {
+ if (parent_node2d && !parent_node2d->can_process()) {
+ map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
+ } else if (parent_node2d && parent_node2d->can_process() && !(map_before_pause == RID())) {
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
+ map_before_pause = RID();
+ }
+ } break;
+
+ case NOTIFICATION_UNPAUSED: {
+ if (parent_node2d && !parent_node2d->can_process()) {
+ map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
+ } else if (parent_node2d && parent_node2d->can_process() && !(map_before_pause == RID())) {
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_before_pause);
+ map_before_pause = RID();
+ }
+ } break;
+
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- if (parent_node2d) {
+ if (parent_node2d && parent_node2d->is_inside_tree()) {
NavigationServer2D::get_singleton()->agent_set_position(agent, parent_node2d->get_global_position());
}
} break;
@@ -103,6 +126,11 @@ TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
warnings.push_back(RTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."));
}
+ if (Object::cast_to<StaticBody2D>(get_parent())) {
+ warnings.push_back(RTR("The NavigationObstacle2D is intended for constantly moving bodies like CharacterBody2D or RigidDynamicBody2D as it creates only an RVO avoidance radius and does not follow scene geometry exactly."
+ "\nNot constantly moving or complete static objects should be captured with a refreshed NavigationPolygon so agents can not only avoid them but also move along those objects outline at high detail"));
+ }
+
return warnings;
}
@@ -122,13 +150,13 @@ void NavigationObstacle2D::reevaluate_agent_radius() {
}
real_t NavigationObstacle2D::estimate_agent_radius() const {
- if (parent_node2d) {
+ if (parent_node2d && parent_node2d->is_inside_tree()) {
// Estimate the radius of this physics body
real_t radius = 0.0;
for (int i(0); i < parent_node2d->get_child_count(); i++) {
// For each collision shape
CollisionShape2D *cs = Object::cast_to<CollisionShape2D>(parent_node2d->get_child(i));
- if (cs) {
+ if (cs && cs->is_inside_tree()) {
// Take the distance between the Body center to the shape center
real_t r = cs->get_transform().get_origin().length();
if (cs->get_shape().is_valid()) {
@@ -139,6 +167,9 @@ real_t NavigationObstacle2D::estimate_agent_radius() const {
r *= MAX(s.x, s.y);
// Takes the biggest radius
radius = MAX(radius, r);
+ } else if (cs && !cs->is_inside_tree()) {
+ WARN_PRINT("A CollisionShape2D of the NavigationObstacle2D parent node was not inside the SceneTree when estimating the obstacle radius."
+ "\nMove the NavigationObstacle2D to a child position below any CollisionShape2D node of the parent node so the CollisionShape2D is already inside the SceneTree.");
}
}
Vector2 s = parent_node2d->get_global_scale();
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index 2a0ef14e73..948cf5b61a 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -39,6 +39,7 @@ class NavigationObstacle2D : public Node {
Node2D *parent_node2d = nullptr;
RID agent;
+ RID map_before_pause;
bool estimate_radius = true;
real_t radius = 1.0;
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 261d371dc4..6e8fd891cb 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -302,19 +302,19 @@ void NavigationPolygon::make_polygons_from_outlines() {
polygons.clear();
vertices.clear();
- Map<Vector2, int> points;
+ HashMap<Vector2, int> points;
for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
TPPLPoly &tp = I->get();
struct Polygon p;
for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
- Map<Vector2, int>::Element *E = points.find(tp[i]);
+ HashMap<Vector2, int>::Iterator E = points.find(tp[i]);
if (!E) {
E = points.insert(tp[i], vertices.size());
vertices.push_back(tp[i]);
}
- p.indices.push_back(E->get());
+ p.indices.push_back(E->value);
}
polygons.push_back(p);
@@ -331,6 +331,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);
@@ -379,12 +380,54 @@ 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_enter_cost(region, travel_cost);
+}
+
+real_t NavigationRegion2D::get_travel_cost() const {
+ return travel_cost;
+}
+
+RID NavigationRegion2D::get_region_rid() const {
+ return region;
}
/////////////////////////////
@@ -505,6 +548,9 @@ void NavigationRegion2D::_navpoly_changed() {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
update();
}
+ if (navpoly.is_valid()) {
+ 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) {
@@ -531,19 +577,34 @@ 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());
}
NavigationRegion2D::~NavigationRegion2D() {
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 487a578401..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,8 +117,19 @@ 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 42c8daa4c7..4599785ce4 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -111,7 +111,7 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
#endif
void Node2D::_update_xform_values() {
- position = transform.elements[2];
+ position = transform.columns[2];
rotation = transform.get_rotation();
scale = transform.get_scale();
skew = transform.get_skew();
@@ -120,7 +120,7 @@ void Node2D::_update_xform_values() {
void Node2D::_update_transform() {
transform.set_rotation_scale_and_skew(rotation, scale, skew);
- transform.elements[2] = position;
+ transform.columns[2] = position;
RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), transform);
@@ -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,16 +437,17 @@ 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, "", PROPERTY_USAGE_NONE), "set_transform", "get_transform");
+ 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, "", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation");
+ 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::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
+ 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");
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 69d14f82ad..473c34768f 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.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);
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index dcbb6507f5..bd5a01f5a4 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -163,25 +163,25 @@ Vector2 ParallaxBackground::get_final_offset() const {
void ParallaxBackground::_bind_methods() {
ClassDB::bind_method(D_METHOD("_camera_moved"), &ParallaxBackground::_camera_moved);
- ClassDB::bind_method(D_METHOD("set_scroll_offset", "ofs"), &ParallaxBackground::set_scroll_offset);
+ ClassDB::bind_method(D_METHOD("set_scroll_offset", "offset"), &ParallaxBackground::set_scroll_offset);
ClassDB::bind_method(D_METHOD("get_scroll_offset"), &ParallaxBackground::get_scroll_offset);
- ClassDB::bind_method(D_METHOD("set_scroll_base_offset", "ofs"), &ParallaxBackground::set_scroll_base_offset);
+ ClassDB::bind_method(D_METHOD("set_scroll_base_offset", "offset"), &ParallaxBackground::set_scroll_base_offset);
ClassDB::bind_method(D_METHOD("get_scroll_base_offset"), &ParallaxBackground::get_scroll_base_offset);
ClassDB::bind_method(D_METHOD("set_scroll_base_scale", "scale"), &ParallaxBackground::set_scroll_base_scale);
ClassDB::bind_method(D_METHOD("get_scroll_base_scale"), &ParallaxBackground::get_scroll_base_scale);
- ClassDB::bind_method(D_METHOD("set_limit_begin", "ofs"), &ParallaxBackground::set_limit_begin);
+ ClassDB::bind_method(D_METHOD("set_limit_begin", "offset"), &ParallaxBackground::set_limit_begin);
ClassDB::bind_method(D_METHOD("get_limit_begin"), &ParallaxBackground::get_limit_begin);
- ClassDB::bind_method(D_METHOD("set_limit_end", "ofs"), &ParallaxBackground::set_limit_end);
+ ClassDB::bind_method(D_METHOD("set_limit_end", "offset"), &ParallaxBackground::set_limit_end);
ClassDB::bind_method(D_METHOD("get_limit_end"), &ParallaxBackground::get_limit_end);
ClassDB::bind_method(D_METHOD("set_ignore_camera_zoom", "ignore"), &ParallaxBackground::set_ignore_camera_zoom);
ClassDB::bind_method(D_METHOD("is_ignore_camera_zoom"), &ParallaxBackground::is_ignore_camera_zoom);
ADD_GROUP("Scroll", "scroll_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_offset", "get_scroll_offset");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_base_offset"), "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_limit_begin"), "set_limit_begin", "get_limit_begin");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_limit_end"), "set_limit_end", "get_limit_end");
+ 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", 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 9e8ab224dc..f0aad1b8a4 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -158,8 +158,8 @@ 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_offset"), "set_motion_offset", "get_motion_offset");
+ 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 aa68349329..9862c4bfb1 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;
}
@@ -295,7 +293,7 @@ void PathFollow2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead);
ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
@@ -306,12 +304,13 @@ 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()) {
real_t path_length = path->get_curve()->get_baked_length();
- if (loop) {
+ if (loop && path_length) {
offset = Math::fposmod(offset, path_length);
if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) {
offset = path_length;
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index c0f2b6f07e..e60a5ed034 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -56,8 +56,10 @@ PhysicsBody2D::~PhysicsBody2D() {
Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_distance, bool p_test_only, real_t p_margin) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_distance, p_margin);
+ parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery.
PhysicsServer2D::MotionResult result;
+
if (move_and_collide(parameters, result, p_test_only)) {
// Create a new instance when the cached reference is invalid or still in use in script.
if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
@@ -119,7 +121,7 @@ bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_
if (!p_test_only) {
Transform2D gt = p_parameters.from;
- gt.elements[2] += r_result.travel;
+ gt.columns[2] += r_result.travel;
set_global_transform(gt);
}
@@ -139,15 +141,9 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distan
}
PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin);
+ parameters.recovery_as_collision = false; // Don't report collisions generated only from recovery.
- bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
-
- if (colliding) {
- // Don't report collision when the whole motion is done.
- return (r->collision_safe_fraction < 1.0);
- } else {
- return false;
- }
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
}
TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
@@ -226,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) :
@@ -335,17 +331,17 @@ void RigidDynamicBody2D::_body_enter_tree(ObjectID p_id) {
ERR_FAIL_COND(!node);
ERR_FAIL_COND(!contact_monitor);
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
+ HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(E->get().in_scene);
+ ERR_FAIL_COND(E->value.in_scene);
contact_monitor->locked = true;
- E->get().in_scene = true;
+ E->value.in_scene = true;
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
+ for (int i = 0; i < E->value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_entered, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape);
}
contact_monitor->locked = false;
@@ -356,17 +352,17 @@ void RigidDynamicBody2D::_body_exit_tree(ObjectID p_id) {
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
ERR_FAIL_COND(!contact_monitor);
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
+ HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
- ERR_FAIL_COND(!E->get().in_scene);
- E->get().in_scene = false;
+ ERR_FAIL_COND(!E->value.in_scene);
+ E->value.in_scene = false;
contact_monitor->locked = true;
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
- for (int i = 0; i < E->get().shapes.size(); i++) {
- emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->get().rid, node, E->get().shapes[i].body_shape, E->get().shapes[i].local_shape);
+ for (int i = 0; i < E->value.shapes.size(); i++) {
+ emit_signal(SceneStringNames::get_singleton()->body_shape_exited, E->value.rid, node, E->value.shapes[i].body_shape, E->value.shapes[i].local_shape);
}
contact_monitor->locked = false;
@@ -380,45 +376,45 @@ void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!contact_monitor);
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid);
+ HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(objid);
ERR_FAIL_COND(!body_in && !E);
if (body_in) {
if (!E) {
E = contact_monitor->body_map.insert(objid, BodyState());
- E->get().rid = p_body;
- //E->get().rc=0;
- E->get().in_scene = node && node->is_inside_tree();
+ E->value.rid = p_body;
+ //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));
- if (E->get().in_scene) {
+ if (E->value.in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
}
- //E->get().rc++;
+ //E->value.rc++;
}
if (node) {
- E->get().shapes.insert(ShapePair(p_body_shape, p_local_shape));
+ E->value.shapes.insert(ShapePair(p_body_shape, p_local_shape));
}
- if (E->get().in_scene) {
+ if (E->value.in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_shape_entered, p_body, node, p_body_shape, p_local_shape);
}
} else {
- //E->get().rc--;
+ //E->value.rc--;
if (node) {
- E->get().shapes.erase(ShapePair(p_body_shape, p_local_shape));
+ E->value.shapes.erase(ShapePair(p_body_shape, p_local_shape));
}
- bool in_scene = E->get().in_scene;
+ bool in_scene = E->value.in_scene;
- if (E->get().shapes.is_empty()) {
+ if (E->value.shapes.is_empty()) {
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody2D::_body_enter_tree));
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody2D::_body_exit_tree));
@@ -427,7 +423,7 @@ void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p
}
}
- contact_monitor->body_map.erase(E);
+ contact_monitor->body_map.remove(E);
}
if (node && in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_shape_exited, p_body, node, p_body_shape, p_local_shape);
@@ -490,7 +486,7 @@ void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state)
int local_shape = p_state->get_contact_local_shape(i);
int shape = p_state->get_contact_collider_shape(i);
- Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
+ HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(obj);
if (!E) {
toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
@@ -501,7 +497,7 @@ void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state)
}
ShapePair sp(shape, local_shape);
- int idx = E->get().shapes.find(sp);
+ int idx = E->value.shapes.find(sp);
if (idx == -1) {
toadd[toadd_count].rid = rid;
toadd[toadd_count].local_shape = local_shape;
@@ -511,7 +507,7 @@ void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state)
continue;
}
- E->get().shapes[idx].tagged = true;
+ E->value.shapes[idx].tagged = true;
}
//put the ones to remove
@@ -924,7 +920,7 @@ TypedArray<String> RigidDynamicBody2D::get_configuration_warnings() const {
TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();
- if (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05) {
+ if (ABS(t.columns[0].length() - 1.0) > 0.05 || ABS(t.columns[1].length() - 1.0) > 0.05) {
warnings.push_back(RTR("Size changes to RigidDynamicBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
@@ -1018,10 +1014,10 @@ void RigidDynamicBody2D::_bind_methods() {
GDVIRTUAL_BIND(_integrate_forces, "state");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5px\u00B2"), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater"), "set_center_of_mass", "get_center_of_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass");
ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass");
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::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
@@ -1035,16 +1031,16 @@ void RigidDynamicBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "freeze"), "set_freeze_enabled", "is_freeze_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "freeze_mode", PROPERTY_HINT_ENUM, "Static,Kinematic"), "set_freeze_mode", "get_freeze_mode");
ADD_GROUP("Linear", "linear_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity", PROPERTY_HINT_NONE, "suffix:px/s"), "set_linear_velocity", "get_linear_velocity");
ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_GROUP("Angular", "angular_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_NONE, "suffix:rad/s"), "set_angular_velocity", "get_angular_velocity");
ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
ADD_GROUP("Constant Forces", "constant_");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_force"), "set_constant_force", "get_constant_force");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_torque"), "set_constant_torque", "get_constant_torque");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_force", PROPERTY_HINT_NONE, U"suffix:kg\u22C5px/s\u00B2"), "set_constant_force", "get_constant_force");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_torque", PROPERTY_HINT_NONE, U"suffix:kg\u22C5px\u00B2/s\u00B2/rad"), "set_constant_torque", "get_constant_torque");
ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index")));
@@ -1106,7 +1102,7 @@ bool CharacterBody2D::move_and_slide() {
Vector2 current_platform_velocity = platform_velocity;
Transform2D gt = get_global_transform();
- previous_position = gt.elements[2];
+ previous_position = gt.columns[2];
if ((on_floor || on_wall) && platform_rid.is_valid()) {
bool excluded = false;
@@ -1119,7 +1115,7 @@ bool CharacterBody2D::move_and_slide() {
//this approach makes sure there is less delay between the actual body velocity and the one we saved
PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(platform_rid);
if (bs) {
- Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2];
+ Vector2 local_position = gt.columns[2] - bs->get_transform().columns[2];
current_platform_velocity = bs->get_velocity_at_local_position(local_position);
} else {
// Body is removed or destroyed, invalidate floor.
@@ -1141,6 +1137,7 @@ bool CharacterBody2D::move_and_slide() {
if (!current_platform_velocity.is_equal_approx(Vector2())) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.exclude_bodies.insert(platform_rid);
if (platform_object_id.is_valid()) {
parameters.exclude_objects.insert(platform_object_id);
@@ -1199,8 +1196,9 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin);
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
- Vector2 prev_position = parameters.from.elements[2];
+ Vector2 prev_position = parameters.from.columns[2];
PhysicsServer2D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, !sliding_enabled);
@@ -1227,7 +1225,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
if (on_floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) {
Transform2D gt = get_global_transform();
if (result.travel.length() <= margin + CMP_EPSILON) {
- gt.elements[2] -= result.travel;
+ gt.columns[2] -= result.travel;
}
set_global_transform(gt);
velocity = Vector2();
@@ -1249,11 +1247,11 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
if (result.travel.length() <= margin + CMP_EPSILON) {
// Cancels the motion.
Transform2D gt = get_global_transform();
- gt.elements[2] -= result.travel;
+ gt.columns[2] -= result.travel;
set_global_transform(gt);
}
// Determines if you are on the ground.
- _snap_on_floor(true, false);
+ _snap_on_floor(true, false, true);
velocity = Vector2();
last_motion = Vector2();
motion = Vector2();
@@ -1308,7 +1306,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
can_apply_constant_speed = false;
sliding_enabled = true;
Transform2D gt = get_global_transform();
- gt.elements[2] = prev_position;
+ gt.columns[2] = prev_position;
set_global_transform(gt);
Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized();
@@ -1355,6 +1353,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
bool first_slide = true;
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin);
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
PhysicsServer2D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, false);
@@ -1392,8 +1391,8 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
}
}
-void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) {
- if (on_floor || !was_on_floor || vel_dir_facing_up) {
+void CharacterBody2D::_snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor) {
+ if (on_floor || !p_was_on_floor || p_vel_dir_facing_up) {
return;
}
@@ -1401,11 +1400,13 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
real_t length = MAX(floor_snap_length, margin);
PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result;
if (move_and_collide(parameters, result, true, false)) {
- if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ if ((result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) ||
+ (p_wall_as_floor && result.get_angle(-up_direction) > floor_max_angle + FLOOR_ANGLE_THRESHOLD)) {
on_floor = true;
floor_normal = result.collision_normal;
_set_platform_data(result);
@@ -1420,14 +1421,14 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
}
}
- parameters.from.elements[2] += result.travel;
+ parameters.from.columns[2] += result.travel;
set_global_transform(parameters.from);
}
}
}
-bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) {
- if (up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) {
+bool CharacterBody2D::_on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up) {
+ if (up_direction == Vector2() || on_floor || !p_was_on_floor || p_vel_dir_facing_up) {
return false;
}
@@ -1435,6 +1436,7 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin
real_t length = MAX(floor_snap_length, margin);
PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result;
@@ -1516,7 +1518,7 @@ const Vector2 &CharacterBody2D::get_last_motion() const {
}
Vector2 CharacterBody2D::get_position_delta() const {
- return get_global_transform().elements[2] - previous_position;
+ return get_global_transform().columns[2] - previous_position;
}
const Vector2 &CharacterBody2D::get_real_velocity() const {
@@ -1750,7 +1752,7 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "suffix:px/s", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle");
@@ -1759,12 +1761,12 @@ 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");
ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:px"), "set_safe_margin", "get_safe_margin");
BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED);
BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 8d9e31d4dd..7401fc7578 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -200,7 +200,7 @@ private:
struct ContactMonitor {
bool locked = false;
- Map<ObjectID, BodyState> body_map;
+ HashMap<ObjectID, BodyState> body_map;
};
ContactMonitor *contact_monitor = nullptr;
@@ -441,11 +441,11 @@ private:
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
Ref<KinematicCollision2D> _get_last_slide_collision();
const Vector2 &get_up_direction() const;
- bool _on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up);
+ bool _on_floor_if_snapped(bool p_was_on_floor, bool p_vel_dir_facing_up);
void set_up_direction(const Vector2 &p_up_direction);
void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
void _set_platform_data(const PhysicsServer2D::MotionResult &p_result);
- void _snap_on_floor(bool was_on_floor, bool vel_dir_facing_up);
+ void _snap_on_floor(bool p_was_on_floor, bool p_vel_dir_facing_up, bool p_wall_as_floor = false);
protected:
void _notification(int p_what);
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index f9986c2f30..ba62941d3a 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -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"), "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_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset");
+ 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/position_2d.cpp b/scene/2d/position_2d.cpp
index d946ea63bf..cfa4d0401e 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -113,7 +113,7 @@ void Position2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gizmo_extents", "extents"), &Position2D::set_gizmo_extents);
ClassDB::bind_method(D_METHOD("get_gizmo_extents"), &Position2D::get_gizmo_extents);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gizmo_extents", PROPERTY_HINT_RANGE, "0,1000,0.1,or_greater"), "set_gizmo_extents", "get_gizmo_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gizmo_extents", PROPERTY_HINT_RANGE, "0,1000,0.1,or_greater,suffix:px"), "set_gizmo_extents", "get_gizmo_extents");
}
Position2D::Position2D() {
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 37db9211e1..8953813452 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -353,7 +353,7 @@ void RayCast2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
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::VECTOR2, "target_position", PROPERTY_HINT_NONE, "suffix:px"), "set_target_position", "get_target_position");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled");
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 2c6f2d5c00..1fb97d89fe 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -44,7 +44,7 @@ class RayCast2D : public Node2D {
int against_shape = 0;
Vector2 collision_point;
Vector2 collision_normal;
- Set<RID> exclude;
+ HashSet<RID> exclude;
uint32_t collision_mask = 1;
bool exclude_parent_body = true;
diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp
index a2f4b16ed3..ae810156a2 100644
--- a/scene/2d/shape_cast_2d.cpp
+++ b/scene/2d/shape_cast_2d.cpp
@@ -444,8 +444,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 15436d6e3d..7ff080aed0 100644
--- a/scene/2d/shape_cast_2d.h
+++ b/scene/2d/shape_cast_2d.h
@@ -46,7 +46,7 @@ class ShapeCast2D : public Node2D {
RID shape_rid;
Vector2 target_position = Vector2(0, 50);
- Set<RID> exclude;
+ HashSet<RID> exclude;
real_t margin = 0.0;
uint32_t collision_mask = 1;
bool exclude_parent_body = true;
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index aa039e07ee..cbacb7f579 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -81,14 +81,14 @@ bool Bone2D::_get(const StringName &p_path, Variant &r_ret) const {
}
void Bone2D::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "auto_calculate_length_and_angle", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("auto_calculate_length_and_angle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (!autocalculate_length_and_angle) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1, 1024, 1", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "bone_angle", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("length"), PROPERTY_HINT_RANGE, "1, 1024, 1", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("bone_angle"), PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
}
#ifdef TOOLS_ENABLED
- p_list->push_back(PropertyInfo(Variant::BOOL, "editor_settings/show_bone_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::BOOL, PNAME("editor_settings/show_bone_gizmo"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
#endif // TOOLS_ENABLED
}
@@ -390,7 +390,7 @@ void Bone2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_angle", "angle"), &Bone2D::set_bone_angle);
ClassDB::bind_method(D_METHOD("get_bone_angle"), &Bone2D::get_bone_angle);
- ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest"), "set_rest", "get_rest");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest", PROPERTY_HINT_NONE, "suffix:px"), "set_rest", "get_rest");
}
void Bone2D::set_rest(const Transform2D &p_rest) {
@@ -560,7 +560,7 @@ bool Skeleton2D::_get(const StringName &p_path, Variant &r_ret) const {
void Skeleton2D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(
- PropertyInfo(Variant::OBJECT, "modification_stack",
+ PropertyInfo(Variant::OBJECT, PNAME("modification_stack"),
PROPERTY_HINT_RESOURCE_TYPE,
"SkeletonModificationStack2D",
PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index facd164a0e..b3062ca02a 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -439,14 +439,14 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_GROUP("Offset", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
- 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::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
ADD_GROUP("Animation", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index cbbadf1178..cf8b6b8f94 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -34,45 +34,36 @@
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
-Map<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping_coords_and_peering_bits() const {
- Map<Vector2i, TileSet::CellNeighbor> output;
+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 @@ Map<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping
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 @@ Map<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping
}
} 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 @@ Map<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping
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:
@@ -742,7 +744,7 @@ Vector2i TileMap::_coords_to_quadrant_coords(int p_layer, const Vector2i &p_coor
p_coords.y > 0 ? p_coords.y / quadrant_size : (p_coords.y - (quadrant_size - 1)) / quadrant_size);
}
-Map<Vector2i, TileMapQuadrant>::Element *TileMap::_create_quadrant(int p_layer, const Vector2i &p_qk) {
+HashMap<Vector2i, TileMapQuadrant>::Iterator TileMap::_create_quadrant(int p_layer, const Vector2i &p_qk) {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
TileMapQuadrant q;
@@ -765,9 +767,9 @@ Map<Vector2i, TileMapQuadrant>::Element *TileMap::_create_quadrant(int p_layer,
return layers[p_layer].quadrant_map.insert(p_qk, q);
}
-void TileMap::_make_quadrant_dirty(Map<Vector2i, TileMapQuadrant>::Element *Q) {
+void TileMap::_make_quadrant_dirty(HashMap<Vector2i, TileMapQuadrant>::Iterator Q) {
// Make the given quadrant dirty, then trigger an update later.
- TileMapQuadrant &q = Q->get();
+ TileMapQuadrant &q = Q->value;
if (!q.dirty_list_element.in_list()) {
layers[q.layer].dirty_quadrant_list.add(&q.dirty_list_element);
}
@@ -810,8 +812,8 @@ void TileMap::_update_dirty_quadrants() {
for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) {
q->self()->map_to_world.clear();
q->self()->world_to_map.clear();
- for (Set<Vector2i>::Element *E = q->self()->cells.front(); E; E = E->next()) {
- Vector2i pk = E->get();
+ for (const Vector2i &E : q->self()->cells) {
+ Vector2i pk = E;
Vector2i pk_world_coords = map_to_world(pk);
q->self()->map_to_world[pk] = pk_world_coords;
q->self()->world_to_map[pk_world_coords] = pk;
@@ -871,18 +873,18 @@ void TileMap::_recreate_layer_internals(int p_layer) {
_rendering_update_layer(p_layer);
// Recreate the quadrants.
- const Map<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
Vector2i qk = _coords_to_quadrant_coords(p_layer, Vector2i(E.key.x, E.key.y));
- Map<Vector2i, TileMapQuadrant>::Element *Q = layers[p_layer].quadrant_map.find(qk);
+ HashMap<Vector2i, TileMapQuadrant>::Iterator Q = layers[p_layer].quadrant_map.find(qk);
if (!Q) {
Q = _create_quadrant(p_layer, qk);
- layers[p_layer].dirty_quadrant_list.add(&Q->get().dirty_list_element);
+ layers[p_layer].dirty_quadrant_list.add(&Q->value.dirty_list_element);
}
Vector2i pk = E.key;
- Q->get().cells.insert(pk);
+ Q->value.cells.insert(pk);
_make_quadrant_dirty(Q);
}
@@ -896,9 +898,9 @@ void TileMap::_recreate_internals() {
}
}
-void TileMap::_erase_quadrant(Map<Vector2i, TileMapQuadrant>::Element *Q) {
+void TileMap::_erase_quadrant(HashMap<Vector2i, TileMapQuadrant>::Iterator Q) {
// Remove a quadrant.
- TileMapQuadrant *q = &(Q->get());
+ TileMapQuadrant *q = &(Q->value);
// Call the cleanup_quadrant method on plugins.
if (tile_set.is_valid()) {
@@ -917,7 +919,7 @@ void TileMap::_erase_quadrant(Map<Vector2i, TileMapQuadrant>::Element *Q) {
RenderingServer *rs = RenderingServer::get_singleton();
rs->free(q->debug_canvas_item);
- layers[q->layer].quadrant_map.erase(Q);
+ layers[q->layer].quadrant_map.remove(Q);
rect_cache_dirty = true;
}
@@ -926,7 +928,7 @@ void TileMap::_clear_layer_internals(int p_layer) {
// Clear quadrants.
while (layers[p_layer].quadrant_map.size()) {
- _erase_quadrant(layers[p_layer].quadrant_map.front());
+ _erase_quadrant(layers[p_layer].quadrant_map.begin());
}
// Clear the layers internals.
@@ -954,15 +956,17 @@ void TileMap::_recompute_rect_cache() {
}
Rect2 r_total;
+ bool first = true;
for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (const Map<Vector2i, TileMapQuadrant>::Element *E = layers[layer].quadrant_map.front(); E; E = E->next()) {
+ for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
Rect2 r;
- r.position = map_to_world(E->key() * get_effective_quadrant_size(layer));
- r.expand_to(map_to_world((E->key() + Vector2i(1, 0)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_world((E->key() + Vector2i(1, 1)) * get_effective_quadrant_size(layer)));
- r.expand_to(map_to_world((E->key() + Vector2i(0, 1)) * get_effective_quadrant_size(layer)));
- if (E == layers[layer].quadrant_map.front()) {
+ r.position = map_to_world(E.key * get_effective_quadrant_size(layer));
+ r.expand_to(map_to_world((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer)));
+ r.expand_to(map_to_world((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer)));
+ r.expand_to(map_to_world((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer)));
+ if (first) {
r_total = r;
+ first = false;
} else {
r_total = r_total.merge(r);
}
@@ -1086,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;
@@ -1125,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.
@@ -1154,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()));
@@ -1201,7 +1206,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
for (int layer = 0; layer < (int)layers.size(); layer++) {
// Sort the quadrants coords per world coordinates
- Map<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> world_to_map;
+ RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> world_to_map;
for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
world_to_map[map_to_world(E.key)] = E.key;
}
@@ -1248,8 +1253,8 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for scenes needing one.
RenderingServer *rs = RenderingServer::get_singleton();
Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
- for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
- const TileMapCell &c = get_cell(p_quadrant->layer, E_cell->get(), true);
+ for (const Vector2i &E_cell : p_quadrant->cells) {
+ const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1279,7 +1284,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D xform;
- xform.set_origin(map_to_world(E_cell->get()) - quadrant_pos);
+ xform.set_origin(map_to_world(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
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);
}
@@ -1462,8 +1467,8 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
q.bodies.clear();
// Recreate bodies and shapes.
- for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
- TileMapCell c = get_cell(q.layer, E_cell->get(), true);
+ for (const Vector2i &E_cell : q.cells) {
+ TileMapCell c = get_cell(q.layer, E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1476,8 +1481,8 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
const TileData *tile_data;
- if (q.runtime_tile_data_cache.has(E_cell->get())) {
- tile_data = q.runtime_tile_data_cache[E_cell->get()];
+ if (q.runtime_tile_data_cache.has(E_cell)) {
+ tile_data = q.runtime_tile_data_cache[E_cell];
} else {
tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
}
@@ -1488,12 +1493,12 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
// Create the body.
RID body = ps->body_create();
- bodies_coords[body] = E_cell->get();
+ bodies_coords[body] = E_cell;
ps->body_set_mode(body, collision_animatable ? PhysicsServer2D::BODY_MODE_KINEMATIC : PhysicsServer2D::BODY_MODE_STATIC);
ps->body_set_space(body, space);
Transform2D xform;
- xform.set_origin(map_to_world(E_cell->get()));
+ xform.set_origin(map_to_world(E_cell));
xform = global_transform * xform;
ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
@@ -1659,8 +1664,8 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
q.navigation_regions.clear();
// Get the navigation polygons and create regions.
- for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
- TileMapCell c = get_cell(q.layer, E_cell->get(), true);
+ for (const Vector2i &E_cell : q.cells) {
+ TileMapCell c = get_cell(q.layer, E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1673,12 +1678,12 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
const TileData *tile_data;
- if (q.runtime_tile_data_cache.has(E_cell->get())) {
- tile_data = q.runtime_tile_data_cache[E_cell->get()];
+ if (q.runtime_tile_data_cache.has(E_cell)) {
+ tile_data = q.runtime_tile_data_cache[E_cell];
} else {
tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
}
- q.navigation_regions[E_cell->get()].resize(tile_set->get_navigation_layers_count());
+ q.navigation_regions[E_cell].resize(tile_set->get_navigation_layers_count());
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
Ref<NavigationPolygon> navpoly;
@@ -1686,13 +1691,13 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
if (navpoly.is_valid()) {
Transform2D tile_transform;
- tile_transform.set_origin(map_to_world(E_cell->get()));
+ tile_transform.set_origin(map_to_world(E_cell));
RID region = NavigationServer2D::get_singleton()->region_create();
NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map());
NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform);
NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly);
- q.navigation_regions[E_cell->get()].write[layer_index] = region;
+ q.navigation_regions[E_cell].write[layer_index] = region;
}
}
}
@@ -1748,8 +1753,8 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
- for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
- TileMapCell c = get_cell(p_quadrant->layer, E_cell->get(), true);
+ for (const Vector2i &E_cell : p_quadrant->cells) {
+ TileMapCell c = get_cell(p_quadrant->layer, E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1762,14 +1767,14 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
const TileData *tile_data;
- if (p_quadrant->runtime_tile_data_cache.has(E_cell->get())) {
- tile_data = p_quadrant->runtime_tile_data_cache[E_cell->get()];
+ if (p_quadrant->runtime_tile_data_cache.has(E_cell)) {
+ tile_data = p_quadrant->runtime_tile_data_cache[E_cell];
} else {
tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
}
Transform2D xform;
- xform.set_origin(map_to_world(E_cell->get()) - quadrant_pos);
+ xform.set_origin(map_to_world(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
@@ -1823,8 +1828,8 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
q.scenes.clear();
// Recreate the scenes.
- for (Set<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) {
- const TileMapCell &c = get_cell(q.layer, E_cell->get(), true);
+ for (const Vector2i &E_cell : q.cells) {
+ const TileMapCell &c = get_cell(q.layer, E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1843,13 +1848,13 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
Control *scene_as_control = Object::cast_to<Control>(scene);
Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene);
if (scene_as_control) {
- scene_as_control->set_position(map_to_world(E_cell->get()) + scene_as_control->get_position());
+ scene_as_control->set_position(map_to_world(E_cell) + scene_as_control->get_position());
} else if (scene_as_node2d) {
Transform2D xform;
- xform.set_origin(map_to_world(E_cell->get()));
+ xform.set_origin(map_to_world(E_cell));
scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform());
}
- q.scenes[E_cell->get()] = scene->get_name();
+ q.scenes[E_cell] = scene->get_name();
}
}
}
@@ -1881,8 +1886,8 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder for scenes needing one.
RenderingServer *rs = RenderingServer::get_singleton();
Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
- for (Set<Vector2i>::Element *E_cell = p_quadrant->cells.front(); E_cell; E_cell = E_cell->next()) {
- const TileMapCell &c = get_cell(p_quadrant->layer, E_cell->get(), true);
+ for (const Vector2i &E_cell : p_quadrant->cells) {
+ const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true);
TileSetSource *source;
if (tile_set->has_source(c.source_id)) {
@@ -1910,7 +1915,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
// Draw a placeholder tile.
Transform2D xform;
- xform.set_origin(map_to_world(E_cell->get()) - quadrant_pos);
+ xform.set_origin(map_to_world(E_cell) - quadrant_pos);
rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
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);
}
@@ -1923,9 +1928,9 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
ERR_FAIL_INDEX(p_layer, (int)layers.size());
// Set the current cell tile (using integer position).
- Map<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
+ HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
Vector2i pk(p_coords);
- Map<Vector2i, TileMapCell>::Element *E = tile_map.find(pk);
+ HashMap<Vector2i, TileMapCell>::Iterator E = tile_map.find(pk);
int source_id = p_source_id;
Vector2i atlas_coords = p_atlas_coords;
@@ -1946,7 +1951,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
// Get the quadrant
Vector2i qk = _coords_to_quadrant_coords(p_layer, pk);
- Map<Vector2i, TileMapQuadrant>::Element *Q = layers[p_layer].quadrant_map.find(qk);
+ HashMap<Vector2i, TileMapQuadrant>::Iterator Q = layers[p_layer].quadrant_map.find(qk);
if (source_id == TileSet::INVALID_SOURCE) {
// Erase existing cell in the tile map.
@@ -1954,7 +1959,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
// Erase existing cell in the quadrant.
ERR_FAIL_COND(!Q);
- TileMapQuadrant &q = Q->get();
+ TileMapQuadrant &q = Q->value;
q.cells.erase(pk);
@@ -1975,18 +1980,18 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
if (!Q) {
Q = _create_quadrant(p_layer, qk);
}
- TileMapQuadrant &q = Q->get();
+ TileMapQuadrant &q = Q->value;
q.cells.insert(pk);
} else {
ERR_FAIL_COND(!Q); // TileMapQuadrant should exist...
- if (E->get().source_id == source_id && E->get().get_atlas_coords() == atlas_coords && E->get().alternative_tile == alternative_tile) {
+ if (E->value.source_id == source_id && E->value.get_atlas_coords() == atlas_coords && E->value.alternative_tile == alternative_tile) {
return; // Nothing changed.
}
}
- TileMapCell &c = E->get();
+ TileMapCell &c = E->value;
c.source_id = source_id;
c.set_atlas_coords(atlas_coords);
@@ -2005,57 +2010,57 @@ int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_us
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSet::INVALID_SOURCE);
// Get a cell source id from position
- const Map<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
+ HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
if (!E) {
return TileSet::INVALID_SOURCE;
}
if (p_use_proxies && tile_set.is_valid()) {
- Array proxyed = tile_set->map_tile_proxy(E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
return proxyed[0];
}
- return E->get().source_id;
+ return E->value.source_id;
}
Vector2i TileMap::get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetSource::INVALID_ATLAS_COORDS);
// Get a cell source id from position
- const Map<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
+ HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
if (!E) {
return TileSetSource::INVALID_ATLAS_COORDS;
}
if (p_use_proxies && tile_set.is_valid()) {
- Array proxyed = tile_set->map_tile_proxy(E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
return proxyed[1];
}
- return E->get().get_atlas_coords();
+ return E->value.get_atlas_coords();
}
int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
// Get a cell source id from position
- const Map<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- const Map<Vector2i, TileMapCell>::Element *E = tile_map.find(p_coords);
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
+ HashMap<Vector2i, TileMapCell>::ConstIterator E = tile_map.find(p_coords);
if (!E) {
return TileSetSource::INVALID_TILE_ALTERNATIVE;
}
if (p_use_proxies && tile_set.is_valid()) {
- Array proxyed = tile_set->map_tile_proxy(E->get().source_id, E->get().get_atlas_coords(), E->get().alternative_tile);
+ Array proxyed = tile_set->map_tile_proxy(E->value.source_id, E->value.get_atlas_coords(), E->value.alternative_tile);
return proxyed[2];
}
- return E->get().alternative_tile;
+ return E->value.alternative_tile;
}
Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
@@ -2143,90 +2148,124 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat
TypedArray<Vector2i> used_cells = p_pattern->get_used_cells();
for (int i = 0; i < used_cells.size(); i++) {
Vector2i coords = map_pattern(p_position, used_cells[i], p_pattern);
- set_cell(p_layer, coords, p_pattern->get_cell_source_id(coords), p_pattern->get_cell_atlas_coords(coords), p_pattern->get_cell_alternative_tile(coords));
+ set_cell(p_layer, coords, p_pattern->get_cell_source_id(used_cells[i]), p_pattern->get_cell_atlas_coords(used_cells[i]), p_pattern->get_cell_alternative_tile(used_cells[i]));
}
}
-Set<TileSet::TerrainsPattern> TileMap::_get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, Set<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 Set<TileSet::TerrainsPattern>();
+ return TileSet::TerrainsPattern();
}
// Returns all tiles compatible with the given constraints.
- Set<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));
- Set<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 min_score_pattern;
+}
+
+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 compatible_terrain_tile_patterns;
+ return output;
}
-Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_cells_list(int p_layer, const Set<Vector2i> &p_to_replace, int p_terrain_set, bool p_ignore_empty_terrains) const {
+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 Set<TerrainConstraint>();
+ return RBSet<TerrainConstraint>();
}
- ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), Set<TerrainConstraint>());
- ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Set<TerrainConstraint>());
+ 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.
- Set<TerrainConstraint> dummy_constraints;
- for (Set<Vector2i>::Element *E = p_to_replace.front(); E; E = E->next()) {
+ // 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.
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) {
- dummy_constraints.insert(TerrainConstraint(this, E->get(), bit, -1));
+ if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
+ dummy_constraints.insert(TerrainConstraint(this, E, bit, -1));
}
}
}
// For each constrained point, we get all overlapping tiles, and select the most adequate terrain for it.
- Set<TerrainConstraint> constraints;
- for (Set<TerrainConstraint>::Element *E = dummy_constraints.front(); E; E = E->next()) {
- TerrainConstraint c = E->get();
-
- Map<int, int> terrain_count;
+ RBSet<TerrainConstraint> constraints;
+ for (const TerrainConstraint &E_constraint : dummy_constraints) {
+ HashMap<int, int> terrain_count;
// Count the number of occurrences per terrain.
- Map<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;
}
}
@@ -2242,154 +2281,332 @@ Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ce
// Set the adequate terrain.
if (max > 0) {
+ TerrainConstraint c = E_constraint;
c.set_terrain(max_terrain);
constraints.insert(c);
}
}
+ // 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);
+ }
+ }
+
+ 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 constraints;
}
-Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const {
+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 Set<TerrainConstraint>();
+ return HashMap<Vector2i, TileSet::TerrainsPattern>();
}
- // Compute the constraints needed from the surrounding tiles.
- Set<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);
+ // Copy the constraints set.
+ RBSet<TerrainConstraint> constraints = p_constraints;
+
+ // Output map.
+ HashMap<Vector2i, TileSet::TerrainsPattern> output;
+
+ // Add all positions to a set.
+ 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;
}
-Map<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse(const Set<Vector2i> &p_to_replace, int p_terrain_set, const Set<TerrainConstraint> p_constraints) {
- if (!tile_set.is_valid()) {
- return Map<Vector2i, TileSet::TerrainsPattern>();
+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);
+ }
+ }
+ }
}
- // Copy the constraints set.
- Set<TerrainConstraint> constraints = p_constraints;
+ // 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);
+ }
+ }
- // Compute all acceptable patterns for each cell.
- Map<Vector2i, Set<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);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set && tile_data->get_terrain() == p_terrain) {
+ connect = true;
+ }
+ }
+ if (connect) {
+ cells_with_terrain_center_bit.insert(coords);
+ }
}
- // Output map.
- Map<Vector2i, TileSet::TerrainsPattern> output;
+ RBSet<TerrainConstraint> constraints;
- // Add all positions to a set.
- Set<Vector2i> to_replace = Set<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, Set<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, Set<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.
- Set<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) {
- Set<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));
+ // 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);
+ }
}
}
- min_terrain_count = MIN(min_terrain_count, terrains.size());
- terrains_counts.push_back(terrains.size());
- pattern_index++;
}
- 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);
+ }
+
+ // 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;
+}
+
+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);
+ }
}
- 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)];
+ RBSet<TerrainConstraint> constraints;
- // 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);
+ // 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);
+ }
- // Add the new constraints from the added tiles.
- Set<TerrainConstraint> new_constraints = get_terrain_constraints_from_added_tile(selected_cell_to_replace, p_terrain_set, selected_terrain_tile_pattern);
- for (Set<TerrainConstraint>::Element *E_constraint = new_constraints.front(); E_constraint; E_constraint = E_constraint->next()) {
- constraints.insert(E_constraint->get());
- }
+ // 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);
+ }
- // 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);
+ // Fill the terrains.
+ output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ return output;
+}
+
+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());
- Set<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);
+ }
+}
- Set<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());
- Map<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);
}
}
TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileMapCell());
- const Map<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
if (!tile_map.has(p_coords)) {
return TileMapCell();
} else {
- TileMapCell c = tile_map.find(p_coords)->get();
+ TileMapCell c = tile_map.find(p_coords)->value;
if (p_use_proxies && tile_set.is_valid()) {
Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile);
c.source_id = proxyed[0];
@@ -2400,7 +2617,7 @@ TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_
}
}
-Map<Vector2i, TileMapQuadrant> *TileMap::get_quadrant_map(int p_layer) {
+HashMap<Vector2i, TileMapQuadrant> *TileMap::get_quadrant_map(int p_layer) {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
return &layers[p_layer].quadrant_map;
@@ -2415,16 +2632,16 @@ void TileMap::fix_invalid_tiles() {
ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open.");
for (unsigned int i = 0; i < layers.size(); i++) {
- const Map<Vector2i, TileMapCell> &tile_map = layers[i].tile_map;
- Set<Vector2i> coords;
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[i].tile_map;
+ RBSet<Vector2i> coords;
for (const KeyValue<Vector2i, TileMapCell> &E : tile_map) {
TileSetSource *source = *tile_set->get_source(E.value.source_id);
if (!source || !source->has_tile(E.value.get_atlas_coords()) || !source->has_alternative_tile(E.value.get_atlas_coords(), E.value.alternative_tile)) {
coords.insert(E.key);
}
}
- for (Set<Vector2i>::Element *E = coords.front(); E; E = E->next()) {
- set_cell(i, E->get(), TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
+ for (const Vector2i &E : coords) {
+ set_cell(i, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
}
}
}
@@ -2512,10 +2729,10 @@ void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) {
uint32_t v = decode_uint32(&local[4]);
// Extract the transform flags that used to be in the tilemap.
- bool flip_h = v & (1 << 29);
- bool flip_v = v & (1 << 30);
- bool transpose = v & (1 << 31);
- v &= (1 << 29) - 1;
+ bool flip_h = v & (1UL << 29);
+ bool flip_v = v & (1UL << 30);
+ bool transpose = v & (1UL << 31);
+ v &= (1UL << 29) - 1;
// Extract autotile/atlas coords.
int16_t coord_x = 0;
@@ -2546,7 +2763,7 @@ Vector<int> TileMap::_get_tile_data(int p_layer) const {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Vector<int>());
// Export tile data to raw format
- const Map<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
Vector<int> data;
data.resize(tile_map.size() * 3);
int *w = data.ptrw();
@@ -2727,7 +2944,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));
}
@@ -3375,10 +3592,10 @@ Rect2 TileMap::get_used_rect() { // Not const because of cache
used_rect_cache = Rect2i();
for (unsigned int i = 0; i < layers.size(); i++) {
- const Map<Vector2i, TileMapCell> &tile_map = layers[i].tile_map;
+ const HashMap<Vector2i, TileMapCell> &tile_map = layers[i].tile_map;
if (tile_map.size() > 0) {
if (first) {
- used_rect_cache = Rect2i(tile_map.front()->key().x, tile_map.front()->key().y, 0, 0);
+ used_rect_cache = Rect2i(tile_map.begin()->key.x, tile_map.begin()->key.y, 0, 0);
first = false;
}
@@ -3448,8 +3665,8 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
// Set a default texture filter for the whole tilemap
CanvasItem::set_texture_filter(p_texture_filter);
for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (Map<Vector2i, TileMapQuadrant>::Element *F = layers[layer].quadrant_map.front(); F; F = F->next()) {
- TileMapQuadrant &q = F->get();
+ 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));
_make_quadrant_dirty(F);
@@ -3463,8 +3680,8 @@ void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
// Set a default texture repeat for the whole tilemap
CanvasItem::set_texture_repeat(p_texture_repeat);
for (unsigned int layer = 0; layer < layers.size(); layer++) {
- for (Map<Vector2i, TileMapQuadrant>::Element *F = layers[layer].quadrant_map.front(); F; F = F->next()) {
- TileMapQuadrant &q = F->get();
+ 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));
_make_quadrant_dirty(F);
@@ -3512,7 +3729,7 @@ TypedArray<Vector2i> TileMap::get_surrounding_tiles(Vector2i coords) {
return around;
}
-void TileMap::draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Color p_color, Transform2D p_transform) {
+void TileMap::draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Color p_color, Transform2D p_transform) {
if (!tile_set.is_valid()) {
return;
}
@@ -3522,11 +3739,11 @@ void TileMap::draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Colo
Vector<Vector2> polygon = tile_set->get_tile_shape_polygon();
TileSet::TileShape shape = tile_set->get_tile_shape();
- for (Set<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) {
- Vector2 center = map_to_world(E->get());
+ for (const Vector2i &E : p_cells) {
+ Vector2 center = map_to_world(E);
#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \
- if (!p_cells.has(get_neighbor_cell(E->get(), side))) { \
+ if (!p_cells.has(get_neighbor_cell(E, side))) { \
Vector2 from = p_transform.xform(center + polygon[polygon_index_from] * tile_size); \
Vector2 to = p_transform.xform(center + polygon[polygon_index_to] * tile_size); \
p_control->draw_line(from, to, p_color); \
@@ -3576,7 +3793,7 @@ TypedArray<String> TileMap::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
// Retrieve the set of Z index values with a Y-sorted layer.
- Set<int> y_sorted_z_index;
+ RBSet<int> y_sorted_z_index;
for (int layer = 0; layer < (int)layers.size(); layer++) {
if (layers[layer].y_sort_enabled) {
y_sorted_z_index.insert(layers[layer].z_index);
@@ -3638,7 +3855,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 a0655dea2a..012bf01df9 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -57,11 +57,11 @@ struct TileMapQuadrant {
Vector2i coords;
// TileMapCells
- Set<Vector2i> cells;
+ RBSet<Vector2i> cells;
// We need those two maps to sort by world position for rendering
// This is kind of workaround, it would be better to sort the cells directly in the "cells" set instead.
- Map<Vector2i, Vector2i> map_to_world;
- Map<Vector2i, Vector2i, CoordsWorldComparator> world_to_map;
+ RBMap<Vector2i, Vector2i> map_to_world;
+ RBMap<Vector2i, Vector2i, CoordsWorldComparator> world_to_map;
// Debug.
RID debug_canvas_item;
@@ -74,13 +74,13 @@ struct TileMapQuadrant {
List<RID> bodies;
// Navigation.
- Map<Vector2i, Vector<RID>> navigation_regions;
+ HashMap<Vector2i, Vector<RID>> navigation_regions;
// Scenes.
- Map<Vector2i, String> scenes;
+ HashMap<Vector2i, String> scenes;
// Runtime TileData cache.
- Map<Vector2i, TileData *> runtime_tile_data_cache;
+ HashMap<Vector2i, TileData *> runtime_tile_data_cache;
void operator=(const TileMapQuadrant &q) {
layer = q.layer;
@@ -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,14 +130,18 @@ 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;
}
- Map<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const;
+ 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) {
terrain = 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 {
@@ -193,22 +208,22 @@ private:
int y_sort_origin = 0;
int z_index = 0;
RID canvas_item;
- Map<Vector2i, TileMapCell> tile_map;
- Map<Vector2i, TileMapQuadrant> quadrant_map;
+ HashMap<Vector2i, TileMapCell> tile_map;
+ HashMap<Vector2i, TileMapQuadrant> quadrant_map;
SelfList<TileMapQuadrant>::List dirty_quadrant_list;
};
LocalVector<TileMapLayer> layers;
int selected_layer = -1;
// Mapping for RID to coords.
- Map<RID, Vector2i> bodies_coords;
+ HashMap<RID, Vector2i> bodies_coords;
// Quadrants and internals management.
Vector2i _coords_to_quadrant_coords(int p_layer, const Vector2i &p_coords) const;
- Map<Vector2i, TileMapQuadrant>::Element *_create_quadrant(int p_layer, const Vector2i &p_qk);
+ HashMap<Vector2i, TileMapQuadrant>::Iterator _create_quadrant(int p_layer, const Vector2i &p_qk);
- void _make_quadrant_dirty(Map<Vector2i, TileMapQuadrant>::Element *Q);
+ void _make_quadrant_dirty(HashMap<Vector2i, TileMapQuadrant>::Iterator Q);
void _make_all_quadrants_dirty();
void _queue_update_dirty_quadrants();
@@ -217,7 +232,7 @@ private:
void _recreate_layer_internals(int p_layer);
void _recreate_internals();
- void _erase_quadrant(Map<Vector2i, TileMapQuadrant>::Element *Q);
+ void _erase_quadrant(HashMap<Vector2i, TileMapQuadrant>::Iterator Q);
void _clear_layer_internals(int p_layer);
void _clear_internals();
@@ -251,7 +266,9 @@ private:
void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
// Terrains.
- Set<TileSet::TerrainsPattern> _get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, Set<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);
@@ -333,14 +350,17 @@ public:
void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern);
// Terrains.
- Set<TerrainConstraint> get_terrain_constraints_from_removed_cells_list(int p_layer, const Set<Vector2i> &p_to_replace, int p_terrain_set, bool p_ignore_empty_terrains = true) const; // Not exposed.
- Set<TerrainConstraint> get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; // Not exposed.
- Map<Vector2i, TileSet::TerrainsPattern> terrain_wave_function_collapse(const Set<Vector2i> &p_to_replace, int p_terrain_set, const Set<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;
- Map<Vector2i, TileMapQuadrant> *get_quadrant_map(int p_layer);
+ HashMap<Vector2i, TileMapQuadrant> *get_quadrant_map(int p_layer);
int get_effective_quadrant_size(int p_layer) const;
//---
@@ -365,7 +385,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
@@ -377,7 +397,7 @@ public:
// Helpers?
TypedArray<Vector2i> get_surrounding_tiles(Vector2i coords);
- void draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Color p_color, Transform2D p_transform = Transform2D());
+ void draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Color p_color, Transform2D p_transform = Transform2D());
// Virtual function to modify the TileData at runtime
GDVIRTUAL2R(bool, _use_tile_data_runtime_update, int, Vector2i);
diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp
index 4bceaf71c6..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 {
@@ -101,7 +102,7 @@ void VisibleOnScreenNotifier2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rect"), &VisibleOnScreenNotifier2D::get_rect);
ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibleOnScreenNotifier2D::is_on_screen);
- 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");
ADD_SIGNAL(MethodInfo("screen_entered"));
ADD_SIGNAL(MethodInfo("screen_exited"));
@@ -198,7 +199,7 @@ void VisibleOnScreenEnabler2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibleOnScreenEnabler2D::get_enable_node_path);
ADD_GROUP("Enabling", "enable_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,When Paused"), "set_enable_mode", "get_enable_mode");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path");
BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
diff --git a/scene/2d/visible_on_screen_notifier_2d.h b/scene/2d/visible_on_screen_notifier_2d.h
index e0d580f174..38b508e2f6 100644
--- a/scene/2d/visible_on_screen_notifier_2d.h
+++ b/scene/2d/visible_on_screen_notifier_2d.h
@@ -37,7 +37,7 @@ class Viewport;
class VisibleOnScreenNotifier2D : public Node2D {
GDCLASS(VisibleOnScreenNotifier2D, Node2D);
- Set<Viewport *> viewports;
+ HashSet<Viewport *> viewports;
Rect2 rect;