diff options
Diffstat (limited to 'scene/3d')
-rw-r--r-- | scene/3d/area_3d.cpp | 4 | ||||
-rw-r--r-- | scene/3d/audio_stream_player_3d.cpp | 8 | ||||
-rw-r--r-- | scene/3d/camera_3d.cpp | 4 | ||||
-rw-r--r-- | scene/3d/collision_object_3d.cpp | 38 | ||||
-rw-r--r-- | scene/3d/collision_object_3d.h | 7 | ||||
-rw-r--r-- | scene/3d/collision_polygon_3d.cpp | 12 | ||||
-rw-r--r-- | scene/3d/collision_shape_3d.cpp | 10 | ||||
-rw-r--r-- | scene/3d/decal.cpp | 4 | ||||
-rw-r--r-- | scene/3d/light_3d.cpp | 13 | ||||
-rw-r--r-- | scene/3d/lightmap_gi.cpp | 21 | ||||
-rw-r--r-- | scene/3d/lightmap_gi.h | 2 | ||||
-rw-r--r-- | scene/3d/navigation_agent_3d.cpp | 32 | ||||
-rw-r--r-- | scene/3d/navigation_agent_3d.h | 10 | ||||
-rw-r--r-- | scene/3d/navigation_link_3d.cpp | 98 | ||||
-rw-r--r-- | scene/3d/navigation_link_3d.h | 17 | ||||
-rw-r--r-- | scene/3d/physics_body_3d.cpp | 17 | ||||
-rw-r--r-- | scene/3d/soft_body_3d.cpp | 13 | ||||
-rw-r--r-- | scene/3d/sprite_3d.cpp | 307 | ||||
-rw-r--r-- | scene/3d/sprite_3d.h | 31 | ||||
-rw-r--r-- | scene/3d/visual_instance_3d.cpp | 12 | ||||
-rw-r--r-- | scene/3d/visual_instance_3d.h | 2 | ||||
-rw-r--r-- | scene/3d/voxel_gi.cpp | 2 | ||||
-rw-r--r-- | scene/3d/xr_nodes.cpp | 37 | ||||
-rw-r--r-- | scene/3d/xr_nodes.h | 9 |
24 files changed, 482 insertions, 228 deletions
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index fa61ce5546..72f186c676 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -230,6 +230,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i return; //likely removed from the tree } + lock_callback(); locked = true; if (body_in) { @@ -279,6 +280,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i } locked = false; + unlock_callback(); } void Area3D::_clear_monitoring() { @@ -417,6 +419,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i return; //likely removed from the tree } + lock_callback(); locked = true; if (area_in) { @@ -466,6 +469,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i } locked = false; + unlock_callback(); } bool Area3D::is_monitoring() const { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 574f5363d4..7ed18d2d41 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -784,10 +784,8 @@ bool AudioStreamPlayer3D::get_stream_paused() const { } Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() { - if (!stream_playbacks.is_empty()) { - return stream_playbacks[stream_playbacks.size() - 1]; - } - return nullptr; + ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback()."); + return stream_playbacks[stream_playbacks.size() - 1]; } void AudioStreamPlayer3D::set_max_polyphony(int p_max_polyphony) { @@ -841,7 +839,7 @@ void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer3D::_set_playing); ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer3D::_is_active); - ClassDB::bind_method(D_METHOD("set_max_distance", "metres"), &AudioStreamPlayer3D::set_max_distance); + ClassDB::bind_method(D_METHOD("set_max_distance", "meters"), &AudioStreamPlayer3D::set_max_distance); ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer3D::get_max_distance); ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer3D::set_area_mask); diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index e91948c6e1..47eb1eaa40 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -554,7 +554,7 @@ void Camera3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1,degrees"), "set_fov", "get_fov"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.001,suffix:m"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.001,or_greater,suffix:m"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_frustum_offset", "get_frustum_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far"); @@ -602,7 +602,7 @@ void Camera3D::set_fov(real_t p_fov) { } void Camera3D::set_size(real_t p_size) { - ERR_FAIL_COND(p_size < 0.001 || p_size > 16384); + ERR_FAIL_COND(p_size <= CMP_EPSILON); size = p_size; _update_camera_mode(); } diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index c408b0714a..19d1b83cab 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -43,6 +43,11 @@ void CollisionObject3D::_notification(int p_what) { } _update_debug_shapes(); } +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + set_notify_local_transform(true); // Used for warnings and only in editor. + } +#endif } break; case NOTIFICATION_EXIT_TREE: { @@ -78,6 +83,14 @@ void CollisionObject3D::_notification(int p_what) { _update_pickable(); } break; +#ifdef TOOLS_ENABLED + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; +#endif + case NOTIFICATION_TRANSFORM_CHANGED: { if (only_update_transform_changes) { return; @@ -100,10 +113,14 @@ void CollisionObject3D::_notification(int p_what) { bool disabled = !is_enabled(); if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + if (callback_lock > 0) { + ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead."); } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } } } @@ -223,10 +240,14 @@ void CollisionObject3D::_apply_disabled() { switch (disable_mode) { case DISABLE_MODE_REMOVE: { if (is_inside_tree()) { - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + if (callback_lock > 0) { + ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead."); } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } } } } break; @@ -716,6 +737,11 @@ PackedStringArray CollisionObject3D::get_configuration_warnings() const { warnings.push_back(RTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape.")); } + Vector3 scale = get_transform().get_basis().get_scale(); + if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) { + warnings.push_back(RTR("With a non-uniform scale this node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change the size in children collision shapes instead.")); + } + return warnings; } diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 656b8c9bf1..ebcbb39e0d 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -52,6 +52,7 @@ private: bool area = false; RID rid; + uint32_t callback_lock = 0; DisableMode disable_mode = DISABLE_MODE_REMOVE; @@ -97,6 +98,12 @@ private: protected: CollisionObject3D(RID p_rid, bool p_area); + _FORCE_INLINE_ void lock_callback() { callback_lock++; } + _FORCE_INLINE_ void unlock_callback() { + ERR_FAIL_COND(callback_lock == 0); + callback_lock--; + } + void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index 5fb8970085..53a61c1368 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -104,6 +104,11 @@ void CollisionPolygon3D::_notification(int p_what) { if (parent) { _update_in_shape_owner(true); } +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } +#endif } break; case NOTIFICATION_UNPARENTED: { @@ -171,13 +176,18 @@ PackedStringArray CollisionPolygon3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape.")); + warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node.\nPlease only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape.")); } if (polygon.is_empty()) { warnings.push_back(RTR("An empty CollisionPolygon3D has no effect on collision.")); } + Vector3 scale = get_transform().get_basis().get_scale(); + if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) { + warnings.push_back(RTR("A non-uniformly scaled CollisionPolygon3D node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change its polygon's vertices instead.")); + } + return warnings; } diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 1709a17bce..dbd50cfd19 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -99,6 +99,11 @@ void CollisionShape3D::_notification(int p_what) { if (parent) { _update_in_shape_owner(true); } +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } +#endif } break; case NOTIFICATION_UNPARENTED: { @@ -134,6 +139,11 @@ PackedStringArray CollisionShape3D::get_configuration_warnings() const { } } + Vector3 scale = get_transform().get_basis().get_scale(); + if (!(Math::is_zero_approx(scale.x - scale.y) && Math::is_zero_approx(scale.y - scale.z))) { + warnings.push_back(RTR("A non-uniformly scaled CollisionShape3D node will probably not function as expected.\nPlease make its scale uniform (i.e. the same on all axes), and change the size of its shape resource instead.")); + } + return warnings; } diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index e9cc4e9479..fbcb1c8f2c 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -156,6 +156,10 @@ void Decal::_validate_property(PropertyInfo &p_property) const { if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } + + if (p_property.name == "sorting_offset") { + p_property.usage = PROPERTY_USAGE_DEFAULT; + } } PackedStringArray Decal::get_configuration_warnings() const { diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 77073ff763..cca84c2b85 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -157,9 +157,16 @@ AABB Light3D::get_aabb() const { return AABB(Vector3(-1, -1, -1) * param[PARAM_RANGE], Vector3(2, 2, 2) * param[PARAM_RANGE]); } else if (type == RenderingServer::LIGHT_SPOT) { - real_t len = param[PARAM_RANGE]; - real_t size = Math::tan(Math::deg_to_rad(param[PARAM_SPOT_ANGLE])) * len; - return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); + real_t cone_slant_height = param[PARAM_RANGE]; + real_t cone_angle_rad = Math::deg_to_rad(param[PARAM_SPOT_ANGLE]); + + if (cone_angle_rad > Math_PI / 2.0) { + // Just return the AABB of an omni light if the spot angle is above 90 degrees. + return AABB(Vector3(-1, -1, -1) * cone_slant_height, Vector3(2, 2, 2) * cone_slant_height); + } + + real_t size = Math::sin(cone_angle_rad) * cone_slant_height; + return AABB(Vector3(-size, -size, -cone_slant_height), Vector3(2 * size, 2 * size, cone_slant_height)); } return AABB(); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 6940bad4a6..fb74cffc94 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -455,8 +455,8 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc Plane best_plane; float best_plane_score = -1.0; - for (uint32_t i = 0; i < p_simplex_indices.size(); i++) { - const BSPSimplex &s = p_simplices[p_simplex_indices[i]]; + for (const int idx : p_simplex_indices) { + const BSPSimplex &s = p_simplices[idx]; for (int j = 0; j < 4; j++) { uint32_t plane_index = s.planes[j]; if (planes_tested[plane_index] == node_index) { @@ -484,8 +484,8 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc int over_count = 0; int under_count = 0; - for (uint32_t k = 0; k < p_simplex_indices.size(); k++) { - int side = _bsp_get_simplex_side(p_points, p_simplices, plane, p_simplex_indices[k]); + for (const int &index : p_simplex_indices) { + int side = _bsp_get_simplex_side(p_points, p_simplices, plane, index); if (side == -2) { continue; //this simplex is invalid, skip for now } else if (side < 0) { @@ -523,8 +523,7 @@ int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const Loc LocalVector<int32_t> indices_under; //split again, but add to list - for (uint32_t i = 0; i < p_simplex_indices.size(); i++) { - uint32_t index = p_simplex_indices[i]; + for (const uint32_t index : p_simplex_indices) { int side = _bsp_get_simplex_side(p_points, p_simplices, best_plane, index); if (side == -2) { @@ -977,8 +976,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } } - for (uint32_t i = 0; i < new_probe_positions.size(); i++) { - probes_found.push_back(new_probe_positions[i]); + for (const Vector3 &position : new_probe_positions) { + probes_found.push_back(position); } } @@ -1219,8 +1218,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa LocalVector<BSPNode> bsp_nodes; LocalVector<int32_t> planes_tested; planes_tested.resize(bsp_planes.size()); - for (uint32_t i = 0; i < planes_tested.size(); i++) { - planes_tested[i] = 0x7FFFFFFF; + for (int &index : planes_tested) { + index = 0x7FFFFFFF; } if (p_bake_step) { @@ -1546,6 +1545,8 @@ void LightmapGI::_bind_methods() { BIND_ENUM_CONSTANT(GENERATE_PROBES_SUBDIV_32); BIND_ENUM_CONSTANT(BAKE_ERROR_OK); + BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SCENE_ROOT); + BIND_ENUM_CONSTANT(BAKE_ERROR_FOREIGN_DATA); BIND_ENUM_CONSTANT(BAKE_ERROR_NO_LIGHTMAPPER); BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SAVE_PATH); BIND_ENUM_CONSTANT(BAKE_ERROR_NO_MESHES); diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index 1294571cc0..40ff9e4cad 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -124,6 +124,8 @@ public: enum BakeError { BAKE_ERROR_OK, + BAKE_ERROR_NO_SCENE_ROOT, + BAKE_ERROR_FOREIGN_DATA, BAKE_ERROR_NO_LIGHTMAPPER, BAKE_ERROR_NO_SAVE_PATH, BAKE_ERROR_NO_MESHES, diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 0034bf78b9..fe7ddcb06e 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -80,10 +80,10 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent3D::set_navigation_map); ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent3D::get_navigation_map); - ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent3D::set_target_location); - ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent3D::get_target_location); + ClassDB::bind_method(D_METHOD("set_target_position", "position"), &NavigationAgent3D::set_target_position); + ClassDB::bind_method(D_METHOD("get_target_position"), &NavigationAgent3D::get_target_position); - ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent3D::get_next_location); + ClassDB::bind_method(D_METHOD("get_next_path_position"), &NavigationAgent3D::get_next_path_position); ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent3D::distance_to_target); ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent3D::set_velocity); ClassDB::bind_method(D_METHOD("get_current_navigation_result"), &NavigationAgent3D::get_current_navigation_result); @@ -92,12 +92,12 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent3D::is_target_reached); ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent3D::is_target_reachable); ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent3D::is_navigation_finished); - ClassDB::bind_method(D_METHOD("get_final_location"), &NavigationAgent3D::get_final_location); + ClassDB::bind_method(D_METHOD("get_final_position"), &NavigationAgent3D::get_final_position); ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent3D::_avoidance_done); ADD_GROUP("Pathfinding", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_location", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_location", "get_target_location"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_position", "get_target_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_path_desired_distance", "get_path_desired_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_target_desired_distance", "get_target_desired_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset"); @@ -344,17 +344,17 @@ real_t NavigationAgent3D::get_path_max_distance() { return path_max_distance; } -void NavigationAgent3D::set_target_location(Vector3 p_location) { - target_location = p_location; +void NavigationAgent3D::set_target_position(Vector3 p_position) { + target_position = p_position; target_position_submitted = true; _request_repath(); } -Vector3 NavigationAgent3D::get_target_location() const { - return target_location; +Vector3 NavigationAgent3D::get_target_position() const { + return target_position; } -Vector3 NavigationAgent3D::get_next_location() { +Vector3 NavigationAgent3D::get_next_path_position() { update_navigation(); const Vector<Vector3> &navigation_path = navigation_result->get_path(); @@ -368,7 +368,7 @@ Vector3 NavigationAgent3D::get_next_location() { real_t NavigationAgent3D::distance_to_target() const { ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent."); - return agent_parent->get_global_transform().origin.distance_to(target_location); + return agent_parent->get_global_transform().origin.distance_to(target_position); } bool NavigationAgent3D::is_target_reached() const { @@ -376,7 +376,7 @@ bool NavigationAgent3D::is_target_reached() const { } bool NavigationAgent3D::is_target_reachable() { - return target_desired_distance >= get_final_location().distance_to(target_location); + return target_desired_distance >= get_final_position().distance_to(target_position); } bool NavigationAgent3D::is_navigation_finished() { @@ -384,7 +384,7 @@ bool NavigationAgent3D::is_navigation_finished() { return navigation_finished; } -Vector3 NavigationAgent3D::get_final_location() { +Vector3 NavigationAgent3D::get_final_position() { update_navigation(); const Vector<Vector3> &navigation_path = navigation_result->get_path(); @@ -467,7 +467,7 @@ void NavigationAgent3D::update_navigation() { if (reload_path) { navigation_query->set_start_position(origin); - navigation_query->set_target_position(target_location); + navigation_query->set_target_position(target_position); navigation_query->set_navigation_layers(navigation_layers); navigation_query->set_metadata_flags(path_metadata_flags); @@ -489,7 +489,7 @@ void NavigationAgent3D::update_navigation() { // Check if we can advance the navigation path if (navigation_finished == false) { - // Advances to the next far away location. + // Advances to the next far away position. const Vector<Vector3> &navigation_path = navigation_result->get_path(); const Vector<int32_t> &navigation_path_types = navigation_result->get_path_types(); const TypedArray<RID> &navigation_path_rids = navigation_result->get_path_rids(); @@ -499,7 +499,7 @@ void NavigationAgent3D::update_navigation() { Dictionary details; const Vector3 waypoint = navigation_path[navigation_path_index]; - details[SNAME("location")] = waypoint; + details[SNAME("position")] = waypoint; int waypoint_type = -1; if (path_metadata_flags.has_flag(NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_TYPES)) { diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index 91be068392..12f83ce6a8 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -62,7 +62,7 @@ class NavigationAgent3D : public Node { real_t path_max_distance = 3.0; - Vector3 target_location; + Vector3 target_position; bool target_position_submitted = false; Ref<NavigationPathQueryParameters3D> navigation_query; Ref<NavigationPathQueryResult3D> navigation_result; @@ -155,10 +155,10 @@ public: void set_path_max_distance(real_t p_pmd); real_t get_path_max_distance(); - void set_target_location(Vector3 p_location); - Vector3 get_target_location() const; + void set_target_position(Vector3 p_position); + Vector3 get_target_position() const; - Vector3 get_next_location(); + Vector3 get_next_path_position(); Ref<NavigationPathQueryResult3D> get_current_navigation_result() const { return navigation_result; @@ -174,7 +174,7 @@ public: bool is_target_reached() const; bool is_target_reachable(); bool is_navigation_finished(); - Vector3 get_final_location(); + Vector3 get_final_position(); void set_velocity(Vector3 p_velocity); void _avoidance_done(Vector3 p_new_velocity); diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp index e058ef62d0..f47fcfaf51 100644 --- a/scene/3d/navigation_link_3d.cpp +++ b/scene/3d/navigation_link_3d.cpp @@ -70,10 +70,10 @@ void NavigationLink3D::_update_debug_mesh() { Vector<Vector3> lines; // Draw line between the points. - lines.push_back(start_location); - lines.push_back(end_location); + lines.push_back(start_position); + lines.push_back(end_position); - // Draw start location search radius + // Draw start position search radius for (int i = 0; i < 30; i++) { // Create a circle const float ra = Math::deg_to_rad((float)(i * 12)); @@ -84,21 +84,21 @@ void NavigationLink3D::_update_debug_mesh() { // Draw axis-aligned circle switch (up_axis) { case Vector3::AXIS_X: - lines.append(start_location + Vector3(0, a.x, a.y)); - lines.append(start_location + Vector3(0, b.x, b.y)); + lines.append(start_position + Vector3(0, a.x, a.y)); + lines.append(start_position + Vector3(0, b.x, b.y)); break; case Vector3::AXIS_Y: - lines.append(start_location + Vector3(a.x, 0, a.y)); - lines.append(start_location + Vector3(b.x, 0, b.y)); + lines.append(start_position + Vector3(a.x, 0, a.y)); + lines.append(start_position + Vector3(b.x, 0, b.y)); break; case Vector3::AXIS_Z: - lines.append(start_location + Vector3(a.x, a.y, 0)); - lines.append(start_location + Vector3(b.x, b.y, 0)); + lines.append(start_position + Vector3(a.x, a.y, 0)); + lines.append(start_position + Vector3(b.x, b.y, 0)); break; } } - // Draw end location search radius + // Draw end position search radius for (int i = 0; i < 30; i++) { // Create a circle const float ra = Math::deg_to_rad((float)(i * 12)); @@ -109,16 +109,16 @@ void NavigationLink3D::_update_debug_mesh() { // Draw axis-aligned circle switch (up_axis) { case Vector3::AXIS_X: - lines.append(end_location + Vector3(0, a.x, a.y)); - lines.append(end_location + Vector3(0, b.x, b.y)); + lines.append(end_position + Vector3(0, a.x, a.y)); + lines.append(end_position + Vector3(0, b.x, b.y)); break; case Vector3::AXIS_Y: - lines.append(end_location + Vector3(a.x, 0, a.y)); - lines.append(end_location + Vector3(b.x, 0, b.y)); + lines.append(end_position + Vector3(a.x, 0, a.y)); + lines.append(end_position + Vector3(b.x, 0, b.y)); break; case Vector3::AXIS_Z: - lines.append(end_location + Vector3(a.x, a.y, 0)); - lines.append(end_location + Vector3(b.x, b.y, 0)); + lines.append(end_position + Vector3(a.x, a.y, 0)); + lines.append(end_position + Vector3(b.x, b.y, 0)); break; } } @@ -157,11 +157,11 @@ void NavigationLink3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink3D::set_navigation_layer_value); ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink3D::get_navigation_layer_value); - ClassDB::bind_method(D_METHOD("set_start_location", "location"), &NavigationLink3D::set_start_location); - ClassDB::bind_method(D_METHOD("get_start_location"), &NavigationLink3D::get_start_location); + ClassDB::bind_method(D_METHOD("set_start_position", "position"), &NavigationLink3D::set_start_position); + ClassDB::bind_method(D_METHOD("get_start_position"), &NavigationLink3D::get_start_position); - ClassDB::bind_method(D_METHOD("set_end_location", "location"), &NavigationLink3D::set_end_location); - ClassDB::bind_method(D_METHOD("get_end_location"), &NavigationLink3D::get_end_location); + ClassDB::bind_method(D_METHOD("set_end_position", "position"), &NavigationLink3D::set_end_position); + ClassDB::bind_method(D_METHOD("get_end_position"), &NavigationLink3D::get_end_position); ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink3D::set_enter_cost); ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink3D::get_enter_cost); @@ -172,12 +172,38 @@ void NavigationLink3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional"); ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_location"), "set_start_location", "get_start_location"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "end_location"), "set_end_location", "get_end_location"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_position"), "set_start_position", "get_start_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "end_position"), "set_end_position", "get_end_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); } +#ifndef DISABLE_DEPRECATED +bool NavigationLink3D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "start_location") { + set_start_position(p_value); + return true; + } + if (p_name == "end_location") { + set_end_position(p_value); + return true; + } + return false; +} + +bool NavigationLink3D::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == "start_location") { + r_ret = get_start_position(); + return true; + } + if (p_name == "end_location") { + r_ret = get_end_position(); + return true; + } + return false; +} +#endif // DISABLE_DEPRECATED + void NavigationLink3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -186,8 +212,8 @@ void NavigationLink3D::_notification(int p_what) { // Update global positions for the link. Transform3D gt = get_global_transform(); - NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); - NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + NavigationServer3D::get_singleton()->link_set_start_position(link, gt.xform(start_position)); + NavigationServer3D::get_singleton()->link_set_end_position(link, gt.xform(end_position)); } #ifdef DEBUG_ENABLED @@ -197,8 +223,8 @@ void NavigationLink3D::_notification(int p_what) { case NOTIFICATION_TRANSFORM_CHANGED: { // Update global positions for the link. Transform3D gt = get_global_transform(); - NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); - NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + NavigationServer3D::get_singleton()->link_set_start_position(link, gt.xform(start_position)); + NavigationServer3D::get_singleton()->link_set_end_position(link, gt.xform(end_position)); #ifdef DEBUG_ENABLED if (is_inside_tree() && debug_instance.is_valid()) { @@ -316,19 +342,19 @@ bool NavigationLink3D::get_navigation_layer_value(int p_layer_number) const { return get_navigation_layers() & (1 << (p_layer_number - 1)); } -void NavigationLink3D::set_start_location(Vector3 p_location) { - if (start_location.is_equal_approx(p_location)) { +void NavigationLink3D::set_start_position(Vector3 p_position) { + if (start_position.is_equal_approx(p_position)) { return; } - start_location = p_location; + start_position = p_position; if (!is_inside_tree()) { return; } Transform3D gt = get_global_transform(); - NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); + NavigationServer3D::get_singleton()->link_set_start_position(link, gt.xform(start_position)); #ifdef DEBUG_ENABLED _update_debug_mesh(); @@ -338,19 +364,19 @@ void NavigationLink3D::set_start_location(Vector3 p_location) { update_configuration_warnings(); } -void NavigationLink3D::set_end_location(Vector3 p_location) { - if (end_location.is_equal_approx(p_location)) { +void NavigationLink3D::set_end_position(Vector3 p_position) { + if (end_position.is_equal_approx(p_position)) { return; } - end_location = p_location; + end_position = p_position; if (!is_inside_tree()) { return; } Transform3D gt = get_global_transform(); - NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + NavigationServer3D::get_singleton()->link_set_end_position(link, gt.xform(end_position)); #ifdef DEBUG_ENABLED _update_debug_mesh(); @@ -385,8 +411,8 @@ void NavigationLink3D::set_travel_cost(real_t p_travel_cost) { PackedStringArray NavigationLink3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); - if (start_location.is_equal_approx(end_location)) { - warnings.push_back(RTR("NavigationLink3D start location should be different than the end location to be useful.")); + if (start_position.is_equal_approx(end_position)) { + warnings.push_back(RTR("NavigationLink3D start position should be different than the end position to be useful.")); } return warnings; diff --git a/scene/3d/navigation_link_3d.h b/scene/3d/navigation_link_3d.h index 175c5cdd5d..5c9ec36189 100644 --- a/scene/3d/navigation_link_3d.h +++ b/scene/3d/navigation_link_3d.h @@ -40,8 +40,8 @@ class NavigationLink3D : public Node3D { RID link; bool bidirectional = true; uint32_t navigation_layers = 1; - Vector3 end_location; - Vector3 start_location; + Vector3 end_position; + Vector3 start_position; real_t enter_cost = 0.0; real_t travel_cost = 1.0; @@ -56,6 +56,11 @@ protected: static void _bind_methods(); void _notification(int p_what); +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; +#endif // DISABLE_DEPRECATED + public: NavigationLink3D(); ~NavigationLink3D(); @@ -72,11 +77,11 @@ public: void set_navigation_layer_value(int p_layer_number, bool p_value); bool get_navigation_layer_value(int p_layer_number) const; - void set_start_location(Vector3 p_location); - Vector3 get_start_location() const { return start_location; } + void set_start_position(Vector3 p_position); + Vector3 get_start_position() const { return start_position; } - void set_end_location(Vector3 p_location); - Vector3 get_end_location() const { return end_location; } + void set_end_position(Vector3 p_position); + Vector3 get_end_position() const { return end_position; } void set_enter_cost(real_t p_enter_cost); real_t get_enter_cost() const { return enter_cost; } diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 46956b0a2e..f4ab09cd9b 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -484,6 +484,8 @@ struct _RigidBodyInOut { }; void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { + lock_callback(); + set_ignore_transform_notification(true); set_global_transform(p_state->get_transform()); @@ -578,6 +580,8 @@ void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { contact_monitor->locked = false; } + + unlock_callback(); } void RigidBody3D::_notification(int p_what) { @@ -973,12 +977,11 @@ TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const { } PackedStringArray RigidBody3D::get_configuration_warnings() const { - Transform3D t = get_transform(); - - PackedStringArray warnings = Node::get_configuration_warnings(); + PackedStringArray warnings = CollisionObject3D::get_configuration_warnings(); - if (ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05) { - warnings.push_back(RTR("Size changes to RigidBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + Vector3 scale = get_transform().get_basis().get_scale(); + if (ABS(scale.x - 1.0) > 0.05 || ABS(scale.y - 1.0) > 0.05 || ABS(scale.z - 1.0) > 0.05) { + warnings.push_back(RTR("Scale changes to RigidBody3D will be overridden by the physics engine when running.\nPlease change the size in children collision shapes instead.")); } return warnings; @@ -1343,7 +1346,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo motion = motion.slide(up_direction); result.travel = Vector3(); } else { - // Travel is too high to be safely cancelled, we take it into account. + // Travel is too high to be safely canceled, we take it into account. result.travel = result.travel.slide(up_direction); motion = motion.normalized() * result.travel.length(); } @@ -1351,7 +1354,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Determines if you are on the ground, and limits the possibility of climbing on the walls because of the approximations. _snap_on_floor(true, false); } else { - // If the movement is not cancelled we only keep the remaining. + // If the movement is not canceled we only keep the remaining. motion = result.remainder; } diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index e8b51ceb92..e7e3084037 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -302,14 +302,6 @@ void SoftBody3D::_notification(int p_what) { _prepare_physics_server(); } } break; - -#ifdef TOOLS_ENABLED - case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - } - } break; -#endif } } @@ -391,11 +383,6 @@ PackedStringArray SoftBody3D::get_configuration_warnings() const { warnings.push_back(RTR("This body will be ignored until you set a mesh.")); } - Transform3D t = get_transform(); - if ((ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05)) { - warnings.push_back(RTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); - } - return warnings; } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 71d76c0d1c..635c566ef8 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -866,7 +866,6 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { } if (p_property.name == "animation") { - p_property.hint = PROPERTY_HINT_ENUM; List<StringName> names; frames->get_animation_list(&names); names.sort_custom<StringName::AlphCompare>(); @@ -916,6 +915,12 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { void AnimatedSprite3D::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_READY: { + if (!Engine::get_singleton()->is_editor_hint() && !frames.is_null() && frames->has_animation(autoplay)) { + play(autoplay); + } + } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (frames.is_null() || !frames->has_animation(animation)) { return; @@ -925,7 +930,8 @@ void AnimatedSprite3D::_notification(int p_what) { int i = 0; while (remaining) { // Animation speed may be changed by animation_finished or frame_changed signals. - double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale); + double speed = frames->get_animation_speed(animation) * speed_scale * custom_speed_scale * frame_speed_scale; + double abs_speed = Math::abs(speed); if (speed == 0) { return; // Do nothing. @@ -934,53 +940,57 @@ void AnimatedSprite3D::_notification(int p_what) { // Frame count may be changed by animation_finished or frame_changed signals. int fc = frames->get_frame_count(animation); - if (timeout <= 0) { - int last_frame = fc - 1; - if (!playing_backwards) { - // Forward. + int last_frame = fc - 1; + if (!signbit(speed)) { + // Forwards. + if (frame_progress >= 1.0) { if (frame >= last_frame) { if (frames->get_animation_loop(animation)) { frame = 0; - emit_signal(SceneStringNames::get_singleton()->animation_finished); + emit_signal("animation_looped"); } else { frame = last_frame; - if (!is_over) { - is_over = true; - emit_signal(SceneStringNames::get_singleton()->animation_finished); - } + pause(); + emit_signal(SceneStringNames::get_singleton()->animation_finished); + return; } } else { frame++; } - } else { - // Reversed. + _calc_frame_speed_scale(); + frame_progress = 0.0; + _queue_redraw(); + emit_signal(SceneStringNames::get_singleton()->frame_changed); + } + double to_process = MIN((1.0 - frame_progress) / abs_speed, remaining); + frame_progress += to_process * abs_speed; + remaining -= to_process; + } else { + // Backwards. + if (frame_progress <= 0) { if (frame <= 0) { if (frames->get_animation_loop(animation)) { frame = last_frame; - emit_signal(SceneStringNames::get_singleton()->animation_finished); + emit_signal("animation_looped"); } else { frame = 0; - if (!is_over) { - is_over = true; - emit_signal(SceneStringNames::get_singleton()->animation_finished); - } + pause(); + emit_signal(SceneStringNames::get_singleton()->animation_finished); + return; } } else { frame--; } + _calc_frame_speed_scale(); + frame_progress = 1.0; + _queue_redraw(); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } - - timeout = _get_frame_duration(); - - _queue_redraw(); - - emit_signal(SceneStringNames::get_singleton()->frame_changed); + double to_process = MIN(frame_progress / abs_speed, remaining); + frame_progress -= to_process * abs_speed; + remaining -= to_process; } - double to_process = MIN(timeout / speed, remaining); - timeout -= to_process * speed; - remaining -= to_process; - i++; if (i > fc) { return; // Prevents freezing if to_process is each time much less than remaining. @@ -991,25 +1001,37 @@ void AnimatedSprite3D::_notification(int p_what) { } void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { + if (frames == p_frames) { + return; + } + if (frames.is_valid()) { frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed)); } - + stop(); frames = p_frames; if (frames.is_valid()) { frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed)); - } - if (frames.is_null()) { - frame = 0; - } else { - set_frame(frame); + List<StringName> al; + frames->get_animation_list(&al); + if (al.size() == 0) { + set_animation(StringName()); + set_autoplay(String()); + } else { + if (!frames->has_animation(animation)) { + set_animation(al[0]); + } + if (!frames->has_animation(autoplay)) { + set_autoplay(String()); + } + } } notify_property_list_changed(); - _reset_timeout(); _queue_redraw(); update_configuration_warnings(); + emit_signal("sprite_frames_changed"); } Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const { @@ -1017,44 +1039,63 @@ Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const { } void AnimatedSprite3D::set_frame(int p_frame) { + set_frame_and_progress(p_frame, signbit(get_playing_speed()) ? 1.0 : 0.0); +} + +int AnimatedSprite3D::get_frame() const { + return frame; +} + +void AnimatedSprite3D::set_frame_progress(real_t p_progress) { + frame_progress = p_progress; +} + +real_t AnimatedSprite3D::get_frame_progress() const { + return frame_progress; +} + +void AnimatedSprite3D::set_frame_and_progress(int p_frame, real_t p_progress) { if (frames.is_null()) { return; } - if (frames->has_animation(animation)) { - int limit = frames->get_frame_count(animation); - if (p_frame >= limit) { - p_frame = limit - 1; - } - } + bool has_animation = frames->has_animation(animation); + int end_frame = has_animation ? MAX(0, frames->get_frame_count(animation) - 1) : 0; + bool is_changed = frame != p_frame; if (p_frame < 0) { - p_frame = 0; + frame = 0; + } else if (has_animation && p_frame > end_frame) { + frame = end_frame; + } else { + frame = p_frame; } - if (frame == p_frame) { - return; - } + _calc_frame_speed_scale(); + frame_progress = p_progress; - frame = p_frame; - _reset_timeout(); + if (!is_changed) { + return; // No change, don't redraw. + } _queue_redraw(); emit_signal(SceneStringNames::get_singleton()->frame_changed); } -int AnimatedSprite3D::get_frame() const { - return frame; -} - void AnimatedSprite3D::set_speed_scale(float p_speed_scale) { speed_scale = p_speed_scale; - playing_backwards = signbit(speed_scale) != backwards; } float AnimatedSprite3D::get_speed_scale() const { return speed_scale; } +float AnimatedSprite3D::get_playing_speed() const { + if (!playing) { + return 0; + } + return speed_scale * custom_speed_scale; +} + Rect2 AnimatedSprite3D::get_item_rect() const { if (frames.is_null() || !frames->has_animation(animation)) { return Rect2(0, 0, 1, 1); @@ -1085,69 +1126,130 @@ Rect2 AnimatedSprite3D::get_item_rect() const { } void AnimatedSprite3D::_res_changed() { - set_frame(frame); + set_frame_and_progress(frame, frame_progress); _queue_redraw(); notify_property_list_changed(); } -void AnimatedSprite3D::set_playing(bool p_playing) { - if (playing == p_playing) { - return; +bool AnimatedSprite3D::is_playing() const { + return playing; +} + +void AnimatedSprite3D::set_autoplay(const String &p_name) { + if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) { + WARN_PRINT("Setting autoplay after the node has been added to the scene has no effect."); } - playing = p_playing; - playing_backwards = signbit(speed_scale) != backwards; - set_process_internal(playing); - notify_property_list_changed(); + + autoplay = p_name; } -bool AnimatedSprite3D::is_playing() const { - return playing; +String AnimatedSprite3D::get_autoplay() const { + return autoplay; } -void AnimatedSprite3D::play(const StringName &p_animation, bool p_backwards) { - backwards = p_backwards; - playing_backwards = signbit(speed_scale) != backwards; +void AnimatedSprite3D::play(const StringName &p_name, float p_custom_scale, bool p_from_end) { + StringName name = p_name; + + if (name == StringName()) { + name = animation; + } + + ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", name)); + ERR_FAIL_COND_MSG(!frames->get_animation_names().has(name), vformat("There is no animation with name '%s'.", name)); - if (p_animation) { - set_animation(p_animation); - if (frames.is_valid() && playing_backwards && get_frame() == 0) { - set_frame(frames->get_frame_count(p_animation) - 1); + if (frames->get_frame_count(name) == 0) { + return; + } + + playing = true; + custom_speed_scale = p_custom_scale; + + int end_frame = MAX(0, frames->get_frame_count(animation) - 1); + if (name != animation) { + animation = name; + if (p_from_end) { + set_frame_and_progress(end_frame, 1.0); + } else { + set_frame_and_progress(0, 0.0); + } + emit_signal("animation_changed"); + } else { + bool is_backward = signbit(speed_scale * custom_speed_scale); + if (p_from_end && is_backward && frame == 0 && frame_progress <= 0.0) { + set_frame_and_progress(end_frame, 1.0); + } else if (!p_from_end && !is_backward && frame == end_frame && frame_progress >= 1.0) { + set_frame_and_progress(0, 0.0); } } - is_over = false; - set_playing(true); + notify_property_list_changed(); + set_process_internal(true); +} + +void AnimatedSprite3D::play_backwards(const StringName &p_name) { + play(p_name, -1, true); +} + +void AnimatedSprite3D::_stop_internal(bool p_reset) { + playing = false; + if (p_reset) { + custom_speed_scale = 1.0; + set_frame_and_progress(0, 0.0); + } + notify_property_list_changed(); + set_process_internal(false); +} + +void AnimatedSprite3D::pause() { + _stop_internal(false); } void AnimatedSprite3D::stop() { - set_playing(false); - backwards = false; - _reset_timeout(); + _stop_internal(true); } double AnimatedSprite3D::_get_frame_duration() { if (frames.is_valid() && frames->has_animation(animation)) { return frames->get_frame_duration(animation, frame); } - return 0.0; + return 1.0; } -void AnimatedSprite3D::_reset_timeout() { - timeout = _get_frame_duration(); - is_over = false; +void AnimatedSprite3D::_calc_frame_speed_scale() { + frame_speed_scale = 1.0 / _get_frame_duration(); } -void AnimatedSprite3D::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().has(p_animation), vformat("There is no animation with name '%s'.", p_animation)); +void AnimatedSprite3D::set_animation(const StringName &p_name) { + if (animation == p_name) { + return; + } + + animation = p_name; - if (animation == p_animation) { + emit_signal("animation_changed"); + + if (frames == nullptr) { + animation = StringName(); + stop(); + ERR_FAIL_MSG(vformat("There is no animation with name '%s'.", p_name)); + } + + int frame_count = frames->get_frame_count(animation); + if (animation == StringName() || frame_count == 0) { + stop(); return; + } else if (!frames->get_animation_names().has(animation)) { + animation = StringName(); + stop(); + ERR_FAIL_MSG(vformat("There is no animation with name '%s'.", p_name)); + } + + if (signbit(get_playing_speed())) { + set_frame_and_progress(frame_count - 1, 1.0); + } else { + set_frame_and_progress(0, 0.0); } - animation = p_animation; - set_frame(0); - _reset_timeout(); notify_property_list_changed(); _queue_redraw(); } @@ -1175,35 +1277,58 @@ void AnimatedSprite3D::get_argument_options(const StringName &p_function, int p_ Node::get_argument_options(p_function, p_idx, r_options); } +#ifndef DISABLE_DEPRECATED +bool AnimatedSprite3D::_set(const StringName &p_name, const Variant &p_value) { + if ((p_name == SNAME("frames"))) { + set_sprite_frames(p_value); + return true; + } + return false; +} +#endif void AnimatedSprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite3D::set_sprite_frames); ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite3D::get_sprite_frames); - ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite3D::set_animation); + ClassDB::bind_method(D_METHOD("set_animation", "name"), &AnimatedSprite3D::set_animation); ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite3D::get_animation); - ClassDB::bind_method(D_METHOD("set_playing", "playing"), &AnimatedSprite3D::set_playing); + ClassDB::bind_method(D_METHOD("set_autoplay", "name"), &AnimatedSprite3D::set_autoplay); + ClassDB::bind_method(D_METHOD("get_autoplay"), &AnimatedSprite3D::get_autoplay); + ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing); - ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite3D::play, DEFVAL(StringName()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("play", "name", "custom_speed", "from_end"), &AnimatedSprite3D::play, DEFVAL(StringName()), DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("play_backwards", "name"), &AnimatedSprite3D::play_backwards, DEFVAL(StringName())); + ClassDB::bind_method(D_METHOD("pause"), &AnimatedSprite3D::pause); ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite3D::stop); ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame); ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame); + ClassDB::bind_method(D_METHOD("set_frame_progress", "progress"), &AnimatedSprite3D::set_frame_progress); + ClassDB::bind_method(D_METHOD("get_frame_progress"), &AnimatedSprite3D::get_frame_progress); + + ClassDB::bind_method(D_METHOD("set_frame_and_progress", "frame", "progress"), &AnimatedSprite3D::set_frame_and_progress); + ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite3D::set_speed_scale); ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite3D::get_speed_scale); + ClassDB::bind_method(D_METHOD("get_playing_speed"), &AnimatedSprite3D::get_playing_speed); ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed); + ADD_SIGNAL(MethodInfo("sprite_frames_changed")); + ADD_SIGNAL(MethodInfo("animation_changed")); ADD_SIGNAL(MethodInfo("frame_changed")); + ADD_SIGNAL(MethodInfo("animation_looped")); ADD_SIGNAL(MethodInfo("animation_finished")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sprite_frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation", PROPERTY_HINT_ENUM, ""), "set_animation", "get_animation"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "autoplay", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_autoplay", "get_autoplay"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frame_progress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_frame_progress", "get_frame_progress"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "set_playing", "is_playing"); } AnimatedSprite3D::AnimatedSprite3D() { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index c5509aa723..d0fd767d89 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -209,24 +209,29 @@ class AnimatedSprite3D : public SpriteBase3D { GDCLASS(AnimatedSprite3D, SpriteBase3D); Ref<SpriteFrames> frames; + String autoplay; + bool playing = false; - bool playing_backwards = false; - bool backwards = false; StringName animation = "default"; int frame = 0; float speed_scale = 1.0; + float custom_speed_scale = 1.0; bool centered = false; - bool is_over = false; - double timeout = 0.0; + real_t frame_speed_scale = 1.0; + real_t frame_progress = 0.0; void _res_changed(); double _get_frame_duration(); - void _reset_timeout(); + void _calc_frame_speed_scale(); + void _stop_internal(bool p_reset); protected: +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); +#endif virtual void _draw() override; static void _bind_methods(); void _notification(int p_what); @@ -236,20 +241,30 @@ public: void set_sprite_frames(const Ref<SpriteFrames> &p_frames); Ref<SpriteFrames> get_sprite_frames() const; - void play(const StringName &p_animation = StringName(), bool p_backwards = false); + void play(const StringName &p_name = StringName(), float p_custom_scale = 1.0, bool p_from_end = false); + void play_backwards(const StringName &p_name = StringName()); + void pause(); void stop(); - void set_playing(bool p_playing); bool is_playing() const; - void set_animation(const StringName &p_animation); + void set_animation(const StringName &p_name); StringName get_animation() const; + void set_autoplay(const String &p_name); + String get_autoplay() const; + void set_frame(int p_frame); int get_frame() const; + void set_frame_progress(real_t p_progress); + real_t get_frame_progress() const; + + void set_frame_and_progress(int p_frame, real_t p_progress); + void set_speed_scale(float p_speed_scale); float get_speed_scale() const; + float get_playing_speed() const; virtual Rect2 get_item_rect() const override; diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 64fb0a7657..8026b12c2b 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -120,6 +120,12 @@ bool VisualInstance3D::is_sorting_use_aabb_center() const { return sorting_use_aabb_center; } +void VisualInstance3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") { + p_property.usage = PROPERTY_USAGE_NONE; + } +} + void VisualInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base); ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base); @@ -437,6 +443,12 @@ PackedStringArray GeometryInstance3D::get_configuration_warnings() const { return warnings; } +void GeometryInstance3D::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") { + p_property.usage = PROPERTY_USAGE_DEFAULT; + } +} + void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override); ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 190ed17753..ef0f7966e2 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -47,6 +47,7 @@ protected: void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; GDVIRTUAL0RC(AABB, _get_aabb) public: @@ -140,6 +141,7 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index 4325152a7b..41dc27352f 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -502,7 +502,7 @@ void VoxelGI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_NONE, "suffix:m"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ALWAYS_DUPLICATE), "set_probe_data", "get_probe_data"); BIND_ENUM_CONSTANT(SUBDIV_64); BIND_ENUM_CONSTANT(SUBDIV_128); diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index a758cc5e5e..ac0a47d1a1 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -432,15 +432,16 @@ PackedStringArray XRNode3D::get_configuration_warnings() const { void XRController3D::_bind_methods() { // passthroughs to information about our related joystick ClassDB::bind_method(D_METHOD("is_button_pressed", "name"), &XRController3D::is_button_pressed); - ClassDB::bind_method(D_METHOD("get_value", "name"), &XRController3D::get_value); - ClassDB::bind_method(D_METHOD("get_axis", "name"), &XRController3D::get_axis); + ClassDB::bind_method(D_METHOD("get_input", "name"), &XRController3D::get_input); + ClassDB::bind_method(D_METHOD("get_float", "name"), &XRController3D::get_float); + ClassDB::bind_method(D_METHOD("get_vector2", "name"), &XRController3D::get_vector2); ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand); ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name"))); - ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value"))); - ADD_SIGNAL(MethodInfo("input_axis_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "value"))); + ADD_SIGNAL(MethodInfo("input_float_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value"))); + ADD_SIGNAL(MethodInfo("input_vector2_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "value"))); }; void XRController3D::_bind_tracker() { @@ -449,8 +450,8 @@ void XRController3D::_bind_tracker() { // bind to input signals tracker->connect("button_pressed", callable_mp(this, &XRController3D::_button_pressed)); tracker->connect("button_released", callable_mp(this, &XRController3D::_button_released)); - tracker->connect("input_value_changed", callable_mp(this, &XRController3D::_input_value_changed)); - tracker->connect("input_axis_changed", callable_mp(this, &XRController3D::_input_axis_changed)); + tracker->connect("input_float_changed", callable_mp(this, &XRController3D::_input_float_changed)); + tracker->connect("input_vector2_changed", callable_mp(this, &XRController3D::_input_vector2_changed)); } } @@ -459,8 +460,8 @@ void XRController3D::_unbind_tracker() { // unbind input signals tracker->disconnect("button_pressed", callable_mp(this, &XRController3D::_button_pressed)); tracker->disconnect("button_released", callable_mp(this, &XRController3D::_button_released)); - tracker->disconnect("input_value_changed", callable_mp(this, &XRController3D::_input_value_changed)); - tracker->disconnect("input_axis_changed", callable_mp(this, &XRController3D::_input_axis_changed)); + tracker->disconnect("input_float_changed", callable_mp(this, &XRController3D::_input_float_changed)); + tracker->disconnect("input_vector2_changed", callable_mp(this, &XRController3D::_input_vector2_changed)); } XRNode3D::_unbind_tracker(); @@ -476,14 +477,14 @@ void XRController3D::_button_released(const String &p_name) { emit_signal(SNAME("button_released"), p_name); } -void XRController3D::_input_value_changed(const String &p_name, float p_value) { +void XRController3D::_input_float_changed(const String &p_name, float p_value) { // just pass it on... - emit_signal(SNAME("input_value_changed"), p_name, p_value); + emit_signal(SNAME("input_float_changed"), p_name, p_value); } -void XRController3D::_input_axis_changed(const String &p_name, Vector2 p_value) { +void XRController3D::_input_vector2_changed(const String &p_name, Vector2 p_value) { // just pass it on... - emit_signal(SNAME("input_axis_changed"), p_name, p_value); + emit_signal(SNAME("input_vector2_changed"), p_name, p_value); } bool XRController3D::is_button_pressed(const StringName &p_name) const { @@ -496,7 +497,15 @@ bool XRController3D::is_button_pressed(const StringName &p_name) const { } } -float XRController3D::get_value(const StringName &p_name) const { +Variant XRController3D::get_input(const StringName &p_name) const { + if (tracker.is_valid()) { + return tracker->get_input(p_name); + } else { + return Variant(); + } +} + +float XRController3D::get_float(const StringName &p_name) const { if (tracker.is_valid()) { // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type, but just in case we convert Variant input = tracker->get_input(p_name); @@ -517,7 +526,7 @@ float XRController3D::get_value(const StringName &p_name) const { } } -Vector2 XRController3D::get_axis(const StringName &p_name) const { +Vector2 XRController3D::get_vector2(const StringName &p_name) const { if (tracker.is_valid()) { // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type, but just in case we convert Variant input = tracker->get_input(p_name); diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index c93cb14d62..6e56aa28de 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -131,13 +131,14 @@ protected: void _button_pressed(const String &p_name); void _button_released(const String &p_name); - void _input_value_changed(const String &p_name, float p_value); - void _input_axis_changed(const String &p_name, Vector2 p_value); + void _input_float_changed(const String &p_name, float p_value); + void _input_vector2_changed(const String &p_name, Vector2 p_value); public: bool is_button_pressed(const StringName &p_name) const; - float get_value(const StringName &p_name) const; - Vector2 get_axis(const StringName &p_name) const; + Variant get_input(const StringName &p_name) const; + float get_float(const StringName &p_name) const; + Vector2 get_vector2(const StringName &p_name) const; XRPositionalTracker::TrackerHand get_tracker_hand() const; |