diff options
Diffstat (limited to 'scene/2d')
78 files changed, 1654 insertions, 1421 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index fad4784d51..b33c2f43d4 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -122,13 +122,13 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &property) const { } property.hint_string += String(E->get()); - if (animation == E) { + if (animation == E->get()) { current_found = true; } } if (!current_found) { - if (property.hint_string == String()) { + if (property.hint_string.is_empty()) { property.hint_string = String(animation); } else { property.hint_string = String(animation) + "," + property.hint_string; @@ -158,14 +158,14 @@ void AnimatedSprite2D::_notification(int p_what) { return; } - double speed = frames->get_animation_speed(animation) * speed_scale; - if (speed == 0) { - return; //do nothing - } - double remaining = get_process_delta_time(); while (remaining) { + double speed = frames->get_animation_speed(animation) * speed_scale; + if (speed == 0) { + return; // Do nothing. + } + if (timeout <= 0) { timeout = _get_frame_duration(); @@ -247,7 +247,6 @@ void AnimatedSprite2D::_notification(int p_what) { } texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false); - } break; } } @@ -366,7 +365,7 @@ void AnimatedSprite2D::_res_changed() { update(); } -void AnimatedSprite2D::_set_playing(bool p_playing) { +void AnimatedSprite2D::set_playing(bool p_playing) { if (playing == p_playing) { return; } @@ -375,7 +374,7 @@ void AnimatedSprite2D::_set_playing(bool p_playing) { set_process_internal(playing); } -bool AnimatedSprite2D::_is_playing() const { +bool AnimatedSprite2D::is_playing() const { return playing; } @@ -389,15 +388,12 @@ void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backward } } - _set_playing(true); + is_over = false; + set_playing(true); } void AnimatedSprite2D::stop() { - _set_playing(false); -} - -bool AnimatedSprite2D::is_playing() const { - return playing; + set_playing(false); } double AnimatedSprite2D::_get_frame_duration() { @@ -421,7 +417,7 @@ void AnimatedSprite2D::_reset_timeout() { void AnimatedSprite2D::set_animation(const StringName &p_animation) { ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", p_animation)); - ERR_FAIL_COND_MSG(frames->get_animation_names().find(p_animation) == -1, vformat("There is no animation with name '%s'.", p_animation)); + ERR_FAIL_COND_MSG(!frames->get_animation_names().has(p_animation), vformat("There is no animation with name '%s'.", p_animation)); if (animation == p_animation) { return; @@ -442,12 +438,23 @@ TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (frames.is_null()) { - warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.")); + warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.")); } 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); @@ -455,12 +462,11 @@ void AnimatedSprite2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite2D::set_animation); ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite2D::get_animation); - ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite2D::_set_playing); - ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite2D::_is_playing); + ClassDB::bind_method(D_METHOD("set_playing", "playing"), &AnimatedSprite2D::set_playing); + ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite2D::is_playing); ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite2D::play, DEFVAL(StringName()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite2D::stop); - ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite2D::is_playing); ClassDB::bind_method(D_METHOD("set_centered", "centered"), &AnimatedSprite2D::set_centered); ClassDB::bind_method(D_METHOD("is_centered"), &AnimatedSprite2D::is_centered); @@ -488,7 +494,7 @@ void AnimatedSprite2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing"); + 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"); diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index ac4b20a6d9..3a41f810dc 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -57,8 +57,6 @@ class AnimatedSprite2D : public Node2D { double _get_frame_duration(); void _reset_timeout(); - void _set_playing(bool p_playing); - bool _is_playing() const; Rect2 _get_rect() const; protected: @@ -85,6 +83,8 @@ public: void play(const StringName &p_animation = StringName(), const bool p_backwards = false); void stop(); + + void set_playing(bool p_playing); bool is_playing() const; void set_animation(const StringName &p_animation); @@ -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 8db1491953..9699f784a2 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -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) { diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index 98ba270a61..a584420ced 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -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 f16e359a1d..eb463864e1 100644 --- a/scene/2d/audio_listener_2d.cpp +++ b/scene/2d/audio_listener_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -67,6 +67,7 @@ void AudioListener2D::_notification(int p_what) { make_current(); } } break; + case NOTIFICATION_EXIT_TREE: { if (!get_tree()->is_node_being_edited(this)) { if (is_current()) { diff --git a/scene/2d/audio_listener_2d.h b/scene/2d/audio_listener_2d.h index 454053bc4a..172d388efc 100644 --- a/scene/2d/audio_listener_2d.h +++ b/scene/2d/audio_listener_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 24da2ce9ce..624ef70468 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,72 +33,75 @@ #include "scene/2d/area_2d.h" #include "scene/2d/audio_listener_2d.h" #include "scene/main/window.h" +#include "scene/resources/world_2d.h" void AudioStreamPlayer2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this); - if (autoplay && !Engine::get_singleton()->is_editor_hint()) { - play(); - } - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this); + if (autoplay && !Engine::get_singleton()->is_editor_hint()) { + play(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - stop(); - AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); - } + case NOTIFICATION_EXIT_TREE: { + stop(); + AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); + } break; - if (p_what == NOTIFICATION_PAUSED) { - if (!can_process()) { - // Node can't process so we start fading out to silence - set_stream_paused(true); - } - } + case NOTIFICATION_PAUSED: { + if (!can_process()) { + // Node can't process so we start fading out to silence. + set_stream_paused(true); + } + } break; - if (p_what == NOTIFICATION_UNPAUSED) { - set_stream_paused(false); - } + case NOTIFICATION_UNPAUSED: { + set_stream_paused(false); + } break; - if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - //update anything related to position first, if possible of course - if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { - _update_panning(); - } + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // Update anything related to position first, if possible of course. + if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { + _update_panning(); + } - if (setplay.get() >= 0 && stream.is_valid()) { - active.set(); - Ref<AudioStreamPlayback> new_playback = stream->instance_playback(); - ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); - AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale); - stream_playbacks.push_back(new_playback); - setplay.set(-1); - } + if (setplay.get() >= 0 && stream.is_valid()) { + active.set(); + Ref<AudioStreamPlayback> new_playback = stream->instance_playback(); + ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); + AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale); + stream_playbacks.push_back(new_playback); + setplay.set(-1); + } - if (!stream_playbacks.is_empty() && active.is_set()) { - // Stop playing if no longer active. - Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; - for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { - if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { - playbacks_to_remove.push_back(playback); + if (!stream_playbacks.is_empty() && active.is_set()) { + // Stop playing if no longer active. + Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { + playbacks_to_remove.push_back(playback); + } + } + // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. + for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { + stream_playbacks.erase(playback); + } + if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { + // This node is no longer actively playing audio. + active.clear(); + set_physics_process_internal(false); + } + if (!playbacks_to_remove.is_empty()) { + emit_signal(SNAME("finished")); } } - // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. - for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { - stream_playbacks.erase(playback); - } - if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { - // This node is no longer actively playing audio. - active.clear(); - set_physics_process_internal(false); - } - if (!playbacks_to_remove.is_empty()) { - emit_signal(SNAME("finished")); - } - } - while (stream_playbacks.size() > max_polyphony) { - AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]); - stream_playbacks.remove(0); - } + while (stream_playbacks.size() > max_polyphony) { + AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]); + stream_playbacks.remove_at(0); + } + } break; } } @@ -145,7 +148,7 @@ void AudioStreamPlayer2D::_update_panning() { Vector2 global_pos = get_global_position(); - Set<Viewport *> viewports = world_2d->get_viewports(); + RBSet<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); diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index 5360fd4934..73b09e432f 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp index 539a66b881..c411aaf411 100644 --- a/scene/2d/back_buffer_copy.cpp +++ b/scene/2d/back_buffer_copy.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h index 6bdb3aaab2..4e7cac1f3e 100644 --- a/scene/2d/back_buffer_copy.h +++ b/scene/2d/back_buffer_copy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index bf5671be19..f61dbc071d 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,6 +30,7 @@ #include "camera_2d.h" +#include "core/config/project_settings.h" #include "scene/main/window.h" void Camera2D::_update_scroll() { @@ -56,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); }; } @@ -78,6 +79,7 @@ void Camera2D::set_zoom(const Vector2 &p_zoom) { ERR_FAIL_COND_MSG(Math::is_zero_approx(p_zoom.x) || Math::is_zero_approx(p_zoom.y), "Zoom level must be different from 0 (can be negative)."); zoom = p_zoom; + zoom_scale = Vector2(1, 1) / zoom; Point2 old_smoothed_camera_pos = smoothed_camera_pos; _update_scroll(); smoothed_camera_pos = old_smoothed_camera_pos; @@ -102,8 +104,8 @@ Transform2D Camera2D::get_camera_transform() { if (!first) { if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) { if (drag_horizontal_enabled && !Engine::get_singleton()->is_editor_hint() && !drag_horizontal_offset_changed) { - camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom.x * drag_margin[SIDE_LEFT])); - camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom.x * drag_margin[SIDE_RIGHT])); + camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom_scale.x * drag_margin[SIDE_LEFT])); + camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom_scale.x * drag_margin[SIDE_RIGHT])); } else { if (drag_horizontal_offset < 0) { camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[SIDE_RIGHT] * drag_horizontal_offset; @@ -115,8 +117,8 @@ Transform2D Camera2D::get_camera_transform() { } if (drag_vertical_enabled && !Engine::get_singleton()->is_editor_hint() && !drag_vertical_offset_changed) { - camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom.y * drag_margin[SIDE_TOP])); - camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom.y * drag_margin[SIDE_BOTTOM])); + camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom_scale.y * drag_margin[SIDE_TOP])); + camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom_scale.y * drag_margin[SIDE_BOTTOM])); } else { if (drag_vertical_offset < 0) { @@ -132,8 +134,8 @@ Transform2D Camera2D::get_camera_transform() { camera_pos = new_camera_pos; } - Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2()); - Rect2 screen_rect(-screen_offset + camera_pos, screen_size * zoom); + Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom_scale) : Point2()); + Rect2 screen_rect(-screen_offset + camera_pos, screen_size * zoom_scale); if (limit_smoothing_enabled) { if (screen_rect.position.x < limit[SIDE_LEFT]) { @@ -167,16 +169,16 @@ Transform2D Camera2D::get_camera_transform() { first = false; } - Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2()); + Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom_scale) : Point2()); real_t angle = get_global_rotation(); if (rotating) { screen_offset = screen_offset.rotated(angle); } - Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom); + Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom_scale); - if (!limit_smoothing_enabled) { + if (!smoothing_enabled || !limit_smoothing_enabled) { if (screen_rect.position.x < limit[SIDE_LEFT]) { screen_rect.position.x = limit[SIDE_LEFT]; } @@ -201,19 +203,11 @@ Transform2D Camera2D::get_camera_transform() { camera_screen_center = screen_rect.get_center(); Transform2D xform; - xform.scale_basis(zoom); + xform.scale_basis(zoom_scale); if (rotating) { xform.set_rotation(angle); } - xform.set_origin(screen_rect.position /*.floor()*/); - - /* - if (0) { - xform = get_global_transform() * xform; - } else { - xform.elements[2]+=get_global_transform().get_origin(); - } -*/ + xform.set_origin(screen_rect.position); return (xform).affine_inverse(); } @@ -223,14 +217,14 @@ void Camera2D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { _update_scroll(); - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_processing_internal() && !is_physics_processing_internal()) { _update_scroll(); } - } break; + case NOTIFICATION_ENTER_TREE: { ERR_FAIL_COND(!is_inside_tree()); if (custom_viewport && ObjectDB::get_instance(custom_viewport_id)) { @@ -255,8 +249,8 @@ void Camera2D::_notification(int p_what) { _update_process_callback(); _update_scroll(); first = true; - } break; + case NOTIFICATION_EXIT_TREE: { if (is_current()) { if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) { @@ -268,8 +262,8 @@ void Camera2D::_notification(int p_what) { remove_from_group(group_name); remove_from_group(canvas_group_name); viewport = nullptr; - } break; + #ifdef TOOLS_ENABLED case NOTIFICATION_DRAW: { if (!is_inside_tree() || !Engine::get_singleton()->is_editor_hint()) { @@ -427,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; } @@ -436,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; } @@ -530,7 +524,7 @@ Point2 Camera2D::get_camera_screen_center() const { Size2 Camera2D::_get_camera_screen_size() const { // special case if the camera2D is in the root viewport if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) { - return Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); + return Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height")); } return get_viewport_rect().size; } diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index d697515547..294a6fcb80 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -61,6 +61,7 @@ protected: RID canvas; Vector2 offset; Vector2 zoom = Vector2(1, 1); + Vector2 zoom_scale = Vector2(1, 1); AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER; bool rotating = false; bool current = false; diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp index ee025b6dfc..37a858330c 100644 --- a/scene/2d/canvas_group.cpp +++ b/scene/2d/canvas_group.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/canvas_group.h b/scene/2d/canvas_group.h index b487d7a098..9bc1772ee2 100644 --- a/scene/2d/canvas_group.h +++ b/scene/2d/canvas_group.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index 4de99959a3..61a17a4845 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,27 +31,32 @@ #include "canvas_modulate.h" void CanvasModulate::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_CANVAS) { - if (is_visible_in_tree()) { - RS::get_singleton()->canvas_set_modulate(get_canvas(), color); - add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } + switch (p_what) { + case NOTIFICATION_ENTER_CANVAS: { + if (is_visible_in_tree()) { + RS::get_singleton()->canvas_set_modulate(get_canvas(), color); + add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } + } break; - } else if (p_what == NOTIFICATION_EXIT_CANVAS) { - if (is_visible_in_tree()) { - RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); - remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } - } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (is_visible_in_tree()) { - RS::get_singleton()->canvas_set_modulate(get_canvas(), color); - add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } else { - RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); - remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } + case NOTIFICATION_EXIT_CANVAS: { + if (is_visible_in_tree()) { + RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); + remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible_in_tree()) { + RS::get_singleton()->canvas_set_modulate(get_canvas(), color); + add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } else { + RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); + remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } - update_configuration_warnings(); + update_configuration_warnings(); + } break; } } @@ -81,7 +86,7 @@ TypedArray<String> CanvasModulate::get_configuration_warnings() const { get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes); if (nodes.size() > 1) { - warnings.push_back(TTR("Only one visible CanvasModulate is allowed per scene (or set of instantiated scenes). The first created one will work, while the rest will be ignored.")); + warnings.push_back(RTR("Only one visible CanvasModulate is allowed per scene (or set of instantiated scenes). The first created one will work, while the rest will be ignored.")); } } diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h index 3d85a92a11..ec37449f8f 100644 --- a/scene/2d/canvas_modulate.h +++ b/scene/2d/canvas_modulate.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 4b348f12e6..a8c12f4893 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,6 +30,7 @@ #include "collision_object_2d.h" +#include "scene/resources/world_2d.h" #include "scene/scene_string_names.h" void CollisionObject2D::_notification(int p_what) { @@ -268,7 +269,7 @@ uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) { id = shapes.back()->key() + 1; } - sd.owner = p_owner; + sd.owner_id = p_owner ? p_owner->get_instance_id() : ObjectID(); shapes[id] = sd; @@ -382,7 +383,7 @@ Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const { ERR_FAIL_COND_V(!shapes.has(p_owner), nullptr); - return shapes[p_owner].owner; + return ObjectDB::get_instance(shapes[p_owner].owner_id); } void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) { @@ -434,7 +435,7 @@ void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) PhysicsServer2D::get_singleton()->body_remove_shape(rid, index_to_remove); } - shapes[p_owner].shapes.remove(p_shape); + shapes[p_owner].shapes.remove_at(p_shape); for (KeyValue<uint32_t, ShapeData> &E : shapes) { for (int i = 0; i < E.value.shapes.size(); i++) { @@ -557,7 +558,7 @@ TypedArray<String> CollisionObject2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (shapes.is_empty()) { - warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape.")); + warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape.")); } return warnings; @@ -605,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 19abacb201..997afee6c4 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -59,7 +59,7 @@ private: PhysicsServer2D::BodyMode body_mode = PhysicsServer2D::BODY_MODE_STATIC; struct ShapeData { - Object *owner = nullptr; + ObjectID owner_id; Transform2D xform; struct Shape { Ref<Shape2D> shape; @@ -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 00bfa62449..20840f5aea 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -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" @@ -102,26 +103,20 @@ void CollisionPolygon2D::_notification(int p_what) { _build_polygon(); _update_in_shape_owner(); } - - /*if (Engine::get_singleton()->is_editor_hint()) { - //display above all else - set_z_as_relative(false); - set_z_index(RS::CANVAS_ITEM_Z_MAX - 1); - }*/ - } break; + case NOTIFICATION_ENTER_TREE: { if (parent) { _update_in_shape_owner(); } - } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { _update_in_shape_owner(true); } - } break; + case NOTIFICATION_UNPARENTED: { if (parent) { parent->remove_shape_owner(owner_id); @@ -164,15 +159,15 @@ void CollisionPolygon2D::_notification(int p_what) { dcol.a = 1.0; Vector2 line_to(0, 20); draw_line(Vector2(), line_to, dcol, 3); - Vector<Vector2> pts; real_t tsize = 8; - pts.push_back(line_to + (Vector2(0, tsize))); - pts.push_back(line_to + (Vector2(Math_SQRT12 * tsize, 0))); - pts.push_back(line_to + (Vector2(-Math_SQRT12 * tsize, 0))); - Vector<Color> cols; - for (int i = 0; i < 3; i++) { - cols.push_back(dcol); - } + + Vector<Vector2> pts = { + line_to + Vector2(0, tsize), + line_to + Vector2(Math_SQRT12 * tsize, 0), + line_to + Vector2(-Math_SQRT12 * tsize, 0) + }; + + Vector<Color> cols{ dcol, dcol, dcol }; draw_primitive(pts, cols, Vector<Vector2>()); //small arrow } @@ -244,22 +239,25 @@ TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject2D>(get_parent())) { - warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidDynamicBody2D, CharacterBody2D, etc. to give them a shape.")); + warnings.push_back(RTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidDynamicBody2D, CharacterBody2D, etc. to give them a shape.")); } int polygon_count = polygon.size(); if (polygon_count == 0) { - warnings.push_back(TTR("An empty CollisionPolygon2D has no effect on collision.")); + warnings.push_back(RTR("An empty CollisionPolygon2D has no effect on collision.")); } else { bool solids = build_mode == BUILD_SOLIDS; if (solids) { if (polygon_count < 3) { - warnings.push_back(TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode.")); + warnings.push_back(RTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode.")); } } else if (polygon_count < 2) { - warnings.push_back(TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode.")); + 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; } @@ -282,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 { diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 6b32923010..e18022ab7e 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index c7742c7ba5..5a25b1705a 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -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" @@ -59,34 +60,28 @@ void CollisionShape2D::_notification(int p_what) { } _update_in_shape_owner(); } - - /*if (Engine::get_singleton()->is_editor_hint()) { - //display above all else - set_z_as_relative(false); - set_z_index(RS::CANVAS_ITEM_Z_MAX - 1); - }*/ - } break; + case NOTIFICATION_ENTER_TREE: { if (parent) { _update_in_shape_owner(); } - } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { _update_in_shape_owner(true); } - } break; + case NOTIFICATION_UNPARENTED: { if (parent) { parent->remove_shape_owner(owner_id); } owner_id = 0; parent = nullptr; - } break; + case NOTIFICATION_DRAW: { ERR_FAIL_COND(!is_inside_tree()); @@ -121,15 +116,15 @@ void CollisionShape2D::_notification(int p_what) { } Vector2 line_to(0, 20); draw_line(Vector2(), line_to, draw_col, 2); - Vector<Vector2> pts; real_t tsize = 8; - pts.push_back(line_to + (Vector2(0, tsize))); - pts.push_back(line_to + (Vector2(Math_SQRT12 * tsize, 0))); - pts.push_back(line_to + (Vector2(-Math_SQRT12 * tsize, 0))); - Vector<Color> cols; - for (int i = 0; i < 3; i++) { - cols.push_back(draw_col); - } + + Vector<Vector2> pts{ + line_to + Vector2(0, tsize), + line_to + Vector2(Math_SQRT12 * tsize, 0), + line_to + Vector2(-Math_SQRT12 * tsize, 0) + }; + + Vector<Color> cols{ draw_col, draw_col, draw_col }; draw_primitive(pts, cols, Vector<Vector2>()); } @@ -177,16 +172,19 @@ TypedArray<String> CollisionShape2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject2D>(get_parent())) { - warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidDynamicBody2D, CharacterBody2D, etc. to give them a shape.")); + warnings.push_back(RTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidDynamicBody2D, CharacterBody2D, etc. to give them a shape.")); } if (!shape.is_valid()) { - warnings.push_back(TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!")); + 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; if (convex.is_valid() || concave.is_valid()) { - warnings.push_back(TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead.")); + warnings.push_back(RTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead.")); } return warnings; @@ -210,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 { diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index eaf72627c8..dbc81e8424 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 80c17b6e88..f5c14b6845 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -152,11 +152,14 @@ void CPUParticles2D::_update_mesh_texture() { } else { tex_size = Size2(1, 1); } - Vector<Vector2> vertices; - vertices.push_back(-tex_size * 0.5); - vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, 0)); - vertices.push_back(-tex_size * 0.5 + tex_size); - vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y)); + + Vector<Vector2> vertices = { + -tex_size * 0.5, + -tex_size * 0.5 + Vector2(tex_size.x, 0), + -tex_size * 0.5 + tex_size, + -tex_size * 0.5 + Vector2(0, tex_size.y) + }; + Vector<Vector2> uvs; AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture); if (atlas_texure && atlas_texure->get_atlas().is_valid()) { @@ -172,18 +175,15 @@ void CPUParticles2D::_update_mesh_texture() { uvs.push_back(Vector2(1, 1)); uvs.push_back(Vector2(0, 1)); } - Vector<Color> colors; - colors.push_back(Color(1, 1, 1, 1)); - colors.push_back(Color(1, 1, 1, 1)); - colors.push_back(Color(1, 1, 1, 1)); - colors.push_back(Color(1, 1, 1, 1)); - Vector<int> indices; - indices.push_back(0); - indices.push_back(1); - indices.push_back(2); - indices.push_back(2); - indices.push_back(3); - indices.push_back(0); + + Vector<Color> colors = { + Color(1, 1, 1, 1), + Color(1, 1, 1, 1), + Color(1, 1, 1, 1), + Color(1, 1, 1, 1) + }; + + Vector<int> indices = { 0, 1, 2, 2, 3, 0 }; Array arr; arr.resize(RS::ARRAY_MAX); @@ -250,7 +250,7 @@ TypedArray<String> CPUParticles2D::get_configuration_warnings() const { if (get_material().is_null() || (mat && !mat->get_particles_animation())) { if (get_param_max(PARAM_ANIM_SPEED) != 0.0 || get_param_max(PARAM_ANIM_OFFSET) != 0.0 || get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) { - warnings.push_back(TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.")); + warnings.push_back(RTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.")); } } @@ -398,6 +398,14 @@ Ref<Gradient> CPUParticles2D::get_color_ramp() const { return color_ramp; } +void CPUParticles2D::set_color_initial_ramp(const Ref<Gradient> &p_ramp) { + color_initial_ramp = p_ramp; +} + +Ref<Gradient> CPUParticles2D::get_color_initial_ramp() const { + return color_initial_ramp; +} + void CPUParticles2D::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) { ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); particle_flags[p_particle_flag] = p_enable; @@ -492,7 +500,7 @@ bool CPUParticles2D::get_split_scale() { } void CPUParticles2D::_validate_property(PropertyInfo &property) const { - if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { + if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) { property.usage = PROPERTY_USAGE_NONE; } @@ -727,9 +735,15 @@ void CPUParticles2D::_particles_process(double p_delta) { p.hue_rot_rand = Math::randf(); p.anim_offset_rand = Math::randf(); + if (color_initial_ramp.is_valid()) { + p.start_color_rand = color_initial_ramp->get_color_at_offset(Math::randf()); + } else { + p.start_color_rand = Color(1, 1, 1, 1); + } + 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], 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); @@ -748,6 +762,11 @@ void CPUParticles2D::_particles_process(double p_delta) { //do none } break; case EMISSION_SHAPE_SPHERE: { + real_t t = Math_TAU * Math::randf(); + real_t radius = emission_sphere_radius * Math::randf(); + p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius; + } break; + case EMISSION_SHAPE_SPHERE_SURFACE: { real_t s = Math::randf(), t = Math_TAU * Math::randf(); real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius; @@ -769,8 +788,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); } @@ -890,7 +909,7 @@ void CPUParticles2D::_particles_process(double p_delta) { real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand); base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed)); p.rotation = Math::deg2rad(base_angle); //angle - p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + p.custom[1] * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed)); + p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + tv * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed)); } //apply color //apply hue rotation @@ -946,17 +965,17 @@ void CPUParticles2D::_particles_process(double p_delta) { p.color.g = color_rgb.y; p.color.b = color_rgb.z; - p.color *= p.base_color; + p.color *= p.base_color * p.start_color_rand; 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 @@ -967,8 +986,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; } @@ -1010,14 +1029,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); @@ -1077,9 +1096,11 @@ void CPUParticles2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { set_process_internal(emitting); } break; + case NOTIFICATION_EXIT_TREE: { _set_redraw(false); } break; + case NOTIFICATION_DRAW: { // first update before rendering to avoid one frame delay after emitting starts if (emitting && (time == 0)) { @@ -1097,9 +1118,11 @@ void CPUParticles2D::_notification(int p_what) { RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); } break; + case NOTIFICATION_INTERNAL_PROCESS: { _update_internal(); } break; + case NOTIFICATION_TRANSFORM_CHANGED: { inv_emission_transform = get_global_transform().affine_inverse(); @@ -1114,14 +1137,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); @@ -1173,6 +1196,11 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) { set_color_ramp(gt->get_gradient()); } + Ref<GradientTexture1D> gti = material->get_color_initial_ramp(); + if (gti.is_valid()) { + set_color_initial_ramp(gti->get_gradient()); + } + set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY)); set_emission_shape(EmissionShape(material->get_emission_shape())); @@ -1295,6 +1323,9 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &CPUParticles2D::set_color_ramp); ClassDB::bind_method(D_METHOD("get_color_ramp"), &CPUParticles2D::get_color_ramp); + ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &CPUParticles2D::set_color_initial_ramp); + ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &CPUParticles2D::get_color_initial_ramp); + ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &CPUParticles2D::set_particle_flag); ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &CPUParticles2D::get_particle_flag); @@ -1331,7 +1362,7 @@ 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,Box,Points,Directed Points", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_emission_shape", "get_emission_shape"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Sphere Surface,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::PACKED_VECTOR2_ARRAY, "emission_points"), "set_emission_points", "get_emission_points"); @@ -1386,6 +1417,7 @@ void CPUParticles2D::_bind_methods() { ADD_GROUP("Color", ""); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_initial_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_initial_ramp", "get_color_initial_ramp"); ADD_GROUP("Hue Variation", "hue_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION); @@ -1420,6 +1452,7 @@ void CPUParticles2D::_bind_methods() { BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE_SURFACE); BIND_ENUM_CONSTANT(EMISSION_SHAPE_RECTANGLE); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 391f51224e..51d58723b4 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -69,6 +69,7 @@ public: enum EmissionShape { EMISSION_SHAPE_POINT, EMISSION_SHAPE_SPHERE, + EMISSION_SHAPE_SPHERE_SURFACE, EMISSION_SHAPE_RECTANGLE, EMISSION_SHAPE_POINTS, EMISSION_SHAPE_DIRECTED_POINTS, @@ -89,6 +90,7 @@ private: real_t scale_rand = 0.0; real_t hue_rot_rand = 0.0; real_t anim_offset_rand = 0.0; + Color start_color_rand; double time = 0.0; double lifetime = 0.0; Color base_color; @@ -135,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; @@ -156,6 +158,7 @@ private: Ref<Curve> curve_parameters[PARAM_MAX]; Color color; Ref<Gradient> color_ramp; + Ref<Gradient> color_initial_ramp; bool particle_flags[PARTICLE_FLAG_MAX]; @@ -250,6 +253,9 @@ public: void set_color_ramp(const Ref<Gradient> &p_ramp); Ref<Gradient> get_color_ramp() const; + void set_color_initial_ramp(const Ref<Gradient> &p_ramp); + Ref<Gradient> get_color_initial_ramp() const; + void set_particle_flag(ParticleFlags p_particle_flag, bool p_enable); bool get_particle_flag(ParticleFlags p_particle_flag) const; diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index f1f4d1b769..d509d93172 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -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); @@ -170,6 +170,13 @@ void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) { update(); } +#ifdef TOOLS_ENABLED +void GPUParticles2D::set_show_visibility_rect(bool p_show_visibility_rect) { + show_visibility_rect = p_show_visibility_rect; + update(); +} +#endif + bool GPUParticles2D::is_trail_enabled() const { return trail_enabled; } @@ -280,15 +287,24 @@ 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(); if (RenderingServer::get_singleton()->is_low_end()) { - warnings.push_back(TTR("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.")); + warnings.push_back(RTR("GPU-based particles are not supported by the OpenGL video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose.")); } if (process_material.is_null()) { - warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted.")); + warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted.")); } else { CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); @@ -297,7 +313,7 @@ TypedArray<String> GPUParticles2D::get_configuration_warnings() const { if (process && (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { - warnings.push_back(TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.")); + warnings.push_back(RTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.")); } } } @@ -328,153 +344,199 @@ Ref<Texture2D> GPUParticles2D::get_texture() const { void GPUParticles2D::_validate_property(PropertyInfo &property) const { } -void GPUParticles2D::restart() { - RS::get_singleton()->particles_restart(particles); - RS::get_singleton()->particles_set_emitting(particles, true); +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_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); + + RS::get_singleton()->particles_emit(particles, transform, velocity, p_color, p_custom, p_emit_flags); } -void GPUParticles2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - RID texture_rid; - Size2 size; - if (texture.is_valid()) { - texture_rid = texture->get_rid(); - size = texture->get_size(); - } else { - size = Size2(1, 1); +void GPUParticles2D::_attach_sub_emitter() { + Node *n = get_node_or_null(sub_emitter); + if (n) { + GPUParticles2D *sen = Object::cast_to<GPUParticles2D>(n); + if (sen && sen != this) { + RS::get_singleton()->particles_set_subemitter(particles, sen->particles); } + } +} - if (trail_enabled) { - RS::get_singleton()->mesh_clear(mesh); - PackedVector2Array points; - PackedVector2Array uvs; - PackedInt32Array bone_indices; - PackedFloat32Array bone_weights; - PackedInt32Array indices; +void GPUParticles2D::set_sub_emitter(const NodePath &p_path) { + if (is_inside_tree()) { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } - int total_segments = trail_sections * trail_section_subdivisions; - real_t depth = size.height * trail_sections; + sub_emitter = p_path; - for (int j = 0; j <= total_segments; j++) { - real_t v = j; - v /= total_segments; + if (is_inside_tree() && sub_emitter != NodePath()) { + _attach_sub_emitter(); + } +} - real_t y = depth * v; - y = (depth * 0.5) - y; +NodePath GPUParticles2D::get_sub_emitter() const { + return sub_emitter; +} - int bone = j / trail_section_subdivisions; - real_t blend = 1.0 - real_t(j % trail_section_subdivisions) / real_t(trail_section_subdivisions); +void GPUParticles2D::restart() { + RS::get_singleton()->particles_restart(particles); + RS::get_singleton()->particles_set_emitting(particles, true); +} - real_t s = size.width; +void GPUParticles2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_DRAW: { + RID texture_rid; + Size2 size; + if (texture.is_valid()) { + texture_rid = texture->get_rid(); + size = texture->get_size(); + } else { + size = Size2(1, 1); + } - points.push_back(Vector2(-s * 0.5, 0)); - points.push_back(Vector2(+s * 0.5, 0)); + if (trail_enabled) { + RS::get_singleton()->mesh_clear(mesh); + PackedVector2Array points; + PackedVector2Array uvs; + PackedInt32Array bone_indices; + PackedFloat32Array bone_weights; + PackedInt32Array indices; + + int total_segments = trail_sections * trail_section_subdivisions; + real_t depth = size.height * trail_sections; + + for (int j = 0; j <= total_segments; j++) { + real_t v = j; + v /= total_segments; + + real_t y = depth * v; + y = (depth * 0.5) - y; + + int bone = j / trail_section_subdivisions; + real_t blend = 1.0 - real_t(j % trail_section_subdivisions) / real_t(trail_section_subdivisions); + + real_t s = size.width; + + points.push_back(Vector2(-s * 0.5, 0)); + points.push_back(Vector2(+s * 0.5, 0)); + + uvs.push_back(Vector2(0, v)); + uvs.push_back(Vector2(1, v)); + + for (int i = 0; i < 2; i++) { + bone_indices.push_back(bone); + bone_indices.push_back(MIN(trail_sections, bone + 1)); + bone_indices.push_back(0); + bone_indices.push_back(0); + + bone_weights.push_back(blend); + bone_weights.push_back(1.0 - blend); + bone_weights.push_back(0); + bone_weights.push_back(0); + } + + if (j > 0) { + int base = j * 2 - 2; + indices.push_back(base + 0); + indices.push_back(base + 1); + indices.push_back(base + 2); + + indices.push_back(base + 1); + indices.push_back(base + 3); + indices.push_back(base + 2); + } + } - uvs.push_back(Vector2(0, v)); - uvs.push_back(Vector2(1, v)); + Array arr; + arr.resize(RS::ARRAY_MAX); + arr[RS::ARRAY_VERTEX] = points; + arr[RS::ARRAY_TEX_UV] = uvs; + arr[RS::ARRAY_BONES] = bone_indices; + arr[RS::ARRAY_WEIGHTS] = bone_weights; + arr[RS::ARRAY_INDEX] = indices; + + RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + + Vector<Transform3D> xforms; + for (int i = 0; i <= trail_sections; i++) { + Transform3D xform; + /* + xform.origin.y = depth / 2.0 - size.height * real_t(i); + xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */ + xforms.push_back(xform); + } - for (int i = 0; i < 2; i++) { - bone_indices.push_back(bone); - bone_indices.push_back(MIN(trail_sections, bone + 1)); - bone_indices.push_back(0); - bone_indices.push_back(0); + RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms); - bone_weights.push_back(blend); - bone_weights.push_back(1.0 - blend); - bone_weights.push_back(0); - bone_weights.push_back(0); - } + } else { + RS::get_singleton()->mesh_clear(mesh); - if (j > 0) { - int base = j * 2 - 2; - indices.push_back(base + 0); - indices.push_back(base + 1); - indices.push_back(base + 2); + Vector<Vector2> points = { + Vector2(-size.x / 2.0, -size.y / 2.0), + Vector2(size.x / 2.0, -size.y / 2.0), + Vector2(size.x / 2.0, size.y / 2.0), + Vector2(-size.x / 2.0, size.y / 2.0) + }; - indices.push_back(base + 1); - indices.push_back(base + 3); - indices.push_back(base + 2); - } - } + Vector<Vector2> uvs = { + Vector2(0, 0), + Vector2(1, 0), + Vector2(1, 1), + Vector2(0, 1) + }; - Array arr; - arr.resize(RS::ARRAY_MAX); - arr[RS::ARRAY_VERTEX] = points; - arr[RS::ARRAY_TEX_UV] = uvs; - arr[RS::ARRAY_BONES] = bone_indices; - arr[RS::ARRAY_WEIGHTS] = bone_weights; - arr[RS::ARRAY_INDEX] = indices; - - RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); - - Vector<Transform3D> xforms; - for (int i = 0; i <= trail_sections; i++) { - Transform3D xform; - /* - xform.origin.y = depth / 2.0 - size.height * real_t(i); - xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */ - xforms.push_back(xform); - } + Vector<int> indices = { 0, 1, 2, 0, 2, 3 }; - RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms); - - } else { - RS::get_singleton()->mesh_clear(mesh); - Vector<Vector2> points; - points.resize(4); - points.write[0] = Vector2(-size.x / 2.0, -size.y / 2.0); - points.write[1] = Vector2(size.x / 2.0, -size.y / 2.0); - points.write[2] = Vector2(size.x / 2.0, size.y / 2.0); - points.write[3] = Vector2(-size.x / 2.0, size.y / 2.0); - Vector<Vector2> uvs; - uvs.resize(4); - uvs.write[0] = Vector2(0, 0); - uvs.write[1] = Vector2(1, 0); - uvs.write[2] = Vector2(1, 1); - uvs.write[3] = Vector2(0, 1); - Vector<int> indices; - indices.resize(6); - indices.write[0] = 0; - indices.write[1] = 1; - indices.write[2] = 2; - indices.write[3] = 0; - indices.write[4] = 2; - indices.write[5] = 3; - Array arr; - arr.resize(RS::ARRAY_MAX); - arr[RS::ARRAY_VERTEX] = points; - arr[RS::ARRAY_TEX_UV] = uvs; - arr[RS::ARRAY_INDEX] = indices; - - RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); - RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform3D>()); - } - RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid); + Array arr; + arr.resize(RS::ARRAY_MAX); + arr[RS::ARRAY_VERTEX] = points; + arr[RS::ARRAY_TEX_UV] = uvs; + arr[RS::ARRAY_INDEX] = indices; + + RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform3D>()); + } + RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid); #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { - draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); - } + if (show_visibility_rect) { + draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); + } #endif - } + } break; - if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { - if (can_process()) { - RS::get_singleton()->particles_set_speed_scale(particles, speed_scale); - } else { - RS::get_singleton()->particles_set_speed_scale(particles, 0); - } - } + case NOTIFICATION_ENTER_TREE: { + if (sub_emitter != NodePath()) { + _attach_sub_emitter(); + } + } break; + + case NOTIFICATION_EXIT_TREE: { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } break; + + case NOTIFICATION_PAUSED: + case NOTIFICATION_UNPAUSED: { + if (can_process()) { + RS::get_singleton()->particles_set_speed_scale(particles, speed_scale); + } else { + RS::get_singleton()->particles_set_speed_scale(particles, 0); + } + } break; - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - _update_particle_emission_transform(); - } + case NOTIFICATION_TRANSFORM_CHANGED: { + _update_particle_emission_transform(); + } break; - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (one_shot && !is_emitting()) { - notify_property_list_changed(); - set_process_internal(false); - } + case NOTIFICATION_INTERNAL_PROCESS: { + if (one_shot && !is_emitting()) { + notify_property_list_changed(); + set_process_internal(false); + } + } break; } } @@ -490,6 +552,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); @@ -505,6 +568,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); @@ -519,6 +583,11 @@ void GPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &GPUParticles2D::restart); + ClassDB::bind_method(D_METHOD("set_sub_emitter", "path"), &GPUParticles2D::set_sub_emitter); + ClassDB::bind_method(D_METHOD("get_sub_emitter"), &GPUParticles2D::get_sub_emitter); + + ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles2D::emit_particle); + ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled); ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length); @@ -534,6 +603,7 @@ void GPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false. 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::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); @@ -542,6 +612,7 @@ void GPUParticles2D::_bind_methods() { 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::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"); @@ -562,6 +633,12 @@ void GPUParticles2D::_bind_methods() { BIND_ENUM_CONSTANT(DRAW_ORDER_INDEX); BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME); BIND_ENUM_CONSTANT(DRAW_ORDER_REVERSE_LIFETIME); + + BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION); + BIND_ENUM_CONSTANT(EMIT_FLAG_ROTATION_SCALE); + BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY); + BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR); + BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM); } GPUParticles2D::GPUParticles2D() { @@ -579,6 +656,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); diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index d7eee461b4..3c7f4cd9b5 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -47,18 +47,21 @@ 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 = false; +#endif Ref<Material> process_material; DrawOrder draw_order; @@ -77,11 +80,12 @@ private: RID mesh; + void _attach_sub_emitter(); + protected: static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; void _notification(int p_what); - void _update_collision_size(); public: @@ -102,6 +106,10 @@ public: void set_trail_sections(int p_sections); void set_trail_section_subdivisions(int p_subdivisions); +#ifdef TOOLS_ENABLED + void set_show_visibility_rect(bool p_show_visibility_rect); +#endif + bool is_emitting() const; int get_amount() const; double get_lifetime() const; @@ -126,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; @@ -134,6 +145,19 @@ public: TypedArray<String> get_configuration_warnings() const override; + void set_sub_emitter(const NodePath &p_path); + NodePath get_sub_emitter() const; + + enum EmitFlags { + EMIT_FLAG_POSITION = RS::PARTICLES_EMIT_FLAG_POSITION, + EMIT_FLAG_ROTATION_SCALE = RS::PARTICLES_EMIT_FLAG_ROTATION_SCALE, + EMIT_FLAG_VELOCITY = RS::PARTICLES_EMIT_FLAG_VELOCITY, + EMIT_FLAG_COLOR = RS::PARTICLES_EMIT_FLAG_COLOR, + EMIT_FLAG_CUSTOM = RS::PARTICLES_EMIT_FLAG_CUSTOM + }; + + void emit_particle(const Transform2D &p_transform, const Vector2 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); + void restart(); Rect2 capture_rect() const; GPUParticles2D(); @@ -141,5 +165,6 @@ public: }; VARIANT_ENUM_CAST(GPUParticles2D::DrawOrder) +VARIANT_ENUM_CAST(GPUParticles2D::EmitFlags) #endif // PARTICLES_2D_H diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index 8a528151cf..cd82b47333 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -77,15 +77,15 @@ void Joint2D::_update_joint(bool p_only_free) { bool valid = false; if (node_a && !body_a && node_b && !body_b) { - warning = TTR("Node A and Node B must be PhysicsBody2Ds"); + warning = RTR("Node A and Node B must be PhysicsBody2Ds"); } else if (node_a && !body_a) { - warning = TTR("Node A must be a PhysicsBody2D"); + warning = RTR("Node A must be a PhysicsBody2D"); } else if (node_b && !body_b) { - warning = TTR("Node B must be a PhysicsBody2D"); + warning = RTR("Node B must be a PhysicsBody2D"); } else if (!body_a || !body_b) { - warning = TTR("Joint is not connected to two PhysicsBody2Ds"); + warning = RTR("Joint is not connected to two PhysicsBody2Ds"); } else if (body_a == body_b) { - warning = TTR("Node A and Node B must be different PhysicsBody2Ds"); + warning = RTR("Node A and Node B must be different PhysicsBody2Ds"); } else { warning = String(); valid = true; @@ -128,7 +128,7 @@ void Joint2D::set_node_a(const NodePath &p_node_a) { return; } - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); } @@ -145,7 +145,7 @@ void Joint2D::set_node_b(const NodePath &p_node_b) { return; } - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); } @@ -159,14 +159,18 @@ NodePath Joint2D::get_node_b() const { void Joint2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { + case NOTIFICATION_POST_ENTER_TREE: { + if (is_configured()) { + _disconnect_signals(); + } _update_joint(); } break; + case NOTIFICATION_EXIT_TREE: { - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); - _update_joint(true); } + _update_joint(true); } break; } } @@ -186,7 +190,9 @@ void Joint2D::set_exclude_nodes_from_collision(bool p_enable) { if (exclude_from_collision == p_enable) { return; } - + if (is_configured()) { + _disconnect_signals(); + } _update_joint(true); exclude_from_collision = p_enable; _update_joint(); diff --git a/scene/2d/joint_2d.h b/scene/2d/joint_2d.h index 0c3956e463..e3cd600cbd 100644 --- a/scene/2d/joint_2d.h +++ b/scene/2d/joint_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 66c0f979ae..b09b1b5047 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -192,21 +192,24 @@ Light2D::BlendMode Light2D::get_blend_mode() const { } void Light2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas()); - _update_light_visibility(); - } - - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform()); - } - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - _update_light_visibility(); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID()); - _update_light_visibility(); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas()); + _update_light_visibility(); + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { + RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform()); + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + _update_light_visibility(); + } break; + + case NOTIFICATION_EXIT_TREE: { + RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID()); + _update_light_visibility(); + } break; } } @@ -391,7 +394,7 @@ TypedArray<String> PointLight2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!texture.is_valid()) { - warnings.push_back(TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.")); + warnings.push_back(RTR("A texture with the shape of the light must be supplied to the \"Texture\" property.")); } return warnings; diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index d9ecd81f1c..f7b1f420e3 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index fdc28f81c2..14188d7120 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,9 +29,9 @@ /*************************************************************************/ #include "light_occluder_2d.h" -#include "core/math/geometry_2d.h" #include "core/config/engine.h" +#include "core/math/geometry_2d.h" #define LINE_GRAB_WIDTH 8 @@ -158,42 +158,46 @@ void LightOccluder2D::_poly_changed() { } void LightOccluder2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_CANVAS) { - RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas()); - RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); - RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); - } - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); - } - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); - } - - if (p_what == NOTIFICATION_DRAW) { - if (Engine::get_singleton()->is_editor_hint()) { - if (occluder_polygon.is_valid()) { - Vector<Vector2> poly = occluder_polygon->get_polygon(); - - if (poly.size()) { - if (occluder_polygon->is_closed()) { - Vector<Color> color; - color.push_back(Color(0, 0, 0, 0.6)); - draw_polygon(Variant(poly), color); - } else { - int ps = poly.size(); - const Vector2 *r = poly.ptr(); - for (int i = 0; i < ps - 1; i++) { - draw_line(r[i], r[i + 1], Color(0, 0, 0, 0.6), 3); + switch (p_what) { + case NOTIFICATION_ENTER_CANVAS: { + RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas()); + RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); + RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { + RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); + } break; + + case NOTIFICATION_DRAW: { + if (Engine::get_singleton()->is_editor_hint()) { + if (occluder_polygon.is_valid()) { + Vector<Vector2> poly = occluder_polygon->get_polygon(); + + if (poly.size()) { + if (occluder_polygon->is_closed()) { + Vector<Color> color; + color.push_back(Color(0, 0, 0, 0.6)); + draw_polygon(Variant(poly), color); + } else { + int ps = poly.size(); + const Vector2 *r = poly.ptr(); + for (int i = 0; i < ps - 1; i++) { + draw_line(r[i], r[i + 1], Color(0, 0, 0, 0.6), 3); + } } } } } - } - } + } break; - if (p_what == NOTIFICATION_EXIT_CANVAS) { - RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID()); + case NOTIFICATION_EXIT_CANVAS: { + RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID()); + } break; } } @@ -246,11 +250,11 @@ TypedArray<String> LightOccluder2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!occluder_polygon.is_valid()) { - warnings.push_back(TTR("An occluder polygon must be set (or drawn) for this occluder to take effect.")); + warnings.push_back(RTR("An occluder polygon must be set (or drawn) for this occluder to take effect.")); } if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) { - warnings.push_back(TTR("The occluder polygon for this occluder is empty. Please draw a polygon.")); + warnings.push_back(RTR("The occluder polygon for this occluder is empty. Please draw a polygon.")); } return warnings; @@ -281,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 b4a48d1062..4acfeaf781 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -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 37eb45c21d..8cbcc9acf6 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -133,7 +133,7 @@ int Line2D::get_point_count() const { void Line2D::clear_points() { int count = _points.size(); if (count > 0) { - _points.resize(0); + _points.clear(); update(); } } @@ -148,7 +148,7 @@ void Line2D::add_point(Vector2 p_pos, int p_atpos) { } void Line2D::remove_point(int i) { - _points.remove(i); + _points.remove_at(i); update(); } @@ -228,9 +228,9 @@ Line2D::LineCapMode Line2D::get_end_cap_mode() const { void Line2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_DRAW: + case NOTIFICATION_DRAW: { _draw(); - break; + } break; } } @@ -247,10 +247,7 @@ float Line2D::get_sharp_limit() const { } void Line2D::set_round_precision(int p_precision) { - if (p_precision < 1) { - p_precision = 1; - } - _round_precision = p_precision; + _round_precision = MAX(1, p_precision); update(); } @@ -268,15 +265,15 @@ bool Line2D::get_antialiased() const { } void Line2D::_draw() { - if (_points.size() <= 1 || _width == 0.f) { + int len = _points.size(); + if (len <= 1 || _width == 0.f) { return; } // TODO Is this really needed? // Copy points for faster access Vector<Vector2> points; - points.resize(_points.size()); - int len = points.size(); + points.resize(len); { const Vector2 *points_read = _points.ptr(); for (int i = 0; i < len; ++i) { @@ -409,7 +406,7 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode"); ADD_GROUP("Border", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sharp_limit"), "set_sharp_limit", "get_sharp_limit"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision"), "set_round_precision", "get_round_precision"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision", PROPERTY_HINT_RANGE, "1,32,1"), "set_round_precision", "get_round_precision"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased"); BIND_ENUM_CONSTANT(LINE_JOINT_SHARP); diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 5e7eb4bac9..5322c5a5fe 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index 05d77f8224..25eb9b9851 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index 16c88d00e9..e50acc9ce4 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index 58bff97da9..178addd62d 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,13 +29,16 @@ /*************************************************************************/ #include "mesh_instance_2d.h" + #include "scene/scene_string_names.h" void MeshInstance2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - if (mesh.is_valid()) { - draw_mesh(mesh, texture); - } + switch (p_what) { + case NOTIFICATION_DRAW: { + if (mesh.is_valid()) { + draw_mesh(mesh, texture); + } + } break; } } diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h index f94d53da7d..0647d1ddd9 100644 --- a/scene/2d/mesh_instance_2d.h +++ b/scene/2d/mesh_instance_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp index 1bff2f337d..8f72ff1757 100644 --- a/scene/2d/multimesh_instance_2d.cpp +++ b/scene/2d/multimesh_instance_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,13 +29,16 @@ /*************************************************************************/ #include "multimesh_instance_2d.h" + #include "scene/scene_string_names.h" void MultiMeshInstance2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - if (multimesh.is_valid()) { - draw_multimesh(multimesh, texture); - } + switch (p_what) { + case NOTIFICATION_DRAW: { + if (multimesh.is_valid()) { + draw_multimesh(multimesh, texture); + } + } break; } } diff --git a/scene/2d/multimesh_instance_2d.h b/scene/2d/multimesh_instance_2d.h index 213cbd19b0..37d0d24f8f 100644 --- a/scene/2d/multimesh_instance_2d.h +++ b/scene/2d/multimesh_instance_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 7faa964407..91549d75f0 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,6 +31,7 @@ #include "navigation_agent_2d.h" #include "core/math/geometry_2d.h" +#include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" void NavigationAgent2D::_bind_methods() { @@ -57,6 +58,9 @@ 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_target_location", "location"), &NavigationAgent2D::set_target_location); ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent2D::get_target_location); ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location); @@ -78,6 +82,7 @@ void NavigationAgent2D::_bind_methods() { 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_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); @@ -96,10 +101,12 @@ void NavigationAgent2D::_notification(int p_what) { } set_physics_process_internal(true); } break; + case NOTIFICATION_EXIT_TREE: { agent_parent = nullptr; set_physics_process_internal(false); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); @@ -124,8 +131,11 @@ NavigationAgent2D::~NavigationAgent2D() { } void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) { + bool layers_changed = navigable_layers != p_layers; navigable_layers = p_layers; - update_navigation(); + if (layers_changed) { + _request_repath(); + } } uint32_t NavigationAgent2D::get_navigable_layers() const { @@ -171,10 +181,7 @@ real_t NavigationAgent2D::get_path_max_distance() { void NavigationAgent2D::set_target_location(Vector2 p_location) { target_location = p_location; - navigation_path.clear(); - target_reached = false; - navigation_finished = false; - update_frame_id = 0; + _request_repath(); } Vector2 NavigationAgent2D::get_target_location() const { @@ -241,7 +248,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(TTR("The NavigationAgent2D can be used only under a Node2D node")); + warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D node.")); } return warnings; @@ -309,6 +316,13 @@ void NavigationAgent2D::update_navigation() { } } +void NavigationAgent2D::_request_repath() { + navigation_path.clear(); + target_reached = false; + navigation_finished = false; + update_frame_id = 0; +} + void NavigationAgent2D::_check_distance_to_target() { if (!target_reached) { if (distance_to_target() < target_desired_distance) { diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 052cd78a56..1447e25e8c 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -45,17 +45,17 @@ class NavigationAgent2D : public Node { uint32_t navigable_layers = 1; 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 +63,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(); @@ -139,6 +139,7 @@ public: private: void update_navigation(); + void _request_repath(); void _check_distance_to_target(); }; diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 8802a1098a..b594aa3bb2 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,9 +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); @@ -53,28 +57,32 @@ void NavigationObstacle2D::_validate_property(PropertyInfo &p_property) const { void NavigationObstacle2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - initialize_agent(); + case NOTIFICATION_ENTER_TREE: { parent_node2d = Object::cast_to<Node2D>(get_parent()); + reevaluate_agent_radius(); if (parent_node2d != 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(), parent_node2d->get_world_2d()->get_navigation_map()); } set_physics_process_internal(true); } break; + case NOTIFICATION_EXIT_TREE: { parent_node2d = nullptr; set_physics_process_internal(false); } break; + case NOTIFICATION_PARENTED: { parent_node2d = Object::cast_to<Node2D>(get_parent()); reevaluate_agent_radius(); } break; + case NOTIFICATION_UNPARENTED: { parent_node2d = nullptr; } 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; @@ -83,6 +91,7 @@ void NavigationObstacle2D::_notification(int p_what) { NavigationObstacle2D::NavigationObstacle2D() { agent = NavigationServer2D::get_singleton()->agent_create(); + initialize_agent(); } NavigationObstacle2D::~NavigationObstacle2D() { @@ -94,7 +103,12 @@ TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<Node2D>(get_parent())) { - warnings.push_back(TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.")); + 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; @@ -110,19 +124,19 @@ void NavigationObstacle2D::initialize_agent() { void NavigationObstacle2D::reevaluate_agent_radius() { if (!estimate_radius) { NavigationServer2D::get_singleton()->agent_set_radius(agent, radius); - } else if (parent_node2d) { + } else if (parent_node2d && parent_node2d->is_inside_tree()) { NavigationServer2D::get_singleton()->agent_set_radius(agent, estimate_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()) { @@ -133,6 +147,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 a5603f059f..2a0ef14e73 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 204ed72878..f46453283c 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,6 +33,7 @@ #include "core/core_string_names.h" #include "core/math/geometry_2d.h" #include "core/os/mutex.h" +#include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" #include "thirdparty/misc/polypartition.h" @@ -104,8 +105,8 @@ void NavigationPolygon::_set_polygons(const TypedArray<Vector<int32_t>> &p_array } } -Array NavigationPolygon::_get_polygons() const { - Array ret; +TypedArray<Vector<int32_t>> NavigationPolygon::_get_polygons() const { + TypedArray<Vector<int32_t>> ret; ret.resize(polygons.size()); for (int i = 0; i < ret.size(); i++) { ret[i] = polygons[i].indices; @@ -122,8 +123,8 @@ void NavigationPolygon::_set_outlines(const TypedArray<Vector<Vector2>> &p_array rect_cache_dirty = true; } -Array NavigationPolygon::_get_outlines() const { - Array ret; +TypedArray<Vector<Vector2>> NavigationPolygon::_get_outlines() const { + TypedArray<Vector<Vector2>> ret; ret.resize(outlines.size()); for (int i = 0; i < ret.size(); i++) { ret[i] = outlines[i]; @@ -207,7 +208,7 @@ void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline) void NavigationPolygon::remove_outline(int p_idx) { ERR_FAIL_INDEX(p_idx, outlines.size()); - outlines.remove(p_idx); + outlines.remove_at(p_idx); rect_cache_dirty = true; } @@ -299,21 +300,21 @@ void NavigationPolygon::make_polygons_from_outlines() { } polygons.clear(); - vertices.resize(0); + 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); @@ -363,10 +364,10 @@ void NavigationRegion2D::set_enabled(bool p_enabled) { if (!enabled) { NavigationServer2D::get_singleton()->region_set_map(region, RID()); - NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } else { NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); - NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) { @@ -386,6 +387,10 @@ uint32_t NavigationRegion2D::get_layers() const { return NavigationServer2D::get_singleton()->region_get_layers(region); } +RID NavigationRegion2D::get_region_rid() const { + return region; +} + ///////////////////////////// #ifdef TOOLS_ENABLED Rect2 NavigationRegion2D::_edit_get_rect() const { @@ -402,18 +407,21 @@ void NavigationRegion2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { if (enabled) { NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); - NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } } break; + case NOTIFICATION_TRANSFORM_CHANGED: { NavigationServer2D::get_singleton()->region_set_transform(region, get_global_transform()); } break; + case NOTIFICATION_EXIT_TREE: { NavigationServer2D::get_singleton()->region_set_map(region, RID()); if (enabled) { - NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); + NavigationServer2D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } } break; + case NOTIFICATION_DRAW: { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) { Vector<Vector2> verts = navpoly->get_vertices(); @@ -513,7 +521,7 @@ TypedArray<String> NavigationRegion2D::get_configuration_warnings() const { if (is_visible_in_tree() && is_inside_tree()) { if (!navpoly.is_valid()) { - warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon.")); + warnings.push_back(RTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon.")); } } @@ -530,6 +538,8 @@ void NavigationRegion2D::_bind_methods() { 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("get_region_rid"), &NavigationRegion2D::get_region_rid); + 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"); diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 2db8d70791..3c4a4e81d9 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -55,10 +55,10 @@ protected: static void _bind_methods(); void _set_polygons(const TypedArray<Vector<int32_t>> &p_array); - Array _get_polygons() const; + TypedArray<Vector<int32_t>> _get_polygons() const; void _set_outlines(const TypedArray<Vector<Vector2>> &p_array); - Array _get_outlines() const; + TypedArray<Vector<Vector2>> _get_outlines() const; public: #ifdef TOOLS_ENABLED @@ -117,6 +117,8 @@ public: void set_layers(uint32_t p_layers); uint32_t get_layers() const; + RID get_region_rid() 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 6a8788ee6e..0e8bb1aad7 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -42,9 +42,9 @@ Dictionary Node2D::_edit_get_state() const { } void Node2D::_edit_set_state(const Dictionary &p_state) { - pos = p_state["position"]; - angle = p_state["rotation"]; - _scale = p_state["scale"]; + position = p_state["position"]; + rotation = p_state["rotation"]; + scale = p_state["scale"]; skew = p_state["skew"]; _update_transform(); @@ -55,7 +55,7 @@ void Node2D::_edit_set_position(const Point2 &p_position) { } Point2 Node2D::_edit_get_position() const { - return pos; + return position; } void Node2D::_edit_set_scale(const Size2 &p_scale) { @@ -63,16 +63,16 @@ void Node2D::_edit_set_scale(const Size2 &p_scale) { } Size2 Node2D::_edit_get_scale() const { - return _scale; + return scale; } void Node2D::_edit_set_rotation(real_t p_rotation) { - angle = p_rotation; + rotation = p_rotation; _update_transform(); } real_t Node2D::_edit_get_rotation() const { - return angle; + return rotation; } bool Node2D::_edit_use_rotation() const { @@ -85,48 +85,44 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) { Rect2 r = _edit_get_rect(); Vector2 zero_offset; - if (r.size.x != 0) { - zero_offset.x = -r.position.x / r.size.x; - } - if (r.size.y != 0) { - zero_offset.y = -r.position.y / r.size.y; - } - Size2 new_scale(1, 1); if (r.size.x != 0) { + zero_offset.x = -r.position.x / r.size.x; new_scale.x = p_edit_rect.size.x / r.size.x; } + if (r.size.y != 0) { + zero_offset.y = -r.position.y / r.size.y; new_scale.y = p_edit_rect.size.y / r.size.y; } Point2 new_pos = p_edit_rect.position + p_edit_rect.size * zero_offset; Transform2D postxf; - postxf.set_rotation_scale_and_skew(angle, _scale, skew); + postxf.set_rotation_scale_and_skew(rotation, scale, skew); new_pos = postxf.xform(new_pos); - pos += new_pos; - _scale *= new_scale; + position += new_pos; + scale *= new_scale; _update_transform(); } #endif void Node2D::_update_xform_values() { - pos = _mat.elements[2]; - angle = _mat.get_rotation(); - _scale = _mat.get_scale(); - skew = _mat.get_skew(); + position = transform.columns[2]; + rotation = transform.get_rotation(); + scale = transform.get_scale(); + skew = transform.get_skew(); _xform_dirty = false; } void Node2D::_update_transform() { - _mat.set_rotation_scale_and_skew(angle, _scale, skew); - _mat.elements[2] = pos; + transform.set_rotation_scale_and_skew(rotation, scale, skew); + transform.columns[2] = position; - RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat); + RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), transform); if (!is_inside_tree()) { return; @@ -137,23 +133,23 @@ void Node2D::_update_transform() { void Node2D::set_position(const Point2 &p_pos) { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } - pos = p_pos; + position = p_pos; _update_transform(); } void Node2D::set_rotation(real_t p_radians) { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } - angle = p_radians; + rotation = p_radians; _update_transform(); } void Node2D::set_skew(real_t p_radians) { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } skew = p_radians; _update_transform(); @@ -161,37 +157,37 @@ void Node2D::set_skew(real_t p_radians) { void Node2D::set_scale(const Size2 &p_scale) { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } - _scale = p_scale; + scale = p_scale; // Avoid having 0 scale values, can lead to errors in physics and rendering. - if (Math::is_zero_approx(_scale.x)) { - _scale.x = CMP_EPSILON; + if (Math::is_zero_approx(scale.x)) { + scale.x = CMP_EPSILON; } - if (Math::is_zero_approx(_scale.y)) { - _scale.y = CMP_EPSILON; + if (Math::is_zero_approx(scale.y)) { + scale.y = CMP_EPSILON; } _update_transform(); } Point2 Node2D::get_position() const { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } - return pos; + return position; } real_t Node2D::get_rotation() const { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } - return angle; + return rotation; } real_t Node2D::get_skew() const { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } return skew; @@ -199,14 +195,14 @@ real_t Node2D::get_skew() const { Size2 Node2D::get_scale() const { if (_xform_dirty) { - ((Node2D *)this)->_update_xform_values(); + const_cast<Node2D *>(this)->_update_xform_values(); } - return _scale; + return scale; } Transform2D Node2D::get_transform() const { - return _mat; + return transform; } void Node2D::rotate(real_t p_radians) { @@ -248,10 +244,9 @@ Point2 Node2D::get_global_position() const { } void Node2D::set_global_position(const Point2 &p_pos) { - Transform2D inv; CanvasItem *pi = get_parent_item(); if (pi) { - inv = pi->get_global_transform().affine_inverse(); + Transform2D inv = pi->get_global_transform().affine_inverse(); set_position(inv.xform(p_pos)); } else { set_position(p_pos); @@ -287,10 +282,10 @@ void Node2D::set_global_scale(const Size2 &p_scale) { } void Node2D::set_transform(const Transform2D &p_transform) { - _mat = p_transform; + transform = p_transform; _xform_dirty = true; - RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), _mat); + RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), transform); if (!is_inside_tree()) { return; @@ -417,7 +412,7 @@ 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,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,noslider,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::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew"); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 3e66541e32..69d14f82ad 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,15 +36,15 @@ class Node2D : public CanvasItem { GDCLASS(Node2D, CanvasItem); - Point2 pos; - real_t angle = 0.0; - Size2 _scale = Vector2(1, 1); + Point2 position; + real_t rotation = 0.0; + Size2 scale = Vector2(1, 1); real_t skew = 0.0; int z_index = 0; bool z_relative = true; bool y_sort_enabled = false; - Transform2D _mat; + Transform2D transform; bool _xform_dirty = false; diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 4870ae614b..335f2404f2 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,6 +29,7 @@ /*************************************************************************/ #include "parallax_background.h" + #include "parallax_layer.h" void ParallaxBackground::_notification(int p_what) { @@ -36,8 +37,8 @@ void ParallaxBackground::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { group_name = "__cameras_" + itos(get_viewport().get_id()); add_to_group(group_name); - } break; + case NOTIFICATION_EXIT_TREE: { remove_from_group(group_name); } break; @@ -162,15 +163,15 @@ 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); diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h index 3745c5b587..1a3cb43999 100644 --- a/scene/2d/parallax_background.h +++ b/scene/2d/parallax_background.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 797e2e59cb..9e8ab224dc 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -99,6 +99,7 @@ void ParallaxLayer::_notification(int p_what) { orig_scale = get_scale(); _update_mirroring(); } break; + case NOTIFICATION_EXIT_TREE: { if (Engine::get_singleton()->is_editor_hint()) { break; @@ -142,7 +143,7 @@ TypedArray<String> ParallaxLayer::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<ParallaxBackground>(get_parent())) { - warnings.push_back(TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.")); + warnings.push_back(RTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.")); } return warnings; diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h index cc2d2e096e..b4dcf0ea61 100644 --- a/scene/2d/parallax_layer.h +++ b/scene/2d/parallax_layer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index ed30e871d7..a21cb7db62 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -86,30 +86,41 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc #endif void Path2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW && curve.is_valid()) { - //draw the curve!! + switch (p_what) { + // Draw the curve if navigation debugging is enabled. + case NOTIFICATION_DRAW: { + if (!curve.is_valid()) { + break; + } - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) { - return; - } + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) { + return; + } + + if (curve->get_point_count() < 2) { + return; + } #ifdef TOOLS_ENABLED - const real_t line_width = 2 * EDSCALE; + const real_t line_width = 2 * EDSCALE; #else - const real_t line_width = 2; + const real_t line_width = 2; #endif - const Color color = Color(0.5, 0.6, 1.0, 0.7); + const Color color = Color(0.5, 0.6, 1.0, 0.7); - for (int i = 0; i < curve->get_point_count(); i++) { - Vector2 prev_p = curve->get_point_position(i); + _cached_draw_pts.resize(curve->get_point_count() * 8); + int count = 0; - for (int j = 1; j <= 8; j++) { - real_t frac = j / 8.0; - Vector2 p = curve->interpolate(i, frac); - draw_line(prev_p, p, color, line_width); - prev_p = p; + for (int i = 0; i < curve->get_point_count(); i++) { + for (int j = 0; j < 8; j++) { + real_t frac = j * (1.0 / 8.0); + Vector2 p = curve->interpolate(i, frac); + _cached_draw_pts.set(count++, p); + } } - } + + draw_polyline(_cached_draw_pts, color, line_width, true); + } break; } } @@ -220,8 +231,8 @@ void PathFollow2D::_notification(int p_what) { if (path) { _update_transform(); } - } break; + case NOTIFICATION_EXIT_TREE: { path = nullptr; } break; @@ -252,7 +263,7 @@ TypedArray<String> PathFollow2D::get_configuration_warnings() const { if (is_visible_in_tree() && is_inside_tree()) { if (!Object::cast_to<Path2D>(get_parent())) { - warnings.push_back(TTR("PathFollow2D only works when set as a child of a Path2D node.")); + warnings.push_back(RTR("PathFollow2D only works when set as a child of a Path2D node.")); } } @@ -300,7 +311,7 @@ void PathFollow2D::set_offset(real_t p_offset) { 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/path_2d.h b/scene/2d/path_2d.h index 3b12f025fc..bc55f84831 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -38,6 +38,7 @@ class Path2D : public Node2D { GDCLASS(Path2D, Node2D); Ref<Curve2D> curve; + Vector<Vector2> _cached_draw_pts; void _curve_changed(); diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp index c1b0bc35dd..2999736d64 100644 --- a/scene/2d/physical_bone_2d.cpp +++ b/scene/2d/physical_bone_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -110,15 +110,15 @@ TypedArray<String> PhysicalBone2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!parent_skeleton) { - warnings.push_back(TTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!")); + warnings.push_back(RTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!")); } if (parent_skeleton && bone2d_index <= -1) { - warnings.push_back(TTR("A PhysicalBone2D needs to be assigned to a Bone2D node in order to function! Please set a Bone2D node in the inspector.")); + warnings.push_back(RTR("A PhysicalBone2D needs to be assigned to a Bone2D node in order to function! Please set a Bone2D node in the inspector.")); } if (!child_joint) { PhysicalBone2D *parent_bone = Object::cast_to<PhysicalBone2D>(get_parent()); if (parent_bone) { - warnings.push_back(TTR("A PhysicalBone2D node should have a Joint2D-based child node to keep bones connected! Please add a Joint2D-based node as a child to this node!")); + warnings.push_back(RTR("A PhysicalBone2D node should have a Joint2D-based child node to keep bones connected! Please add a Joint2D-based node as a child to this node!")); } } diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h index 8b41f75c3e..22d329c320 100644 --- a/scene/2d/physical_bone_2d.h +++ b/scene/2d/physical_bone_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -49,7 +49,7 @@ private: NodePath bone2d_nodepath; bool follow_bone_when_simulating = false; - Joint2D *child_joint; + Joint2D *child_joint = nullptr; bool auto_configure_joint = true; bool simulate_physics = false; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index f0e51097db..f345d8c3c9 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,8 +34,8 @@ #include "scene/scene_string_names.h" void PhysicsBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08)); - ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("move_and_collide", "distance", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("test_move", "from", "distance", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08)); ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); @@ -54,14 +54,15 @@ PhysicsBody2D::~PhysicsBody2D() { } } -Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_linear_velocity, bool p_test_only, real_t p_margin) { - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_linear_velocity * delta, p_margin); +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); PhysicsServer2D::MotionResult result; - if (move_and_collide(parameters, result, p_test_only)) { + + bool collided = move_and_collide(parameters, result, p_test_only); + + // Don't report collision when the whole motion is done. + if (collided && result.collision_safe_fraction < 1) { // 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) { motion_cache.instantiate(); @@ -122,14 +123,14 @@ 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); } return colliding; } -bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { +bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { ERR_FAIL_COND_V(!is_inside_tree(), false); PhysicsServer2D::MotionResult *r = nullptr; @@ -141,10 +142,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear r = &temp_result; } - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky. - double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); - - PhysicsServer2D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin); + PhysicsServer2D::MotionParameters parameters(p_from, p_distance, p_margin); bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r); @@ -283,7 +281,7 @@ void AnimatableBody2D::_update_kinematic_motion() { } void AnimatableBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) { - AnimatableBody2D *body = (AnimatableBody2D *)p_instance; + AnimatableBody2D *body = static_cast<AnimatableBody2D *>(p_instance); body->_body_state_changed(p_state); } @@ -341,17 +339,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; @@ -362,17 +360,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; @@ -386,45 +384,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)); @@ -433,7 +431,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); @@ -449,7 +447,7 @@ struct _RigidDynamicBody2DInOut { }; void RigidDynamicBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) { - RigidDynamicBody2D *body = (RigidDynamicBody2D *)p_instance; + RigidDynamicBody2D *body = static_cast<RigidDynamicBody2D *>(p_instance); body->_body_state_changed(p_state); } @@ -496,7 +494,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; @@ -507,7 +505,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; @@ -517,7 +515,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 @@ -809,32 +807,44 @@ void RigidDynamicBody2D::apply_torque_impulse(real_t p_torque) { PhysicsServer2D::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque); } -void RigidDynamicBody2D::set_applied_force(const Vector2 &p_force) { - PhysicsServer2D::get_singleton()->body_set_applied_force(get_rid(), p_force); -}; +void RigidDynamicBody2D::apply_central_force(const Vector2 &p_force) { + PhysicsServer2D::get_singleton()->body_apply_central_force(get_rid(), p_force); +} -Vector2 RigidDynamicBody2D::get_applied_force() const { - return PhysicsServer2D::get_singleton()->body_get_applied_force(get_rid()); -}; +void RigidDynamicBody2D::apply_force(const Vector2 &p_force, const Vector2 &p_position) { + PhysicsServer2D::get_singleton()->body_apply_force(get_rid(), p_force, p_position); +} -void RigidDynamicBody2D::set_applied_torque(const real_t p_torque) { - PhysicsServer2D::get_singleton()->body_set_applied_torque(get_rid(), p_torque); -}; +void RigidDynamicBody2D::apply_torque(real_t p_torque) { + PhysicsServer2D::get_singleton()->body_apply_torque(get_rid(), p_torque); +} -real_t RigidDynamicBody2D::get_applied_torque() const { - return PhysicsServer2D::get_singleton()->body_get_applied_torque(get_rid()); -}; +void RigidDynamicBody2D::add_constant_central_force(const Vector2 &p_force) { + PhysicsServer2D::get_singleton()->body_add_constant_central_force(get_rid(), p_force); +} + +void RigidDynamicBody2D::add_constant_force(const Vector2 &p_force, const Vector2 &p_position) { + PhysicsServer2D::get_singleton()->body_add_constant_force(get_rid(), p_force, p_position); +} + +void RigidDynamicBody2D::add_constant_torque(const real_t p_torque) { + PhysicsServer2D::get_singleton()->body_add_constant_torque(get_rid(), p_torque); +} + +void RigidDynamicBody2D::set_constant_force(const Vector2 &p_force) { + PhysicsServer2D::get_singleton()->body_set_constant_force(get_rid(), p_force); +} -void RigidDynamicBody2D::add_central_force(const Vector2 &p_force) { - PhysicsServer2D::get_singleton()->body_add_central_force(get_rid(), p_force); +Vector2 RigidDynamicBody2D::get_constant_force() const { + return PhysicsServer2D::get_singleton()->body_get_constant_force(get_rid()); } -void RigidDynamicBody2D::add_force(const Vector2 &p_force, const Vector2 &p_position) { - PhysicsServer2D::get_singleton()->body_add_force(get_rid(), p_force, p_position); +void RigidDynamicBody2D::set_constant_torque(real_t p_torque) { + PhysicsServer2D::get_singleton()->body_set_constant_torque(get_rid(), p_torque); } -void RigidDynamicBody2D::add_torque(const real_t p_torque) { - PhysicsServer2D::get_singleton()->body_add_torque(get_rid(), p_torque); +real_t RigidDynamicBody2D::get_constant_torque() const { + return PhysicsServer2D::get_singleton()->body_get_constant_torque(get_rid()); } void RigidDynamicBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) { @@ -900,7 +910,7 @@ void RigidDynamicBody2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); //used for warnings and only in editor + set_notify_local_transform(true); // Used for warnings and only in editor. } } break; @@ -918,8 +928,8 @@ 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) { - warnings.push_back(TTR("Size changes to RigidDynamicBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + 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.")); } return warnings; @@ -979,15 +989,19 @@ void RigidDynamicBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidDynamicBody2D::apply_impulse, Vector2()); ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidDynamicBody2D::apply_torque_impulse); - ClassDB::bind_method(D_METHOD("set_applied_force", "force"), &RigidDynamicBody2D::set_applied_force); - ClassDB::bind_method(D_METHOD("get_applied_force"), &RigidDynamicBody2D::get_applied_force); + ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidDynamicBody2D::apply_central_force); + ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidDynamicBody2D::apply_force, Vector2()); + ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidDynamicBody2D::apply_torque); - ClassDB::bind_method(D_METHOD("set_applied_torque", "torque"), &RigidDynamicBody2D::set_applied_torque); - ClassDB::bind_method(D_METHOD("get_applied_torque"), &RigidDynamicBody2D::get_applied_torque); + ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidDynamicBody2D::add_constant_central_force); + ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidDynamicBody2D::add_constant_force, Vector2()); + ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidDynamicBody2D::add_constant_torque); - ClassDB::bind_method(D_METHOD("add_central_force", "force"), &RigidDynamicBody2D::add_central_force); - ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &RigidDynamicBody2D::add_force, Vector2()); - ClassDB::bind_method(D_METHOD("add_torque", "torque"), &RigidDynamicBody2D::add_torque); + ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidDynamicBody2D::set_constant_force); + ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidDynamicBody2D::get_constant_force); + + ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidDynamicBody2D::set_constant_torque); + ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidDynamicBody2D::get_constant_torque); ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidDynamicBody2D::set_sleeping); ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidDynamicBody2D::is_sleeping); @@ -1032,9 +1046,9 @@ void RigidDynamicBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity"), "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("Applied Forces", "applied_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "applied_force"), "set_applied_force", "get_applied_force"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "applied_torque"), "set_applied_torque", "get_applied_torque"); + 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_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"))); @@ -1096,7 +1110,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; @@ -1109,7 +1123,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. @@ -1146,7 +1160,7 @@ bool CharacterBody2D::move_and_slide() { if (motion_mode == MOTION_MODE_GROUNDED) { _move_and_slide_grounded(delta, was_on_floor); } else { - _move_and_slide_free(delta); + _move_and_slide_floating(delta); } // Compute real velocity. @@ -1158,7 +1172,7 @@ bool CharacterBody2D::move_and_slide() { if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) { current_platform_velocity = current_platform_velocity.slide(up_direction); } - motion_velocity += current_platform_velocity; + velocity += current_platform_velocity; } } @@ -1166,7 +1180,7 @@ bool CharacterBody2D::move_and_slide() { } void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { - Vector2 motion = motion_velocity * p_delta; + Vector2 motion = velocity * p_delta; Vector2 motion_slide_up = motion.slide(up_direction); Vector2 prev_floor_normal = floor_normal; @@ -1184,13 +1198,13 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // If the platform's ceiling push down the body. bool apply_ceiling_velocity = false; bool first_slide = true; - bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0; + bool vel_dir_facing_up = velocity.dot(up_direction) > 0; Vector2 last_travel; for (int iteration = 0; iteration < max_slides; ++iteration) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin); - 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); @@ -1201,26 +1215,26 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo motion_results.push_back(result); _set_collision_direction(result); - // If we hit a ceiling platform, we set the vertical motion_velocity to at least the platform one. + // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. if (on_ceiling && result.collider_velocity != Vector2() && result.collider_velocity.dot(up_direction) < 0) { // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (result.collision_normal + up_direction).length() < 0.01) { apply_ceiling_velocity = true; Vector2 ceiling_vertical_velocity = up_direction * up_direction.dot(result.collider_velocity); - Vector2 motion_vertical_velocity = up_direction * up_direction.dot(motion_velocity); + Vector2 motion_vertical_velocity = up_direction * up_direction.dot(velocity); if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { - motion_velocity = ceiling_vertical_velocity + motion_velocity.slide(up_direction); + velocity = ceiling_vertical_velocity + velocity.slide(up_direction); } } } - if (on_floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) { + 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); - motion_velocity = Vector2(); + velocity = Vector2(); last_motion = Vector2(); motion = Vector2(); break; @@ -1239,12 +1253,12 @@ 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); - motion_velocity = Vector2(); + _snap_on_floor(true, false, true); + velocity = Vector2(); last_motion = Vector2(); motion = Vector2(); break; @@ -1266,7 +1280,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { Vector2 slide_motion = result.remainder.slide(result.collision_normal); - if (slide_motion.dot(motion_velocity) > 0.0) { + if (slide_motion.dot(velocity) > 0.0) { motion = slide_motion; } else { motion = Vector2(); @@ -1274,10 +1288,10 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (slide_on_ceiling && on_ceiling) { // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. if (vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(result.collision_normal); + velocity = velocity.slide(result.collision_normal); } else { // Avoid acceleration in slope when falling. - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } } } @@ -1285,7 +1299,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo else { motion = result.remainder; if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); motion = motion.slide(up_direction); } } @@ -1298,7 +1312,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(); @@ -1319,23 +1333,23 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Scales the horizontal velocity according to the wall slope. if (is_on_wall_only() && motion_slide_up.dot(motion_results.get(0).collision_normal) < 0) { - Vector2 slide_motion = motion_velocity.slide(motion_results.get(0).collision_normal); + Vector2 slide_motion = velocity.slide(motion_results.get(0).collision_normal); if (motion_slide_up.dot(slide_motion) < 0) { - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } else { - // Keeps the vertical motion from motion_velocity and add the horizontal motion of the projection. - motion_velocity = up_direction * up_direction.dot(motion_velocity) + slide_motion.slide(up_direction); + // Keeps the vertical motion from velocity and add the horizontal motion of the projection. + velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); } } // Reset the gravity accumulation when touching the ground. if (on_floor && !vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); } } -void CharacterBody2D::_move_and_slide_free(double p_delta) { - Vector2 motion = motion_velocity * p_delta; +void CharacterBody2D::_move_and_slide_floating(double p_delta) { + Vector2 motion = velocity * p_delta; platform_rid = RID(); platform_object_id = ObjectID(); @@ -1360,7 +1374,7 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) { break; } - if (free_mode_min_slide_angle != 0 && result.get_angle(-motion_velocity.normalized()) < free_mode_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + if (wall_min_slide_angle != 0 && result.get_angle(-velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { motion = Vector2(); } else if (first_slide) { Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); @@ -1369,7 +1383,7 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) { motion = result.remainder.slide(result.collision_normal); } - if (motion.dot(motion_velocity) <= 0.0) { + if (motion.dot(velocity) <= 0.0) { motion = Vector2(); } } @@ -1382,8 +1396,8 @@ void CharacterBody2D::_move_and_slide_free(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; } @@ -1395,7 +1409,8 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) 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); @@ -1410,14 +1425,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; } @@ -1461,12 +1476,12 @@ void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_ platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); } -const Vector2 &CharacterBody2D::get_motion_velocity() const { - return motion_velocity; +const Vector2 &CharacterBody2D::get_velocity() const { + return velocity; } -void CharacterBody2D::set_motion_velocity(const Vector2 &p_velocity) { - motion_velocity = p_velocity; +void CharacterBody2D::set_velocity(const Vector2 &p_velocity) { + velocity = p_velocity; } bool CharacterBody2D::is_on_floor() const { @@ -1506,7 +1521,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 { @@ -1652,12 +1667,12 @@ void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) { floor_snap_length = p_floor_snap_length; } -real_t CharacterBody2D::get_free_mode_min_slide_angle() const { - return free_mode_min_slide_angle; +real_t CharacterBody2D::get_wall_min_slide_angle() const { + return wall_min_slide_angle; } -void CharacterBody2D::set_free_mode_min_slide_angle(real_t p_radians) { - free_mode_min_slide_angle = p_radians; +void CharacterBody2D::set_wall_min_slide_angle(real_t p_radians) { + wall_min_slide_angle = p_radians; } const Vector2 &CharacterBody2D::get_up_direction() const { @@ -1665,7 +1680,7 @@ const Vector2 &CharacterBody2D::get_up_direction() const { } void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) { - ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Free motion mode instead."); + ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Floating motion mode instead."); up_direction = p_up_direction.normalized(); } @@ -1687,8 +1702,8 @@ void CharacterBody2D::_notification(int p_what) { void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide); - ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody2D::set_motion_velocity); - ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody2D::get_motion_velocity); + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity); ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); @@ -1712,8 +1727,8 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle); ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody2D::get_floor_snap_length); ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody2D::set_floor_snap_length); - ClassDB::bind_method(D_METHOD("get_free_mode_min_slide_angle"), &CharacterBody2D::get_free_mode_min_slide_angle); - ClassDB::bind_method(D_METHOD("set_free_mode_min_slide_angle", "radians"), &CharacterBody2D::set_free_mode_min_slide_angle); + ClassDB::bind_method(D_METHOD("get_wall_min_slide_angle"), &CharacterBody2D::get_wall_min_slide_angle); + ClassDB::bind_method(D_METHOD("set_wall_min_slide_angle", "radians"), &CharacterBody2D::set_wall_min_slide_angle); ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction); ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction); ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode); @@ -1738,28 +1753,26 @@ void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision); ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody2D::_get_last_slide_collision); - ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Free", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); + 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, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_motion_velocity", "get_motion_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "", 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_GROUP("Free Mode", "free_mode_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "free_mode_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_free_mode_min_slide_angle", "get_free_mode_min_slide_angle"); + 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"); ADD_GROUP("Floor", "floor_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled"); 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_GROUP("Moving platform", "moving_platform"); + 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"); BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED); - BIND_ENUM_CONSTANT(MOTION_MODE_FREE); + BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING); BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS); BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY); @@ -1767,12 +1780,12 @@ void CharacterBody2D::_bind_methods() { } void CharacterBody2D::_validate_property(PropertyInfo &property) const { - if (motion_mode == MOTION_MODE_FREE) { + if (motion_mode == MOTION_MODE_FLOATING) { if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") { property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } else { - if (property.name == "free_mode_min_slide_angle") { + if (property.name == "wall_min_slide_angle") { property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; } } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 2abce4b0a5..7401fc7578 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -47,11 +47,11 @@ protected: Ref<KinematicCollision2D> motion_cache; - Ref<KinematicCollision2D> _move(const Vector2 &p_linear_velocity, bool p_test_only = false, real_t p_margin = 0.08); + Ref<KinematicCollision2D> _move(const Vector2 &p_distance, bool p_test_only = false, real_t p_margin = 0.08); public: bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); - bool test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); + bool test_move(const Transform2D &p_from, const Vector2 &p_distance, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); TypedArray<PhysicsBody2D> get_collision_exceptions(); void add_collision_exception_with(Node *p_node); //must be physicsbody @@ -200,7 +200,7 @@ private: struct ContactMonitor { bool locked = false; - Map<ObjectID, BodyState> body_map; + HashMap<ObjectID, BodyState> body_map; }; ContactMonitor *contact_monitor = nullptr; @@ -292,15 +292,19 @@ public: void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()); void apply_torque_impulse(real_t p_torque); - void set_applied_force(const Vector2 &p_force); - Vector2 get_applied_force() const; + void apply_central_force(const Vector2 &p_force); + void apply_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); + void apply_torque(real_t p_torque); - void set_applied_torque(const real_t p_torque); - real_t get_applied_torque() const; + void add_constant_central_force(const Vector2 &p_force); + void add_constant_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); + void add_constant_torque(real_t p_torque); - void add_central_force(const Vector2 &p_force); - void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); - void add_torque(real_t p_torque); + void set_constant_force(const Vector2 &p_force); + Vector2 get_constant_force() const; + + void set_constant_torque(real_t p_torque); + real_t get_constant_torque() const; TypedArray<Node2D> get_colliding_bodies() const; //function for script @@ -324,7 +328,7 @@ class CharacterBody2D : public PhysicsBody2D { public: enum MotionMode { MOTION_MODE_GROUNDED, - MOTION_MODE_FREE, + MOTION_MODE_FLOATING, }; enum MovingPlatformApplyVelocityOnLeave { PLATFORM_VEL_ON_LEAVE_ALWAYS, @@ -333,8 +337,8 @@ public: }; bool move_and_slide(); - const Vector2 &get_motion_velocity() const; - void set_motion_velocity(const Vector2 &p_velocity); + const Vector2 &get_velocity() const; + void set_velocity(const Vector2 &p_velocity); bool is_on_floor() const; bool is_on_floor_only() const; @@ -370,11 +374,11 @@ private: int platform_layer = 0; real_t floor_max_angle = Math::deg2rad((real_t)45.0); real_t floor_snap_length = 1; - real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0); + real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0); Vector2 up_direction = Vector2(0.0, -1.0); uint32_t moving_platform_floor_layers = UINT32_MAX; uint32_t moving_platform_wall_layers = 0; - Vector2 motion_velocity; + Vector2 velocity; Vector2 floor_normal; Vector2 platform_velocity; @@ -416,8 +420,8 @@ private: real_t get_floor_snap_length(); void set_floor_snap_length(real_t p_floor_snap_length); - real_t get_free_mode_min_slide_angle() const; - void set_free_mode_min_slide_angle(real_t p_radians); + real_t get_wall_min_slide_angle() const; + void set_wall_min_slide_angle(real_t p_radians); uint32_t get_moving_platform_floor_layers() const; void set_moving_platform_floor_layers(const uint32_t p_exclude_layer); @@ -431,17 +435,17 @@ private: void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity); MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const; - void _move_and_slide_free(double p_delta); + void _move_and_slide_floating(double p_delta); void _move_and_slide_grounded(double p_delta, bool p_was_on_floor); 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 f00959bbb6..f9986c2f30 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -295,14 +295,14 @@ void Polygon2D::_notification(int p_what) { } Vector<Color> colors; + colors.resize(len); + if (vertex_colors.size() == points.size()) { - colors.resize(len); const Color *color_r = vertex_colors.ptr(); for (int i = 0; i < len; i++) { colors.write[i] = color_r[i]; } } else { - colors.resize(len); for (int i = 0; i < len; i++) { colors.write[i] = color; } @@ -428,15 +428,6 @@ Vector<Color> Polygon2D::get_vertex_colors() const { void Polygon2D::set_texture(const Ref<Texture2D> &p_texture) { texture = p_texture; - - /*if (texture.is_valid()) { - uint32_t flags=texture->get_flags(); - flags&=~Texture::FLAG_REPEAT; - if (tex_tile) - flags|=Texture::FLAG_REPEAT; - - texture->set_flags(flags); - }*/ update(); } @@ -532,7 +523,7 @@ Vector<float> Polygon2D::get_bone_weights(int p_index) const { void Polygon2D::erase_bone(int p_idx) { ERR_FAIL_INDEX(p_idx, bone_weights.size()); - bone_weights.remove(p_idx); + bone_weights.remove_at(p_idx); } void Polygon2D::clear_bones() { @@ -662,7 +653,7 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "uv"), "set_uv", "get_uv"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "vertex_colors"), "set_vertex_colors", "get_vertex_colors"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons"), "set_polygons", "get_polygons"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_bones", "_get_bones"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_bones", "_get_bones"); ADD_PROPERTY(PropertyInfo(Variant::INT, "internal_vertex_count", PROPERTY_HINT_RANGE, "0,1000"), "set_internal_vertex_count", "get_internal_vertex_count"); } diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index bf386b9ace..d6a1be0f6d 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index 4f053ff8b0..d946ea63bf 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,43 +30,45 @@ #include "position_2d.h" -const real_t DEFAULT_GIZMO_EXTENTS = 10.0; - void Position2D::_draw_cross() { const real_t extents = get_gizmo_extents(); // Add more points to create a "hard stop" in the color gradient. - PackedVector2Array points_x; - points_x.push_back(Point2(+extents, 0)); - points_x.push_back(Point2()); - points_x.push_back(Point2()); - points_x.push_back(Point2(-extents, 0)); - - PackedVector2Array points_y; - points_y.push_back(Point2(0, +extents)); - points_y.push_back(Point2()); - points_y.push_back(Point2()); - points_y.push_back(Point2(0, -extents)); + PackedVector2Array points_x = { + Point2(+extents, 0), + Point2(), + Point2(), + Point2(-extents, 0) + }; + + PackedVector2Array points_y = { + Point2(0, +extents), + Point2(), + Point2(), + Point2(0, -extents) + }; // Use the axis color which is brighter for the positive axis. // Use a darkened axis color for the negative axis. // This makes it possible to see in which direction the Position3D node is rotated // (which can be important depending on how it's used). // Axis colors are taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`). - PackedColorArray colors_x; const Color color_x = Color(0.96, 0.20, 0.32); - colors_x.push_back(color_x); - colors_x.push_back(color_x); - colors_x.push_back(color_x.lerp(Color(0, 0, 0), 0.5)); - colors_x.push_back(color_x.lerp(Color(0, 0, 0), 0.5)); + PackedColorArray colors_x = { + color_x, + color_x, + color_x.lerp(Color(0, 0, 0), 0.5), + color_x.lerp(Color(0, 0, 0), 0.5) + }; draw_multiline_colors(points_x, colors_x); - PackedColorArray colors_y; const Color color_y = Color(0.53, 0.84, 0.01); - colors_y.push_back(color_y); - colors_y.push_back(color_y); - colors_y.push_back(color_y.lerp(Color(0, 0, 0), 0.5)); - colors_y.push_back(color_y.lerp(Color(0, 0, 0), 0.5)); + PackedColorArray colors_y = { + color_y, + color_y, + color_y.lerp(Color(0, 0, 0), 0.5), + color_y.lerp(Color(0, 0, 0), 0.5) + }; draw_multiline_colors(points_y, colors_y); } @@ -86,6 +88,7 @@ void Position2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { update(); } break; + case NOTIFICATION_DRAW: { if (!is_inside_tree()) { break; @@ -93,34 +96,24 @@ void Position2D::_notification(int p_what) { if (Engine::get_singleton()->is_editor_hint()) { _draw_cross(); } - } break; } } void Position2D::set_gizmo_extents(real_t p_extents) { - if (p_extents == DEFAULT_GIZMO_EXTENTS) { - set_meta("_gizmo_extents_", Variant()); - } else { - set_meta("_gizmo_extents_", p_extents); - } - + gizmo_extents = p_extents; update(); } real_t Position2D::get_gizmo_extents() const { - if (has_meta("_gizmo_extents_")) { - return get_meta("_gizmo_extents_"); - } else { - return DEFAULT_GIZMO_EXTENTS; - } + return gizmo_extents; } 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); + 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", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_gizmo_extents", "_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"); } Position2D::Position2D() { diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h index 9ed622c8f6..99b0266130 100644 --- a/scene/2d/position_2d.h +++ b/scene/2d/position_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -36,6 +36,8 @@ class Position2D : public Node2D { GDCLASS(Position2D, Node2D); + real_t gizmo_extents = 10.0; + void _draw_cross(); protected: diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index f9830a8743..37db9211e1 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,6 +31,7 @@ #include "ray_cast_2d.h" #include "collision_object_2d.h" +#include "scene/resources/world_2d.h" void RayCast2D::set_target_position(const Vector2 &p_point) { target_position = p_point; @@ -149,11 +150,11 @@ void RayCast2D::_notification(int p_what) { } } } break; + case NOTIFICATION_EXIT_TREE: { if (enabled) { set_physics_process_internal(false); } - } break; case NOTIFICATION_DRAW: { @@ -162,16 +163,13 @@ void RayCast2D::_notification(int p_what) { break; } _draw_debug_shape(); - } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) { break; } - _update_raycast_state(); - } break; } } @@ -244,15 +242,13 @@ void RayCast2D::_draw_debug_shape() { xf.rotate(target_position.angle()); xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); - Vector<Vector2> pts; - pts.push_back(xf.xform(Vector2(arrow_size, 0))); - pts.push_back(xf.xform(Vector2(0, 0.5 * arrow_size))); - pts.push_back(xf.xform(Vector2(0, -0.5 * arrow_size))); + Vector<Vector2> pts = { + xf.xform(Vector2(arrow_size, 0)), + xf.xform(Vector2(0, 0.5 * arrow_size)), + xf.xform(Vector2(0, -0.5 * arrow_size)) + }; - Vector<Color> cols; - for (int i = 0; i < 3; i++) { - cols.push_back(draw_col); - } + Vector<Color> cols = { draw_col, draw_col, draw_col }; draw_primitive(pts, cols, Vector<Vector2>()); } @@ -265,30 +261,29 @@ void RayCast2D::add_exception_rid(const RID &p_rid) { exclude.insert(p_rid); } -void RayCast2D::add_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - add_exception_rid(co->get_rid()); +void RayCast2D::add_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + add_exception_rid(p_node->get_rid()); } void RayCast2D::remove_exception_rid(const RID &p_rid) { exclude.erase(p_rid); } -void RayCast2D::remove_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - remove_exception_rid(co->get_rid()); +void RayCast2D::remove_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + remove_exception_rid(p_node->get_rid()); } void RayCast2D::clear_exceptions() { exclude.clear(); + + if (exclude_parent_body && is_inside_tree()) { + CollisionObject2D *parent = Object::cast_to<CollisionObject2D>(get_parent()); + if (parent) { + exclude.insert(parent->get_rid()); + } + } } void RayCast2D::set_collide_with_areas(bool p_enabled) { diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index 3ee09fad32..b809bc4b8e 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,6 +33,8 @@ #include "scene/2d/node_2d.h" +class CollisionObject2D; + class RayCast2D : public Node2D { GDCLASS(RayCast2D, Node2D); @@ -42,7 +44,7 @@ class RayCast2D : public Node2D { int against_shape = 0; Vector2 collision_point; Vector2 collision_normal; - Set<RID> exclude; + RBSet<RID> exclude; uint32_t collision_mask = 1; bool exclude_parent_body = true; @@ -94,9 +96,9 @@ public: Vector2 get_collision_normal() const; void add_exception_rid(const RID &p_rid); - void add_exception(const Object *p_object); + void add_exception(const CollisionObject2D *p_node); void remove_exception_rid(const RID &p_rid); - void remove_exception(const Object *p_object); + void remove_exception(const CollisionObject2D *p_node); void clear_exceptions(); RayCast2D(); diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index fe3e867424..6c4bfd58ce 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -115,8 +115,8 @@ void RemoteTransform2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { _update_cache(); - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_inside_tree()) { break; @@ -125,7 +125,6 @@ void RemoteTransform2D::_notification(int p_what) { if (cache.is_valid()) { _update_remote(); } - } break; } } @@ -188,7 +187,7 @@ TypedArray<String> RemoteTransform2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) { - warnings.push_back(TTR("Path property must point to a valid Node2D node to work.")); + warnings.push_back(RTR("Path property must point to a valid Node2D node to work.")); } return warnings; diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h index 36fddb58c7..bd352e1054 100644 --- a/scene/2d/remote_transform_2d.h +++ b/scene/2d/remote_transform_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index 50b44eb4ef..a2f4b16ed3 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -201,6 +201,7 @@ void ShapeCast2D::_notification(int p_what) { } } } break; + case NOTIFICATION_EXIT_TREE: { if (enabled) { set_physics_process_internal(false); @@ -223,7 +224,7 @@ void ShapeCast2D::_notification(int p_what) { draw_col.g = g; draw_col.b = g; } - // Draw continuos chain of shapes along the cast. + // Draw continuous chain of shapes along the cast. const int steps = MAX(2, target_position.length() / shape->get_rect().get_size().length() * 4); for (int i = 0; i <= steps; ++i) { Vector2 t = (real_t(i) / steps) * target_position; @@ -239,19 +240,22 @@ void ShapeCast2D::_notification(int p_what) { xf.translate(Vector2(target_position.length(), 0)); draw_line(Vector2(), target_position, draw_col, 2); - Vector<Vector2> pts; + float tsize = 8; - pts.push_back(xf.xform(Vector2(tsize, 0))); - pts.push_back(xf.xform(Vector2(0, Math_SQRT12 * tsize))); - pts.push_back(xf.xform(Vector2(0, -Math_SQRT12 * tsize))); - Vector<Color> cols; - for (int i = 0; i < 3; i++) - cols.push_back(draw_col); + + Vector<Vector2> pts = { + xf.xform(Vector2(tsize, 0)), + xf.xform(Vector2(0, Math_SQRT12 * tsize)), + xf.xform(Vector2(0, -Math_SQRT12 * tsize)) + }; + + Vector<Color> cols = { draw_col, draw_col, draw_col }; draw_primitive(pts, cols, Vector<Vector2>()); } #endif } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) { break; @@ -320,26 +324,18 @@ void ShapeCast2D::add_exception_rid(const RID &p_rid) { exclude.insert(p_rid); } -void ShapeCast2D::add_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - add_exception_rid(co->get_rid()); +void ShapeCast2D::add_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + add_exception_rid(p_node->get_rid()); } void ShapeCast2D::remove_exception_rid(const RID &p_rid) { exclude.erase(p_rid); } -void ShapeCast2D::remove_exception(const Object *p_object) { - ERR_FAIL_NULL(p_object); - const CollisionObject2D *co = Object::cast_to<CollisionObject2D>(p_object); - if (!co) { - return; - } - remove_exception_rid(co->get_rid()); +void ShapeCast2D::remove_exception(const CollisionObject2D *p_node) { + ERR_FAIL_NULL_MSG(p_node, "The passed Node must be an instance of CollisionObject2D."); + remove_exception_rid(p_node->get_rid()); } void ShapeCast2D::clear_exceptions() { @@ -386,7 +382,7 @@ TypedArray<String> ShapeCast2D::get_configuration_warnings() const { TypedArray<String> warnings = Node2D::get_configuration_warnings(); if (shape.is_null()) { - warnings.push_back(TTR("This node cannot interact with other objects unless a Shape2D is assigned.")); + warnings.push_back(RTR("This node cannot interact with other objects unless a Shape2D is assigned.")); } return warnings; } diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/shape_cast_2d.h index fca6b46155..78125b08bd 100644 --- a/scene/2d/shape_cast_2d.h +++ b/scene/2d/shape_cast_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -33,6 +33,9 @@ #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" +#include "scene/resources/world_2d.h" + +class CollisionObject2D; class ShapeCast2D : public Node2D { GDCLASS(ShapeCast2D, Node2D); @@ -43,7 +46,7 @@ class ShapeCast2D : public Node2D { RID shape_rid; Vector2 target_position = Vector2(0, 50); - Set<RID> exclude; + RBSet<RID> exclude; real_t margin = 0.0; uint32_t collision_mask = 1; bool exclude_parent_body = true; @@ -109,9 +112,9 @@ public: real_t get_closest_collision_unsafe_fraction() const; void add_exception_rid(const RID &p_rid); - void add_exception(const Object *p_object); + void add_exception(const CollisionObject2D *p_node); void remove_exception_rid(const RID &p_rid); - void remove_exception(const Object *p_object); + void remove_exception(const CollisionObject2D *p_node); void clear_exceptions(); TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 63a0fb9b89..aa039e07ee 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,6 +31,7 @@ #include "skeleton_2d.h" #ifdef TOOLS_ENABLED +#include "editor/editor_data.h" #include "editor/editor_settings.h" #include "editor/plugins/canvas_item_editor_plugin.h" #endif //TOOLS_ENABLED @@ -92,223 +93,228 @@ void Bone2D::_get_property_list(List<PropertyInfo> *p_list) const { } void Bone2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - Node *parent = get_parent(); - parent_bone = Object::cast_to<Bone2D>(parent); - skeleton = nullptr; - while (parent) { - skeleton = Object::cast_to<Skeleton2D>(parent); - if (skeleton) { - break; - } - if (!Object::cast_to<Bone2D>(parent)) { - break; //skeletons must be chained to Bone2Ds. - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + Node *parent = get_parent(); + parent_bone = Object::cast_to<Bone2D>(parent); + skeleton = nullptr; + while (parent) { + skeleton = Object::cast_to<Skeleton2D>(parent); + if (skeleton) { + break; + } + if (!Object::cast_to<Bone2D>(parent)) { + break; //skeletons must be chained to Bone2Ds. + } - parent = parent->get_parent(); - } + parent = parent->get_parent(); + } - if (skeleton) { - Skeleton2D::Bone bone; - bone.bone = this; - skeleton->bones.push_back(bone); - skeleton->_make_bone_setup_dirty(); - } + if (skeleton) { + Skeleton2D::Bone bone; + bone.bone = this; + skeleton->bones.push_back(bone); + skeleton->_make_bone_setup_dirty(); + } - cache_transform = get_transform(); - copy_transform_to_cache = true; + cache_transform = get_transform(); + copy_transform_to_cache = true; #ifdef TOOLS_ENABLED - // Only draw the gizmo in the editor! - if (Engine::get_singleton()->is_editor_hint() == false) { - return; - } + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; + } - update(); + update(); #endif // TOOLS_ENABLED - } + } break; - else if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (skeleton) { - skeleton->_make_transform_dirty(); - } - if (copy_transform_to_cache) { - cache_transform = get_transform(); - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (skeleton) { + skeleton->_make_transform_dirty(); + } + if (copy_transform_to_cache) { + cache_transform = get_transform(); + } #ifdef TOOLS_ENABLED - // Only draw the gizmo in the editor! - if (Engine::get_singleton()->is_editor_hint() == false) { - return; - } + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; + } - update(); + update(); - if (get_parent()) { - Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent()); - if (parent_bone) { - parent_bone->update(); + if (get_parent()) { + Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent()); + if (parent_bone) { + parent_bone->update(); + } } - } #endif // TOOLS_ENABLED - } + } break; - else if (p_what == NOTIFICATION_MOVED_IN_PARENT) { - if (skeleton) { - skeleton->_make_bone_setup_dirty(); - } - if (copy_transform_to_cache) { - cache_transform = get_transform(); - } - } + case NOTIFICATION_MOVED_IN_PARENT: { + if (skeleton) { + skeleton->_make_bone_setup_dirty(); + } + if (copy_transform_to_cache) { + cache_transform = get_transform(); + } + } break; - else if (p_what == NOTIFICATION_EXIT_TREE) { - if (skeleton) { - for (int i = 0; i < skeleton->bones.size(); i++) { - if (skeleton->bones[i].bone == this) { - skeleton->bones.remove(i); - break; + case NOTIFICATION_EXIT_TREE: { + if (skeleton) { + for (int i = 0; i < skeleton->bones.size(); i++) { + if (skeleton->bones[i].bone == this) { + skeleton->bones.remove_at(i); + break; + } } + skeleton->_make_bone_setup_dirty(); + skeleton = nullptr; } - skeleton->_make_bone_setup_dirty(); - skeleton = nullptr; - } - parent_bone = nullptr; - set_transform(cache_transform); - } + parent_bone = nullptr; + set_transform(cache_transform); + } break; + + case NOTIFICATION_READY: { + if (autocalculate_length_and_angle) { + calculate_length_and_rotation(); + } + } break; - else if (p_what == NOTIFICATION_READY) { - if (autocalculate_length_and_angle) { - calculate_length_and_rotation(); - } - } #ifdef TOOLS_ENABLED - else if (p_what == NOTIFICATION_EDITOR_PRE_SAVE || p_what == NOTIFICATION_EDITOR_POST_SAVE) { - Transform2D tmp_trans = get_transform(); - set_transform(cache_transform); - cache_transform = tmp_trans; - } - // Bone2D Editor gizmo drawing: + case NOTIFICATION_EDITOR_PRE_SAVE: + case NOTIFICATION_EDITOR_POST_SAVE: { + Transform2D tmp_trans = get_transform(); + set_transform(cache_transform); + cache_transform = tmp_trans; + } break; + + // Bone2D Editor gizmo drawing: #ifndef _MSC_VER #warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin #endif - else if (p_what == NOTIFICATION_DRAW) { - // Only draw the gizmo in the editor! - if (Engine::get_singleton()->is_editor_hint() == false) { - return; - } - - if (editor_gizmo_rid.is_null()) { - editor_gizmo_rid = RenderingServer::get_singleton()->canvas_item_create(); - RenderingServer::get_singleton()->canvas_item_set_parent(editor_gizmo_rid, get_canvas_item()); - RenderingServer::get_singleton()->canvas_item_set_z_as_relative_to_parent(editor_gizmo_rid, true); - RenderingServer::get_singleton()->canvas_item_set_z_index(editor_gizmo_rid, 10); - } - RenderingServer::get_singleton()->canvas_item_clear(editor_gizmo_rid); - - if (!_editor_show_bone_gizmo) { - return; - } - - // Undo scaling - Transform2D editor_gizmo_trans = Transform2D(); - editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale()); - RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans); - - Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); - Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); - Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); - Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); - Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); - - bool Bone2D_found = false; - for (int i = 0; i < get_child_count(); i++) { - Bone2D *child_node = nullptr; - child_node = Object::cast_to<Bone2D>(get_child(i)); - if (!child_node) { - continue; + case NOTIFICATION_DRAW: { + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; } - Bone2D_found = true; - - Vector<Vector2> bone_shape; - Vector<Vector2> bone_shape_outline; - _editor_get_bone_shape(&bone_shape, &bone_shape_outline, child_node); - - Vector<Color> colors; - if (has_meta("_local_pose_override_enabled_")) { - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - } else { - colors.push_back(bone_color1); - colors.push_back(bone_color2); - colors.push_back(bone_color1); - colors.push_back(bone_color2); + if (editor_gizmo_rid.is_null()) { + editor_gizmo_rid = RenderingServer::get_singleton()->canvas_item_create(); + RenderingServer::get_singleton()->canvas_item_set_parent(editor_gizmo_rid, get_canvas_item()); + RenderingServer::get_singleton()->canvas_item_set_z_as_relative_to_parent(editor_gizmo_rid, true); + RenderingServer::get_singleton()->canvas_item_set_z_index(editor_gizmo_rid, 10); } + RenderingServer::get_singleton()->canvas_item_clear(editor_gizmo_rid); - Vector<Color> outline_colors; - if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - } else { - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); + if (!_editor_show_bone_gizmo) { + return; } - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); - } - - if (!Bone2D_found) { - Vector<Vector2> bone_shape; - Vector<Vector2> bone_shape_outline; + // Undo scaling + Transform2D editor_gizmo_trans = Transform2D(); + editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale()); + RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans); + + Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); + Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); + Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); + Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); + Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); + + bool Bone2D_found = false; + for (int i = 0; i < get_child_count(); i++) { + Bone2D *child_node = nullptr; + child_node = Object::cast_to<Bone2D>(get_child(i)); + if (!child_node) { + continue; + } + Bone2D_found = true; + + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + + _editor_get_bone_shape(&bone_shape, &bone_shape_outline, child_node); + + Vector<Color> colors; + if (has_meta("_local_pose_override_enabled_")) { + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + } else { + colors.push_back(bone_color1); + colors.push_back(bone_color2); + colors.push_back(bone_color1); + colors.push_back(bone_color2); + } - _editor_get_bone_shape(&bone_shape, &bone_shape_outline, nullptr); + Vector<Color> outline_colors; + if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + } else { + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + } - Vector<Color> colors; - if (has_meta("_local_pose_override_enabled_")) { - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - } else { - colors.push_back(bone_color1); - colors.push_back(bone_color2); - colors.push_back(bone_color1); - colors.push_back(bone_color2); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); } - Vector<Color> outline_colors; - if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - } else { - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - } + if (!Bone2D_found) { + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + + _editor_get_bone_shape(&bone_shape, &bone_shape_outline, nullptr); + + Vector<Color> colors; + if (has_meta("_local_pose_override_enabled_")) { + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + } else { + colors.push_back(bone_color1); + colors.push_back(bone_color2); + colors.push_back(bone_color1); + colors.push_back(bone_color2); + } - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); - } + Vector<Color> outline_colors; + if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + } else { + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + } + + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); + } + } break; +#endif // TOOLS_ENABLED } -#endif // TOOLS_ENALBED } #ifdef TOOLS_ENABLED @@ -432,14 +438,14 @@ TypedArray<String> Bone2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!skeleton) { if (parent_bone) { - warnings.push_back(TTR("This Bone2D chain should end at a Skeleton2D node.")); + warnings.push_back(RTR("This Bone2D chain should end at a Skeleton2D node.")); } else { - warnings.push_back(TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node.")); + warnings.push_back(RTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node.")); } } if (rest == Transform2D(0, 0, 0, 0, 0, 0)) { - warnings.push_back(TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.")); + warnings.push_back(RTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.")); } return warnings; diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 56fd0e8504..98fb867d99 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index b2302d09db..facd164a0e 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -122,11 +122,6 @@ void Sprite2D::_notification(int p_what) { RID ci = get_canvas_item(); - /* - texture->draw(ci,Point2()); - break; - */ - Rect2 src_rect, dst_rect; bool filter_clip_enabled; _get_rects(src_rect, dst_rect, filter_clip_enabled); diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h index 49df78c59d..6893e92d4a 100644 --- a/scene/2d/sprite_2d.h +++ b/scene/2d/sprite_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 96c4164721..19c341c1e1 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,11 +31,11 @@ #include "tile_map.h" #include "core/io/marshalls.h" - +#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; Ref<TileSet> tile_set = tile_map->get_tileset(); ERR_FAIL_COND_V(!tile_set.is_valid(), output); @@ -489,6 +489,7 @@ void TileMap::_notification(int p_what) { _clear_internals(); _recreate_internals(); } break; + case NOTIFICATION_EXIT_TREE: { _clear_internals(); } break; @@ -576,7 +577,7 @@ void TileMap::move_layer(int p_layer, int p_to_pos) { TileMapLayer tl = layers[p_layer]; layers.insert(p_to_pos, tl); - layers.remove(p_to_pos < p_layer ? p_layer + 1 : p_layer); + layers.remove_at(p_to_pos < p_layer ? p_layer + 1 : p_layer); _recreate_internals(); notify_property_list_changed(); @@ -595,7 +596,7 @@ void TileMap::remove_layer(int p_layer) { // Clear before removing the layer. _clear_internals(); - layers.remove(p_layer); + layers.remove_at(p_layer); _recreate_internals(); notify_property_list_changed(); @@ -741,7 +742,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; @@ -764,9 +765,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); } @@ -809,7 +810,7 @@ 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()) { + for (RBSet<Vector2i>::Element *E = q->self()->cells.front(); E; E = E->next()) { Vector2i pk = E->get(); Vector2i pk_world_coords = map_to_world(pk); q->self()->map_to_world[pk] = pk_world_coords; @@ -866,22 +867,22 @@ void TileMap::_recreate_layer_internals(int p_layer) { return; } - // Upadate the layer internals. + // Update the layer internals. _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); } @@ -895,9 +896,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()) { @@ -916,7 +917,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; } @@ -925,7 +926,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. @@ -953,15 +954,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); } @@ -980,7 +983,7 @@ void TileMap::_recompute_rect_cache() { void TileMap::_rendering_notification(int p_what) { switch (p_what) { - case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: { + case NOTIFICATION_VISIBILITY_CHANGED: { bool visible = is_visible_in_tree(); for (int layer = 0; layer < (int)layers.size(); layer++) { for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) { @@ -997,7 +1000,8 @@ void TileMap::_rendering_notification(int p_what) { } } } break; - case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { + + case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_inside_tree()) { return; } @@ -1016,7 +1020,8 @@ void TileMap::_rendering_notification(int p_what) { } } } break; - case CanvasItem::NOTIFICATION_DRAW: { + + case NOTIFICATION_DRAW: { if (tile_set.is_valid()) { RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), is_y_sort_enabled()); } @@ -1119,7 +1124,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List if (q.runtime_tile_data_cache.has(E_cell.value)) { tile_data = q.runtime_tile_data_cache[E_cell.value]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } Ref<ShaderMaterial> mat = tile_data->get_material(); @@ -1198,7 +1203,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; } @@ -1245,7 +1250,7 @@ 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()) { + for (RBSet<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); TileSetSource *source; @@ -1311,7 +1316,7 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe } // Get tile data. - const TileData *tile_data = p_tile_data_override ? p_tile_data_override : Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile)); + const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile); // Get the tile modulation. Color modulate = tile_data->get_modulate() * p_modulation; @@ -1369,20 +1374,21 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe void TileMap::_physics_notification(int p_what) { switch (p_what) { - case CanvasItem::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { bool in_editor = false; #ifdef TOOLS_ENABLED in_editor = Engine::get_singleton()->is_editor_hint(); #endif if (is_inside_tree() && collision_animatable && !in_editor) { - // Update tranform on the physics tick when in animatable mode. + // Update transform on the physics tick when in animatable mode. last_valid_transform = new_transform; set_notify_local_transform(false); set_global_transform(new_transform); set_notify_local_transform(true); } } break; - case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { + + case NOTIFICATION_TRANSFORM_CHANGED: { bool in_editor = false; #ifdef TOOLS_ENABLED in_editor = Engine::get_singleton()->is_editor_hint(); @@ -1404,6 +1410,7 @@ void TileMap::_physics_notification(int p_what) { } } } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { bool in_editor = false; #ifdef TOOLS_ENABLED @@ -1457,7 +1464,7 @@ 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()) { + for (RBSet<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) { TileMapCell c = get_cell(q.layer, E_cell->get(), true); TileSetSource *source; @@ -1474,7 +1481,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r if (q.runtime_tile_data_cache.has(E_cell->get())) { tile_data = q.runtime_tile_data_cache[E_cell->get()]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } for (int tile_set_physics_layer = 0; tile_set_physics_layer < tile_set->get_physics_layers_count(); tile_set_physics_layer++) { Ref<PhysicsMaterial> physics_material = tile_set->get_physics_layer_physics_material(tile_set_physics_layer); @@ -1600,7 +1607,7 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { void TileMap::_navigation_notification(int p_what) { switch (p_what) { - case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { + case NOTIFICATION_TRANSFORM_CHANGED: { if (is_inside_tree()) { for (int layer = 0; layer < (int)layers.size(); layer++) { Transform2D tilemap_xform = get_global_transform(); @@ -1654,7 +1661,7 @@ 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()) { + for (RBSet<Vector2i>::Element *E_cell = q.cells.front(); E_cell; E_cell = E_cell->next()) { TileMapCell c = get_cell(q.layer, E_cell->get(), true); TileSetSource *source; @@ -1671,7 +1678,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List if (q.runtime_tile_data_cache.has(E_cell->get())) { tile_data = q.runtime_tile_data_cache[E_cell->get()]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + 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()); @@ -1743,7 +1750,7 @@ 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()) { + for (RBSet<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); TileSetSource *source; @@ -1760,7 +1767,7 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { if (p_quadrant->runtime_tile_data_cache.has(E_cell->get())) { tile_data = p_quadrant->runtime_tile_data_cache[E_cell->get()]; } else { - tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } Transform2D xform; @@ -1809,7 +1816,7 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ // Clear the scenes. for (const KeyValue<Vector2i, String> &E : q.scenes) { - Node *node = get_node(E.value); + Node *node = get_node_or_null(E.value); if (node) { node->queue_delete(); } @@ -1818,7 +1825,7 @@ 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()) { + for (RBSet<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); TileSetSource *source; @@ -1857,7 +1864,7 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) { // Clear the scenes. for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) { - Node *node = get_node(E.value); + Node *node = get_node_or_null(E.value); if (node) { node->queue_delete(); } @@ -1876,7 +1883,7 @@ 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()) { + for (RBSet<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); TileSetSource *source; @@ -1918,9 +1925,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; @@ -1928,7 +1935,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c if ((source_id == TileSet::INVALID_SOURCE || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) && (source_id != TileSet::INVALID_SOURCE || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) { - WARN_PRINT("Setting a cell a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly."); + WARN_PRINT("Setting a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly."); source_id = TileSet::INVALID_SOURCE; atlas_coords = TileSetSource::INVALID_ATLAS_COORDS; alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE; @@ -1941,7 +1948,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. @@ -1949,7 +1956,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); @@ -1970,18 +1977,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); @@ -1992,61 +1999,65 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c } } +void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) { + set_cell(p_layer, p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); +} + int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { 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) { @@ -2104,6 +2115,7 @@ Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coo } Vector2i TileMap::map_pattern(Vector2i p_position_in_tilemap, Vector2i p_coords_in_pattern, Ref<TileMapPattern> p_pattern) { + ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i()); ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i()); Vector2i output = p_position_in_tilemap + p_coords_in_pattern; @@ -2133,17 +2145,17 @@ 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) { +RBSet<TileSet::TerrainsPattern> TileMap::_get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) { if (!tile_set.is_valid()) { - return Set<TileSet::TerrainsPattern>(); + return RBSet<TileSet::TerrainsPattern>(); } // Returns all tiles compatible with the given constraints. - Set<TileSet::TerrainsPattern> compatible_terrain_tile_patterns; + RBSet<TileSet::TerrainsPattern> compatible_terrain_tile_patterns; for (TileSet::TerrainsPattern &terrain_pattern : tile_set->get_terrains_pattern_set(p_terrain_set)) { int valid = true; for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { @@ -2151,7 +2163,7 @@ Set<TileSet::TerrainsPattern> TileMap::_get_valid_terrains_patterns_for_constrai if (tile_set->is_valid_peering_bit_terrain(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); + RBSet<TerrainConstraint>::Element *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; @@ -2167,17 +2179,17 @@ Set<TileSet::TerrainsPattern> TileMap::_get_valid_terrains_patterns_for_constrai return compatible_terrain_tile_patterns; } -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_removed_cells_list(int p_layer, const RBSet<Vector2i> &p_to_replace, 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()) { + RBSet<TerrainConstraint> dummy_constraints; + for (RBSet<Vector2i>::Element *E = p_to_replace.front(); E; E = E->next()) { 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)) { @@ -2187,14 +2199,14 @@ Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ce } // 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()) { + RBSet<TerrainConstraint> constraints; + for (RBSet<TerrainConstraint>::Element *E = dummy_constraints.front(); E; E = E->next()) { TerrainConstraint c = E->get(); - Map<int, int> terrain_count; + 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 = c.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; @@ -2203,7 +2215,7 @@ Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ce Ref<TileSetSource> source = tile_set->get_source(neighbor_cell.source_id); Ref<TileSetAtlasSource> atlas_source = source; if (atlas_source.is_valid()) { - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(neighbor_cell.get_atlas_coords(), neighbor_cell.alternative_tile)); + 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; } @@ -2240,13 +2252,13 @@ Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_removed_ce 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 { +RBSet<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { if (!tile_set.is_valid()) { - return Set<TerrainConstraint>(); + return RBSet<TerrainConstraint>(); } // Compute the constraints needed from the surrounding tiles. - Set<TerrainConstraint> output; + RBSet<TerrainConstraint> output; for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { TileSet::CellNeighbor side = TileSet::CellNeighbor(i); if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) { @@ -2258,35 +2270,35 @@ Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_added_tile 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) { +HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse(const RBSet<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) { if (!tile_set.is_valid()) { - return Map<Vector2i, TileSet::TerrainsPattern>(); + return HashMap<Vector2i, TileSet::TerrainsPattern>(); } // Copy the constraints set. - Set<TerrainConstraint> constraints = p_constraints; + RBSet<TerrainConstraint> constraints = p_constraints; // Compute all acceptable patterns for each cell. - Map<Vector2i, Set<TileSet::TerrainsPattern>> per_cell_acceptable_tiles; + HashMap<Vector2i, RBSet<TileSet::TerrainsPattern>> per_cell_acceptable_tiles; for (Vector2i cell : p_to_replace) { per_cell_acceptable_tiles[cell] = _get_valid_terrains_patterns_for_constraints(p_terrain_set, cell, constraints); } // Output map. - Map<Vector2i, TileSet::TerrainsPattern> output; + HashMap<Vector2i, TileSet::TerrainsPattern> output; // Add all positions to a set. - Set<Vector2i> to_replace = Set<Vector2i>(p_to_replace); + RBSet<Vector2i> to_replace = RBSet<Vector2i>(p_to_replace); while (!to_replace.is_empty()) { // Compute the minimum number of tile possibilities for each cell. int min_nb_possibilities = 100000000; - for (const KeyValue<Vector2i, Set<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) { + for (const KeyValue<Vector2i, RBSet<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) { min_nb_possibilities = MIN(min_nb_possibilities, E.value.size()); } // Get the set of possible cells to fill, out of the most constrained ones. LocalVector<Vector2i> to_choose_from; - for (const KeyValue<Vector2i, Set<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) { + for (const KeyValue<Vector2i, RBSet<TileSet::TerrainsPattern>> &E : per_cell_acceptable_tiles) { if (E.value.size() == min_nb_possibilities) { to_choose_from.push_back(E.key); } @@ -2295,8 +2307,8 @@ Map<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse( // 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 pattens for the given cell. - Set<TileSet::TerrainsPattern> valid_tiles = per_cell_acceptable_tiles[selected_cell_to_replace]; + // Get the list of acceptable patterns for the given cell. + RBSet<TileSet::TerrainsPattern> valid_tiles = per_cell_acceptable_tiles[selected_cell_to_replace]; if (valid_tiles.is_empty()) { break; // No possibilities :/ } @@ -2307,7 +2319,7 @@ Map<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse( LocalVector<int> terrains_counts; int pattern_index = 0; for (const TileSet::TerrainsPattern &pattern : valid_tiles) { - Set<int> terrains; + RBSet<int> terrains; for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { TileSet::CellNeighbor side = TileSet::CellNeighbor(i); if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) { @@ -2335,8 +2347,8 @@ Map<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse( per_cell_acceptable_tiles.erase(selected_cell_to_replace); // 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()) { + RBSet<TerrainConstraint> new_constraints = get_terrain_constraints_from_added_tile(selected_cell_to_replace, p_terrain_set, selected_terrain_tile_pattern); + for (RBSet<TerrainConstraint>::Element *E_constraint = new_constraints.front(); E_constraint; E_constraint = E_constraint->next()) { constraints.insert(E_constraint->get()); } @@ -2359,14 +2371,14 @@ void TileMap::set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector ERR_FAIL_INDEX(p_layer, (int)layers.size()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); - Set<Vector2i> coords_set; + RBSet<Vector2i> coords_set; for (int i = 0; i < p_coords_array.size(); i++) { coords_set.insert(p_coords_array[i]); } - Set<TileMap::TerrainConstraint> constraints = get_terrain_constraints_from_removed_cells_list(p_layer, coords_set, p_terrain_set, p_ignore_empty_terrains); + RBSet<TileMap::TerrainConstraint> constraints = get_terrain_constraints_from_removed_cells_list(p_layer, coords_set, p_terrain_set, p_ignore_empty_terrains); - Map<Vector2i, TileSet::TerrainsPattern> wfc_output = terrain_wave_function_collapse(coords_set, p_terrain_set, constraints); + HashMap<Vector2i, TileSet::TerrainsPattern> wfc_output = terrain_wave_function_collapse(coords_set, p_terrain_set, constraints); for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : wfc_output) { TileMapCell cell = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); set_cell(p_layer, kv.key, cell.source_id, cell.get_atlas_coords(), cell.alternative_tile); @@ -2375,11 +2387,11 @@ void TileMap::set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector 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]; @@ -2390,7 +2402,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; @@ -2405,15 +2417,15 @@ 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()) { + for (RBSet<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); } } @@ -2502,10 +2514,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; @@ -2536,7 +2548,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(); @@ -2579,7 +2591,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r if (atlas_source) { bool ret = false; if (GDVIRTUAL_CALL(_use_tile_data_runtime_update, q.layer, E_cell.value, ret) && ret) { - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); + TileData *tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); // Create the runtime TileData. TileData *tile_data_runtime_use = tile_data->duplicate(); @@ -2724,7 +2736,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { } Vector2 TileMap::map_to_world(const Vector2i &p_pos) const { - // SHOULD RETURN THE CENTER OF THE TILE + // SHOULD RETURN THE CENTER OF THE CELL ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2()); Vector2 ret = p_pos; @@ -3365,10 +3377,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; } @@ -3438,8 +3450,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); @@ -3453,8 +3465,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); @@ -3502,7 +3514,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; } @@ -3512,7 +3524,7 @@ 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()) { + for (RBSet<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) { Vector2 center = map_to_world(E->get()); #define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \ @@ -3566,7 +3578,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); @@ -3576,7 +3588,7 @@ TypedArray<String> TileMap::get_configuration_warnings() const { // Check if we have a non-sorted layer in a Z-index with a Y-sorted layer. for (int layer = 0; layer < (int)layers.size(); layer++) { if (!layers[layer].y_sort_enabled && y_sorted_z_index.has(layers[layer].z_index)) { - warnings.push_back(TTR("A Y-sorted layer has the same Z-index value as a not Y-sorted layer.\nThis may lead to unwanted behaviors, as a layer that is not Y-sorted will be Y-sorted as a whole with tiles from Y-sorted layers.")); + warnings.push_back(RTR("A Y-sorted layer has the same Z-index value as a not Y-sorted layer.\nThis may lead to unwanted behaviors, as a layer that is not Y-sorted will be Y-sorted as a whole with tiles from Y-sorted layers.")); break; } } @@ -3616,7 +3628,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_visibility_mode", "navigation_visibility_mode"), &TileMap::set_navigation_visibility_mode); ClassDB::bind_method(D_METHOD("get_navigation_visibility_mode"), &TileMap::get_navigation_visibility_mode); - ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE)); + ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell); ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id); ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords); ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile); @@ -3647,9 +3660,6 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants); - ClassDB::bind_method(D_METHOD("_set_tile_data", "layer", "data"), &TileMap::_set_tile_data); - ClassDB::bind_method(D_METHOD("_get_tile_data", "layer"), &TileMap::_get_tile_data); - ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileMap::_tile_set_changed_deferred_update); GDVIRTUAL_BIND(_use_tile_data_runtime_update, "layer", "coords"); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index f260422290..02a2b3a1c6 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -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; @@ -135,7 +135,7 @@ public: return base_cell_coords; } - Map<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const; + HashMap<Vector2i, TileSet::CellNeighbor> get_overlapping_coords_and_peering_bits() const; void set_terrain(int p_terrain) { terrain = p_terrain; @@ -193,22 +193,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 +217,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 +251,7 @@ 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); + RBSet<TileSet::TerrainsPattern> _get_valid_terrains_patterns_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints); // Set and get tiles from data arrays. void _set_tile_data(int p_layer, const Vector<int> &p_data); @@ -321,7 +321,8 @@ public: VisibilityMode get_navigation_visibility_mode(); // Cells accessors. - void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE); + void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); + void erase_cell(int p_layer, const Vector2i &p_coords); int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; @@ -332,14 +333,14 @@ 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. + RBSet<TerrainConstraint> get_terrain_constraints_from_removed_cells_list(int p_layer, const RBSet<Vector2i> &p_to_replace, int p_terrain_set, bool p_ignore_empty_terrains = true) const; // Not exposed. + RBSet<TerrainConstraint> get_terrain_constraints_from_added_tile(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_wave_function_collapse(const RBSet<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed. void set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector2i> p_coords_array, int p_terrain_set, bool p_ignore_empty_terrains = true); // 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; //--- @@ -376,7 +377,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/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index 8bd7b696f2..4a4a2a1da0 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,13 +32,13 @@ #include "scene/main/window.h" -void TouchScreenButton::set_texture(const Ref<Texture2D> &p_texture) { - texture = p_texture; +void TouchScreenButton::set_texture_normal(const Ref<Texture2D> &p_texture) { + texture_normal = p_texture; update(); } -Ref<Texture2D> TouchScreenButton::get_texture() const { - return texture; +Ref<Texture2D> TouchScreenButton::get_texture_normal() const { + return texture_normal; } void TouchScreenButton::set_texture_pressed(const Ref<Texture2D> &p_texture_pressed) { @@ -107,13 +107,13 @@ void TouchScreenButton::_notification(int p_what) { if (finger_pressed != -1) { if (texture_pressed.is_valid()) { draw_texture(texture_pressed, Point2()); - } else if (texture.is_valid()) { - draw_texture(texture, Point2()); + } else if (texture_normal.is_valid()) { + draw_texture(texture_normal, Point2()); } } else { - if (texture.is_valid()) { - draw_texture(texture, Point2()); + if (texture_normal.is_valid()) { + draw_texture(texture_normal, Point2()); } } @@ -127,15 +127,15 @@ void TouchScreenButton::_notification(int p_what) { Color draw_col = get_tree()->get_debug_collisions_color(); Vector2 pos; - if (shape_centered && texture.is_valid()) { - pos = texture->get_size() * 0.5; + if (shape_centered && texture_normal.is_valid()) { + pos = texture_normal->get_size() * 0.5; } draw_set_transform_matrix(get_canvas_transform().translated(pos)); shape->draw(get_canvas_item(), draw_col); } - } break; + case NOTIFICATION_ENTER_TREE: { if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY) { return; @@ -145,13 +145,14 @@ void TouchScreenButton::_notification(int p_what) { if (!Engine::get_singleton()->is_editor_hint()) { set_process_input(is_visible_in_tree()); } - } break; + case NOTIFICATION_EXIT_TREE: { if (is_pressed()) { _release(true); } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (Engine::get_singleton()->is_editor_hint()) { break; @@ -165,6 +166,7 @@ void TouchScreenButton::_notification(int p_what) { } } } break; + case NOTIFICATION_PAUSED: { if (is_pressed()) { _release(); @@ -188,7 +190,7 @@ String TouchScreenButton::get_action() const { void TouchScreenButton::input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!get_tree()) { + if (!is_visible_in_tree()) { return; } @@ -196,8 +198,6 @@ void TouchScreenButton::input(const Ref<InputEvent> &p_event) { return; } - ERR_FAIL_COND(!is_visible_in_tree()); - const InputEventScreenTouch *st = Object::cast_to<InputEventScreenTouch>(*p_event); if (passby_press) { @@ -254,8 +254,8 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { check_rect = false; Vector2 pos; - if (shape_centered && texture.is_valid()) { - pos = texture->get_size() * 0.5; + if (shape_centered && texture_normal.is_valid()) { + pos = texture_normal->get_size() * 0.5; } touched = shape->collide(Transform2D().translated(pos), unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); @@ -271,8 +271,8 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { } if (!touched && check_rect) { - if (texture.is_valid()) { - touched = Rect2(Size2(), texture->get_size()).has_point(coord); + if (texture_normal.is_valid()) { + touched = Rect2(Size2(), texture_normal->get_size()).has_point(coord); } } @@ -317,24 +317,24 @@ void TouchScreenButton::_release(bool p_exiting_tree) { #ifdef TOOLS_ENABLED Rect2 TouchScreenButton::_edit_get_rect() const { - if (texture.is_null()) { + if (texture_normal.is_null()) { return CanvasItem::_edit_get_rect(); } - return Rect2(Size2(), texture->get_size()); + return Rect2(Size2(), texture_normal->get_size()); } bool TouchScreenButton::_edit_use_rect() const { - return !texture.is_null(); + return !texture_normal.is_null(); } #endif Rect2 TouchScreenButton::get_anchorable_rect() const { - if (texture.is_null()) { + if (texture_normal.is_null()) { return CanvasItem::get_anchorable_rect(); } - return Rect2(Size2(), texture->get_size()); + return Rect2(Size2(), texture_normal->get_size()); } void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) { @@ -355,10 +355,10 @@ bool TouchScreenButton::is_passby_press_enabled() const { } void TouchScreenButton::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TouchScreenButton::set_texture); - ClassDB::bind_method(D_METHOD("get_texture"), &TouchScreenButton::get_texture); + ClassDB::bind_method(D_METHOD("set_texture_normal", "texture"), &TouchScreenButton::set_texture_normal); + ClassDB::bind_method(D_METHOD("get_texture_normal"), &TouchScreenButton::get_texture_normal); - ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture_pressed"), &TouchScreenButton::set_texture_pressed); + ClassDB::bind_method(D_METHOD("set_texture_pressed", "texture"), &TouchScreenButton::set_texture_pressed); ClassDB::bind_method(D_METHOD("get_texture_pressed"), &TouchScreenButton::get_texture_pressed); ClassDB::bind_method(D_METHOD("set_bitmask", "bitmask"), &TouchScreenButton::set_bitmask); @@ -384,8 +384,8 @@ void TouchScreenButton::_bind_methods() { ClassDB::bind_method(D_METHOD("is_pressed"), &TouchScreenButton::is_pressed); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_pressed", "get_texture_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_normal", "get_texture_normal"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_pressed", "get_texture_pressed"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "bitmask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_bitmask", "get_bitmask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shape_centered"), "set_shape_centered", "is_shape_centered"); diff --git a/scene/2d/touch_screen_button.h b/scene/2d/touch_screen_button.h index 1c515149d4..e7f6da9f50 100644 --- a/scene/2d/touch_screen_button.h +++ b/scene/2d/touch_screen_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -46,7 +46,7 @@ public: }; private: - Ref<Texture2D> texture; + Ref<Texture2D> texture_normal; Ref<Texture2D> texture_pressed; Ref<BitMap> bitmask; Ref<Shape2D> shape; @@ -78,8 +78,8 @@ public: virtual bool _edit_use_rect() const override; #endif - void set_texture(const Ref<Texture2D> &p_texture); - Ref<Texture2D> get_texture() const; + void set_texture_normal(const Ref<Texture2D> &p_texture); + Ref<Texture2D> get_texture_normal() const; void set_texture_pressed(const Ref<Texture2D> &p_texture_pressed); Ref<Texture2D> get_texture_pressed() const; diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp index eb4bedb6a3..2aae383cdf 100644 --- a/scene/2d/visible_on_screen_notifier_2d.cpp +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -75,15 +75,16 @@ Rect2 VisibleOnScreenNotifier2D::get_rect() const { void VisibleOnScreenNotifier2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - //get_world_2d()-> on_screen = false; 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)); } break; + case NOTIFICATION_DRAW: { if (Engine::get_singleton()->is_editor_hint()) { draw_rect(rect, Color(1, 0.5, 1, 0.2)); } } break; + case NOTIFICATION_EXIT_TREE: { on_screen = false; RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), false, Rect2(), Callable(), Callable()); @@ -169,21 +170,23 @@ void VisibleOnScreenEnabler2D::_update_enable_mode(bool p_enable) { } } void VisibleOnScreenEnabler2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } - node_id = ObjectID(); - Node *node = get_node(enable_node_path); - if (node) { - node_id = node->get_instance_id(); - node->set_process_mode(PROCESS_MODE_DISABLED); - } - } + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - node_id = ObjectID(); + case NOTIFICATION_EXIT_TREE: { + node_id = ObjectID(); + } break; } } @@ -195,7 +198,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 9c236a138f..3165eb92df 100644 --- a/scene/2d/visible_on_screen_notifier_2d.h +++ b/scene/2d/visible_on_screen_notifier_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -37,7 +37,7 @@ class Viewport; class VisibleOnScreenNotifier2D : public Node2D { GDCLASS(VisibleOnScreenNotifier2D, Node2D); - Set<Viewport *> viewports; + RBSet<Viewport *> viewports; Rect2 rect; |